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;
018:
019: import java.io.IOException;
020: import java.net.URL;
021: import java.util.Collections;
022: import java.util.List;
023:
024: import org.eclipse.core.runtime.IProgressMonitor;
025: import org.eclipse.core.runtime.NullProgressMonitor;
026:
027: /**
028: * Represents a handle to a spatial resource.
029: * <p>
030: * The resource is not guaranteed to exist, nor do we guarantee that we can connect with the
031: * resource. Some/All potions of this handle may be loaded as required. This resource handle may
032: * also be the result a metadata service query.
033: *
034: * <h2>Implementing an IService</h2>
035: * <p>
036: * Implement the abstract methods and you are good to go.
037: * <p>
038: * Please consider implementing support for resolve( ImageDescriptor.class, null ) as it
039: * will allow your IGeoResource to show up with a unqiue representation in the catalog.
040: * </p>
041: * @author David Zwiers, Refractions Research
042: * @since 0.6
043: */
044: public abstract class IGeoResource implements IResolve {
045:
046: private volatile String stringURL;
047:
048: /**
049: * Blocking operation to resolve into the adaptee, if available.
050: * <p>
051: * Required adaptions:
052: * <ul>
053: * <li>GeoResource.class - this
054: * <li>IGeoResourceInfo.class - getInfo( monitor ) ie about this handles contents
055: * <li>IService.class - service( monitor ) ie that is responsible for this GeoResource
056: * </ul>
057: * <p>
058: * Example Use (no casting required!):
059: *
060: * <pre><code>
061: * IGeoResourceInfo info = resolve(IGeoResourceInfo.class);
062: * </code></pre>
063: *
064: * </p>
065: * <p>
066: * Recommendated adaptions:
067: * <ul>
068: * <li>ImageDescriptor.class (for icon provided by external service)
069: * <li>List.class - members( monitor ) ie children of this georesource as in the wms layer case
070: * </ul>
071: * </p>
072: *
073: * @param adaptee
074: * @param monitor
075: * @return instance of adaptee, or null if unavailable (IGeoResourceInfo and IService must be
076: * supported)
077: * @see IGeoResourceInfo
078: * @see IService
079: * @see IResolve#resolve(Class, IProgressMonitor)
080: */
081: public <T> T resolve(Class<T> adaptee, IProgressMonitor monitor)
082: throws IOException {
083:
084: if (monitor == null)
085: monitor = new NullProgressMonitor();
086:
087: if (adaptee == null) {
088: throw new NullPointerException("No adaptor specified"); //$NON-NLS-1$
089: }
090: if (adaptee.isAssignableFrom(IServiceInfo.class)) {
091: return adaptee.cast(getInfo(monitor));
092: }
093: if (adaptee.isAssignableFrom(IService.class)) {
094: return adaptee.cast(parent(monitor));
095: }
096: if (adaptee.isAssignableFrom(IGeoResource.class)) {
097: monitor.done();
098: return adaptee.cast(this );
099: }
100: // if (adaptee.isAssignableFrom(List.class)) {
101: // return adaptee.cast(members(monitor));
102: // }
103: IResolveManager rm = CatalogPlugin.getDefault()
104: .getResolveManager();
105: if (rm.canResolve(this , adaptee)) {
106: return rm.resolve(this , adaptee, monitor);
107: }
108: return null; // no adapter found (check to see if ResolveAdapter is registered?)
109: }
110:
111: /**
112: * Harded coded to capture the IGeoResource contract.
113: * <p>
114: * That is we *must* resolve the following:
115: * <p>
116: * Required adaptions:
117: * <ul>
118: * <li>GeoResource.class - this
119: * <li>IGeoResourceInfo.class - getInfo (ie about this handles contents)
120: * <li>IService.class - service (ie that is responsible for this GeoResource)
121: * </ul>
122: * <p>
123: * Recommendated adaptions:
124: * <ul>
125: * <li>ImageDescriptor.class (for icon provided by external service)
126: * <li>List.class - members (ie children of this georesource as in the wms layer case)
127: * </ul>
128: * <p>
129: * Here is an implementation example (for something that can adapt to ImageDescriptor and
130: * FeatureSource):
131: *
132: * <pre><code>
133: * public <T> boolean canResolve( Class<T> adaptee ) {
134: * return adaptee != null
135: * && (adaptee.isAssignableFrom(ImageDescriptor.class)
136: * || adaptee.isAssignableFrom(FeatureSource.class) || super.canResolve(adaptee));
137: * }
138: * </code></pre>
139: */
140: public <T> boolean canResolve(Class<T> adaptee) {
141: return adaptee != null
142: && (adaptee.isAssignableFrom(IGeoResource.class) || // this
143: adaptee.isAssignableFrom(IService.class) || // service( monitor )
144: // adaptee.isAssignableFrom(List.class) || // members( monitor )
145: adaptee.isAssignableFrom(IResolve.class) || // parent
146: CatalogPlugin.getDefault().getResolveManager()
147: .canResolve(this , adaptee));
148: }
149:
150: /**
151: * Blocking operation to describe this service.
152: * <p>
153: * As an example this method is used by LabelDecorators to acquire title, and icon.
154: * </p>
155: *
156: * @return IGeoResourceInfo resolve(IGeoResourceInfo.class,IProgressMonitor monitor);
157: * @see IGeoResource#resolve(Class, IProgressMonitor)
158: */
159: public abstract IGeoResourceInfo getInfo(IProgressMonitor monitor)
160: throws IOException;
161:
162: /**
163: * Returns the IService for this GeoResource.
164: * <p>
165: * Method is useful in dealing with deeply nested GeoResource children (where parent may not
166: * always be an IService).
167: *
168: * @return IService for this GeoResource
169: * @see IGeoResource#resolve(Class, IProgressMonitor)
170: */
171: public abstract IService service(IProgressMonitor monitor)
172: throws IOException;
173:
174: /**
175: * Returns parent for this GeoResource.
176: * <p>
177: * Most implementations will use the following code example:
178: *
179: * <pre><code>
180: * public IService parent( IProgressMonitor monitor ) throws IOException {
181: * return service(monitor);
182: * }
183: * </code></pre>
184: *
185: * This code example preserves backwords compatibility with uDig 1.0 via type narrowing IResolve
186: * to IService.
187: * <p>
188: * You will need to provide a different implementation when working with nested content (like
189: * database schema or wms layers).
190: *
191: * @return parent IResolve for this GeoResource
192: * @see IGeoResource#resolve(Class, IProgressMonitor)
193: */
194: // TODO public abstract IResolve parent( IProgressMonitor monitor ) throws IOException;
195: public IResolve parent(IProgressMonitor monitor) throws IOException {
196: return service(monitor);
197: }
198:
199: /**
200: * List of children, or EMPTY_LIST for a leaf.
201: * <p>
202: * The provided implementation indicates that this IGeoResource is a leaf.
203: * </p>
204: * @return Collections.emptyList();
205: * @see net.refractions.udig.catalog.IResolve#members(org.eclipse.core.runtime.IProgressMonitor)
206: */
207: public List<IResolve> members(IProgressMonitor monitor) {
208: return Collections.emptyList(); // type safe EMPTY_LIST
209: }
210:
211: /**
212: * This should represent the identifier
213: *
214: * @see Object#equals(java.lang.Object)
215: * @param arg0
216: * @return
217: */
218: public boolean equals(Object arg0) {
219: if (arg0 != null && arg0 instanceof IGeoResource) {
220: IGeoResource resource = (IGeoResource) arg0;
221: if (getIdentifier() != null
222: && resource.getIdentifier() != null)
223: return getStringURL().equals(resource.getStringURL());
224: }
225: return false;
226: }
227:
228: private String getStringURL() {
229: if (stringURL == null) {
230: synchronized (this ) {
231: if (stringURL == null) {
232: stringURL = URLUtils.urlToString(getIdentifier(),
233: false);
234: }
235: }
236: }
237: return stringURL;
238: }
239:
240: /**
241: * This should represent the identified
242: *
243: * @see Object#hashCode()
244: * @return
245: */
246: public int hashCode() {
247: if (getIdentifier() != null)
248: return URLUtils.urlToString(getIdentifier(), false)
249: .hashCode();
250: return super .hashCode();
251: }
252:
253: /**
254: * Non blocking label used by LabelProvider. public static final String
255: * getGenericLabel(IGeoResource resource){ assert resource.getIdentifier() != null; return
256: * resource==null ||
257: * resource.getIdentifier()==null?"Resource":resource.getIdentifier().toString(); }
258: */
259: /**
260: * Non blocking icon used by LabelProvider. public static final ImageDescriptor
261: * getGenericIcon(IGeoResource resource){ if(resource !=null){ assert resource.getIdentifier() !=
262: * null; if(resource.canResolve(FeatureSource.class)){ // default feature return
263: * Images.getDescriptor(ISharedImages.FEATURE_OBJ); }
264: * if(resource.canResolve(GridCoverage.class)){ // default raster return
265: * Images.getDescriptor(ISharedImages.GRID_OBJ); } } return
266: * Images.getDescriptor(ISharedImages.RESOURCE_OBJ); }
267: */
268: /**
269: * Indicate class and id.
270: *
271: * @return string representing this IResolve
272: */
273: public String toString() {
274: StringBuffer buf = new StringBuffer();
275: String classname = getClass().getName();
276: String name = classname
277: .substring(classname.lastIndexOf('.') + 1);
278: buf.append(name);
279: buf.append("("); //$NON-NLS-1$
280: buf.append(getIdentifier());
281: buf.append(")"); //$NON-NLS-1$
282: return buf.toString();
283: }
284:
285: /**
286: * The identifier of a IGeoResource is identified by parent().getIdentifer()#ResourceID
287: * <p>
288: * For example: A WMS (IService) with an id of http://www.something.com/wms?Service=WMS would
289: * have georesources with ids similar to: http://www.something.com/wms?Service=WMS#layer1
290: *
291: * @see IResolve#getIdentifier()
292: */
293: public abstract URL getIdentifier();
294:
295: /**
296: * Disposes of any resources or listeners required. Default implementation does nothing.
297: *
298: * @param monitor monitor to show progress
299: */
300: public void dispose(IProgressMonitor monitor) {
301: // default impl does nothing
302: }
303: }
|