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;
018:
019: import static net.refractions.udig.catalog.IResolve.Status.CONNECTED;
020: import static net.refractions.udig.catalog.IResolve.Status.NOTCONNECTED;
021:
022: import java.io.File;
023: import java.io.FileInputStream;
024: import java.io.FileOutputStream;
025: import java.io.IOException;
026: import java.lang.reflect.InvocationTargetException;
027: import java.net.MalformedURLException;
028: import java.net.URL;
029: import java.util.ArrayList;
030: import java.util.Collections;
031: import java.util.HashSet;
032: import java.util.Iterator;
033: import java.util.LinkedHashSet;
034: import java.util.LinkedList;
035: import java.util.List;
036: import java.util.Set;
037:
038: import net.refractions.udig.catalog.CatalogPlugin;
039: import net.refractions.udig.catalog.ICatalog;
040: import net.refractions.udig.catalog.ICatalogInfo;
041: import net.refractions.udig.catalog.IGeoResource;
042: import net.refractions.udig.catalog.IGeoResourceInfo;
043: import net.refractions.udig.catalog.IResolve;
044: import net.refractions.udig.catalog.IResolveChangeEvent;
045: import net.refractions.udig.catalog.IResolveChangeListener;
046: import net.refractions.udig.catalog.IResolveDelta;
047: import net.refractions.udig.catalog.IService;
048: import net.refractions.udig.catalog.IServiceFactory;
049: import net.refractions.udig.catalog.IServiceInfo;
050: import net.refractions.udig.catalog.ServiceParameterPersister;
051: import net.refractions.udig.catalog.TemporaryResourceFactory;
052: import net.refractions.udig.catalog.URLUtils;
053: import net.refractions.udig.catalog.util.AST;
054: import net.refractions.udig.catalog.util.ASTFactory;
055: import net.refractions.udig.catalog.util.IFriend;
056: import net.refractions.udig.core.WeakHashSet;
057: import net.refractions.udig.core.internal.ExtensionPointList;
058: import net.refractions.udig.core.internal.ExtensionPointProcessor;
059: import net.refractions.udig.core.internal.ExtensionPointUtil;
060: import net.refractions.udig.ui.PlatformGIS;
061:
062: import org.eclipse.core.runtime.IConfigurationElement;
063: import org.eclipse.core.runtime.IExtension;
064: import org.eclipse.core.runtime.IProgressMonitor;
065: import org.eclipse.core.runtime.NullProgressMonitor;
066: import org.eclipse.core.runtime.Platform;
067: import org.eclipse.core.runtime.SubProgressMonitor;
068: import org.eclipse.core.runtime.preferences.IEclipsePreferences;
069: import org.eclipse.core.runtime.preferences.IExportedPreferences;
070: import org.eclipse.core.runtime.preferences.IPreferencesService;
071: import org.eclipse.core.runtime.preferences.InstanceScope;
072: import org.eclipse.jface.operation.IRunnableWithProgress;
073: import org.osgi.service.prefs.BackingStoreException;
074: import org.osgi.service.prefs.Preferences;
075:
076: import com.vividsolutions.jts.geom.Envelope;
077:
078: /**
079: * Implementation of an in memory catalog.
080: *
081: * @author David Zwiers, Refractions Research
082: * @since 0.6
083: */
084: public class CatalogImpl extends ICatalog {
085: private static final String TEMPORARY_RESOURCE_EXT_ID = "net.refractions.udig.catalog.temporaryResource"; //$NON-NLS-1$
086: private HashSet<IService> services = new HashSet<IService>();
087: private ICatalogInfo metadata;
088: private Set<IResolveChangeListener> catalogListeners;
089: private String[] descriptors;
090:
091: public CatalogImpl() {
092: CatalogInfoImpl metadata = new CatalogInfoImpl();
093: metadata.setTitle(Messages.CatalogImpl_localCatalog_title);
094: try {
095: metadata.setSource(new URL("http://localhost")); //$NON-NLS-1$
096: } catch (MalformedURLException e) {
097: // do nothing
098: }
099:
100: this .metadata = metadata;
101: catalogListeners = Collections
102: .synchronizedSet(new WeakHashSet<IResolveChangeListener>());
103: }
104:
105: public CatalogImpl(ICatalogInfo metadata) {
106: this ();
107: this .metadata = metadata;
108: }
109:
110: /**
111: * @see net.refractions.udig.catalog.ICatalog#addCatalogListener(net.refractions.udig.catalog.ICatalog.ICatalogListener)
112: * @param listener
113: */
114: public void addCatalogListener(IResolveChangeListener listener) {
115: catalogListeners.add(listener);
116: }
117:
118: /**
119: * @see net.refractions.udig.catalog.ICatalog#removeCatalogListener(net.refractions.udig.catalog.ICatalog.ICatalogListener)
120: * @param listener
121: */
122: public void removeCatalogListener(IResolveChangeListener listener) {
123: catalogListeners.remove(listener);
124: }
125:
126: /**
127: * @see net.refractions.udig.catalog.ICatalog#add(net.refractions.udig.catalog.IService)
128: * @param entry
129: * @throws UnsupportedOperationException
130: */
131: public void add(IService entry)
132: throws UnsupportedOperationException {
133: if (entry == null || entry.getIdentifier() == null)
134: throw new NullPointerException("Cannot have a null id"); //$NON-NLS-1$
135: if (!findService(entry.getIdentifier()).isEmpty())
136: return;
137: services.add(entry);
138: IResolveDelta deltaAdded = new ResolveDelta(entry,
139: IResolveDelta.Kind.ADDED);
140: IResolveDelta deltaChanged = new ResolveDelta(this , Collections
141: .singletonList(deltaAdded));
142: fire(new ResolveChangeEvent(CatalogImpl.this ,
143: IResolveChangeEvent.Type.POST_CHANGE, deltaChanged));
144: }
145:
146: /**
147: * @see net.refractions.udig.catalog.ICatalog#remove(net.refractions.udig.catalog.IService)
148: * @param entry
149: * @throws UnsupportedOperationException
150: */
151: public void remove(IService entry)
152: throws UnsupportedOperationException {
153: if (entry == null || entry.getIdentifier() == null)
154: throw new NullPointerException("Cannot have a null id"); //$NON-NLS-1$
155: IResolveDelta deltaRemoved = new ResolveDelta(entry,
156: IResolveDelta.Kind.REMOVED);
157: IResolveDelta deltaChanged = new ResolveDelta(this , Collections
158: .singletonList(deltaRemoved));
159: fire(new ResolveChangeEvent(CatalogImpl.this ,
160: IResolveChangeEvent.Type.PRE_DELETE, deltaChanged));
161: services.remove(entry);
162: fire(new ResolveChangeEvent(CatalogImpl.this ,
163: IResolveChangeEvent.Type.POST_CHANGE, deltaRemoved));
164: }
165:
166: public void replace(URL id, IService entry)
167: throws UnsupportedOperationException {
168: if (entry == null || entry.getIdentifier() == null
169: || id == null)
170: throw new NullPointerException("Cannot have a null id"); //$NON-NLS-1$
171:
172: final List<IService> victims = findService(id);
173:
174: List<IResolveDelta> changes = new ArrayList<IResolveDelta>();
175: for (IService service : victims) {
176: List<IResolveDelta> childChanges = new ArrayList<IResolveDelta>();
177: try {
178: List<? extends IGeoResource> newChildren = entry
179: .members(null);
180: List<? extends IGeoResource> oldChildren = service
181: .members(null);
182: if (oldChildren != null)
183: for (IGeoResource oldChild : oldChildren) {
184: String oldName = oldChild.getIdentifier()
185: .toString();
186:
187: for (IGeoResource child : newChildren) {
188: String name = child.getIdentifier()
189: .toString();
190: if (oldName.equals(name)) {
191: childChanges.add(new ResolveDelta(
192: child, oldChild,
193: IResolveDelta.NO_CHILDREN));
194: break;
195: }
196: }
197: }
198: } catch (IOException ignore) {
199: // no children? Not a very good entry ..
200: }
201: changes.add(new ResolveDelta(service, entry, childChanges));
202: }
203: IResolveDelta deltas = new ResolveDelta(this , changes);
204: IResolveChangeEvent event = new ResolveChangeEvent(this ,
205: IResolveChangeEvent.Type.PRE_DELETE, deltas);
206: fire(event);
207:
208: services.removeAll(victims);
209: PlatformGIS.run(new IRunnableWithProgress() {
210:
211: public void run(IProgressMonitor monitor)
212: throws InvocationTargetException,
213: InterruptedException {
214: monitor.beginTask(
215: "Disposing replaced services", victims.size()); //$NON-NLS-1$
216: for (IService service : victims) {
217: try {
218: SubProgressMonitor subProgressMonitor = new SubProgressMonitor(
219: monitor, 1);
220: service.dispose(subProgressMonitor);
221: subProgressMonitor.done();
222: } catch (Throwable e) {
223: CatalogPlugin
224: .log(
225: "error disposing of: " + service.getIdentifier(), e); //$NON-NLS-1$
226: }
227: }
228: }
229:
230: });
231: services.add(entry);
232:
233: event = new ResolveChangeEvent(this ,
234: IResolveChangeEvent.Type.POST_CHANGE, deltas);
235: fire(event);
236: }
237:
238: /**
239: * Quick search by url match.
240: * @param query
241: *
242: * @see net.refractions.udig.catalog.ICatalog#search(org.geotools.filter.Filter)
243: * @return List<IResolve>
244: * @throws IOException
245: */
246: public List<IResolve> find(URL query, IProgressMonitor monitor) {
247: Set<IResolve> found = new LinkedHashSet<IResolve>();
248:
249: // first pass 1.1- use urlEquals on CONNECTED service for subset check
250: for (IService service : services) {
251: if (service.getStatus() != CONNECTED)
252: continue; // skip non connected service
253: URL identifier = service.getIdentifier();
254: if (URLUtils.urlEquals(query, identifier, true)) {
255: if (matchedService(query, identifier)) {
256: found.add(service);
257: found.addAll(friends(service));
258: break;
259: } else {
260: IResolve res = getChildById(service, query, monitor);
261: if (res != null) {
262: found.add(res);
263: found.addAll(friends(res));
264: break;
265: }
266: }
267: }
268: }
269: // first pass 1.2 - use urlEquals on CONNECTED service for subset check
270: for (IService service : services) {
271: if (service.getStatus() == CONNECTED)
272: continue; // already checked in pass 1.1
273: URL identifier = service.getIdentifier();
274: if (URLUtils.urlEquals(query, identifier, true)) {
275: if (service.getStatus() != NOTCONNECTED)
276: continue; // look into notconnected service that "match"
277: if (matchedService(query, identifier)) {
278: found.add(service);
279: found.addAll(friends(service));
280: break;
281: } else {
282: IResolve res = getChildById(service, query, monitor);
283: if (res != null) {
284: found.add(res);
285: found.addAll(friends(res));
286: break;
287: }
288: }
289: }
290: }
291: // first pass 1.3 - use urlEquals on BROKEN or RESTRICTED_ACCESS service for subset check
292: // the hope here is that a "friend" will still have data! May be tough for friends
293: // to negotiate a match w/ a broken services - but there is still hope...
294: for (IService service : services) {
295: if (service.getStatus() == CONNECTED
296: || service.getStatus() == NOTCONNECTED) {
297: continue; // already checked in pass 1.1-1.2
298: }
299: URL identifier = service.getIdentifier();
300: if (URLUtils.urlEquals(query, identifier, true)) {
301: if (matchedService(query, identifier)) {
302: found.add(service);
303: found.addAll(friends(service));
304: break;
305: } else {
306: IResolve res = getChildById(service, query, monitor);
307: if (res != null) {
308: found.add(res);
309: found.addAll(friends(res));
310: break;
311: }
312: }
313: }
314: }
315: // second pass - deep check for georesource on connected services
316: if (found.isEmpty() && query.getRef() != null) {
317: // we have not found anything; and we are looking for a georesource
318: // search connected resources ...
319: for (IService service : services) {
320: if (service.getStatus() == CONNECTED) {
321: IResolve res = getChildById(service, query, monitor);
322: if (res != null) {
323: found.add(res);
324: found.addAll(friends(res));
325: break;
326: }
327: }
328: }
329: }
330: // thirdpass - deep check for georesource on connected services
331: if (found.isEmpty() && query.getRef() != null) {
332: assert deepCheckWarning();
333: // we have not found anything; and we are looking for a georesource
334: // search not connected resources ...
335: for (IService service : services) {
336: if (service.getStatus() == NOTCONNECTED) {
337: IResolve res = getChildById(service, query, monitor);
338: if (res != null) {
339: found.add(res);
340: found.addAll(friends(res));
341: break;
342: }
343: }
344: }
345: }
346: return new ArrayList<IResolve>(found);
347: }
348:
349: private boolean matchedService(URL query, URL identifier) {
350: return query.getRef() == null
351: && URLUtils.urlEquals(query, identifier, false);
352: }
353:
354: private boolean deepCheckWarning() {
355: CatalogPlugin
356: .log(
357: "Warning Deep search in catalog is occurring this is VERY expensive", new Exception("JUST A WARNING")); //$NON-NLS-1$ //$NON-NLS-2$
358: return true;
359: }
360:
361: /**
362: * Returns a list of friendly resources working with related data.
363: * <p>
364: * This method is used internally to determine resource handles that
365: * offer different entry points to the same information.
366: * </p>
367: * A friend can be found via:
368: * <ul>
369: * <li>Making use of a CSW2.0 association
370: * <li>URL Pattern matching for well known cases like GeoServer and MapServer
371: * <li>Service Metadata, for example WMS resourceURL referencing a WFS FeatureType
372: * </ul>
373: * All of these handles will be returned from the find( URL, monitor ) method.
374: * </ul>
375: * @param handle
376: * @return List of frends, possibly empty
377: */
378: public List<IResolve> friends(final IResolve handle) {
379: if (false) {
380: return Collections.emptyList();
381: }
382: final List<IResolve> friends = new ArrayList<IResolve>();
383: ExtensionPointUtil
384: .process(
385: CatalogPlugin.getDefault(),
386: "net.refractions.udig.catalog.friendly", new ExtensionPointProcessor() { //$NON-NLS-1$
387: /**
388: * Lets find our friends.
389: */
390: public void process(IExtension extension,
391: IConfigurationElement element)
392: throws Exception {
393: try {
394: String target = element
395: .getAttribute("target"); //$NON-NLS-1$
396: String contain = element
397: .getAttribute("contain"); //$NON-NLS-1$
398: if (target != null) {
399: // perform target check
400: if (target.equals(target
401: .getClass().toString())) {
402: return;
403: }
404: }
405: if (contain != null) {
406: String uri = handle
407: .getIdentifier()
408: .toExternalForm();
409: if (!uri.contains(contain)) {
410: return;
411: }
412: }
413:
414: IFriend friendly = (IFriend) element
415: .createExecutableExtension("class"); //$NON-NLS-1$
416: friends.addAll(friendly.friendly(
417: handle, null));
418: } catch (Throwable t) {
419: CatalogPlugin.log(t
420: .getLocalizedMessage(), t);
421: }
422: }
423: });
424: return friends;
425: }
426:
427: /**
428: * Quick search by url match.
429: *
430: * @see net.refractions.udig.catalog.ICatalog#search(org.geotools.filter.Filter)
431: * @param query
432: * @return List<IResolve>
433: * @throws IOException
434: * @deprecated
435: */
436: public List<IService> findService(URL query) {
437: IService service = getServiceById(query);
438: if (service == null)
439: return Collections.emptyList();
440: else
441: return Collections.singletonList(service);
442: }
443:
444: /**
445: * Utility method to quick hunt for matching service.
446: *
447: * @param ID Identification of service to find
448: * @return Found service handle or null
449: */
450: public IService getServiceById(final URL ID) {
451: if (ID == null || ID.getRef() != null)
452: return null;
453: for (IService service : services) {
454: if (URLUtils.urlEquals(ID, service.getIdentifier(), false)) {
455: return service;
456: }
457: }
458: return null;
459: }
460:
461: @Override
462: public <T extends IResolve> T getById(Class<T> type, final URL ID,
463: IProgressMonitor monitor) {
464:
465: IProgressMonitor monitor2 = monitor;
466: ;
467: if (monitor2 == null)
468: monitor2 = new NullProgressMonitor();
469: if (ID == null)
470: return null;
471:
472: if (IService.class.isAssignableFrom(type)) {
473: monitor2.beginTask(Messages.CatalogImpl_monitorTask, 1);
474: IService service = getServiceById(ID);
475: monitor2.done();
476: return type.cast(service);
477: }
478:
479: if (IGeoResource.class.isAssignableFrom(type)) {
480: // String uri = ID.toExternalForm();
481:
482: for (IService service : services) {
483: if (URLUtils.urlEquals(ID, service.getIdentifier(),
484: true)) {
485: IResolve child = getChildById(service, ID, monitor2);
486: if (child != null)
487: return type.cast(child);
488: }
489: }
490: }
491: return null;
492: }
493:
494: /**
495: * Utility method that will search in the provided handle for an ID match; especially good for
496: * nested content such as folders or WMS layers.
497: *
498: * <h4>Old Comment</h4>
499: * The following comment was origional included in the source code: we are not sure it should
500: * be belived ... we will do our best to search CONNECTED services first, nut NOTCONNECTED
501: * is included in our search.
502: * <quote>
503: * Although the following is a 'blocking' call, we have deemed it safe based on
504: * the following reasons:
505: * <ul>
506: * <li>This will only be called for Identifiers which are well known.
507: * <li>The Services being checked have already been screened, and only a
508: * limited number of services (ussually 1) will be called.
509: * <ol>
510: * <li>The Id was acquired from the catalog ... and this is a look-up, in which case the uri exists.
511: * <li>The Id was persisted.
512: * </ol>
513: * </ul>
514: * In the future this will also be free, as we plan on caching the equivalent of a getCapabilities
515: * document between runs (will have to be updated too as the app has time).
516: * </quote>
517: * Repeate the following comment is out of date since people are using this method to look
518: * for entries that have not been aded to the catalog yet.
519: */
520: public IResolve getChildById(IResolve handle, final URL ID,
521: IProgressMonitor monitor) {
522: IProgressMonitor monitor2 = monitor;
523: if (monitor2 == null)
524: monitor2 = new NullProgressMonitor();
525:
526: if (URLUtils.urlEquals(handle.getIdentifier(), ID, false)) {
527: return handle;
528: }
529: try {
530: List<? extends IResolve> children = handle
531: .members(monitor2);
532: if (children == null || children.isEmpty())
533: return null;
534:
535: monitor2.beginTask(Messages.CatalogImpl_monitorTask2,
536: children.size());
537: for (IResolve child : children) {
538: IResolve found = getChildById(child, ID, null);
539: if (found != null)
540: return found;
541: }
542: } catch (IOException e) {
543: CatalogPlugin
544: .log(
545: "Could not search children of " + handle.getIdentifier(), e); //$NON-NLS-1$
546: }
547: return null;
548: }
549:
550: /**
551: * Performs a search on this catalog based on the specified inputs. The pattern uses the
552: * following conventions: use " " to surround a phase use + to represent 'AND' use - to
553: * represent 'OR' use ! to represent 'NOT' use ( ) to designate scope The bbox provided shall be
554: * in Lat - Long, or null if the search is not to be contained within a specified area.
555: *
556: * @see net.refractions.udig.catalog.ICatalog#search(java.lang.String,
557: * com.vividsolutions.jts.geom.Envelope)
558: * @param pattern
559: * @param bbox used for an intersection test
560: * @return
561: */
562: public synchronized List<IResolve> search(String pattern,
563: Envelope bbox, IProgressMonitor monitor2) {
564: IProgressMonitor monitor = monitor2;
565: if (monitor == null)
566: monitor = new NullProgressMonitor();
567: if ((pattern == null || "".equals(pattern.trim())) //$NON-NLS-1$
568: && (bbox == null || bbox.isNull())) {
569: return new LinkedList<IResolve>();
570: }
571:
572: AST ast = null;
573: if (pattern != null && !"".equals(pattern.trim())) //$NON-NLS-1$
574: ast = ASTFactory.parse(pattern);
575:
576: // TODO check cuncurrency issues here
577:
578: List<IResolve> result = new LinkedList<IResolve>();
579: HashSet<IService> tmp = new HashSet<IService>();
580: tmp.addAll(this .services);
581: try {
582: monitor.beginTask(Messages.CatalogImpl_finding,
583: tmp.size() * 10);
584: Iterator<IService> services = tmp.iterator();
585: if (services != null) {
586: while (services.hasNext()) {
587: IService service = services.next();
588: if (check(service, ast)) {
589: result.add(service);
590: }
591: Iterator<? extends IGeoResource> resources;
592: SubProgressMonitor submonitor = new SubProgressMonitor(
593: monitor, 10);
594: try {
595: List<? extends IGeoResource> t = service
596: .members(submonitor);
597: resources = t == null ? null : t.iterator();
598: while (resources != null && resources.hasNext()) {
599: IGeoResource resource = resources.next();
600: if (check(resource, ast, bbox)) {
601: result.add(resource);
602: }
603: }
604: } catch (IOException e) {
605: CatalogPlugin.log(null, e);
606: } finally {
607: submonitor.done();
608: }
609: }
610: }
611: return result;
612: } finally {
613: monitor.done();
614: }
615: }
616:
617: /* check the fields we catre about */
618: protected static boolean check(IService service, AST pattern) {
619: if (pattern == null) {
620: return false;
621: }
622: IServiceInfo info;
623: try {
624: info = service == null ? null : service.getInfo(null);
625: } catch (IOException e) {
626: info = null;
627: CatalogPlugin.log(null, e);
628: }
629: boolean t = false;
630: if (info != null) {
631: if (info.getTitle() != null)
632: t = pattern.accept(info.getTitle());
633: if (!t && info.getKeywords() != null) {
634: String[] keys = info.getKeywords();
635: for (int i = 0; !t && i < keys.length; i++)
636: if (keys[i] != null)
637: t = pattern.accept(keys[i]);
638: }
639: if (!t && info.getSchema() != null)
640: t = pattern.accept(info.getSchema().toString());
641: if (!t && info.getAbstract() != null)
642: t = pattern.accept(info.getAbstract());
643: if (!t && info.getDescription() != null)
644: t = pattern.accept(info.getDescription());
645: }
646: return t;
647: }
648:
649: /* check the fields we catre about */
650: protected static boolean check(IGeoResource resource, AST pattern) {
651: if (pattern == null)
652: return true;
653: IGeoResourceInfo info;
654: try {
655: info = (resource == null ? null : resource.getInfo(null));
656: } catch (IOException e) {
657: CatalogPlugin.log(null, e);
658: info = null;
659: }
660: boolean t = false;
661: if (info != null) {
662: if (info.getTitle() != null)
663: t = pattern.accept(info.getTitle());
664: if (!t && info.getName() != null)
665: t = pattern.accept(info.getName());
666: if (!t && info.getKeywords() != null) {
667: String[] keys = info.getKeywords();
668: for (int i = 0; !t && i < keys.length; i++)
669: if (keys[i] != null)
670: t = pattern.accept(keys[i]);
671: }
672: if (!t && info.getSchema() != null)
673: t = pattern.accept(info.getSchema().toString());
674: if (!t && info.getDescription() != null)
675: t = pattern.accept(info.getDescription());
676: }
677: return t;
678: }
679:
680: protected static boolean check(IGeoResource resource, AST pattern,
681: Envelope bbox) {
682: if (!check(resource, pattern))
683: return false;
684: if (bbox == null || bbox.isNull())
685: return true; // no checking here
686: try {
687: return bbox.intersects(resource.getInfo(null).getBounds());
688: } catch (Throwable e) {
689: CatalogPlugin.log(null, e);
690: return false;
691: }
692: }
693:
694: /**
695: * Fire a resource changed event, these may be batched into one delta for performance.
696: *
697: * @param resoruce IGeoResource undergoing change
698: * @param mask of IDelta constants indicating change
699: * @throws IOException protected void fireResourceEvent( IGeoResource resource,
700: * IResolveDelta.Kind kind ) throws IOException { Object[] listeners =
701: * catalogListeners.getListeners(); if( listeners.length == 0 ) return;
702: * GeoReferenceDelta rDelta = new GeoReferenceDelta( resource, kind ); ServiceDelta
703: * sDelta = new ServiceDelta( resource.getService(null), IDelta.Kind.NO_CHANGE,
704: * Collections.singletonList( rDelta ) ); CatalogDelta cDelta = new CatalogDelta(
705: * Collections.singletonList( (IDelta)sDelta ) ); fire( new CatalogChangeEvent(
706: * resource, ICatalogChangeEvent.Type.POST_CHANGE, cDelta ) ); }
707: */
708: public void fire(IResolveChangeEvent event) {
709: if (catalogListeners.size() == 0)
710: return;
711:
712: HashSet<IResolveChangeListener> copy;
713: synchronized (catalogListeners) {
714: copy = new HashSet<IResolveChangeListener>(catalogListeners);
715: }
716:
717: for (IResolveChangeListener listener : copy) {
718: try {
719: listener.changed(event);
720: } catch (Throwable die) {
721: CatalogPlugin.log(null, new Exception(die));
722: }
723: }
724: }
725:
726: /*
727: * protected void fireServiceChanged( Object source, ServiceDelta sDelta ) { Object[] listeners =
728: * catalogListeners.getListeners(); if( listeners.length == 0 ) return; CatalogDelta cDelta =
729: * new CatalogDelta( Collections.singletonList( (IDelta)sDelta ) ); fire( new
730: * CatalogChangeEvent( source , ICatalogChangeEvent.Type.POST_CHANGE, cDelta ) ); }
731: */
732:
733: /**
734: * @see net.refractions.udig.catalog.ICatalog#resolve(java.lang.Class,
735: * org.eclipse.core.runtime.IProgressMonitor)
736: * @SuppressWarnings(value={"unchecked"})
737: */
738: public <T> T resolve(Class<T> adaptee, IProgressMonitor monitor2) {
739: IProgressMonitor monitor;
740: if (monitor2 == null)
741: monitor = new NullProgressMonitor();
742: else
743: monitor = monitor2;
744: try {
745: if (adaptee == null)
746: return null;
747: monitor.beginTask(Messages.CatalogImpl_resolving
748: + adaptee.getSimpleName(), 2);
749: monitor.worked(1);
750: if (adaptee.isAssignableFrom(CatalogImpl.class))
751: return adaptee.cast(this );
752: if (adaptee.isAssignableFrom(CatalogInfoImpl.class))
753: return adaptee.cast(metadata);
754: if (adaptee.isAssignableFrom(services.getClass()))
755: return adaptee.cast(services);
756: if (adaptee.isAssignableFrom(List.class))
757: return adaptee.cast(new LinkedList<IService>(services));
758: if (adaptee.isAssignableFrom(catalogListeners.getClass()))
759: return adaptee.cast(catalogListeners);
760: } finally {
761: monitor.worked(1);
762: monitor.done();
763: }
764: return null;
765: }
766:
767: /*
768: * @see net.refractions.udig.catalog.IResolve#canResolve(java.lang.Class)
769: */
770: public <T> boolean canResolve(Class<T> adaptee) {
771: Object value = resolve(adaptee, null);
772: return value != null;
773: }
774:
775: /*
776: * @see net.refractions.udig.catalog.IResolve#members(org.eclipse.core.runtime.IProgressMonitor)
777: */
778: public List<IResolve> members(IProgressMonitor monitor2) {
779: IProgressMonitor monitor = monitor2;
780: if (monitor == null)
781: monitor = new NullProgressMonitor();
782: monitor.beginTask(Messages.CatalogImpl_finding, 1);
783: monitor.done();
784: return new LinkedList<IResolve>(services);
785: }
786:
787: /*
788: * @see net.refractions.udig.catalog.IResolve#getStatus()
789: */
790: public Status getStatus() {
791: return Status.CONNECTED;
792: }
793:
794: /*
795: * @see net.refractions.udig.catalog.IResolve#getMessage()
796: */
797: public Throwable getMessage() {
798: return null;
799: }
800:
801: /*
802: * @see net.refractions.udig.catalog.IResolve#getIdentifier()
803: */
804: public URL getIdentifier() {
805: return metadata.getSource();
806: }
807:
808: @Override
809: public IGeoResource createTemporaryResource(Object descriptor) {
810: List<IConfigurationElement> list = ExtensionPointList
811: .getExtensionPointList(TEMPORARY_RESOURCE_EXT_ID);
812: for (IConfigurationElement element : list) {
813: try {
814: Class<?> c = descriptor
815: .getClass()
816: .getClassLoader()
817: .loadClass(
818: element.getAttribute("descriptorClass")); //$NON-NLS-1$
819: if (c.isAssignableFrom(descriptor.getClass())) {
820: TemporaryResourceFactory fac = (TemporaryResourceFactory) element
821: .createExecutableExtension("factory"); //$NON-NLS-1$
822: return fac.createResource(descriptor);
823: }
824: } catch (ClassNotFoundException e) {
825: //thats fine. Lets allow tracing to get this.
826: CatalogPlugin.trace("Trying to match classes", e); //$NON-NLS-1$
827: } catch (Exception e) {
828: throw (RuntimeException) new RuntimeException()
829: .initCause(e);
830: }
831: }
832: throw new IllegalArgumentException(
833: descriptor.getClass()
834: + " is not a legal descriptor type. If must be one of " + //$NON-NLS-1$
835: String.valueOf(getTemporaryDescriptorClasses()));
836: }
837:
838: @Override
839: public synchronized String[] getTemporaryDescriptorClasses() {
840: if (descriptors == null) {
841: List<IConfigurationElement> list = ExtensionPointList
842: .getExtensionPointList(TEMPORARY_RESOURCE_EXT_ID);
843: ArrayList<String> temp = new ArrayList<String>();
844: for (IConfigurationElement element : list) {
845: try {
846: String desc = element
847: .getAttribute("descriptorClass"); //$NON-NLS-1$
848: if (desc != null)
849: temp.add(desc);
850: } catch (Exception e) {
851: CatalogPlugin.log("", e); //$NON-NLS-1$
852: }
853: }
854: descriptors = temp.toArray(new String[temp.size()]);
855: }
856: int i = 0;
857: if (descriptors != null)
858: i = descriptors.length;
859: String[] k = new String[i];
860: if (descriptors != null)
861: System.arraycopy(descriptors, 0, k, 0, k.length);
862: return k;
863: }
864:
865: public void loadFromFile(File catalogLocation,
866: IServiceFactory factory) {
867: try {
868: FileInputStream input = new FileInputStream(catalogLocation);
869: IPreferencesService preferencesService = Platform
870: .getPreferencesService();
871: IExportedPreferences paramsNode = preferencesService
872: .readPreferences(input);
873:
874: ServiceParameterPersister persister = new ServiceParameterPersister(
875: this , factory, catalogLocation);
876:
877: persister.restore(findParameterNode(paramsNode));
878: } catch (Throwable e) {
879: // ok maybe it is an from an older version of uDig so try the oldCatalogRef
880: try {
881: IPreferencesService prefs = Platform
882: .getPreferencesService();
883: IEclipsePreferences root = prefs.getRootNode();
884: Preferences node = root.node(InstanceScope.SCOPE).node(
885: CatalogPlugin.ID + ".services"); //$NON-NLS-1$
886: ServiceParameterPersister persister = new ServiceParameterPersister(
887: this , factory);
888: persister.restore(node);
889: } catch (Throwable e2) {
890: CatalogPlugin.log("Unable to load services", e); //$NON-NLS-1$
891: }
892: }
893: }
894:
895: private Preferences findParameterNode(
896: IExportedPreferences paramsNode)
897: throws BackingStoreException {
898: String[] name = paramsNode.childrenNames();
899:
900: Preferences plugin = paramsNode.node(name[0]);
901: name = plugin.childrenNames();
902:
903: return plugin.node(name[0]);
904: }
905:
906: public void saveToFile(File catalogLocation,
907: IServiceFactory factory, IProgressMonitor monitor) {
908: try {
909: Preferences toSave = Platform.getPreferencesService()
910: .getRootNode().node(CatalogPlugin.ID).node(
911: "LOCAL_CATALOG_SERVICES");
912: if (services != null) {
913: ServiceParameterPersister persister = new ServiceParameterPersister(
914: this , factory, catalogLocation);
915:
916: persister.store(monitor, toSave, services);
917: }
918:
919: FileOutputStream out = new FileOutputStream(catalogLocation);
920: Platform.getPreferencesService().exportPreferences(
921: (IEclipsePreferences) toSave, out, null);
922: toSave.clear();
923:
924: } catch (Throwable t) {
925: CatalogPlugin.log(
926: "Error saving services for the local catalog", t); //$NON-NLS-1$//$NON-NLS-2$ //$NON-NLS-3$
927: }
928: }
929:
930: }
|