001package com.hfg.sql.table;
002
003import java.sql.ResultSet;
004import java.sql.SQLException;
005import java.util.List;
006
007import com.hfg.xml.XMLTag;
008
009//------------------------------------------------------------------------------
010/**
011 Database row object which has Long as a primary key.
012 <div>
013 @author J. Alex Taylor, hairyfatguy.com
014 </div>
015 */
016//------------------------------------------------------------------------------
017// com.hfg XML/HTML Coding Library
018//
019// This library is free software; you can redistribute it and/or
020// modify it under the terms of the GNU Lesser General Public
021// License as published by the Free Software Foundation; either
022// version 2.1 of the License, or (at your option) any later version.
023//
024// This library is distributed in the hope that it will be useful,
025// but WITHOUT ANY WARRANTY; without even the implied warranty of
026// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
027// Lesser General Public License for more details.
028//
029// You should have received a copy of the GNU Lesser General Public
030// License along with this library; if not, write to the Free Software
031// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
032//
033// J. Alex Taylor, President, Founder, CEO, COO, CFO, OOPS hairyfatguy.com
034// jataylor@hairyfatguy.com
035//------------------------------------------------------------------------------
036
037public abstract class DatabaseRowWithLongPrimaryKey extends DatabaseRow
038{
039
040   // Cached value
041   private Long mRowId;
042
043   //###########################################################################
044   // CONSTRUCTORS
045   //###########################################################################
046
047   //---------------------------------------------------------------------------
048   public DatabaseRowWithLongPrimaryKey(DatabaseTable<? extends DatabaseRow> inTable)
049   {
050      super(inTable);
051   }
052
053   //---------------------------------------------------------------------------
054   public DatabaseRowWithLongPrimaryKey(DatabaseTable<? extends DatabaseRow> inTable, ResultSet inResultSet)
055   {
056      super(inTable, inResultSet);
057   }
058
059   //---------------------------------------------------------------------------
060   public DatabaseRowWithLongPrimaryKey(XMLTag inXMLTag)
061   {
062      super(inXMLTag);
063   }
064
065
066   //###########################################################################
067   // PUBLIC METHODS
068   //###########################################################################
069
070   //---------------------------------------------------------------------------
071   public Long getId()
072   {
073      if (null == mRowId)
074      {
075         mRowId = (Long) getField(getIdCol()).getValue();
076      }
077
078      return mRowId;
079   }
080
081   //---------------------------------------------------------------------------
082   @SuppressWarnings("unchecked")
083   public void clearId()
084   {
085      getField(getIdCol()).setValue(null);
086      mRowId = null;
087   }
088
089   //---------------------------------------------------------------------------
090   /**
091    Searches a List of DatabaseRowWithLongPrimaryKey objects sorted in ascending order
092    to find the matching row with the specified id. Slower than a HashMap approach
093    but more memory efficient. More performant when used with ArrayLists than with LinkedLists.
094    * @param inList the sorted List to be searched
095    * @param inTargetRowId the row id to be searched for
096    * @return the index of the row with the matching rowId or -1 if it is not present in the list
097    */
098   public static int interpolationSearch(List<? extends DatabaseRowWithLongPrimaryKey> inList,
099                                         Long inTargetRowId)
100   {
101      int listSize = inList.size();
102      int leftIdx = 0;
103      int rightIdx = inList.size() - 1;
104
105      DatabaseRowWithLongPrimaryKey leftRow  = inList.get(leftIdx);
106      DatabaseRowWithLongPrimaryKey rightRow = inList.get(rightIdx);
107
108      while (leftIdx < rightIdx)
109      {
110         // Guess where to check next
111         int nextIdx = leftIdx + (int) ((inTargetRowId - leftRow.getId()) * (rightIdx - leftIdx) /
112                                        (rightRow.getId() - leftRow.getId()));
113
114         if (nextIdx < 0)
115         {
116            nextIdx = 0;
117         }
118         else if (nextIdx >= listSize)
119         {
120            nextIdx = listSize - 1;
121         }
122
123         long comparison = inTargetRowId - inList.get(nextIdx).getId();
124         if (0 == comparison)
125         {
126            return nextIdx;
127         }
128         else if (comparison < 0)
129         {
130            if (nextIdx <= 0
131                || rightIdx <= nextIdx - 1)
132            {
133               break; // Or we'll end up in an infinite loop
134            }
135
136            rightIdx = nextIdx - 1;
137            rightRow = inList.get(rightIdx);
138         }
139         else
140         {
141            if (nextIdx == listSize - 1
142                || leftIdx >= nextIdx + 1)
143            {
144               break; // Or we'll end up in an infinite loop
145            }
146
147            leftIdx = nextIdx + 1;
148            leftRow = inList.get(leftIdx);
149         }
150      }
151
152      return (inTargetRowId.equals(leftRow.getId()) ? leftIdx : -1);
153   }
154
155}