001: /*
002: * Copyright 2004 (C) TJDO.
003: * All rights reserved.
004: *
005: * This software is distributed under the terms of the TJDO License version 1.0.
006: * See the terms of the TJDO License in the documentation provided with this software.
007: *
008: * $Id: ClassViewExtent.java,v 1.9 2004/02/01 18:22:42 jackknifebarber Exp $
009: */
010:
011: package com.triactive.jdo.store;
012:
013: import com.triactive.jdo.PersistenceManager;
014: import com.triactive.jdo.model.ClassMetaData;
015: import com.triactive.jdo.util.IntArrayList;
016: import java.util.HashMap;
017: import java.util.Iterator;
018: import javax.jdo.Extent;
019: import javax.jdo.JDOFatalInternalException;
020: import javax.jdo.JDOFatalUserException;
021:
022: /**
023: * An Extent of all persistent objects backed by a view.
024: *
025: * @author <a href="mailto:mmartin5@austin.rr.com">Mike Martin</a>
026: * @version $Revision: 1.9 $
027: *
028: * @see Extent
029: */
030:
031: class ClassViewExtent implements Extent, Queryable {
032: private final PersistenceManager pm;
033: private final ClassView view;
034: private final boolean subclasses;
035: private final StoreManager storeMgr;
036: private final DatabaseAdapter dba;
037: private final Query query;
038: private final int fieldCount;
039: private final int[] prefetchFieldNumbers;
040: private final ColumnMapping[] prefetchFieldMappings;
041:
042: private HashMap queryResultsByIterator = new HashMap();
043:
044: public ClassViewExtent(PersistenceManager pm, ClassView view,
045: boolean subclasses) {
046: this .pm = pm;
047: this .view = view;
048: this .subclasses = subclasses;
049:
050: storeMgr = view.getStoreManager();
051: dba = storeMgr.getDatabaseAdapter();
052: query = storeMgr.getQuery(pm, null);
053:
054: Class candidateClass = getCandidateClass();
055:
056: query.setClass(candidateClass);
057: query.setCandidates(this );
058:
059: ClassMetaData cmd = ClassMetaData.forClass(candidateClass);
060: fieldCount = cmd.getFieldCount();
061: IntArrayList colfn = new IntArrayList(fieldCount);
062: ColumnMapping[] colfm = new ColumnMapping[fieldCount];
063:
064: for (int i = 0; i < fieldCount; ++i) {
065: if (view.isFieldPersistent(i)) {
066: Mapping m = view.getFieldMapping(i);
067:
068: if (!(m instanceof ColumnMapping))
069: throw new JDOFatalInternalException("Mapping " + m
070: + " not suitable for a view column?");
071:
072: colfn.add(i);
073: colfm[i] = (ColumnMapping) m;
074: }
075: }
076:
077: if (colfn.isEmpty())
078: throw new JDOFatalUserException(
079: "View class has no persistent fields: "
080: + candidateClass.getName());
081:
082: prefetchFieldNumbers = colfn.toArray();
083: prefetchFieldMappings = colfm;
084: }
085:
086: /**
087: * Returns an iterator over all the instances in the Extent.
088: *
089: * @return an iterator over all the instances in the Extent.
090: */
091:
092: public Iterator iterator() {
093: QueryResult qr = (QueryResult) query.execute();
094: Iterator i = qr.iterator();
095:
096: queryResultsByIterator.put(i, qr);
097:
098: return i;
099: }
100:
101: /**
102: * Returns whether this Extent was defined to contain subclasses.
103: *
104: * @return true if this Extent was defined to contain instances
105: * that are of a subclass type
106: */
107:
108: public boolean hasSubclasses() {
109: return subclasses;
110: }
111:
112: /**
113: * An Extent contains all instances of a particular Class in the data
114: * store; this method returns the Class of the instances
115: *
116: * @return the Class of instances of this Extent
117: */
118:
119: public Class getCandidateClass() {
120: return view.getType();
121: }
122:
123: /**
124: * An Extent is managed by a PersistenceManager; this method gives access
125: * to the owning PersistenceManager.
126: *
127: * @return the owning PersistenceManager
128: */
129:
130: public javax.jdo.PersistenceManager getPersistenceManager() {
131: return pm;
132: }
133:
134: /**
135: * Close an Iterator associated with this Extent instance. Iterators closed
136: * by this method will return false to hasNext() and will throw
137: * NoSuchElementException on next(). The Extent instance can still be used
138: * as a parameter of Query.setCandidates, and to get an Iterator.
139: *
140: * @param it an iterator obtained by the method iterator() on this Extent
141: * instance.
142: */
143:
144: public void close(Iterator it) {
145: QueryResult qr = (QueryResult) queryResultsByIterator
146: .remove(it);
147:
148: qr.close();
149: }
150:
151: /**
152: * Close all Iterators associated with this Extent instance. Iterators
153: * closed by this method will return false to hasNext() and will throw
154: * NoSuchElementException on next(). The Extent instance can still be used
155: * as a parameter of Query.setCandidates, and to get an Iterator.
156: */
157:
158: public void closeAll() {
159: Iterator i = queryResultsByIterator.values().iterator();
160:
161: while (i.hasNext()) {
162: QueryResult qr = (QueryResult) i.next();
163:
164: qr.close();
165: i.remove();
166: }
167: }
168:
169: public QueryStatement newQueryStatement(Class candidateClass) {
170: Class extentType = view.getType();
171:
172: if (!extentType.equals(candidateClass))
173: throw new IncompatibleQueryElementTypeException(extentType,
174: candidateClass);
175:
176: return dba.newQueryStatement(view);
177: }
178:
179: public Query.ResultObjectFactory newResultObjectFactory(
180: QueryStatement stmt) {
181: int[] columnNumbersByField = new int[prefetchFieldMappings.length];
182:
183: for (int i = 0; i < prefetchFieldMappings.length; ++i) {
184: ColumnMapping m = prefetchFieldMappings[i];
185:
186: if (m != null)
187: columnNumbersByField[i] = stmt.select(m.getColumn());
188: }
189:
190: return new TransientIDROF(pm, getCandidateClass(),
191: prefetchFieldNumbers, prefetchFieldMappings,
192: columnNumbersByField);
193: }
194:
195: public String toString() {
196: return "Extent of " + getCandidateClass();
197: }
198: }
|