Java tutorial
package org.apache.ojb.odmg.collections; /* Copyright 2003-2005 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.util.AbstractList; import java.util.ArrayList; import java.util.Iterator; import java.util.List; import java.util.ListIterator; import org.apache.commons.lang.builder.ToStringBuilder; import org.apache.ojb.broker.ManageableCollection; import org.apache.ojb.broker.OJBRuntimeException; import org.apache.ojb.broker.PBKey; import org.apache.ojb.broker.PersistenceBroker; import org.apache.ojb.broker.PersistenceBrokerAware; 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.RuntimeObject; import org.apache.ojb.odmg.oql.OQLQueryImpl; import org.odmg.DArray; import org.odmg.DCollection; import org.odmg.DList; import org.odmg.ODMGRuntimeException; import org.odmg.OQLQuery; import org.odmg.QueryInvalidException; import org.odmg.Transaction; /** * * @author Thomas Mahler * @author <a href="mailto:armin@codeAuLait.de">Armin Waibel</a> * @version $Id: DListImpl.java,v 1.27.2.5 2005/12/21 22:29:50 tomdz Exp $ */ public class DListImpl extends AbstractList implements DList, DArray, ManageableCollection, PersistenceBrokerAware { private static final long serialVersionUID = -9219943066614026526L; private transient Logger log; private Integer id; private List elements; private PBKey pbKey; /** * Used by PB-Kernel to instantiate ManageableCollections * FOR INTERNAL USE ONLY */ public DListImpl() { super(); elements = new ArrayList(); // if(getTransaction() == null) // { // throw new TransactionNotInProgressException("Materialization of DCollection instances must be done" + // " within a odmg-tx"); // } getPBKey(); } /** * Used on odmg-level */ public DListImpl(PBKey pbKey) { this(); this.pbKey = pbKey; } protected Logger getLog() { if (log == null) { log = LoggerFactory.getLogger(DListImpl.class); } return log; } private DListEntry prepareEntry(Object obj) { return new DListEntry(this, obj); } protected TransactionImpl getTransaction() { return TxManagerFactory.instance().getTransaction(); } protected boolean checkForOpenTransaction(TransactionImpl tx) { boolean result = false; if (tx != null && tx.isOpen()) { result = true; } return result; } public PBKey getPBKey() { if (pbKey == null) { TransactionImpl tx = getTransaction(); if (tx != null && tx.isOpen()) { pbKey = tx.getBroker().getPBKey(); } } return pbKey; } public void setPBKey(PBKey pbKey) { this.pbKey = pbKey; } /** * Inserts the specified element at the specified position in this list * (optional operation). Shifts the element currently at that position * (if any) and any subsequent elements to the right (adds one to their * indices). * * @param index index at which the specified element is to be inserted. * @param element element to be inserted. * * @throws UnsupportedOperationException if the <tt>add</tt> method is not * supported by this list. * @throws ClassCastException if the class of the specified element * prevents it from being added to this list. * @throws IllegalArgumentException if some aspect of the specified * element prevents it from being added to this list. * @throws IndexOutOfBoundsException if the index is out of range * (index < 0 || index > size()). */ public void add(int index, Object element) { DListEntry entry = prepareEntry(element); elements.add(index, entry); // if we are in a transaction: acquire locks ! TransactionImpl tx = getTransaction(); if (checkForOpenTransaction(tx)) { RuntimeObject rt = new RuntimeObject(this, tx); List regList = tx.getRegistrationList(); tx.lockAndRegister(rt, Transaction.WRITE, false, regList); rt = new RuntimeObject(element, tx); tx.lockAndRegister(rt, Transaction.READ, regList); rt = new RuntimeObject(entry, tx, true); tx.lockAndRegister(rt, Transaction.WRITE, false, regList); } // changing the position markers of entries: int offset = 0; try { offset = ((DListEntry) elements.get(index - 1)).getPosition(); } catch (Exception ignored) { } for (int i = offset; i < elements.size(); i++) { entry = (DListEntry) elements.get(i); entry.setPosition(i); } } /** * Removes the element at the specified position in this list (optional * operation). Shifts any subsequent elements to the left (subtracts one * from their indices). Returns the element that was removed from the * list.<p> * * This implementation always throws an * <tt>UnsupportedOperationException</tt>. * * @param index the index of the element to remove. * @return the element previously at the specified position. * * @throws UnsupportedOperationException if the <tt>remove</tt> method is * not supported by this list. * @throws IndexOutOfBoundsException if the specified index is out of * range (<tt>index < 0 || index >= size()</tt>). */ public Object remove(int index) { DListEntry entry = (DListEntry) elements.get(index); // if we are in a transaction: acquire locks ! TransactionImpl tx = getTransaction(); if (checkForOpenTransaction(tx)) { tx.deletePersistent(new RuntimeObject(entry, tx)); } elements.remove(index); // changing the position markers of entries: int offset = 0; try { offset = ((DListEntry) elements.get(index)).getPosition(); } catch (Exception ignored) { } for (int i = offset; i < elements.size(); i++) { entry = (DListEntry) elements.get(i); entry.setPosition(i); } return entry.getRealSubject(); } /** * Creates a new <code>DList</code> object that contains the contents of this * <code>DList</code> object concatenated * with the contents of the <code>otherList</code> object. * @param otherList The list whose elements are placed at the end of the list * returned by this method. * @return A new <code>DList</code> that is the concatenation of this list and * the list referenced by <code>otherList</code>. */ public DList concat(DList otherList) { DListImpl result = new DListImpl(pbKey); result.addAll(this); result.addAll(otherList); 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; } /** * Returns the element at the specified position in this list. * * @param index index of element to return. * @return the element at the specified position in this list. * * @throws IndexOutOfBoundsException if the index is out of range (index * < 0 || index >= size()). */ public Object get(int index) { DListEntry entry = (DListEntry) elements.get(index); return entry.getRealSubject(); } /** * Insert the method's description here. * Creation date: (10.02.2001 20:53:01) * @return java.util.Vector */ public List getElements() { return elements; } /** * Lazily return the Id, no point in precomputing it. * @return int */ public Integer getId() { return id; } /** * 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 Iterator iterator() { return new DListIterator(this); } /** * Returns a list iterator of the elements in this list (in proper * sequence). * * @return a list iterator of the elements in this list (in proper * sequence). */ public ListIterator listIterator() { return new DListIterator(this); } /** * Returns a list iterator of the elements in this list (in proper * sequence), starting at the specified position in this list. The * specified index indicates the first element that would be returned by * an initial call to the <tt>next</tt> method. An initial call to * the <tt>previous</tt> method would return the element with the * specified index minus one. * * @param index index of first element to be returned from the * list iterator (by a call to the <tt>next</tt> method). * @return a list iterator of the elements in this list (in proper * sequence), starting at the specified position in this list. * @throws IndexOutOfBoundsException if the index is out of range (index * < 0 || index > size()). */ public ListIterator listIterator(int index) { return new DListIterator(this, index); } private Criteria getPkCriteriaForAllElements(PersistenceBroker brokerForClass) { try { Criteria crit = null; for (int i = 0; i < elements.size(); i++) { DListEntry entry = (DListEntry) elements.get(i); Object obj = entry.getRealSubject(); ClassDescriptor cld = brokerForClass.getClassDescriptor(obj.getClass()); FieldDescriptor[] pkFields = cld.getPkFields(); ValueContainer[] pkValues = brokerForClass.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) { return null; } } private Class getElementsExtentClass(PersistenceBroker brokerForClass) 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 = brokerForClass.getTopLevelClass(elementsClass); return extentClass; } /** * 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 DCollection query(String predicate) throws QueryInvalidException { // 1.build complete OQL statement String oql = "select all from java.lang.Object where " + predicate; TransactionImpl tx = getTransaction(); if (tx == null) throw new QueryInvalidException("Need running transaction to do query"); OQLQuery predicateQuery = tx.getImplementation().newOQLQuery(); predicateQuery.create(oql); Query pQ = ((OQLQueryImpl) predicateQuery).getQuery(); Criteria pCrit = pQ.getCriteria(); PBCapsule handle = new PBCapsule(pbKey, tx); DList result; try { PersistenceBroker broker = handle.getBroker(); Criteria allElementsCriteria = this.getPkCriteriaForAllElements(broker); // join selection of elements with predicate criteria: allElementsCriteria.addAndCriteria(pCrit); Class clazz = null; try { clazz = this.getElementsExtentClass(broker); } catch (PersistenceBrokerException e) { getLog().error(e); throw new ODMGRuntimeException(e.getMessage()); } Query q = new QueryByCriteria(clazz, allElementsCriteria); if (getLog().isDebugEnabled()) getLog().debug(q.toString()); result = null; try { result = (DList) broker.getCollectionByQuery(DListImpl.class, q); } catch (PersistenceBrokerException e) { getLog().error("Query failed", e); throw new OJBRuntimeException(e); } } finally { // cleanup stuff if (handle != null) handle.destroy(); } // 3. return resulting collection return result; } public int hashCode() { int hashCode = 1; Iterator it = elements.iterator(); while (it.hasNext()) { Object obj = it.next(); hashCode = 31 * hashCode + (obj == null ? 0 : obj.hashCode()); } return hashCode; } public String toString() { ToStringBuilder buf = new ToStringBuilder(this); buf.append("id", id); buf.append("pbKey", pbKey); buf.append("[containing elements: "); Iterator it = elements.iterator(); while (it.hasNext()) { Object obj = it.next(); buf.append(obj != null ? obj.toString() : null); } buf.append("]"); return buf.toString(); } /** * 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 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); } /** * 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(); } /** * add a single Object to the Collection. This method is used during reading Collection elements * from the database. Thus it is is save to cast anObject to the underlying element type of the * collection. */ public void ojbAdd(Object anObject) { DListEntry entry = prepareEntry(anObject); entry.setPosition(elements.size()); elements.add(entry); } /** * adds a Collection to this collection. Used in reading Extents from the Database. * Thus it is save to cast otherCollection to this.getClass(). */ public void ojbAddAll(ManageableCollection otherCollection) { // don't use this to avoid locking // this.addAll((DListImpl) otherCollection); Iterator it = otherCollection.ojbIterator(); while (it.hasNext()) { ojbAdd(it.next()); } } public void afterStore(PersistenceBroker broker) throws PersistenceBrokerException { } /** * returns an Iterator over all elements in the collection. Used during store and delete Operations. * If the implementor does not return an iterator over ALL elements, OJB cannot store and delete all elements properly. */ public Iterator ojbIterator() { return this.iterator(); } /** * Resize the array to have <code>newSize</code> elements. * @param newSize The new size of the array. */ public void resize(int newSize) { } /** * Sets the elements. * @param elements The elements to set */ public void setElements(List elements) { this.elements = elements; } /** * Sets the id. * @param id The id to set */ public void setId(Integer id) { this.id = id; } //*************************************************************** // PersistenceBrokerAware interface //*************************************************************** /** * prepare itself for persistence. Each DList entry generates an * {@link org.apache.ojb.broker.Identity} for the wrapped persistent * object. */ public void beforeInsert(PersistenceBroker broker) throws PersistenceBrokerException { // Iterator it = elements.iterator(); // DListEntry entry; // while (it.hasNext()) // { // entry = (DListEntry) it.next(); // entry.prepareForPersistency(broker); // } } /** * noop */ public void beforeUpdate(PersistenceBroker broker) throws PersistenceBrokerException { } /** * noop */ public void beforeDelete(PersistenceBroker broker) throws PersistenceBrokerException { } /** * noop */ public void afterUpdate(PersistenceBroker broker) throws PersistenceBrokerException { } /** * noop */ public void afterInsert(PersistenceBroker broker) throws PersistenceBrokerException { } /** * noop */ public void afterDelete(PersistenceBroker broker) throws PersistenceBrokerException { } /** * noop */ public void afterLookup(PersistenceBroker broker) throws PersistenceBrokerException { } }