001: /*
002: * GeoTools - OpenSource mapping toolkit
003: * http://geotools.org
004: * (C) 2004-2006, GeoTools Project Managment Committee (PMC)
005: *
006: * This library is free software; you can redistribute it and/or
007: * modify it under the terms of the GNU Lesser General Public
008: * License as published by the Free Software Foundation;
009: * version 2.1 of the License.
010: *
011: * This library is distributed in the hope that it will be useful,
012: * but WITHOUT ANY WARRANTY; without even the implied warranty of
013: * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
014: * Lesser General Public License for more details.
015: */
016: package org.geotools.data.store;
017:
018: import java.io.IOException;
019: import java.util.Collections;
020: import java.util.Iterator;
021: import java.util.List;
022: import java.util.logging.Logger;
023:
024: import org.geotools.data.DataStore;
025: import org.geotools.data.EmptyFeatureWriter;
026: import org.geotools.data.FeatureReader;
027: import org.geotools.data.FeatureSource;
028: import org.geotools.data.FeatureWriter;
029: import org.geotools.data.FilteringFeatureWriter;
030: import org.geotools.data.InProcessLockingManager;
031: import org.geotools.data.LockingManager;
032: import org.geotools.data.Query;
033: import org.geotools.data.Transaction;
034: import org.geotools.data.view.DefaultView;
035: import org.geotools.feature.FeatureType;
036: import org.geotools.feature.SchemaException;
037: import org.opengis.filter.Filter;
038:
039: /**
040: * Represents a stating point for implementing your own DataStore.
041: *
042: * <p>
043: * The goal is to have this class provide <b>everything</b> else if you only
044: * need to provide:
045: * </p>
046: *
047: * <ul>
048: * <li>
049: * Set getContents() - set of TypeEntry
050: * </li>
051: * <li>
052: * FeatureReader getFeatureReader( typeName )
053: * </li>
054: * </ul>
055: *
056: * To support writing:
057: * <ul>
058: * <li>set isWritable to true
059: * <li>implement FeatureWriter getFeatureWriter( typeName )
060: * </ul>
061: *
062: * <p>
063: * All remaining functionality is implemented against these methods, including
064: * Transaction and Locking Support. These implementations will not be optimal
065: * but they will work.
066: * </p>
067: *
068: * To support custom query optimizations:
069: * <ul>
070: * <li> Filter getUnsupportedFilter(String typeName, Filter filter)
071: * <li> FeatureReader getFeatureReader(String typeName, Query query)
072: * </ul>
073: *
074: * To provide high-level writing optimizations:
075: * <ul>
076: * <li> Override createFeatureSource to use your own custom FeatureSource
077: * </ul>
078: *
079: * To provide low-level writing optimizations:
080: * <ul>
081: * <li> FeatureWriter getFeatureWriterAppend( typeName, transaction )
082: * <li> FeatureWriter getFeatureWriterAppend( typeName, Filter, transaction )
083: * <li>
084: * </ul>
085: *
086: * To provide high-level writing optimizations:
087: * <ul>
088: * <li> Stop using FeatureWriter completely
089: * <li> Override createFeatureStore to use your own custom FeatureStore
090: * </ul>
091: * <p>
092: * Pleae note that there may be a better place for you to start out from, (like
093: * JDBCDataStore).
094: * </p>
095: *
096: * @author jgarnett
097: * @source $URL: http://svn.geotools.org/geotools/tags/2.4.1/modules/library/main/src/main/java/org/geotools/data/store/AbstractDataStore2.java $
098: */
099: public class AbstractDataStore2 implements DataStore {
100: /** The logger for the data module. */
101: protected static final Logger LOGGER = org.geotools.util.logging.Logging
102: .getLogger("org.geotools.data");
103:
104: /**
105: * Manages InProcess locks for FeatureLocking implementations.
106: *
107: * <p>
108: * May be null if subclass is providing real locking.
109: * </p>
110: */
111: private InProcessLockingManager lockingManager;
112:
113: /** Default (Writeable) DataStore */
114: public AbstractDataStore2() {
115: lockingManager = createLockingManager();
116: }
117:
118: /** List<ActiveTypeEntry> subclass control provided by createContents */
119: private List contents = null;
120:
121: /**
122: * Currently returns an InProcessLockingManager.
123: *
124: * <p>
125: * Subclasses that implement real locking may override this method to
126: * return <code>null</code>.
127: * </p>
128: *
129: * @return InProcessLockingManager or null.
130: */
131: protected InProcessLockingManager createLockingManager() {
132: return new InProcessLockingManager();
133: }
134:
135: /** List of ActiveTypeEntry entries - one for each featureType provided by this Datastore */
136: public List entries() {
137: if (contents == null) {
138: contents = createContents();
139: }
140: return Collections.unmodifiableList(contents);
141: }
142:
143: /**
144: * Subclass must overrride to connet to contents.
145: * <p>
146: * An implementation that has any doubt about its contents should aquire
147: * them during object creation (where an IOException can be thrown).
148: * </p>
149: * <p>
150: * This method is lazyly called to create a List of ActiveTypeEntry for
151: * each FeatureCollection in this DataStore.
152: * </p>
153: * @return List<ActiveTypeEntry>.
154: */
155: protected List createContents() {
156: throw new UnsupportedOperationException(
157: "createContent not implemented");
158: }
159:
160: /** Convience method for retriving all the names from the Catalog Entires */
161: public String[] getTypeNames() {
162: List all = entries();
163: String names[] = new String[all.size()];
164: int index = 0;
165: for (Iterator i = all.iterator(); i.hasNext(); index++) {
166: ActiveTypeEntry entry = (ActiveTypeEntry) i.next();
167: names[index] = entry.getTypeName();
168: }
169: return names;
170: }
171:
172: public ActiveTypeEntry entry(String typeName) {
173: if (typeName == null)
174: return null;
175: for (Iterator i = entries().iterator(); i.hasNext();) {
176: ActiveTypeEntry entry = (ActiveTypeEntry) i.next();
177: if (typeName.equals(entry.getTypeName())) {
178: return entry;
179: }
180: }
181: return null;
182: }
183:
184: /** Retrive schema information for typeName */
185: public FeatureType getSchema(String typeName) throws IOException {
186: return entry(typeName).getFeatureType();
187: }
188:
189: /**
190: * Subclass should implement to provide for creation.
191: *
192: * @param featureType Requested FeatureType
193: *
194: * @throws IOException Subclass may throw IOException
195: * @throws UnsupportedOperationException Subclass may implement
196: */
197: public void createSchema(FeatureType featureType)
198: throws IOException {
199: throw new UnsupportedOperationException(
200: "Schema creation not supported");
201: }
202:
203: /**
204: * Subclass should implement to provide modification support.
205: */
206: public void updateSchema(String typeName, FeatureType featureType)
207: throws IOException {
208: throw new UnsupportedOperationException(
209: "Schema modification not supported");
210: }
211:
212: // Jody - This is my recomendation for DataStore in order to support CS reprojection and override
213: /**
214: * Create a FeatureSource that represents your Query.
215: * <p>
216: * If we can make this part of the public API, we can phase out FeatureResults.
217: * (and reduce the number of classes people need to know about).
218: * </p>
219: */
220: public FeatureSource getView(final Query query) throws IOException,
221: SchemaException {
222: return new DefaultView(getFeatureSource(query.getTypeName()),
223: query);
224: }
225:
226: /**
227: * Aqure FeatureSource for indicated typeName.
228: * <p>
229: * Note this API is not sufficient; Namespace needs to be used as well.
230: * </p>
231: */
232: public FeatureSource getFeatureSource(final String typeName)
233: throws IOException {
234: return entry(typeName).createFeatureSource();
235: }
236:
237: /**
238: * Access a FeatureReader providing access to Feature information.
239: * <p>
240: * This implementation passes off responsibility to the following overrideable methods:
241: * <ul>
242: * <li>getFeatureReader(String typeName) - subclass *required* to implement
243: * </ul>
244: * </p>
245: * <p>If you can handle some aspects of Query natively (say expressions or reprojection) override the following:
246: * <li>
247: * <li>getFeatureReader(typeName, query) - override to handle query natively
248: * <li>getUnsupportedFilter(typeName, filter) - everything you cannot handle natively
249: * <li>getFeatureReader(String typeName) - you must implement this, but you could point it back to getFeatureReader( typeName, Query.ALL );
250: * </ul>
251: * </p>
252: */
253: public FeatureReader getFeatureReader(Query query,
254: Transaction transaction) throws IOException {
255: if (query.getTypeName() == null) {
256: throw new NullPointerException(
257: "getFeatureReader requires typeName: "
258: + "use getTypeNames() for a list of available types");
259: }
260: ActiveTypeEntry entry = entry(query.getTypeName());
261: return entry.reader(query, transaction);
262: }
263:
264: /* (non-Javadoc)
265: * @see org.geotools.data.DataStore#getFeatureWriter(java.lang.String, org.geotools.filter.Filter, org.geotools.data.Transaction)
266: */
267: public FeatureWriter getFeatureWriter(String typeName,
268: Filter filter, Transaction transaction) throws IOException {
269: if (filter == null) {
270: throw new NullPointerException(
271: "getFeatureReader requires Filter: "
272: + "did you mean Filter.INCLUDE?");
273: }
274:
275: if (filter == Filter.EXCLUDE) {
276: FeatureType featureType = getSchema(typeName);
277:
278: return new EmptyFeatureWriter(featureType);
279: }
280:
281: FeatureWriter writer = getFeatureWriter(typeName, transaction);
282:
283: if (filter != Filter.INCLUDE) {
284: writer = new FilteringFeatureWriter(writer, filter);
285: }
286:
287: return writer;
288: }
289:
290: /**
291: * TODO summary sentence for getFeatureWriter ...
292: *
293: * @see org.geotools.data.DataStore#getFeatureWriter(java.lang.String, org.geotools.data.Transaction)
294: * @param typeName
295: * @param transaction
296: * @return FeatureWriter
297: * @throws IOException
298: */
299: public FeatureWriter getFeatureWriter(String typeName,
300: Transaction transaction) throws IOException {
301: return entry(typeName).writer(transaction);
302: }
303:
304: /**
305: * FeatureWriter setup to add new content.
306: *
307: * @see org.geotools.data.DataStore#getFeatureWriterAppend(java.lang.String, org.geotools.data.Transaction)
308: * @param typeName
309: * @param transaction
310: * @return FeatureWriter already skipped to the end
311: * @throws IOException
312: */
313: public FeatureWriter getFeatureWriterAppend(String typeName,
314: Transaction transaction) throws IOException {
315: return entry(typeName).createAppend(transaction);
316: }
317:
318: /**
319: * Locking manager used for this DataStore.
320: *
321: * <p>
322: * By default AbstractDataStore makes use of InProcessLockingManager.
323: * </p>
324: *
325: *
326: * @see org.geotools.data.DataStore#getLockingManager()
327: */
328: public LockingManager getLockingManager() {
329: return lockingManager;
330: }
331:
332: /**
333: * Dummy implementation, it's a no-op. Subclasses holding to system resources must
334: * override this method and release them.
335: */
336: public void dispose() {
337: // nothing to do
338: }
339: }
|