001: /*
002: * GeoTools - OpenSource mapping toolkit
003: * http://geotools.org
004: * (C) 2005-2006, GeoTools Project Managment Committee (PMC)
005: * (C) 2005, Refractions Research Inc.
006: *
007: * This library is free software; you can redistribute it and/or
008: * modify it under the terms of the GNU Lesser General Public
009: * License as published by the Free Software Foundation;
010: * version 2.1 of the License.
011: *
012: * This library is distributed in the hope that it will be useful,
013: * but WITHOUT ANY WARRANTY; without even the implied warranty of
014: * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
015: * Lesser General Public License for more details.
016: */
017: package org.geotools.catalog;
018:
019: import java.io.IOException;
020: import java.net.URI;
021: import java.net.URISyntaxException;
022: import java.util.ArrayList;
023: import java.util.List;
024: import java.util.Map;
025: import java.util.logging.Level;
026:
027: import org.geotools.catalog.defaults.DefaultServiceInfo;
028: import org.geotools.data.DataStore;
029: import org.geotools.data.DataStoreFactorySpi;
030: import org.geotools.util.ProgressListener;
031:
032: /**
033: * Service implementation for services which resolve to a
034: * {@link org.geotools.data.DataStore}.
035: * <p>
036: * Subclasses may wish to override the following methods.
037: * <ul>
038: * <li>{@link org.geotools.catalog.Resolve#getIdentifier()}
039: * <li>{@link #createDataStoreFactory()}
040: * <li>{@link #createMetaData(DataStore, ProgressListener)}
041: * <li>{@link #createGeoResource(String, DataStore)}
042: * </ul>
043: * In addition, subclasses may wish to <b>extend</b> the following methods in
044: * order to support additional resolves.
045: * <ul>
046: * <li>{@link #canResolve(Class)}
047: * <li>{@link #resolve(Class, ProgressListener)}
048: * </ul>
049: *
050: * For example, the following implements an additional resolve to a particular
051: * data store implementation.
052: * <br>
053: * <code>
054: * <pre>
055: * class ShapefileService extends DataStoreService {
056: * ...
057: * boolean canResolve( Class adaptee ) {
058: * if (adaptee != null) {
059: * if ( adaptee.isAssignableFrom( ShapefileDataStore.class ) ) {
060: * return true;
061: * }
062: * }
063: *
064: * return super.canResolve( adaptee );
065: * }
066: * ...
067: * }
068: * </pre>
069: * </code>
070: * </p>
071: *
072: * @author Justin Deoliveira, The Open Planning Project, jdeolive@openplans.org
073: *
074: */
075: public class DataStoreService extends AbstractService {
076:
077: /**
078: * Factory used to create datastores.
079: */
080: DataStoreFactorySpi dataStoreFactory;
081:
082: /**
083: * The underying datastore, cached.
084: */
085: DataStore dataStore;
086:
087: /**
088: * cached service info.
089: */
090: ServiceInfo info;
091:
092: public DataStoreService(Catalog parent, Map params,
093: DataStoreFactorySpi dataStoreFactory) {
094: super (parent, params);
095: this .dataStoreFactory = dataStoreFactory;
096: }
097:
098: /**
099: * @return The datastore factory.
100: */
101: public DataStoreFactorySpi getDataStoreFactory() {
102: return dataStoreFactory;
103: }
104:
105: /**
106: * Returns a uri constructed from {@link DataStoreFactorySpi#getDisplayName()},
107: * sublcasses may wish to override.
108: */
109: public URI getIdentifier() {
110: try {
111: return new URI(dataStoreFactory.getDisplayName());
112: } catch (URISyntaxException e) {
113: throw new RuntimeException(e);
114: }
115: }
116:
117: /**
118: * Supports the required Service resolves with an additional resolve to
119: * {@link DataStore}.
120: * <p>
121: * Subclasses may wish to extend this method.
122: * </p>
123: */
124: public boolean canResolve(Class adaptee) {
125: if (adaptee == null)
126: return false;
127:
128: return adaptee.isAssignableFrom(ServiceInfo.class)
129: || adaptee.isAssignableFrom(List.class)
130: || adaptee.isAssignableFrom(DataStore.class);
131: }
132:
133: /**
134: * Supports the required Service resolves with an additional resolve to
135: * {@link DataStore}.
136: * <p>
137: * Subclasses may wish to extend this method.
138: * </p>
139: */
140: public Object resolve(Class adaptee, ProgressListener monitor)
141: throws IOException {
142:
143: if (adaptee == null)
144: return null;
145:
146: if (adaptee.isAssignableFrom(ServiceInfo.class)) {
147: return getInfo(monitor);
148: }
149:
150: if (adaptee.isAssignableFrom(List.class)) {
151: return members(monitor);
152: }
153:
154: if (adaptee.isAssignableFrom(DataStore.class)) {
155: return dataStore(monitor);
156: }
157:
158: return null;
159: }
160:
161: public List members(ProgressListener monitor) throws IOException {
162: if (getMembers() == null) {
163: DataStore dataStore = dataStore(monitor);
164: synchronized (dataStore) {
165: if (getMembers() == null) {
166: ArrayList members = new ArrayList();
167: String[] typeNames = dataStore.getTypeNames();
168: for (int i = 0; i < typeNames.length; i++) {
169: String typeName = typeNames[i];
170: GeoResource resource = createGeoResource(
171: typeName, dataStore);
172: if (resource != null) {
173: members.add(resource);
174: } else {
175: String msg = "Unable to create resource for "
176: + typeName;
177: logger.warning(msg);
178: }
179: }
180:
181: setMembers(members);
182: }
183: }
184: }
185:
186: return getMembers();
187: }
188:
189: public ServiceInfo getInfo(ProgressListener monitor)
190: throws IOException {
191: if (info == null) {
192: DataStore dataStore = dataStore(monitor);
193: synchronized (dataStore) {
194: if (info == null) {
195: try {
196: info = createMetaData(dataStore, null);
197: setMessage(null);
198: } catch (Throwable t) {
199: String msg = "Error retreiving medatata.";
200: logger.log(Level.SEVERE, msg, t);
201: setMessage(t);
202: }
203: }
204: }
205: }
206:
207: return info;
208: }
209:
210: protected DataStore dataStore(ProgressListener monitor) {
211: if (dataStore == null) {
212:
213: synchronized (dataStoreFactory.getClass()) {
214: if (dataStore == null) {
215: try {
216: dataStore = dataStoreFactory
217: .createDataStore(getConnectionParams());
218: if (dataStore == null) {
219: throw new NullPointerException();
220: }
221:
222: setMessage(null);
223: } catch (Throwable t) {
224: String msg = "Unable to resolve datastore";
225: logger.log(Level.SEVERE, msg, t);
226: setMessage(t);
227: }
228: }
229: }
230: }
231:
232: return dataStore;
233: }
234:
235: /**
236: * Creates the service metadata.
237: * <p>
238: * Sublcasses should override to supply custom metadata specific to
239: * a particular DataStore. This default implementation supplies the
240: * following metadata mappings in an instance of {@link DefaultServiceInfo}.
241: * <ul>
242: * <li>{@link DataStoreFactorySpi#getDisplayName()} -> {@link ServiceInfo#getTitle()}
243: * <li>{@link DataStoreFactorySpi#getDescription()} -> {@link ServiceInfo#getDescription()}.
244: * </ul>
245: * </p>
246: *
247: * @param dataStore The underlying datastore.
248: * @param monitor Progress monitor for blocking calls.
249: *
250: * @return An instance of {@link DefaultServiceInfo}.
251: */
252: protected ServiceInfo createMetaData(DataStore dataStore,
253: ProgressListener monitor) {
254: return new DefaultServiceInfo(
255: dataStoreFactory.getDisplayName(), dataStoreFactory
256: .getDescription(), null, null, null, null,
257: null, null);
258: }
259:
260: /**
261: * Creates the GeoResource handle for a specified feature type name.
262: * <p>
263: * Subclasses should override this method if they need to create a custom geo resource.
264: * The default implementation returns a new instance of {@link FeatureSourceGeoResource}.
265: * </p>
266: * @param typeName The name of the feature type.
267: * @param dataStore The datastore containing the feature type.
268: *
269: * @return The GeoResource handle, or null if it could not be created.
270: */
271: protected GeoResource createGeoResource(String typeName,
272: DataStore dataStore) {
273: return new FeatureSourceGeoResource(this, typeName);
274: }
275:
276: }
|