001: package net.refractions.udig.project.internal.impl;
002:
003: import java.io.IOException;
004: import java.net.URL;
005: import java.util.ArrayList;
006: import java.util.Collections;
007: import java.util.Comparator;
008: import java.util.HashMap;
009: import java.util.List;
010: import java.util.Map;
011: import java.util.Set;
012: import java.util.Map.Entry;
013:
014: import net.refractions.udig.catalog.IGeoResource;
015: import net.refractions.udig.catalog.IGeoResourceInfo;
016: import net.refractions.udig.catalog.IResolve;
017: import net.refractions.udig.catalog.IService;
018: import net.refractions.udig.core.internal.ExtensionPointList;
019: import net.refractions.udig.project.ILayer;
020: import net.refractions.udig.project.IResourceCachingInterceptor;
021: import net.refractions.udig.project.IResourceInterceptor;
022: import net.refractions.udig.project.internal.ProjectPlugin;
023: import net.refractions.udig.project.preferences.PreferenceConstants;
024:
025: import org.eclipse.core.runtime.CoreException;
026: import org.eclipse.core.runtime.IConfigurationElement;
027: import org.eclipse.core.runtime.IProgressMonitor;
028:
029: /**
030: * Wraps a IGeoResource for a layer. This is to ensure that each item that is resolved to is the
031: * same instance regardless of how the IGeoResource's resolve method is implemented.
032: *
033: * @author Jesse
034: * @since 1.0.0
035: */
036: public class LayerResource extends IGeoResource {
037:
038: /**
039: * The layer that owns/created the Resource
040: */
041: private final LayerImpl layer;
042:
043: /**
044: * The resource that is wrapped by this object
045: */
046: IGeoResource geoResource;
047:
048: private volatile InterceptorsBag interceptors;
049:
050: private Sorter postSorter;
051:
052: private Sorter preSorter;
053:
054: /**
055: * @see java.lang.Object#equals(java.lang.Object)
056: */
057: public boolean equals(Object obj) {
058: if (obj instanceof LayerResource) {
059: LayerResource other = (LayerResource) obj;
060: return geoResource.equals(other.geoResource);
061: }
062: return false;
063: }
064:
065: /**
066: * @see net.refractions.udig.catalog.IGeoResource#hashCode()
067: */
068: public int hashCode() {
069: return geoResource.hashCode();
070: }
071:
072: /**
073: * Construct <code>LayerImpl.LayerResource</code>.
074: */
075: public LayerResource(LayerImpl impl, IGeoResource resource) {
076: layer = impl;
077: this .geoResource = resource;
078: }
079:
080: /**
081: * @see net.refractions.udig.catalog.IResolve#canResolve(java.lang.Class)
082: */
083: public <T> boolean canResolve(Class<T> adaptee) {
084: return geoResource.canResolve(adaptee);
085: }
086:
087: /**
088: * @see net.refractions.udig.catalog.IResolve#getIdentifier()
089: */
090: public URL getIdentifier() {
091: return geoResource.getIdentifier();
092: }
093:
094: /**
095: * @see net.refractions.udig.catalog.IResolve#getMessage()
096: */
097: public Throwable getMessage() {
098: return geoResource.getMessage();
099: }
100:
101: /**
102: * @see net.refractions.udig.catalog.IResolve#getStatus()
103: */
104: public Status getStatus() {
105: return geoResource.getStatus();
106: }
107:
108: /**
109: * @see net.refractions.udig.catalog.IResolve#members(org.eclipse.core.runtime.IProgressMonitor)
110: */
111: public List<IResolve> members(IProgressMonitor monitor) {
112: return geoResource.members(monitor);
113: }
114:
115: /**
116: * @see net.refractions.udig.catalog.IGeoResource#resolve(java.lang.Class,
117: * org.eclipse.core.runtime.IProgressMonitor)
118: */
119: public synchronized <T> T resolve(Class<T> adaptee,
120: IProgressMonitor monitor) throws IOException {
121: if (IGeoResource.class == adaptee)
122: return adaptee.cast(this );
123: if (this .geoResource.getClass().isAssignableFrom(adaptee))
124: return adaptee.cast(geoResource);
125: T resource = processResourceCachingStrategy(monitor, adaptee);
126: if (resource == null)
127: return null;
128: resource = processPostResourceInterceptors(resource, adaptee);
129: return resource;
130: }
131:
132: public IService service(IProgressMonitor monitor)
133: throws IOException {
134: return resolve(IService.class, monitor);
135: }
136:
137: @Override
138: public IResolve parent(IProgressMonitor monitor) throws IOException {
139: return geoResource.parent(monitor);
140: }
141:
142: private <T> T processPreResourceInterceptors(T resource,
143: Class<T> requestedType) {
144: List<Wrapper<T>> pre = getPreInterceptors(resource);
145: return runInterceptors(requestedType, resource, pre);
146: }
147:
148: private <T> T runInterceptors(Class<T> requestedType, T resource,
149: List<Wrapper<T>> pre) {
150: T resource2 = resource;
151: for (Wrapper<T> interceptor : pre) {
152: if (resource2 == null)
153: return null;
154: if (isAssignable(resource2, interceptor.targetType))
155: resource2 = interceptor.run(layer, resource2,
156: requestedType);
157: }
158: return resource2;
159: }
160:
161: private <T> List<Wrapper<T>> getPreInterceptors(T resource) {
162: loadInterceptors();
163: Set<Entry<IConfigurationElement, Wrapper>> entires = interceptors.pre
164: .entrySet();
165: List<Wrapper<T>> result = findValidInterceptors(resource,
166: entires);
167: if (preSorter != null) {
168: Collections.sort(result, preSorter);
169: }
170: return result;
171: }
172:
173: @SuppressWarnings("unchecked")
174: private <T> List<Wrapper<T>> findValidInterceptors(T resource,
175: Set<Entry<IConfigurationElement, Wrapper>> entires) {
176: List<Wrapper<T>> result = new ArrayList<Wrapper<T>>();
177: for (Entry<IConfigurationElement, Wrapper> entry : entires) {
178: String attribute = entry.getKey().getAttribute("target"); //$NON-NLS-1$
179: if (attribute == null) {
180: result.add(entry.getValue());
181: } else {
182: boolean assignableFrom = isAssignable(resource,
183: attribute);
184: if (assignableFrom)
185: result.add(entry.getValue());
186: }
187: }
188: return result;
189: }
190:
191: @SuppressWarnings("unchecked")
192: private <T> boolean isAssignable(T resource, String attribute) {
193: if (attribute == null)
194: return true;
195: boolean assignableFrom;
196: try {
197: Class<? extends Object> class1 = resource.getClass();
198: Class<T> loadClass = (Class<T>) class1.getClassLoader()
199: .loadClass(attribute);
200: assignableFrom = (loadClass).isAssignableFrom(class1);
201: } catch (ClassNotFoundException e) {
202: return false;
203: }
204: return assignableFrom;
205: }
206:
207: private <T> T processResourceCachingStrategy(
208: IProgressMonitor monitor, Class<T> requestedType)
209: throws IOException {
210: IResourceCachingInterceptor cachingStrategy = getCachingInterceptors();
211: T resource2;
212: if (cachingStrategy == null) {
213: resource2 = geoResource.resolve(requestedType, monitor);
214: if (resource2 == null)
215: return null;
216: return processPreResourceInterceptors(resource2,
217: requestedType);
218: }
219:
220: if (cachingStrategy.isCached(layer, geoResource, requestedType)) {
221: return cachingStrategy.get(layer, requestedType);
222: } else {
223:
224: resource2 = geoResource.resolve(requestedType, monitor);
225: if (resource2 == null)
226: return null;
227: resource2 = processPreResourceInterceptors(resource2,
228: requestedType);
229: cachingStrategy.put(layer, resource2, requestedType);
230: return resource2;
231: }
232: }
233:
234: private IResourceCachingInterceptor getCachingInterceptors() {
235: loadInterceptors();
236: String string = ProjectPlugin
237: .getPlugin()
238: .getPreferenceStore()
239: .getString(
240: PreferenceConstants.P_LAYER_RESOURCE_CACHING_STRATEGY);
241: return interceptors.caching.get(string);
242: }
243:
244: private <T> T processPostResourceInterceptors(T resource2,
245: Class<T> requestedType) {
246: T resource = resource2;
247: List<Wrapper<T>> interceptors = getPostInterceptors(resource);
248: return runInterceptors(requestedType, resource, interceptors);
249: }
250:
251: private <T> List<Wrapper<T>> getPostInterceptors(T resource) {
252: loadInterceptors();
253: List<Wrapper<T>> findValidInterceptors = findValidInterceptors(
254: resource, interceptors.post.entrySet());
255: if (postSorter != null) {
256: Collections.sort(findValidInterceptors, postSorter);
257: }
258: return findValidInterceptors;
259: }
260:
261: @SuppressWarnings("unchecked")
262: private void loadInterceptors() {
263: if (interceptors == null) {
264: synchronized (this ) {
265: if (interceptors == null) {
266:
267: final Map<IConfigurationElement, Wrapper> pre = new HashMap<IConfigurationElement, Wrapper>();
268: final Map<String, IResourceCachingInterceptor> caching = new HashMap<String, IResourceCachingInterceptor>();
269: final Map<IConfigurationElement, Wrapper> post = new HashMap<IConfigurationElement, Wrapper>();
270:
271: List<IConfigurationElement> list = ExtensionPointList
272: .getExtensionPointList("net.refractions.udig.project.resourceInterceptor"); //$NON-NLS-1$
273: for (IConfigurationElement element : list) {
274: try {
275: if (element.getName().equals(
276: "cachingStrategy")) { //$NON-NLS-1$
277: IResourceCachingInterceptor strategy = (IResourceCachingInterceptor) element
278: .createExecutableExtension("class"); //$NON-NLS-1$
279: caching
280: .put(
281: element
282: .getNamespaceIdentifier()
283: + "." + element.getAttribute("id"), strategy); //$NON-NLS-1$ //$NON-NLS-2$
284: } else {
285: IResourceInterceptor tmp = (IResourceInterceptor) element
286: .createExecutableExtension("class"); //$NON-NLS-1$
287:
288: Wrapper interceptor = new Wrapper(tmp,
289: element.getAttribute("target")); //$NON-NLS-1$
290: String order = element
291: .getAttribute("order"); //$NON-NLS-1$
292: if ("PRE".equals(order)) { //$NON-NLS-1$
293: pre.put(element, interceptor);
294: } else if ("POST".equals(order)) { //$NON-NLS-1$
295: post.put(element, interceptor);
296: }
297: }
298: } catch (CoreException e) {
299: ProjectPlugin
300: .log(
301: "Failed to load resource interceptor:" + element.getNamespaceIdentifier() + "." + element.getAttribute("id"), e); //$NON-NLS-1$//$NON-NLS-2$ //$NON-NLS-3$
302: }
303: }
304:
305: interceptors = new InterceptorsBag(pre, caching,
306: post);
307: }
308: }
309: }
310: }
311:
312: @Override
313: public IGeoResourceInfo getInfo(IProgressMonitor monitor)
314: throws IOException {
315: return resolve(IGeoResourceInfo.class, monitor);
316: }
317:
318: public LayerImpl getLayer() {
319: return layer;
320: }
321:
322: /**
323: * ONLY FOR TESTING
324: *
325: * @param <T>
326: * @param comparator the comparator for sorting
327: * @param sortPre if true the preResourceInterceptors will be sorted other wise the postResourceInterceptors will
328: * be sorted.
329: */
330: public void testingOnly_sort(
331: Comparator<IResourceInterceptor<? extends Object>> comparator,
332: boolean sortPre) {
333: if (sortPre)
334: preSorter = new Sorter(comparator);
335: else
336: postSorter = new Sorter(comparator);
337:
338: }
339:
340: private static class InterceptorsBag {
341: final Map<IConfigurationElement, Wrapper> pre;
342: final Map<String, IResourceCachingInterceptor> caching;
343: final Map<IConfigurationElement, Wrapper> post;
344:
345: public InterceptorsBag(
346: final Map<IConfigurationElement, Wrapper> pre,
347: final Map<String, IResourceCachingInterceptor> caching,
348: final Map<IConfigurationElement, Wrapper> post) {
349: super ();
350: this .pre = pre;
351: this .caching = caching;
352: this .post = post;
353: }
354: }
355:
356: private static class Sorter implements
357: Comparator<Wrapper<? extends Object>> {
358:
359: private Comparator<IResourceInterceptor<? extends Object>> wrapped;
360:
361: public Sorter(
362: Comparator<IResourceInterceptor<? extends Object>> comparator) {
363: wrapped = comparator;
364: }
365:
366: public int compare(Wrapper<? extends Object> o1,
367: Wrapper<? extends Object> o2) {
368: return wrapped.compare(o1.interceptor, o2.interceptor);
369: }
370:
371: }
372:
373: /**
374: * Provides extra info.
375: *
376: * @author Jesse
377: * @since 1.1.0
378: */
379: private static class Wrapper<T> implements IResourceInterceptor<T> {
380:
381: public String targetType;
382: private IResourceInterceptor<T> interceptor;
383:
384: public Wrapper(IResourceInterceptor<T> interceptor,
385: String targetType) {
386: this .interceptor = interceptor;
387: this .targetType = targetType;
388: }
389:
390: @SuppressWarnings("unchecked")
391: public T run(ILayer layer, T resource,
392: Class<? super T> requestedType) {
393: try {
394: return interceptor.run(layer, resource, requestedType);
395: } catch (Throwable t) {
396: ProjectPlugin
397: .log(
398: "Exception when running interceptor: " + interceptor, t); //$NON-NLS-1$
399: return resource;
400: }
401: }
402:
403: @Override
404: public String toString() {
405: return interceptor.toString();
406: }
407:
408: }
409: }
|