package org.apache.ojb.odmg.collections;
/* Copyright 2002-2004 The Apache Software Foundation
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
import java.io.Serializable;
import java.util.Iterator;
import java.util.Vector;
import org.apache.ojb.broker.PBKey;
import org.apache.ojb.broker.PersistenceBroker;
import org.apache.ojb.broker.PersistenceBrokerException;
import org.apache.ojb.broker.core.ValueContainer;
import org.apache.ojb.broker.metadata.ClassDescriptor;
import org.apache.ojb.broker.metadata.FieldDescriptor;
import org.apache.ojb.broker.query.Criteria;
import org.apache.ojb.broker.query.Query;
import org.apache.ojb.broker.query.QueryByCriteria;
import org.apache.ojb.broker.util.logging.Logger;
import org.apache.ojb.broker.util.logging.LoggerFactory;
import org.apache.ojb.odmg.PBCapsule;
import org.apache.ojb.odmg.TransactionImpl;
import org.apache.ojb.odmg.TxManagerFactory;
import org.apache.ojb.odmg.oql.OQLQueryImpl;
import org.odmg.DList;
import org.odmg.DSet;
import org.odmg.ODMGRuntimeException;
import org.odmg.OQLQuery;
import org.odmg.Transaction;
/**
*
*/
public class DSetImpl extends java.util.AbstractSet implements org.odmg.DSet, Serializable
{
private static final long serialVersionUID = -4459673364598652639L;
private Logger log = LoggerFactory.getLogger(DSetImpl.class);
private int id = -1;
private Vector elements;
private int size;
private PBKey pbKey;
/**
* DSetImpl constructor comment.
*/
public DSetImpl()
{
super();
elements = new Vector();
this.size = 0;
}
/**
* DSetImpl constructor comment.
*/
public DSetImpl(PBKey pbKey)
{
super();
elements = new Vector();
this.size = 0;
this.pbKey = pbKey;
}
/**
* DListImpl constructor comment.
*/
public DSetImpl(int theId, int theSize)
{
super();
elements = new Vector();
id = theId;
this.size = theSize;
}
private TransactionImpl getTransaction()
{
return TxManagerFactory.instance().getTransaction();
}
/**
*
*/
public boolean add(Object o)
{
if (!this.contains(o))
{
this.size++;
DSetEntry entry = new DSetEntry(this, o);
elements.add(entry);
// if we are in a transaction: get locks !
TransactionImpl tx = getTransaction();
if ((tx != null) && (tx.isOpen()))
{
tx.lock(this, Transaction.WRITE);
tx.lock(entry, Transaction.WRITE);
tx.lock(o, Transaction.READ);
}
return true;
}
else
{
return false;
}
}
/**
* Create a new <code>DSet</code> object that contains the elements of this
* collection minus the elements in <code>otherSet</code>.
* @param otherSet A set containing elements that should not be in the result set.
* @return A newly created <code>DSet</code> instance that contains the elements
* of this set minus those elements in <code>otherSet</code>.
*/
public org.odmg.DSet difference(org.odmg.DSet otherSet)
{
DSetImpl result = new DSetImpl(pbKey);
Iterator iter = this.iterator();
while (iter.hasNext())
{
Object candidate = iter.next();
if (!otherSet.contains(candidate))
{
result.add(candidate);
}
}
return result;
}
/**
* Determines whether there is an element of the collection that evaluates to true
* for the predicate.
* @param predicate An OQL boolean query predicate.
* @return True if there is an element of the collection that evaluates to true
* for the predicate, otherwise false.
* @exception org.odmg.QueryInvalidException The query predicate is invalid.
*/
public boolean existsElement(String predicate) throws org.odmg.QueryInvalidException
{
DList results = (DList) this.query(predicate);
if (results == null || results.size() == 0)
return false;
else
return true;
}
/**
* return a unique id
*/
protected int generateNewId()
{
PBCapsule capsule = new PBCapsule(null, TxManagerFactory.instance().getTransaction());
try
{
ClassDescriptor cld = capsule.getBroker().getClassDescriptor(this.getClass());
FieldDescriptor fld = cld.getFieldDescriptorByName("id");
Integer val = (Integer) capsule.getBroker().serviceSequenceManager().getUniqueValue(fld);
int result = val.intValue();
return result;
}
catch (Exception e)
{
log.error("Generation of new id failed", e);
throw new PersistenceBrokerException(e);
}
finally
{
capsule.destroy();
}
}
/**
* Insert the method's description here.
* Creation date: (26.02.2001 13:29:42)
* @return java.util.Vector
*/
public java.util.Vector getElements()
{
return elements;
}
/**
* Insert the method's description here.
* Creation date: (26.02.2001 13:50:57)
* @return int
*/
public int getId()
{
if (id == -1)
{
id = generateNewId();
}
return id;
}
/**
* Create a new <code>DSet</code> object that is the set intersection of this
* <code>DSet</code> object and the set referenced by <code>otherSet</code>.
* @param otherSet The other set to be used in the intersection operation.
* @return A newly created <code>DSet</code> instance that contains the
* intersection of the two sets.
*/
public org.odmg.DSet intersection(org.odmg.DSet otherSet)
{
DSet union = this.union(otherSet);
DSetImpl result = new DSetImpl(pbKey);
Iterator iter = union.iterator();
while (iter.hasNext())
{
Object candidate = iter.next();
if (this.contains(candidate) && otherSet.contains(candidate))
{
result.add(candidate);
}
}
return result;
}
/**
* Returns an iterator over the elements in this collection. There are no
* guarantees concerning the order in which the elements are returned
* (unless this collection is an instance of some class that provides a
* guarantee).
*
* @return an <tt>Iterator</tt> over the elements in this collection
*/
public java.util.Iterator iterator()
{
return new DSetIterator(this);
}
/**
* Determine whether this set is a proper subset of the set referenced by
* <code>otherSet</code>.
* @param otherSet Another set.
* @return True if this set is a proper subset of the set referenced by
* <code>otherSet</code>, otherwise false.
*/
public boolean properSubsetOf(org.odmg.DSet otherSet)
{
return (this.size() > 0 && this.size() < otherSet.size() && this.subsetOf(otherSet));
}
/**
* Determine whether this set is a proper superset of the set referenced by
* <code>otherSet</code>.
* @param otherSet Another set.
* @return True if this set is a proper superset of the set referenced by
* <code>otherSet</code>, otherwise false.
*/
public boolean properSupersetOf(org.odmg.DSet otherSet)
{
return (otherSet.size() > 0 && otherSet.size() < this.size() && this.supersetOf(otherSet));
}
/**
* Evaluate the boolean query predicate for each element of the collection and
* return a new collection that contains each element that evaluated to true.
* @param predicate An OQL boolean query predicate.
* @return A new collection containing the elements that evaluated true for the predicate.
* @exception org.odmg.QueryInvalidException The query predicate is invalid.
*/
public org.odmg.DCollection query(String predicate) throws org.odmg.QueryInvalidException
{
// 1.build complete OQL statement
String oql = "select all from java.lang.Object where " + predicate;
OQLQuery predicateQuery = new OQLQueryImpl(pbKey, this.getClass());
Transaction tx = getTransaction();
PBCapsule capsule = new PBCapsule(pbKey, tx);
PersistenceBroker broker = capsule.getBroker();
try
{
predicateQuery.create(oql);
Query pQ = ((OQLQueryImpl) predicateQuery).getQuery();
Criteria pCrit = pQ.getCriteria();
Criteria allElementsCriteria = this.getPkCriteriaForAllElements(broker);
// join selection of elements with predicate criteria:
pCrit.addAndCriteria(allElementsCriteria);
Class clazz = this.getElementsExtentClass(broker);
Query q = new QueryByCriteria(clazz, pCrit);
if (log.isDebugEnabled()) log.debug(q.toString());
// 2. perfom query
return (DSetImpl) broker.getCollectionByQuery(DSetImpl.class, q);
}
catch (PersistenceBrokerException e)
{
throw new ODMGRuntimeException(e.getMessage());
}
finally
{
capsule.destroy();
}
}
private Criteria getPkCriteriaForAllElements(PersistenceBroker broker)
{
try
{
Criteria crit = null;
for (int i = 0; i < elements.size(); i++)
{
DListEntry entry = (DListEntry) elements.get(i);
Object obj = entry.getRealSubject();
ClassDescriptor cld = broker.getClassDescriptor(obj.getClass());
FieldDescriptor[] pkFields = cld.getPkFields();
ValueContainer[] pkValues = broker.serviceBrokerHelper().getKeyValues(cld, obj);
Criteria criteria = new Criteria();
for (int j = 0; j < pkFields.length; j++)
{
FieldDescriptor fld = pkFields[j];
criteria.addEqualTo(fld.getPersistentField().getName(), pkValues[j].getValue());
}
if (crit == null)
crit = criteria;
else
crit.addOrCriteria(criteria);
}
return crit;
}
catch (PersistenceBrokerException e)
{
log.error(e);
return null;
}
}
private Class getElementsExtentClass(PersistenceBroker broker) throws PersistenceBrokerException
{
// we ll have to compute the most general extent class here !!!
DListEntry entry = (DListEntry) elements.get(0);
Class elementsClass = entry.getRealSubject().getClass();
Class extentClass = broker.getTopLevelClass(elementsClass);
return extentClass;
}
/**
* Access all of the elements of the collection that evaluate to true for the
* provided query predicate.
* @param predicate An OQL boolean query predicate.
* @return An iterator used to iterate over the elements that evaluated true for the predicate.
* @exception org.odmg.QueryInvalidException The query predicate is invalid.
*/
public java.util.Iterator select(String predicate) throws org.odmg.QueryInvalidException
{
return this.query(predicate).iterator();
}
/**
* Selects the single element of the collection for which the provided OQL query
* predicate is true.
* @param predicate An OQL boolean query predicate.
* @return The element that evaluates to true for the predicate. If no element
* evaluates to true, null is returned.
* @exception org.odmg.QueryInvalidException The query predicate is invalid.
*/
public Object selectElement(String predicate) throws org.odmg.QueryInvalidException
{
return ((DList) this.query(predicate)).get(0);
}
/**
* Sets the elements.
* @param elements The elements to set
*/
public void setElements(Vector elements)
{
this.elements = elements;
}
/**
* Sets the id.
* @param id The id to set
*/
public void setId(int id)
{
this.id = id;
}
/**
* Returns the number of elements in this collection. If this collection
* contains more than <tt>Integer.MAX_VALUE</tt> elements, returns
* <tt>Integer.MAX_VALUE</tt>.
*
* @return the number of elements in this collection
*/
public int size()
{
return elements.size();
}
/**
* Determine whether this set is a subset of the set referenced by <code>otherSet</code>.
* @param otherSet Another set.
* @return True if this set is a subset of the set referenced by <code>otherSet</code>,
* otherwise false.
*/
public boolean subsetOf(org.odmg.DSet otherSet)
{
return otherSet.containsAll(this);
}
/**
* Determine whether this set is a superset of the set referenced by <code>otherSet</code>.
* @param otherSet Another set.
* @return True if this set is a superset of the set referenced by <code>otherSet</code>,
* otherwise false.
*/
public boolean supersetOf(org.odmg.DSet otherSet)
{
return this.containsAll(otherSet);
}
/**
* Create a new <code>DSet</code> object that is the set union of this
* <code>DSet</code> object and the set referenced by <code>otherSet</code>.
* @param otherSet The other set to be used in the union operation.
* @return A newly created <code>DSet</code> instance that contains the union of the two sets.
*/
public org.odmg.DSet union(org.odmg.DSet otherSet)
{
DSetImpl result = new DSetImpl(pbKey);
result.addAll(this);
result.addAll(otherSet);
return result;
}
/**
* Gets the size.
* @return Returns a int
*/
public int getSize()
{
return size;
}
/**
* Sets the size.
* @param size The size to set
*/
public void setSize(int size)
{
this.size = size;
}
}