001: package org.apache.ojb.broker.accesslayer;
002:
003: /* Copyright 2002-2005 The Apache Software Foundation
004: *
005: * Licensed under the Apache License, Version 2.0 (the "License");
006: * you may not use this file except in compliance with the License.
007: * You may obtain a copy of the License at
008: *
009: * http://www.apache.org/licenses/LICENSE-2.0
010: *
011: * Unless required by applicable law or agreed to in writing, software
012: * distributed under the License is distributed on an "AS IS" BASIS,
013: * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
014: * See the License for the specific language governing permissions and
015: * limitations under the License.
016: */
017:
018: import java.lang.reflect.Array;
019: import java.util.ArrayList;
020: import java.util.Collection;
021: import java.util.HashMap;
022: import java.util.HashSet;
023: import java.util.Iterator;
024: import java.util.List;
025:
026: import org.apache.ojb.broker.Identity;
027: import org.apache.ojb.broker.ManageableCollection;
028: import org.apache.ojb.broker.OJBRuntimeException;
029: import org.apache.ojb.broker.PersistenceBroker;
030: import org.apache.ojb.broker.IdentityFactory;
031: import org.apache.ojb.broker.core.PersistenceBrokerImpl;
032: import org.apache.ojb.broker.core.proxy.CollectionProxyDefaultImpl;
033: import org.apache.ojb.broker.core.proxy.ProxyHelper;
034: import org.apache.ojb.broker.metadata.ClassDescriptor;
035: import org.apache.ojb.broker.metadata.CollectionDescriptor;
036: import org.apache.ojb.broker.metadata.FieldHelper;
037: import org.apache.ojb.broker.metadata.MetadataException;
038: import org.apache.ojb.broker.metadata.ObjectReferenceDescriptor;
039: import org.apache.ojb.broker.metadata.fieldaccess.PersistentField;
040: import org.apache.ojb.broker.query.Query;
041: import org.apache.ojb.broker.query.QueryByCriteria;
042: import org.apache.ojb.broker.util.BrokerHelper;
043: import org.apache.ojb.broker.util.collections.RemovalAwareCollection;
044: import org.apache.ojb.broker.util.collections.RemovalAwareList;
045: import org.apache.ojb.broker.util.collections.RemovalAwareSet;
046:
047: /**
048: * Relationship Prefetcher for Collections.
049: *
050: * @author <a href="mailto:jbraeuchi@gmx.ch">Jakob Braeuchi</a>
051: * @version $Id: CollectionPrefetcher.java,v 1.29.2.5 2005/12/21 22:22:58 tomdz Exp $
052: */
053: public class CollectionPrefetcher extends RelationshipPrefetcherImpl {
054:
055: /**
056: * Constructor for CollectionPrefetcher.
057: *
058: * @param aBroker
059: * @param anOrd
060: */
061: public CollectionPrefetcher(PersistenceBrokerImpl aBroker,
062: ObjectReferenceDescriptor anOrd) {
063: super (aBroker, anOrd);
064: }
065:
066: /**
067: * Build the multiple queries for one relationship because of limitation of IN(...)
068: *
069: * @param owners Collection containing all objects of the ONE side
070: */
071: protected Query[] buildPrefetchQueries(Collection owners,
072: Collection children) {
073: ClassDescriptor cld = getOwnerClassDescriptor();
074: Class topLevelClass = getBroker().getTopLevelClass(
075: cld.getClassOfObject());
076: BrokerHelper helper = getBroker().serviceBrokerHelper();
077: Collection queries = new ArrayList(owners.size());
078: Collection idsSubset = new HashSet(owners.size());
079: Object[] fkValues;
080: Object owner;
081: Identity id;
082:
083: Iterator iter = owners.iterator();
084: while (iter.hasNext()) {
085: owner = iter.next();
086: fkValues = helper.extractValueArray(helper.getKeyValues(
087: cld, owner));
088: id = getBroker().serviceIdentity().buildIdentity(null,
089: topLevelClass, fkValues);
090: idsSubset.add(id);
091: if (idsSubset.size() == pkLimit) {
092: queries.add(buildPrefetchQuery(idsSubset));
093: idsSubset.clear();
094: }
095: }
096:
097: if (idsSubset.size() > 0) {
098: queries.add(buildPrefetchQuery(idsSubset));
099: }
100:
101: return (Query[]) queries.toArray(new Query[queries.size()]);
102: }
103:
104: /**
105: * Build the query to perform a batched read get orderBy settings from CollectionDescriptor
106: *
107: * @param ids Collection containing all identities of objects of the ONE side
108: */
109: protected Query buildPrefetchQuery(Collection ids) {
110: CollectionDescriptor cds = getCollectionDescriptor();
111: QueryByCriteria query = buildPrefetchQuery(
112: ids,
113: cds
114: .getForeignKeyFieldDescriptors(getItemClassDescriptor()));
115:
116: // check if collection must be ordered
117: if (!cds.getOrderBy().isEmpty()) {
118: Iterator iter = cds.getOrderBy().iterator();
119: while (iter.hasNext()) {
120: query.addOrderBy((FieldHelper) iter.next());
121: }
122: }
123:
124: return query;
125: }
126:
127: /**
128: * associate the batched Children with their owner object loop over children
129: */
130: protected void associateBatched(Collection owners,
131: Collection children) {
132: CollectionDescriptor cds = getCollectionDescriptor();
133: PersistentField field = cds.getPersistentField();
134: PersistenceBroker pb = getBroker();
135: Class ownerTopLevelClass = pb
136: .getTopLevelClass(getOwnerClassDescriptor()
137: .getClassOfObject());
138: Class collectionClass = cds.getCollectionClass(); // this collection type will be used:
139: HashMap ownerIdsToLists = new HashMap(owners.size());
140:
141: IdentityFactory identityFactory = pb.serviceIdentity();
142: // initialize the owner list map
143: for (Iterator it = owners.iterator(); it.hasNext();) {
144: Object owner = it.next();
145: ownerIdsToLists.put(identityFactory.buildIdentity(
146: getOwnerClassDescriptor(), owner), new ArrayList());
147: }
148:
149: // build the children lists for the owners
150: for (Iterator it = children.iterator(); it.hasNext();) {
151: Object child = it.next();
152: // BRJ: use cld for real class, relatedObject could be Proxy
153: ClassDescriptor cld = getDescriptorRepository()
154: .getDescriptorFor(ProxyHelper.getRealClass(child));
155:
156: Object[] fkValues = cds.getForeignKeyValues(child, cld);
157: Identity ownerId = identityFactory.buildIdentity(null,
158: ownerTopLevelClass, fkValues);
159: List list = (List) ownerIdsToLists.get(ownerId);
160: if (list != null) {
161: list.add(child);
162: }
163: }
164:
165: // connect children list to owners
166: for (Iterator it = owners.iterator(); it.hasNext();) {
167: Object result;
168: Object owner = it.next();
169: Identity ownerId = identityFactory.buildIdentity(owner);
170: List list = (List) ownerIdsToLists.get(ownerId);
171:
172: if ((collectionClass == null) && field.getType().isArray()) {
173: int length = list.size();
174: Class itemtype = field.getType().getComponentType();
175: result = Array.newInstance(itemtype, length);
176: for (int j = 0; j < length; j++) {
177: Array.set(result, j, list.get(j));
178: }
179: } else {
180: ManageableCollection col = createCollection(cds,
181: collectionClass);
182: for (Iterator it2 = list.iterator(); it2.hasNext();) {
183: col.ojbAdd(it2.next());
184: }
185: result = col;
186: }
187:
188: Object value = field.get(owner);
189: if ((value instanceof CollectionProxyDefaultImpl)
190: && (result instanceof Collection)) {
191: ((CollectionProxyDefaultImpl) value)
192: .setData((Collection) result);
193: } else {
194: field.set(owner, result);
195: }
196: }
197: }
198:
199: /**
200: * Create a collection object of the given collection type. If none has been given,
201: * OJB uses RemovalAwareList, RemovalAwareSet, or RemovalAwareCollection depending
202: * on the field type.
203: *
204: * @param desc The collection descriptor
205: * @param collectionClass The collection class specified in the collection-descriptor
206: * @return The collection object
207: */
208: protected ManageableCollection createCollection(
209: CollectionDescriptor desc, Class collectionClass) {
210: Class fieldType = desc.getPersistentField().getType();
211: ManageableCollection col;
212:
213: if (collectionClass == null) {
214: if (ManageableCollection.class.isAssignableFrom(fieldType)) {
215: try {
216: col = (ManageableCollection) fieldType
217: .newInstance();
218: } catch (Exception e) {
219: throw new OJBRuntimeException(
220: "Cannot instantiate the default collection type "
221: + fieldType.getName()
222: + " of collection "
223: + desc.getAttributeName()
224: + " in type "
225: + desc.getClassDescriptor()
226: .getClassNameOfObject());
227: }
228: } else if (fieldType
229: .isAssignableFrom(RemovalAwareCollection.class)) {
230: col = new RemovalAwareCollection();
231: } else if (fieldType
232: .isAssignableFrom(RemovalAwareList.class)) {
233: col = new RemovalAwareList();
234: } else if (fieldType
235: .isAssignableFrom(RemovalAwareSet.class)) {
236: col = new RemovalAwareSet();
237: } else {
238: throw new MetadataException(
239: "Cannot determine a default collection type for collection "
240: + desc.getAttributeName()
241: + " in type "
242: + desc.getClassDescriptor()
243: .getClassNameOfObject());
244: }
245: } else {
246: try {
247: col = (ManageableCollection) collectionClass
248: .newInstance();
249: } catch (Exception e) {
250: throw new OJBRuntimeException(
251: "Cannot instantiate the collection class "
252: + collectionClass.getName()
253: + " of collection "
254: + desc.getAttributeName()
255: + " in type "
256: + desc.getClassDescriptor()
257: .getClassNameOfObject());
258: }
259: }
260: return col;
261: }
262:
263: protected CollectionDescriptor getCollectionDescriptor() {
264: return (CollectionDescriptor) getObjectReferenceDescriptor();
265: }
266: }
|