package com.idega.data;
import java.sql.Connection;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.sql.Statement;
import java.util.ArrayList;
import java.util.Collection;
import java.util.Collections;
import java.util.Comparator;
import java.util.HashMap;
import java.util.Iterator;
import java.util.List;
import java.util.ListIterator;
import java.util.RandomAccess;
import java.util.Vector;
import java.util.logging.Level;
import java.util.logging.Logger;
import javax.ejb.FinderException;
import com.idega.data.query.Criteria;
import com.idega.data.query.InCriteria;
import com.idega.data.query.JoinCriteria;
import com.idega.data.query.MatchCriteria;
import com.idega.data.query.Order;
import com.idega.data.query.SelectQuery;
import com.idega.data.query.Table;
import com.idega.data.query.WildCardColumn;
import com.idega.util.logging.LoggingHelper;
/**
* <p>Title: idegaWeb</p>
* <p>Description: </p>
* <p>Copyright: Copyright (c) 2002</p>
* <p>Company: idega Software</p>
* @author <a href="gummi@idega.is">Gudmundur Agust Saemundsson</a>
* @version 2.0
*/
public class IDOPrimaryKeyList extends Vector implements List, Runnable {
//TODO gummi: replace GenericEntity with IDOEntity and IDOContainer
private String _dataSource = GenericEntity.DEFAULT_DATASOURCE;
private SelectQuery _sqlQuery;
private SelectQuery _loadQueryBase;
private GenericEntity _entity;
private Class allowedPrimaryKeyClass; // varaable set in the initialize method where it is fetched ones from the variable _entity for optimizing reasons
private String pkColumnName;
private Table sqlQueryTable;
private GenericEntity _returnProxy;
private String _returnProxyPkColumnName;
private Table _returnProxySqlQueryTable;
private SelectQuery _returnProxyQueryConstraints;
private int _cursor = 0;
//This Vector contains the loaded IDOEntities but the super list of this object contains list of all primary keys
private Vector _entities=null;
private LoadTracker _tracker;
private int fetchSize = 1;
private int _prefetchSize=100;
private boolean isSublist = false;
private IDOPrimaryKeyList() {
}
// private void reloadResultSet(){
//
// }
private void debugPKs(){
debug("[IDOPrimaryKeyList]: _PKs content ->");
debug("Index\tObject");
debug("-----\t------");
ListIterator iter = this._entities.listIterator();
int count=0;
boolean showNulls = true;
while (iter.hasNext()) {
int index = iter.nextIndex();
Object item = iter.next();
if(item != null || showNulls){
debug(index+"\t"+item);
if(item != null){
showNulls = true;
} else {
showNulls = false;
count++;
}
} else {
count++;
}
}
debug("Number of null objects: "+count);
debug("[IDOPrimaryKeyList]: _PKs content ends");
}
public IDOPrimaryKeyList(SelectQuery sqlQuery, GenericEntity entity, int prefetchSize) throws IDOFinderException {
this(sqlQuery,entity,null,null,prefetchSize);
}
public IDOPrimaryKeyList(SelectQuery sqlQuery, GenericEntity entity, GenericEntity returnProxy, SelectQuery proxyQueryConstraints, int prefetchSize) throws IDOFinderException {
this._sqlQuery = sqlQuery;
// _Stmt = Stmt;
// _RS = RS;
this._entity = entity;
if (entity != null) {
this._dataSource = entity.getDatasource();
}
this._prefetchSize = prefetchSize;
this._returnProxy = returnProxy;
this._returnProxyQueryConstraints = proxyQueryConstraints;
initialize(null);
}
public IDOPrimaryKeyList(Collection primaryKeyList, GenericEntity entity, int prefetchSize) throws IDOFinderException {
this._sqlQuery = null;
// _Stmt = Stmt;
// _RS = RS;
this._entity = entity;
if (entity != null) {
this._dataSource = entity.getDatasource();
}
this._prefetchSize = prefetchSize;
initialize(primaryKeyList);
}
public IDOPrimaryKeyList(Collection primaryKeyList, Class entityInterfaceClass, int prefetchSize) throws IDOFinderException {
this._sqlQuery = null;
// _Stmt = Stmt;
// _RS = RS;
this._entity = (GenericEntity)IDOLookup.instanciateEntity(entityInterfaceClass);
if (this._entity != null) {
this._dataSource = this._entity.getDatasource();
}
this._prefetchSize = prefetchSize;
initialize(primaryKeyList);
}
private void loadInBackground(){
Thread thread = new Thread(this);
thread.setPriority(Thread.MIN_PRIORITY);
thread.start();
}
public void run() {
// int loadIntervalSize = fetchSize;
// if(_size < loadIntervalSize){
try {
loadSubset(0,size());
}
catch (Exception ex) {
logError("["+this.getClass()+"]: Exeption: "+ex.getClass()+" occured while executing: "+this._sqlQuery);
}
// } else {
// try{
// int numberOfSubsets = _size/loadIntervalSize + ((_size%loadIntervalSize > 0)?1:0);
// for (int i = 0; i < loadIntervalSize; i++) {
// loadSubset(i*loadIntervalSize, (i+1)*loadIntervalSize);
// }
// }
// catch (Exception ex) {
// logError("["+this.getClass()+"]: Exeption: "+ex.getClass()+" occured while executing: "+_sqlQuery);
// }
// }
}
private void initialize(Collection primaryKeyCollection) throws IDOFinderException {
IDOPrimaryKeyDefinition pkDefinition = this._entity.getEntityDefinition().getPrimaryKeyDefinition();
IDOEntityField[] pkFields = pkDefinition.getFields();
if(pkFields==null || pkFields.length>1){
throw new UnsupportedOperationException("IDOPrimaryKeyList is capable of handling entities whith one primary key only, this entity: "+this._entity.getClass().getName()+" has "+ ((pkFields==null)?"none":String.valueOf(pkFields.length)));
}
this.allowedPrimaryKeyClass = pkDefinition.getPrimaryKeyClass();
this.pkColumnName = pkFields[0].getSQLFieldName();
if (this._sqlQuery != null && this._sqlQuery.getBaseTable() != null) {
this.sqlQueryTable = this._sqlQuery.getBaseTable();
} else {
this.sqlQueryTable = new Table(this._entity);
}
if(this._returnProxy!=null){
IDOPrimaryKeyDefinition proxyPkDefinition = this._returnProxy.getEntityDefinition().getPrimaryKeyDefinition();
IDOEntityField[] proxyPkFields = proxyPkDefinition.getFields();
if(pkFields==null || pkFields.length>1){
throw new UnsupportedOperationException("IDOPrimaryKeyList is capable of handling entities whith one primary key only, this entity: "+this._returnProxy.getClass().getName()+" has "+ ((pkFields==null)?"none":String.valueOf(pkFields.length)));
}
this._returnProxyPkColumnName = proxyPkFields[0].getSQLFieldName();
this._returnProxySqlQueryTable = new Table(this._returnProxy);
}
if(primaryKeyCollection != null){
debug("[IDOPrimaryKeyList - Initialize - primary key list added]: length "+ primaryKeyCollection.size());
super.addAll(primaryKeyCollection);
this._entities = new Vector();
this._entities.setSize(size());
this._tracker = new LoadTracker(size(),this.fetchSize);
} else {
SelectQuery initialQuery = (SelectQuery)this._sqlQuery.clone();
this._loadQueryBase = (SelectQuery)this._sqlQuery.clone();
initialQuery.removeAllColumns();
initialQuery.addColumn(this.sqlQueryTable,this.pkColumnName);
if(this._returnProxy!=null && this._returnProxyQueryConstraints!=null){
boolean join = false;
Collection criteria = this._returnProxyQueryConstraints.getCriteria();
if(criteria!=null && !criteria.isEmpty()){
for (Iterator iter = criteria.iterator(); iter.hasNext();) {
Criteria cr = (Criteria) iter.next();
initialQuery.addCriteria(cr);
}
join = true;
}
Collection order = this._returnProxyQueryConstraints.getOrder();
if(order!=null && !order.isEmpty()){
for (Iterator iter = order.iterator(); iter.hasNext();) {
Order o = (Order) iter.next();
initialQuery.addOrder(o);
this._loadQueryBase.addOrder(o);
}
join = true;
}
if(join){
initialQuery.addJoin(this.sqlQueryTable,this.pkColumnName,this._returnProxySqlQueryTable,this._returnProxyPkColumnName);
}
}
initialQuery.addOrder(this.sqlQueryTable,this.pkColumnName,true);
this._loadQueryBase.addOrder(this.sqlQueryTable,this.pkColumnName,true);
Connection conn = null;
Statement Stmt = null;
ResultSet RS=null;
try
{
conn = this._entity.getConnection(this._entity.getDatasource());
Stmt = null;//conn.createStatement();
if (this._entity.isDebugActive())
{
debug("[IDOPrimaryKeyList - Initialize - orginal query]: "+ this._sqlQuery.toString());
debug("[IDOPrimaryKeyList - Initialize - modified query]: "+ initialQuery.toString());
debug("[IDOPrimaryKeyList - Initialize - load query base]: "+ this._loadQueryBase.toString());
}
List placeHolderValues = initialQuery.getValues();
if(placeHolderValues==null || placeHolderValues.isEmpty()){
Stmt = conn.createStatement();
RS = Stmt.executeQuery(initialQuery.toString());
}
// use PreparedStatement
else{
Stmt = conn.prepareStatement(initialQuery.toString(true));
DatastoreInterface dsi = DatastoreInterface.getInstance(this._entity);
dsi.insertIntoPreparedStatement(placeHolderValues,(PreparedStatement)Stmt,1);
RS = ((PreparedStatement)Stmt).executeQuery();
}
//ResultSet RS=Stmt.executeQuery(initialQuery.toString());
this._entities = new Vector();
// int fetchIndex = 0;
Object pk = null;
while(RS.next()){
pk = this._entity.getPrimaryKeyFromResultSet(this.allowedPrimaryKeyClass,pkFields,RS);
super.add(pk);
// if(fetchIndex++<=_prefetchSize){
// _entities.add(_entity.prefetchBeanFromResultSet(pk, RS,_entity.getDatasource()));
// }
}
RS.close();
this._entities.setSize(size());
this._tracker = new LoadTracker(size(),this.fetchSize);
// _tracker.setSubsetAsLoaded(0,_prefetchSize);
}
catch (SQLException sqle)
{
logError("[IDOPrimaryKeyList]: Went to database for SQL query: " + initialQuery);
throw new IDOFinderException(sqle);
}
// catch (FinderException e) {
// logError("[IDOPrimaryKeyList]: Went to database for SQL query: " + _sqlQuery);
// e.printStackTrace();
// throw new IDOFinderException(e);
// }
finally
{
if (Stmt != null)
{
try
{
Stmt.close();
}
catch (SQLException e)
{
e.printStackTrace();
}
}
// if(RS!=null){
// try {
// RS.close();
// }
// catch (SQLException e) {
// e.printStackTrace();
// }
// }
if (conn != null)
{
this._entity.freeConnection(this._entity.getDatasource(), conn);
}
}
}
}
/**
* @param fromIndex low endpoint (inclusive).
* @param toIndex high endpoint (exclusive).
*/
private void loadSubset(int fromIndex, int toIndex) throws IDOFinderException
{
List setsToLoad = this._tracker.getNotLoadedSubsets(fromIndex,toIndex);
if (this._entity.isDebugActive())
{
debug("############################[PrimaryKeyList]: method loadSubset ##################################");
debug("[PrimaryKeyList]: method loadSubset("+fromIndex+","+toIndex+") before");
}
if(setsToLoad != null && !setsToLoad.isEmpty())
{
DatastoreInterface iFace = DatastoreInterface.getInstance(this._entity);
for (Iterator iter = setsToLoad.iterator(); iter.hasNext();) {
int[] item = (int[]) iter.next();
int fIndex = item[LoadTracker.FROM_INDEX_IN_ARRAY];
int tIndex = item[LoadTracker.TO_INDEX_IN_ARRAY];
int partitionSize = iFace.getOptimalEJBLoadFetchSize();
int partitions = (tIndex-fIndex)/partitionSize;
if((tIndex-fIndex)%partitionSize>0){
partitions++;
}
for(int i = 0; i < partitions; i++){
int f = fIndex+(i*partitionSize);
int t =Math.min(tIndex,f+partitionSize);
if(f<=t){
if (this._entity.isDebugActive())
{
debug("[PrimaryKeyList]: method loadList("+f+","+t+") before");
}
this._tracker.printLoadInformations();
loadSubset(subList(f,t), f);
if (this._entity.isDebugActive())
{
debug("[PrimaryKeyList]: after");
this._tracker.printLoadInformations();
}
} else {
logError("[PrimaryKeyList]: method loadList(...) from > to, "+f+" > "+t);
}
}
}
}
}
private void loadSubset(List listOfPrimaryKeys, int firstIndex) throws IDOFinderException {
SelectQuery subsetQuery = null;
GenericEntity proxyEntity = this._entity;
if(this._loadQueryBase==null){
subsetQuery = new SelectQuery(this.sqlQueryTable);
subsetQuery.addColumn(new WildCardColumn(this.sqlQueryTable));
if(listOfPrimaryKeys.size()==1){
Object pk = listOfPrimaryKeys.get(0);
if(pk instanceof String){
subsetQuery.addCriteria(new MatchCriteria(this.sqlQueryTable,this.pkColumnName,MatchCriteria.EQUALS,(String)pk,true));
} else {
subsetQuery.addCriteria(new MatchCriteria(this.sqlQueryTable,this.pkColumnName,MatchCriteria.EQUALS,pk));
}
} else {
subsetQuery.addCriteria(new InCriteria(this.sqlQueryTable,this.pkColumnName,listOfPrimaryKeys));
}
} else {
subsetQuery = (SelectQuery)this._loadQueryBase.clone();
subsetQuery.removeAllCriteria();
subsetQuery.clearLeftJoins();
if(listOfPrimaryKeys.size()==1){
Object pk = listOfPrimaryKeys.get(0);
if(pk instanceof String){
subsetQuery.addCriteria(new MatchCriteria(this.sqlQueryTable,this.pkColumnName,MatchCriteria.EQUALS,(String)pk,true));
} else {
subsetQuery.addCriteria(new MatchCriteria(this.sqlQueryTable,this.pkColumnName,MatchCriteria.EQUALS,pk));
}
} else {
subsetQuery.addCriteria(new InCriteria(this.sqlQueryTable,this.pkColumnName,listOfPrimaryKeys));
}
if(this._returnProxy!=null){
subsetQuery.removeAllColumns();
subsetQuery.addColumn(new WildCardColumn(this._returnProxySqlQueryTable));
subsetQuery.addCriteria(new JoinCriteria(this.sqlQueryTable.getColumn(this.pkColumnName),this._returnProxySqlQueryTable.getColumn(this._returnProxyPkColumnName)));
proxyEntity = this._returnProxy;
}
}
Connection conn = null;
Statement Stmt = null;
try {
conn = proxyEntity.getConnection(this._dataSource);
Stmt = null;
//conn.createStatement();
if (this._entity.isDebugActive())
{
debug("[IDOPrimaryKeyList - Load index "+firstIndex+" to "+(firstIndex+listOfPrimaryKeys.size())+"]: "+ subsetQuery);
}
//ResultSet RS=Stmt.executeQuery(subsetQuery.toString());
ResultSet RS = null;
List placeHolderValues = subsetQuery.getValues();
if(placeHolderValues==null || placeHolderValues.isEmpty()){
Stmt = conn.createStatement();
RS = Stmt.executeQuery(subsetQuery.toString());
}
// use PreparedStatement
else{
Stmt = conn.prepareStatement(subsetQuery.toString(true));
DatastoreInterface dsi = DatastoreInterface.getInstance(this._entity);
dsi.insertIntoPreparedStatement(placeHolderValues,(PreparedStatement)Stmt,1);
RS = ((PreparedStatement)Stmt).executeQuery();
}
int total = 0;
int no = 0;
IDOHome home = (IDOHome)proxyEntity.getEJBLocalHome();
Class interfaceClass = proxyEntity.getInterfaceClass();
if(this._loadQueryBase==null){ // if there is no SQL query the primaryKeys must be added by searching the pk list for the right index
HashMap mapOfEntities = new HashMap();
while(RS.next())
{
Object pk = proxyEntity.getPrimaryKeyFromResultSet(RS);
if (pk != null)
{
try {
IDOEntity bean = IDOContainer.getInstance().findByPrimaryKey(interfaceClass, pk, RS, home,this._dataSource);
//IDOEntity bean = proxyEntity.prefetchBeanFromResultSet(pk, RS,);
mapOfEntities.put(pk,bean);
} catch (FinderException e) {
//The row must have been deleted from database
// this.remove(pk);
e.printStackTrace();
}
}
total++;
}
Iterator iter = listOfPrimaryKeys.iterator();
for (int i = firstIndex; iter.hasNext();i++) {
Object pk = iter.next();
Object entity = mapOfEntities.get(pk);
this._entities.set(i,entity);
// _tracker.setAsLoaded(firstIndex+i);
if(entity == null) {
System.out.println("An entity was not found, id=" + pk);
} else if(!this.get(i).equals(((IDOEntity)this._entities.get(i)).getPrimaryKey())){
no++;;
logError("[IDOPrimaryKeyList]: At index "+(i)+" loadSubset set entity with primary key "+pk+" but the primaryKeyList contains primary key "+this.get(i)+" at that index");
logError("[IDOPrimaryKeyList]: The right index would have been "+indexOf(pk));
}
}
this._tracker.setSubsetAsLoaded(firstIndex,firstIndex+listOfPrimaryKeys.size());
} else {
for(int i = firstIndex; RS.next(); i++)
{
Object pk = proxyEntity.getPrimaryKeyFromResultSet(RS);
if (pk != null)
{
try {
IDOEntity bean = IDOContainer.getInstance().findByPrimaryKey(interfaceClass, pk, RS, home,this._dataSource);
this._entities.set(i,bean);
if(!pk.equals(this.get(i))){
// logError("[IDOPrimaryKeyList - WARNING]: "+ subsetQuery);
no++;
logError("[IDOPrimaryKeyList]: At index "+i+" loadSubset set entity with primary key "+pk+" but the primaryKeyList contains primary key "+this.get(i)+" at that index");
logError("[IDOPrimaryKeyList]: The right index would have been "+indexOf(pk));
}
//Althoug the same object is more than ones in the primary key list it is only ones
//in the resultset. Since the primary key list is orderd by id we can assume that the
//duplicated primary keys lie side by side.
int numberOfEqualObjectsInSequence = 1;
while(this.size()>(i+numberOfEqualObjectsInSequence) && this.get(i).equals(this.get(i+numberOfEqualObjectsInSequence))){
this._entities.set(i+numberOfEqualObjectsInSequence,bean);
numberOfEqualObjectsInSequence++;
}
i+=numberOfEqualObjectsInSequence-1;
total+=numberOfEqualObjectsInSequence-1;
} catch (FinderException e) {
//The row must have been deleted from database
// this.remove(pk);
e.printStackTrace();
}
}
total++;
}
this._tracker.setSubsetAsLoaded(firstIndex,firstIndex+listOfPrimaryKeys.size());
}
if (this._entity.isDebugActive())
{
logError("[IDOPrimaryKeyList]: "+no+" of "+total+ " where not loaded right");
}
RS.close();
} catch (SQLException sqle) {
logError("[IDOPrimaryKeyList]: Went to database for SQL query: " + subsetQuery);
sqle.printStackTrace();
throw new IDOFinderException(sqle);
} finally {
if (Stmt != null) {
try {
Stmt.close();
}
catch (SQLException e) {
e.printStackTrace();
}
}
if (conn != null) {
proxyEntity.freeConnection(proxyEntity.getDatasource(), conn);
}
}
}
public Object validatePrimaryKeyObject(Object o){
if(!this.allowedPrimaryKeyClass.equals(o.getClass())){
throw new UnsupportedOperationException("Object of type "+o.getClass().getName()+" is not allowed as primary key in this IDOPrimaryKeyList, it needs to be "+this.allowedPrimaryKeyClass.getName());
}
return o;
}
public IDOEntity validateIDOEntityObject(IDOEntity o){
if(!this._entity.getInterfaceClass().equals(o.getEntityDefinition().getInterfaceClass())){
throw new UnsupportedOperationException("Object of type "+o.getEntityDefinition().getInterfaceClass()+" is not allowed as entity in this IDOPrimaryKeyList/IDOEntityList, it needs to be "+this._entity.getInterfaceClass().getName());
}
return o;
}
public void clear() {
super.clear();
this._entities.clear();
this._tracker = new LoadTracker(0,this.fetchSize);
//_initialized=false;
}
/**
* Logs out to the default log level (which is by default INFO)
* @param msg The message to log out
*/
protected void log(String msg) {
//System.out.println(string);
getLogger().log(getDefaultLogLevel(),msg);
}
/**
* Logs out to the error log level (which is by default WARNING) to the default Logger
* @param e The Exception to log out
*/
protected void log(Exception e) {
LoggingHelper.logException(e,this,getLogger(),getErrorLogLevel());
}
/**
* Logs out to the specified log level to the default Logger
* @param level The log level
* @param msg The message to log out
*/
protected void log(Level level,String msg) {
//System.out.println(msg);
getLogger().log(level,msg);
}
/**
* Logs out to the error log level (which is by default WARNING) to the default Logger
* @param msg The message to log out
*/
protected void logError(String msg) {
//logError(msg);
getLogger().log(getErrorLogLevel(),msg);
}
/**
* Logs out to the debug log level (which is by default FINER) to the default Logger
* @param msg The message to log out
*/
protected void logDebug(String msg) {
//System.err.println(msg);
getLogger().log(getDebugLogLevel(),msg);
}
/**
* Logs out to the SEVERE log level to the default Logger
* @param msg The message to log out
*/
protected void logSevere(String msg) {
//System.err.println(msg);
getLogger().log(Level.SEVERE,msg);
}
/**
* Logs out to the WARNING log level to the default Logger
* @param msg The message to log out
*/
protected void logWarning(String msg) {
//System.err.println(msg);
getLogger().log(Level.WARNING,msg);
}
/**
* Logs out to the CONFIG log level to the default Logger
* @param msg The message to log out
*/
protected void logConfig(String msg) {
//System.err.println(msg);
getLogger().log(Level.CONFIG,msg);
}
/**
* Logs out to the debug log level to the default Logger
* @param msg The message to log out
*/
protected void debug(String msg) {
logDebug(msg);
}
/**
* Gets the default Logger. By default it uses the package and the class name to get the logger.<br>
* This behaviour can be overridden in subclasses.
* @return the default Logger
*/
protected Logger getLogger(){
return Logger.getLogger(this.getClass().getName());
}
/**
* Gets the log level which messages are sent to when no log level is given.
* @return the Level
*/
protected Level getDefaultLogLevel(){
return Level.INFO;
}
/**
* Gets the log level which debug messages are sent to.
* @return the Level
*/
protected Level getDebugLogLevel(){
return Level.FINER;
}
/**
* Gets the log level which error messages are sent to.
* @return the Level
*/
protected Level getErrorLogLevel(){
return Level.WARNING;
}
// public Iterator iterator() {
// return listIterator();
// }
//
// public ListIterator listIterator() {
// return listIterator(0);
// }
//
// public ListIterator listIterator(int index) {
// return new IDOPrimaryKeyListIterator(this,index);
// }
// /**
// * Returns a view of the portion of this List between fromIndex,
// * inclusive, and toIndex, exclusive. (If fromIndex and ToIndex are
// * equal, the returned List is empty.) The returned List is not backed by this
// * List, so changes in the returned List will not affect this List.
// *
// * @param fromIndex low endpoint (inclusive) of the subList.
// * @param toIndex high endpoint (exclusive) of the subList.
// * @return a view of the specified range within this List.
// * @throws IndexOutOfBoundsException endpoint index value out of range
// * <code>(fromIndex < 0 || toIndex > size)</code>
// * @throws IllegalArgumentException endpoint indices out of order
// * <code>(fromIndex > toIndex)</code>
// */
// List subIDOEntityList(int fromIndex, int toIndex) {
// try
// {
// this.loadSubset(fromIndex,toIndex);
// }
// catch (Exception ex)
// {
// ex.printStackTrace();
// }
// return (List)((Vector)_entities.subList(fromIndex, toIndex)).clone();
// }
public boolean equals(Object o) {
if(!super.equals(o)) {
return false;
}
IDOPrimaryKeyList obj = (IDOPrimaryKeyList)o;
if(!this._sqlQuery.equals(obj._sqlQuery)) {
return false;
}
if(!this._entity.equals(obj._entity)) {
return false;
}
if(this.isSublist != obj.isSublist) {
return false;
}
return true;
}
Object getIDOEntity(int index) {
Object obj = this._entities.get(index);
if(obj == null){
try{
loadSubset(index,index+this._prefetchSize);
obj = this._entities.get(index);
}
catch (Exception ex){
ex.printStackTrace();
}
}
return obj;
}
public Object remove(int index) {
super.remove(index);
debug("[PrimaryKeyList]: method remove("+index+") before");
this._tracker.printLoadInformations();
this._tracker.remove(index);
debug("[PrimaryKeyList]: after");
this._tracker.printLoadInformations();
return this._entities.remove(index);
}
public boolean remove(Object o) {
if(o instanceof IDOEntity){
return removeIDOEntity((IDOEntity)o);
}
int index = super.indexOf(o);
if(index==-1){
return false;
}
remove(index);
return true;
}
boolean removeIDOEntity(IDOEntity o){
int index = this._entities.indexOf(o);
if(index==-1){
return false;
}
remove(index);
return true;
}
boolean containsIDOEntity(Object o) {
if(this._tracker.getLoadRatio() != 1){
try {
loadSubset(0,size());
} catch (IDOFinderException e) {
logError("[WARNING!!!][IDOPrimaryKeyList]: failed to load entities and can therefore return incorrect result");
e.printStackTrace();
}
}
return this._entities.contains(o);
}
Object[] toIDOEntityArray() {
try {
loadSubset(0,size());
} catch (IDOFinderException e) {
logError("[WARNING!!!][IDOPrimaryKeyList]: failed to load entities and will therefore return incorrect result");
e.printStackTrace();
}
return this._entities.toArray();
}
Object[] toIDOEntityArray(Object[] a) {
try {
loadSubset(0,size());
} catch (IDOFinderException e) {
logError("[WARNING!!!][IDOPrimaryKeyList]: failed to load entities and will therefore return incorrect result");
e.printStackTrace();
}
return this._entities.toArray(a);
}
public boolean containsAll(Collection c) { //Implementation copied from java.util.AbstractCollection
Iterator e = c.iterator();
while (e.hasNext()) {
if(!contains(e.next())) {
return false;
}
}
return true;
}
public boolean add(Object o) {
boolean toReturn;
if(o instanceof IDOEntity){
toReturn = this._entities.add(validateIDOEntityObject((IDOEntity)o)) && super.add(((IDOEntity)o).getPrimaryKey());
debug("[PrimaryKeyList]: method add("+o+") before");
this._tracker.printLoadInformations();
this._tracker.addLoadedSubset(1);
debug("[PrimaryKeyList]: after");
this._tracker.printLoadInformations();
} else {
Object pk = o;
if(pk instanceof String){
pk = this._entity.decode((String)pk);
} else {
validatePrimaryKeyObject(pk);
}
toReturn = super.add(pk);
debug("[PrimaryKeyList]: method add("+o+") before");
this._tracker.printLoadInformations();
this._tracker.addUnloadedSubset(1);
debug("[PrimaryKeyList]: after");
this._tracker.printLoadInformations();
}
return toReturn;
}
public void add(int index, Object element) {
if(element instanceof IDOEntity){
this._entities.add(index,validateIDOEntityObject((IDOEntity)element));
super.add(index,((IDOEntity)element).getPrimaryKey());
debug("[PrimaryKeyList]: method add("+index+","+element+") before");
this._tracker.printLoadInformations();
this._tracker.addLoadedSubset(index,1);
debug("[PrimaryKeyList]: after");
this._tracker.printLoadInformations();
} else {
Object pk = element;
if(pk instanceof String){
pk = this._entity.decode((String)pk);
} else {
validatePrimaryKeyObject(pk);
}
super.add(index,pk);
debug("[PrimaryKeyList]: method add("+index+","+element+") before");
this._tracker.printLoadInformations();
this._tracker.addUnloadedSubset(index,1);
debug("[PrimaryKeyList]: after");
this._tracker.printLoadInformations();
}
}
public boolean addAll(Collection c) {
boolean toReturn=true;
for (Iterator iter = c.iterator(); iter.hasNext();) {
Object element = iter.next();
if(!add(element)){
toReturn = false;
}
}
return toReturn;
}
public boolean addAll(int index, Collection c) {
int i = index;
for (Iterator iter = c.iterator(); iter.hasNext();i++) {
Object element = iter.next();
add(i,element);
}
return c.size() != 0; // this return implementation is copied from java.util.Vector
}
public boolean removeAll(Collection c) { //Implementation copied from java.util.AbstractCollection
boolean modified = false;
Iterator e = iterator();
while (e.hasNext()) {
if(c.contains(e.next())) {
e.remove();
modified = true;
}
}
return modified;
}
public boolean retainAll(Collection c) { //Implementation copied from java.util.AbstractCollection
boolean modified = false;
Iterator e = iterator();
while (e.hasNext()) {
if(!c.contains(e.next())) {
e.remove();
modified = true;
}
}
return modified;
}
public Object set(int index, Object element) {
Object toReturn = null;
if(element instanceof IDOEntity){
toReturn=this._entities.set(index,validateIDOEntityObject((IDOEntity)element));
super.set(index,((IDOEntity)element).getPrimaryKey());
debug("[PrimaryKeyList]: method set("+index+","+element+") before");
this._tracker.printLoadInformations();
this._tracker.setAsLoaded(index);
debug("[PrimaryKeyList]: after");
this._tracker.printLoadInformations();
} else {
Object pk = element;
if(pk instanceof String){
pk = this._entity.decode((String)pk);
} else {
validatePrimaryKeyObject(pk);
}
toReturn=super.set(index,pk);
this._entities.add(index,null);
debug("[PrimaryKeyList]: method set("+index+","+element+") before");
this._tracker.printLoadInformations();
this._tracker.setAsNotLoaded(index);
debug("[PrimaryKeyList]: after");
this._tracker.printLoadInformations();
}
return toReturn;
}
public int indexOf(Object o) {
if(o instanceof IDOEntity){
return this._entities.indexOf(o);
} else {
return super.indexOf(o);
}
}
public int lastIndexOf(Object o) {
if(o instanceof IDOEntity){
return this._entities.lastIndexOf(o);
} else {
return super.lastIndexOf(o);
}
}
private boolean merge(IDOPrimaryKeyList l){
debug("[IDOPrimaryKeyList - Merge - primary key list added]: length"+ l.size());
int sizeBefore = this.size();
super.addAll(l);
this._entities.setSize(this.size());
IDOPrimaryKeyList.copy(this._entities,l._entities,sizeBefore);
this._tracker.add(l._tracker);
return true;
}
static boolean areMergeable(IDOPrimaryKeyList l1, IDOPrimaryKeyList l2){
return l1._entity.getClass() == l2._entity.getClass();
}
static IDOPrimaryKeyList merge(IDOPrimaryKeyList l1, IDOPrimaryKeyList l2) throws IDOFinderException{
IDOPrimaryKeyList l = new IDOPrimaryKeyList(l1,l1._entity,((l1._prefetchSize+l2._prefetchSize)/2));
Collections.copy(l._entities,l1._entities);
l._tracker = (LoadTracker)l1._tracker.clone();
l.merge(l2);
return l;
}
/**
* Copies all of the elements from one list into another. After the
* operation, the index of each copied element in the destination list
* will be identical to its index in the source list. The destination
* list must be at least as long as the source list. If it is longer, the
* remaining elements in the destination list are unaffected. <p>
*
* This method runs in linear time.
*
* @param dest The destination list.
* @param src The source list.
* @throws IndexOutOfBoundsException if the destination list is too small
* to contain the entire source List.
* @throws UnsupportedOperationException if the destination list's
* list-iterator does not support the <tt>set</tt> operation.
*/
private static void copy(List dest, List src, int startIndexInSrc) {
//implementation copied from java.util.Collections but modified
int srcSize = src.size();
if (srcSize > dest.size()) {
throw new IndexOutOfBoundsException("Source does not fit in dest");
}
int COPY_THRESHOLD = 10;
if (srcSize < COPY_THRESHOLD ||
(src instanceof RandomAccess && dest instanceof RandomAccess)) {
for (int i=0; i<srcSize; i++) {
dest.set(i+startIndexInSrc, src.get(i));
}
} else {
ListIterator di=dest.listIterator(startIndexInSrc), si=src.listIterator();
for (int i=0; i<srcSize; i++) {
di.next();
di.set(si.next());
}
}
}
public class LoadTracker implements Cloneable {
// int initialCapacity;
private int _subsetMinLength = 100;
private IntervalComparator _comparator = new IntervalComparator();
/**
* int this list there are added int[] of length 2 wherre the int in index 0 is first loaded object in subset but the int in index 1 is the index after the last loaded object in that subset
*/
private Vector _loadedSubSets = new Vector();
// private int _numberOfSubsets = 0;
public static final int FROM_INDEX_IN_ARRAY = 0;
public static final int TO_INDEX_IN_ARRAY = 1;
private int _size;
public LoadTracker(int size, int subsetMinLength){
this._size = size;
this._subsetMinLength = subsetMinLength;
}
boolean add(LoadTracker tracker){
for (Iterator iter = tracker._loadedSubSets.iterator(); iter.hasNext();) {
int[] sub = (int[]) iter.next();
sub[FROM_INDEX_IN_ARRAY] += this._size;
sub[TO_INDEX_IN_ARRAY] += this._size;
this._loadedSubSets.add(sub);
}
this._size += tracker._size;
return true;
}
public Object clone(){
LoadTracker obj = null;
try {
obj= (LoadTracker)super.clone();
obj._loadedSubSets = (Vector)this._loadedSubSets.clone();
obj._comparator = this._comparator;
obj._subsetMinLength = this._subsetMinLength;
obj._size = this._size;
} catch (CloneNotSupportedException e) {
e.printStackTrace();
}
return obj;
}
private void debugLoadedSubSets(){
debug("[IDOPrimaryKeyList.LoadTracker]: not loaded subsets ->");
debug("From\tTo");
debug("-----\t------");
List notLoaded = getNotLoadedSubsets(0,this._size);
if(notLoaded != null){
Iterator iter = notLoaded.iterator();
boolean showNulls = true;
while (iter.hasNext()) {
int[] item = (int[])iter.next();
if(item != null || showNulls){
debug(item[0]+"\t"+item[1]);
}
}
}
debug("[IDOPrimaryKeyList]: _loadedSubSets content ends");
}
public float getLoadRatio(){
if(this._size != 0){
int NumberOfLoadedElements = 0;
ListIterator iter = this._loadedSubSets.listIterator();
while (iter.hasNext()) {
//int index = iter.nextIndex();
int[] item = (int[])iter.next();
NumberOfLoadedElements += item[TO_INDEX_IN_ARRAY] - item[FROM_INDEX_IN_ARRAY];
}
return ((float)NumberOfLoadedElements)/(this._size);
} else {
return 1;
}
}
// private void increaseCapacity(){
// int newCapacity = _loadedSubSets.length + _capacityIncrement;
// int oldCapacity = _loadedSubSets.length;
// int[][] newObject = new int[newCapacity][2];
// System.arraycopy(_loadedSubSets,0,newObject,0,oldCapacity);
// _loadedSubSets = newObject;
// }
/**
* @param fromIndex low endpoint (inclusive).
* @param toIndex high endpoint (exclusive).
*/
private boolean isLoaded(int fromIndex, int toIndex){
// int fIndex = Math.min(fromIndex,toIndex);
int fIndex = fromIndex;
// fIndex = Math.min(fIndex,_size);
if(fromIndex > this._size){
return false;
}
// int tIndex = Math.max(fromIndex,toIndex);
int tIndex = Math.min(toIndex,this._size);
Iterator iter = this._loadedSubSets.iterator();
while (iter.hasNext()) {
int[] item = (int[])iter.next();
if(item[FROM_INDEX_IN_ARRAY]<= fIndex){
if(item[TO_INDEX_IN_ARRAY] >= tIndex){
return true;
} else {
int joint = item[TO_INDEX_IN_ARRAY];
while(iter.hasNext()){
int[] anotherItem = (int[])iter.next();
if(joint == anotherItem[FROM_INDEX_IN_ARRAY]){
if(anotherItem[TO_INDEX_IN_ARRAY] >= tIndex){
return true;
} else {
joint = anotherItem[TO_INDEX_IN_ARRAY];
}
} else { // that is if (joint < anotherItem[FROM_INDEX_IN_ARRAY])
return false;
}
}
}
}
if(item[FROM_INDEX_IN_ARRAY] > tIndex ){
break;
}
}
return false;
}
/**
* @param fromIndex low endpoint (inclusive).
* @param toIndex high endpoint (exclusive).
*/
public List getNotLoadedSubsets(int fromIndex, int toIndex){
// if (_entity.isDebugActive()){
// debug("[IDOPrimaryKeyList]: _size = "+_size);
// debugLoadedSubSets();
// }
List toReturn = new ArrayList();
int fIndex = Math.min(fromIndex,toIndex);
fIndex = Math.min(fIndex,this._size);
int tIndex = Math.max(fromIndex,toIndex);
// if (_entity.isDebugActive()){
// debug("[IDOPrimaryKeyList]: 1");
// debug("[IDOPrimaryKeyList]: getNotLoadedSubsets("+fIndex+","+tIndex+")");
// debug("[IDOPrimaryKeyList]: isLoaded("+fromIndex+","+toIndex+") = "+isLoaded(fromIndex,toIndex));
//
// }
if(this._size == 0 || isLoaded(fromIndex,toIndex)){
return toReturn;
}
tIndex = Math.max(tIndex,fromIndex+this._subsetMinLength);
tIndex = Math.min(tIndex,this._size);
if(this._loadedSubSets.size() == 0){
int [] interval = new int[2];
interval[FROM_INDEX_IN_ARRAY] = fIndex;
interval[TO_INDEX_IN_ARRAY] = tIndex;
// if (_entity.isDebugActive()){
// debug("[IDOPrimaryKeyList]: 2");
// debug("[IDOPrimaryKeyList]: getNotLoadedSubsets("+fIndex+","+tIndex+")");
// }
toReturn.add(interval);
return toReturn;
} else {
ListIterator iter = this._loadedSubSets.listIterator();
while (iter.hasNext()) {
int index = iter.nextIndex();
int[] item = (int[])iter.next();
if(( fIndex >= item[TO_INDEX_IN_ARRAY] && !iter.hasNext() )||(tIndex <= item[FROM_INDEX_IN_ARRAY] && (index != 0 && ((int[])this._loadedSubSets.get(index-1))[TO_INDEX_IN_ARRAY] <= fIndex))){ // interval is not part of any other interval
// if(index == 0){
int [] interval = new int[2];
interval[FROM_INDEX_IN_ARRAY] = fIndex;
interval[TO_INDEX_IN_ARRAY] = Math.min(tIndex,this._size);
// if (_entity.isDebugActive()){
// debug("[IDOPrimaryKeyList]: 3");
// debug("[IDOPrimaryKeyList]: getNotLoadedSubsets("+interval[FROM_INDEX_IN_ARRAY]+","+interval[TO_INDEX_IN_ARRAY]+")");
// }
if(interval[FROM_INDEX_IN_ARRAY]<interval[TO_INDEX_IN_ARRAY]){
fIndex = interval[TO_INDEX_IN_ARRAY];
toReturn.add(interval);
}
// }
break;
}
if(fIndex < item[FROM_INDEX_IN_ARRAY] && tIndex >= item[FROM_INDEX_IN_ARRAY] && tIndex <= item[TO_INDEX_IN_ARRAY]){ // interval begins before item's interval and covers at least some of it or is right beside it
int [] interval = new int[2];
interval[FROM_INDEX_IN_ARRAY] = fIndex;
if(!toReturn.isEmpty()){
interval[FROM_INDEX_IN_ARRAY] = Math.max(interval[FROM_INDEX_IN_ARRAY],((int[])this._loadedSubSets.get(toReturn.size()-1))[TO_INDEX_IN_ARRAY]);
}
if(this._loadedSubSets.size() > index+1){
interval[FROM_INDEX_IN_ARRAY] = Math.max(interval[FROM_INDEX_IN_ARRAY],((int[])this._loadedSubSets.get(index+1))[TO_INDEX_IN_ARRAY]);
}
int min = Math.min(tIndex,item[FROM_INDEX_IN_ARRAY]);
interval[TO_INDEX_IN_ARRAY] = min;
// if(_loadedSubSets.size() > index+1){
// interval[TO_INDEX_IN_ARRAY] = Math.min(min,((int[])_loadedSubSets.get(index+1))[FROM_INDEX_IN_ARRAY]);
// } else {
// interval[TO_INDEX_IN_ARRAY] = min;
// }
// if (_entity.isDebugActive()){
// debug("[IDOPrimaryKeyList]: 4");
// debug("[IDOPrimaryKeyList]: getNotLoadedSubsets("+interval[FROM_INDEX_IN_ARRAY]+","+interval[TO_INDEX_IN_ARRAY]+")");
// }
if(interval[FROM_INDEX_IN_ARRAY]<interval[TO_INDEX_IN_ARRAY]){
fIndex = interval[TO_INDEX_IN_ARRAY];
toReturn.add(interval);
}
}
if(fIndex < item[TO_INDEX_IN_ARRAY] && tIndex > item[TO_INDEX_IN_ARRAY] ){ // interval outreaches item's interval
int [] interval = new int[2];
interval[FROM_INDEX_IN_ARRAY] = item[TO_INDEX_IN_ARRAY];
int min = Math.min(tIndex,this._size);
if(this._loadedSubSets.size() > index+1){
interval[TO_INDEX_IN_ARRAY] = Math.min(min,((int[])this._loadedSubSets.get(index+1))[FROM_INDEX_IN_ARRAY]);
} else {
interval[TO_INDEX_IN_ARRAY] = min;
}
// if (_entity.isDebugActive()){
// debug("[IDOPrimaryKeyList]: 5");
// debug("[IDOPrimaryKeyList]: getNotLoadedSubsets("+interval[FROM_INDEX_IN_ARRAY]+","+interval[TO_INDEX_IN_ARRAY]+")");
// }
if(interval[FROM_INDEX_IN_ARRAY]<interval[TO_INDEX_IN_ARRAY]){
fIndex = interval[TO_INDEX_IN_ARRAY];
toReturn.add(interval);
}
}
}
// Collections.sort(toReturn,_comparator);
return toReturn;
}
}
public void printLoadInformations(){
// debug("-------[IDOPrimaryKeyList.LoadTracker]: begin -------");
// debug("[IDOPrimaryKeyList.LoadTracker]: Load ratio "+getLoadRatio());
// debug("[IDOPrimaryKeyList.LoadTracker]: Size "+_size);
//// debugLoadedSubSets();
// debugLoadedSubSets();
////// for (Iterator iter = _loadedSubSets.iterator(); iter.hasNext();) {
////// int[] loadedSets = (int[]) iter.next();
////// debug("[IDOPrimaryKeyList.LoadTracker]: Loaded from "+loadedSets[FROM_INDEX_IN_ARRAY]+" to "+loadedSets[TO_INDEX_IN_ARRAY]);
////// }
// debug("-------[IDOPrimaryKeyList.LoadTracker]: end -------");
}
public void removeSubset(int index, int size){
this._size -= size;
int toIndex = index+size;
for (Iterator iter = this._loadedSubSets.iterator(); iter.hasNext();) {
int[] subset = (int[]) iter.next();
int f = subset[FROM_INDEX_IN_ARRAY];
int t = subset[TO_INDEX_IN_ARRAY];
if(f >= index && t > toIndex){ // cut left and lower index
subset[FROM_INDEX_IN_ARRAY] = index+1;
subset[TO_INDEX_IN_ARRAY] = t+size;
}
if(f < index && t >= index && t <= toIndex){ // cut right
subset[TO_INDEX_IN_ARRAY] = index;
}
if( f <= index && t > toIndex){ // if set is from within a loaded subset
if(t == toIndex && f == index){ // if set is a loaded subset
iter.remove();
} else {
subset[TO_INDEX_IN_ARRAY] = t-size;
}
}
if(f>toIndex){ // all loaded subsets that start after the removed subset
subset[FROM_INDEX_IN_ARRAY] = f-size;
subset[TO_INDEX_IN_ARRAY] = t-size;
}
}
}
public void remove(int index){
removeSubset(index,1);
}
public void addUnloadedSubset(int index, int size){
this._size += size;
int[] setToAdd = null;
for (Iterator iter = this._loadedSubSets.iterator(); iter.hasNext();) {
int[] subset = (int[]) iter.next();
int f = subset[FROM_INDEX_IN_ARRAY];
int t = subset[TO_INDEX_IN_ARRAY];
if(t >= index && f <= index){ // if set is added into a loaded subset or right after it
subset[TO_INDEX_IN_ARRAY] = index;
setToAdd = new int[2];
setToAdd[FROM_INDEX_IN_ARRAY] = index+size;
setToAdd[TO_INDEX_IN_ARRAY] = t+size;
}
if(f>(index)){ // all loaded subsets that start after where the current subset is added
subset[FROM_INDEX_IN_ARRAY] = f+size;
subset[TO_INDEX_IN_ARRAY] = t+size;
}
}
if(setToAdd !=null){
this._loadedSubSets.add(setToAdd);
Collections.sort(this._loadedSubSets,this._comparator);
}
}
public void addLoadedSubset(int index, int size){
this._size += size;
boolean isLoaded = false;
for (Iterator iter = this._loadedSubSets.iterator(); iter.hasNext();) {
int[] subset = (int[]) iter.next();
int f = subset[FROM_INDEX_IN_ARRAY];
int t = subset[TO_INDEX_IN_ARRAY];
if(t >= index && f <= index){ // if set is added into a loaded subset
subset[TO_INDEX_IN_ARRAY] = t+size;
isLoaded = true;
}
if(f>index){ // all loaded subsets that start after where the current subset is added
subset[FROM_INDEX_IN_ARRAY] = f+size;
subset[TO_INDEX_IN_ARRAY] = t+size;
}
}
if(!isLoaded){
int [] interval = new int[2];
interval[FROM_INDEX_IN_ARRAY] = index;
interval[TO_INDEX_IN_ARRAY] = index+size;
this._loadedSubSets.add(interval);
Collections.sort(this._loadedSubSets,this._comparator);
}
}
public void addUnloadedSubset(int size){
addUnloadedSubset(this._size,size);
}
public void addLoadedSubset(int size){
addLoadedSubset(this._size,size);
}
public void setAsNotLoaded(int index){
setSubsetAsNotLoaded(index,index+1);
}
public void setAsLoaded(int index){
setSubsetAsLoaded(index,index+1);
}
/**
* @param fromIndex low endpoint (inclusive).
* @param toIndex high endpoint (exclusive).
*/
public void setSubsetAsNotLoaded(int fromIndex, int toIndex){
int[] setToAdd = null;
for (Iterator iter = this._loadedSubSets.iterator(); iter.hasNext();) {
int[] subset = (int[]) iter.next();
int f = subset[FROM_INDEX_IN_ARRAY];
int t = subset[TO_INDEX_IN_ARRAY];
if(t >= fromIndex && f <= fromIndex){ // if set is subset of a loaded subset
subset[TO_INDEX_IN_ARRAY] = fromIndex;
setToAdd = new int[2];
setToAdd[FROM_INDEX_IN_ARRAY] = toIndex;
setToAdd[TO_INDEX_IN_ARRAY] = t;
break;
}
if(f>(toIndex)){ // cut left
subset[FROM_INDEX_IN_ARRAY] = toIndex;
}
if(t>(fromIndex)){ // cut right
subset[TO_INDEX_IN_ARRAY] = fromIndex;
}
}
if(setToAdd !=null){
this._loadedSubSets.add(setToAdd);
Collections.sort(this._loadedSubSets,this._comparator);
}
}
/**
* @param fromIndex low endpoint (inclusive).
* @param toIndex high endpoint (exclusive).
*/
public void setSubsetAsLoaded(int fromIndex, int toIndex){
if (IDOPrimaryKeyList.this._entity.isDebugActive()){
debug("[IDOPrimaryKeyList]: addLoadedSubSet("+fromIndex+","+toIndex+") -> begins");
debugLoadedSubSets();
}
int fIndex = Math.min(fromIndex,toIndex);
fIndex = Math.min(fIndex,this._size);
int tIndex = Math.max(fromIndex,toIndex);
// if (_entity.isDebugActive()){
// debug("[IDOPrimaryKeyList]: 1");
// debug("[IDOPrimaryKeyList]: addLoadedSubSet("+fIndex+","+tIndex+")");
// }
// if(isLoaded(fromIndex,toIndex)){
// return toReturn;
// }
tIndex = Math.max(tIndex,fromIndex+this._subsetMinLength);
tIndex = Math.min(tIndex,this._size);
if(this._loadedSubSets.size() == 0){
int [] interval = new int[2];
interval[FROM_INDEX_IN_ARRAY] = fIndex;
interval[TO_INDEX_IN_ARRAY] = tIndex;
// if (_entity.isDebugActive()){
// debug("[IDOPrimaryKeyList]: 2");
// debug("[IDOPrimaryKeyList]: addLoadedSubSet("+fIndex+","+tIndex+")");
// }
this._loadedSubSets.add(interval);
} else {
ListIterator iter = this._loadedSubSets.listIterator();
while (iter.hasNext()) {
int index = iter.nextIndex();
int[] item = (int[])iter.next();
if(( fIndex >= item[TO_INDEX_IN_ARRAY] && !iter.hasNext() )||(tIndex <= item[FROM_INDEX_IN_ARRAY] && (index != 0 && ((int[])this._loadedSubSets.get(index-1))[TO_INDEX_IN_ARRAY] <= fIndex))){ // interval is not part of any other interval
// if(index == 0){
int [] interval = new int[2];
interval[FROM_INDEX_IN_ARRAY] = fIndex;
interval[TO_INDEX_IN_ARRAY] = Math.min(tIndex,this._size);
// if (_entity.isDebugActive()){
// debug("[IDOPrimaryKeyList]: 3");
// debug("[IDOPrimaryKeyList]: addLoadedSubSet("+interval[FROM_INDEX_IN_ARRAY]+","+interval[TO_INDEX_IN_ARRAY]+")");
// }
iter.add(interval);
// }
break;
}
if(fIndex < item[FROM_INDEX_IN_ARRAY] && tIndex >= item[FROM_INDEX_IN_ARRAY]){ // interval begins before item's interval and covers at least some of it
int [] interval = new int[2];
interval[FROM_INDEX_IN_ARRAY] = fIndex;
int min = Math.min(tIndex,item[FROM_INDEX_IN_ARRAY]);
interval[TO_INDEX_IN_ARRAY] = min;
// if(_loadedSubSets.size() > index+1){
// interval[TO_INDEX_IN_ARRAY] = Math.min(min,((int[])_loadedSubSets.get(index+1))[FROM_INDEX_IN_ARRAY]);
// } else {
// interval[TO_INDEX_IN_ARRAY] = min;
// }
// if (_entity.isDebugActive()){
// debug("[IDOPrimaryKeyList]: 4");
// debug("[IDOPrimaryKeyList]: addLoadedSubSet("+interval[FROM_INDEX_IN_ARRAY]+","+interval[TO_INDEX_IN_ARRAY]+")");
// }
iter.add(interval);
}
if(fIndex < item[TO_INDEX_IN_ARRAY] && tIndex > item[TO_INDEX_IN_ARRAY] ){ // interval outreaches item's interval
int [] interval = new int[2];
interval[FROM_INDEX_IN_ARRAY] = item[TO_INDEX_IN_ARRAY];
int min = Math.min(tIndex,this._size);
if(this._loadedSubSets.size() > index+1){
interval[TO_INDEX_IN_ARRAY] = Math.min(min,((int[])this._loadedSubSets.get(index+1))[FROM_INDEX_IN_ARRAY]);
} else {
interval[TO_INDEX_IN_ARRAY] = min;
}
// if (_entity.isDebugActive()){
// debug("[IDOPrimaryKeyList]: 5");
// debug("[IDOPrimaryKeyList]: addLoadedSubSet("+interval[FROM_INDEX_IN_ARRAY]+","+interval[TO_INDEX_IN_ARRAY]+")");
// }
iter.add(interval);
}
}
Collections.sort(this._loadedSubSets,this._comparator);
}
if (IDOPrimaryKeyList.this._entity.isDebugActive()){
debug("And then");
debugLoadedSubSets();
debug("[IDOPrimaryKeyList]: addLoadedSubSet("+fromIndex+","+toIndex+") -> ends");
}
}
public class IntervalComparator implements Comparator {
public IntervalComparator() {
}
public int compare(Object o1, Object o2) {
int[] p1 = (int[]) o1;
int[] p2 = (int[]) o2;
int result = 0;
if(!(p1[FROM_INDEX_IN_ARRAY] == p2[FROM_INDEX_IN_ARRAY])){
result = (p1[FROM_INDEX_IN_ARRAY] < p2[FROM_INDEX_IN_ARRAY])?-1:1;
}
return result;
}
public boolean equals(Object obj) {
/**@todo: Implement this java.util.Comparator method*/
throw new java.lang.UnsupportedOperationException("Method equals() not yet implemented.");
}
}
} //LoadTracker Ends
public class IDOPrimaryKeyListIterator implements ListIterator{
private int _index;
private List _list;
private Object lastObject;
private boolean _hasPrevious=false;
public IDOPrimaryKeyListIterator(IDOPrimaryKeyList list,int index){
this._list=list;
this._index=index;
}
// /**
// * @see java.util.ListIterator#add(java.lang.Object)
// */
// public void add(Object o) {
// _list.add(o);
// }
/**
* @see java.util.Iterator#hasNext()
*/
public boolean hasNext() {
return this._list.size()>this._index;
}
/**
* @see java.util.ListIterator#hasPrevious()
*/
public boolean hasPrevious() {
return this._hasPrevious;
}
/**
* @see java.util.Iterator#next()
*/
public Object next() {
Object o = this._list.get(nextIndex());
this._index++;
this._hasPrevious=true;
return o;
}
/**
* @see java.util.ListIterator#nextIndex()
*/
public int nextIndex() {
return this._index;
}
/**
* @see java.util.ListIterator#previous()
*/
public Object previous() {
Object o = this._list.get(previousIndex());
this._index=this._index-1;
if(this._index==0){
this._hasPrevious=false;
}
return o;
}
/**
* @see java.util.ListIterator#previousIndex()
*/
public int previousIndex() {
return this._index-1;
}
/**
* @see java.util.Iterator#remove()
*/
public void remove() {
this._list.remove(previousIndex());
}
// /**
// * @see java.util.ListIterator#set(java.lang.Object)
// */
// public void set(Object o) {
// _list.set(previousIndex(),o);
// }
public void set(Object o) {
this._list.set(this._index-1,((IDOEntity)o));
}
public void add(Object o) {
this._list.add(this._index,((IDOEntity)o));
}
}
}