001: /*
002: * uDig - User Friendly Desktop Internet GIS client
003: * http://udig.refractions.net
004: * (C) 2004, Refractions Research Inc.
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: */
017: package net.refractions.udig.catalog.internal.shp;
018:
019: import java.io.File;
020: import java.io.IOException;
021: import java.io.Serializable;
022: import java.lang.reflect.InvocationTargetException;
023: import java.net.URI;
024: import java.net.URISyntaxException;
025: import java.net.URL;
026: import java.util.LinkedList;
027: import java.util.List;
028: import java.util.Map;
029: import java.util.concurrent.locks.Lock;
030:
031: import net.refractions.udig.catalog.CatalogPlugin;
032: import net.refractions.udig.catalog.IResolve;
033: import net.refractions.udig.catalog.IResolveChangeEvent;
034: import net.refractions.udig.catalog.IResolveDelta;
035: import net.refractions.udig.catalog.IService;
036: import net.refractions.udig.catalog.IServiceInfo;
037: import net.refractions.udig.catalog.URLUtils;
038: import net.refractions.udig.catalog.internal.CatalogImpl;
039: import net.refractions.udig.catalog.internal.ResolveChangeEvent;
040: import net.refractions.udig.catalog.internal.ResolveDelta;
041: import net.refractions.udig.catalog.shp.internal.Messages;
042: import net.refractions.udig.ui.ErrorManager;
043: import net.refractions.udig.ui.PlatformGIS;
044: import net.refractions.udig.ui.UDIGDisplaySafeLock;
045:
046: import org.eclipse.core.runtime.IProgressMonitor;
047: import org.eclipse.core.runtime.NullProgressMonitor;
048: import org.eclipse.core.runtime.SubProgressMonitor;
049: import org.eclipse.jface.operation.IRunnableWithProgress;
050: import org.eclipse.ui.PlatformUI;
051: import org.geotools.data.DefaultQuery;
052: import org.geotools.data.FeatureReader;
053: import org.geotools.data.Transaction;
054: import org.geotools.data.shapefile.ShapefileDataStore;
055: import org.geotools.data.shapefile.indexed.IndexedShapefileDataStore;
056: import org.geotools.data.shapefile.indexed.IndexedShapefileDataStoreFactory;
057: import org.geotools.filter.Filter;
058:
059: /**
060: * Connect to a shapefile
061: *
062: * @author David Zwiers, Refractions Research
063: * @since 0.6
064: */
065: public class ShpServiceImpl extends IService {
066:
067: private URL url = null;
068:
069: private Map<String, Serializable> params = null;
070:
071: /**
072: * Construct <code>ShpServiceImpl</code>.
073: *
074: * @param arg1
075: * @param arg2
076: */
077: public ShpServiceImpl(URL arg1, Map<String, Serializable> arg2) {
078: url = arg1;
079: params = arg2;
080: Serializable memorymapped = params.get("memory mapped buffer"); //$NON-NLS-1$
081: if (memorymapped == null) {
082: memorymapped = false;
083: try {
084: File file = URLUtils.urlToFile(url);
085: final int maxsize = 1024 * 2048;
086: if (file.length() > maxsize) {
087: memorymapped = false;
088: }
089: } catch (Exception e) {
090: memorymapped = false;
091: }
092: }
093: if (!params
094: .containsKey(IndexedShapefileDataStoreFactory.CREATE_SPATIAL_INDEX.key))
095: params
096: .put(
097: IndexedShapefileDataStoreFactory.CREATE_SPATIAL_INDEX.key,
098: ShpPlugin.getDefault().isUseSpatialIndex());
099: }
100:
101: /*
102: * Required adaptions: <ul> <li>IServiceInfo.class <li>List.class
103: * <IGeoResource> </ul>
104: *
105: * @see net.refractions.udig.catalog.IService#resolve(java.lang.Class,
106: * org.eclipse.core.runtime.IProgressMonitor)
107: */
108: public <T> T resolve(Class<T> adaptee, IProgressMonitor monitor)
109: throws IOException {
110: if (monitor == null)
111: monitor = new NullProgressMonitor();
112:
113: if (adaptee == null) {
114: throw new NullPointerException("No adaptor specified"); //$NON-NLS-1$
115: }
116: if (adaptee.isAssignableFrom(ShapefileDataStore.class))
117: return adaptee.cast(getDS(monitor));
118: return super .resolve(adaptee, monitor);
119: }
120:
121: /*
122: * @see net.refractions.udig.catalog.IResolve#canResolve(java.lang.Class)
123: */
124: public <T> boolean canResolve(Class<T> adaptee) {
125: if (adaptee == null)
126: return false;
127: return adaptee.isAssignableFrom(ShapefileDataStore.class)
128: || super .canResolve(adaptee);
129: }
130:
131: public void dispose(IProgressMonitor monitor) {
132: if (members == null)
133: return;
134:
135: int steps = (int) ((double) 99 / (double) members.size());
136: for (IResolve resolve : members) {
137: try {
138: SubProgressMonitor subProgressMonitor = new SubProgressMonitor(
139: monitor, steps);
140: resolve.dispose(subProgressMonitor);
141: subProgressMonitor.done();
142: } catch (Throwable e) {
143: ErrorManager
144: .get()
145: .displayException(
146: e,
147: "Error disposing members of service: " + getIdentifier(), CatalogPlugin.ID); //$NON-NLS-1$
148: }
149: }
150: }
151:
152: /*
153: * @see net.refractions.udig.catalog.IResolve#members(org.eclipse.core.runtime.IProgressMonitor)
154: */
155: public List<ShpGeoResourceImpl> members(IProgressMonitor monitor)
156: throws IOException {
157:
158: if (members == null) {
159: getDS(monitor); // slap it to load datastore
160: rLock.lock();
161: try {
162: if (members == null) {
163: members = new LinkedList<ShpGeoResourceImpl>();
164: String[] typenames = ds.getTypeNames();
165: if (typenames != null)
166: for (int i = 0; i < typenames.length; i++) {
167: members.add(new ShpGeoResourceImpl(this ,
168: typenames[i]));
169: }
170: }
171: } finally {
172: rLock.unlock();
173: }
174: }
175: return members;
176: }
177:
178: private volatile List<ShpGeoResourceImpl> members = null;
179:
180: /*
181: * @see net.refractions.udig.catalog.IService#getInfo(org.eclipse.core.runtime.IProgressMonitor)
182: */
183: public IServiceInfo getInfo(IProgressMonitor monitor)
184: throws IOException {
185: getDS(monitor); // load ds
186: if (info == null && ds != null) {
187: rLock.lock();
188: try {
189: if (info == null) {
190: info = new IServiceShpInfo();
191: }
192: } finally {
193: rLock.unlock();
194: }
195: IResolveDelta delta = new ResolveDelta(this ,
196: IResolveDelta.Kind.CHANGED);
197: ((CatalogImpl) CatalogPlugin.getDefault().getLocalCatalog())
198: .fire(new ResolveChangeEvent(this ,
199: IResolveChangeEvent.Type.POST_CHANGE, delta));
200: }
201: return info;
202: }
203:
204: private volatile IServiceInfo info = null;
205:
206: /*
207: * @see net.refractions.udig.catalog.IService#getConnectionParams()
208: */
209: public Map<String, Serializable> getConnectionParams() {
210: return params;
211: }
212:
213: private Throwable msg = null;
214:
215: private volatile ShapefileDataStore ds = null;
216:
217: protected final Lock rLock = new UDIGDisplaySafeLock();
218:
219: private final static Lock dsInstantiationLock = new UDIGDisplaySafeLock();
220:
221: ShapefileDataStore getDS(IProgressMonitor monitor)
222: throws IOException {
223: if (ds == null) {
224: dsInstantiationLock.lock();
225: try {
226: if (ds == null) {
227: IndexedShapefileDataStoreFactory dsf = new IndexedShapefileDataStoreFactory();
228: if (dsf.canProcess(params)) {
229:
230: try {
231: ds = (ShapefileDataStore) dsf
232: .createDataStore(params);
233: openIndexGenerationDialog(ds);
234: // hit it lightly to make sure it exists.
235: ds.getFeatureSource();
236:
237: } catch (IOException e) {
238: msg = e;
239: try {
240: params
241: .remove(IndexedShapefileDataStoreFactory.CREATE_SPATIAL_INDEX.key);
242: ds = (ShapefileDataStore) dsf
243: .createDataStore(params);
244: // hit it lightly to make sure it exists.
245: ds.getFeatureSource();
246:
247: } catch (Exception e2) {
248: msg = e2;
249: throw (IOException) new IOException()
250: .initCause(e2);
251: }
252: }
253: }
254: }
255: } finally {
256: dsInstantiationLock.unlock();
257: }
258: IResolveDelta delta = new ResolveDelta(this ,
259: IResolveDelta.Kind.CHANGED);
260: ((CatalogImpl) CatalogPlugin.getDefault().getLocalCatalog())
261: .fire(new ResolveChangeEvent(this ,
262: IResolveChangeEvent.Type.POST_CHANGE, delta));
263: }
264: return ds;
265: }
266:
267: private void openIndexGenerationDialog(final ShapefileDataStore ds) {
268: rLock.lock();
269: try {
270: if (ds instanceof IndexedShapefileDataStore) {
271: IndexedShapefileDataStore ids = (IndexedShapefileDataStore) ds;
272: if (ids.isIndexed())
273: return;
274: String name = getIdentifier().getFile();
275: int lastIndexOf = name.lastIndexOf(File.separator);
276: if (lastIndexOf > 0)
277: name = name.substring(lastIndexOf + 1);
278: final String finalName = name;
279: IRunnableWithProgress runnable = new IRunnableWithProgress() {
280:
281: public void run(IProgressMonitor monitor)
282: throws InvocationTargetException,
283: InterruptedException {
284: monitor
285: .beginTask(
286: Messages.ShpPreferencePage_createindex
287: + " " + finalName, IProgressMonitor.UNKNOWN); //$NON-NLS-1$
288: index(ds, ds.getTypeNames()[0]);
289: monitor.done();
290: }
291:
292: };
293: if (PlatformUI.getWorkbench().isClosing() && false) {
294: try {
295: runnable.run(new NullProgressMonitor());
296: } catch (InvocationTargetException e) {
297: ShpPlugin.log("", e); //$NON-NLS-1$
298: } catch (InterruptedException e) {
299: ShpPlugin.log("", e); //$NON-NLS-1$
300: }
301: } else {
302: PlatformGIS
303: .runInProgressDialog(
304: Messages.ShpServiceImpl_indexing
305: + " " + finalName, true, runnable, false); //$NON-NLS-1$
306: }
307: }
308: } finally {
309: rLock.unlock();
310: }
311:
312: }
313:
314: private void index(final ShapefileDataStore ds,
315: final String typename) {
316: FeatureReader reader = null;
317: try {
318: // smack Datastore to generate indices
319: reader = ds.getFeatureReader(new DefaultQuery(typename,
320: Filter.NONE, new String[0]),
321: Transaction.AUTO_COMMIT);
322: } catch (Exception e) {
323: ShpPlugin.log("", e); //$NON-NLS-1$
324: } finally {
325: if (reader != null)
326: try {
327: reader.close();
328: } catch (IOException e) {
329: ShpPlugin.log("", e); //$NON-NLS-1$
330: }
331: }
332: }
333:
334: /*
335: * @see net.refractions.udig.catalog.IResolve#getStatus()
336: */
337: public Status getStatus() {
338: return msg != null ? Status.BROKEN
339: : ds == null ? Status.NOTCONNECTED : Status.CONNECTED;
340: }
341:
342: /*
343: * @see net.refractions.udig.catalog.IResolve#getMessage()
344: */
345: public Throwable getMessage() {
346: return msg;
347: }
348:
349: /*
350: * @see net.refractions.udig.catalog.IResolve#getIdentifier()
351: */
352: public URL getIdentifier() {
353: return url;
354: }
355:
356: private class IServiceShpInfo extends IServiceInfo {
357:
358: IServiceShpInfo() {
359: super ();
360: keywords = new String[] { ".shp", "Shapefile", //$NON-NLS-1$ //$NON-NLS-2$
361: ds.getTypeNames()[0] };
362:
363: try {
364: schema = new URI("shp://www.opengis.net/gml"); //$NON-NLS-1$
365: } catch (URISyntaxException e) {
366: ShpPlugin.log(null, e);
367: schema = null;
368: }
369: }
370:
371: public String getDescription() {
372: return getIdentifier().toString();
373: }
374:
375: public String getTitle() {
376: return getIdentifier().getFile();
377: }
378: }
379: }
|