001: /*
002: * GeoTools - OpenSource mapping toolkit
003: * http://geotools.org
004: * (C) 2006, GeoTools Project Managment Committee (PMC)
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: package org.geotools.catalog.adaptable;
017:
018: import java.io.IOException;
019: import java.net.URI;
020: import java.util.ArrayList;
021: import java.util.HashMap;
022: import java.util.Iterator;
023: import java.util.List;
024:
025: import org.geotools.catalog.Catalog;
026: import org.geotools.catalog.GeoResource;
027: import org.geotools.catalog.Resolve;
028: import org.geotools.catalog.ResolveAdapterFactory;
029: import org.geotools.catalog.ResolveChangeEvent;
030: import org.geotools.catalog.ResolveChangeListener;
031: import org.geotools.catalog.Service;
032: import org.geotools.resources.Utilities;
033: import org.geotools.util.ProgressListener;
034:
035: /**
036: * Base class for "adapting" resolves.
037: *
038: *
039: * @author Justin Deoliveira, The Open Planning Project, jdeolive@openplans.org
040: *
041: */
042: public abstract class AdaptingResolve implements Resolve {
043:
044: /**
045: * The wrapped resolve.
046: */
047: protected Resolve resolve;
048: /**
049: * Adapter used to adapt the resolve.
050: */
051: protected ResolveAdapterFactoryFinder finder;
052: /**
053: * Cached wrapped parent
054: */
055: AdaptingResolve parent;
056: /**
057: * Cached wrapped members
058: */
059: List members;
060: /**
061: * Cached adaptations
062: */
063: HashMap adapterCache;
064:
065: /**
066: * a tuple to be used as the key in the adapter cache.
067: */
068: private static class Key {
069:
070: public Resolve resolve;
071: public Class adaptee;
072:
073: public Key(Resolve resolve, Class adaptee) {
074: this .resolve = resolve;
075: this .adaptee = adaptee;
076: }
077:
078: public boolean equals(Object obj) {
079: if (obj instanceof Key) {
080: Key other = (Key) obj;
081: return Utilities.equals(resolve, other.resolve)
082: && Utilities.equals(adaptee, other.adaptee);
083: }
084:
085: return false;
086: }
087:
088: public int hashCode() {
089: int hash = 7;
090: hash = 31 * hash
091: + (resolve != null ? resolve.hashCode() : 0);
092: hash = 31 * hash
093: + (adaptee != null ? adaptee.hashCode() : 0);
094:
095: return hash;
096: }
097: }
098:
099: AdaptingResolve(Resolve resolve, ResolveAdapterFactoryFinder finder) {
100: this .resolve = resolve;
101: this .finder = finder;
102: adapterCache = new HashMap();
103: }
104:
105: public ResolveAdapterFactoryFinder getResolveAdapterFactoryFinder() {
106: return finder;
107: }
108:
109: /**
110: * Sublcasses need to override and ensure that returned members are
111: * instances of {@link AdaptingResolve}.
112: * <p>
113: * As a convenience the {@link #wrap(List, Class)} method can be used as
114: * follows:
115: *
116: * <code>
117: * <pre>
118: * return wrap( resolve.members( monitor), AbstractResolve.class );
119: * </pre>
120: * </code>
121: * </p>
122: */
123: public synchronized final List members(ProgressListener monitor)
124: throws IOException {
125:
126: //get members from underlying handle
127: List rMembers = resolve.members(monitor);
128:
129: // reupdate cached members if
130: // 1. the cache is null
131: // 2. the cache does match rMembers
132: if (members == null) {
133: members = wrap(rMembers);
134: } else {
135: boolean equal = true;
136: if (members.size() != rMembers.size()) {
137: equal = false;
138: } else {
139: Iterator r = rMembers.iterator();
140: Iterator m = members.iterator();
141:
142: while (r.hasNext() && equal) {
143: Resolve rMember = (Resolve) r.next();
144: AdaptingResolve member = (AdaptingResolve) m.next();
145:
146: equal = Utilities.equals(rMember, member);
147:
148: }
149: }
150:
151: if (!equal) {
152: members = wrap(rMembers);
153: }
154: }
155:
156: return members;
157: }
158:
159: /**
160: * Wraps a list of catalog handles in an associated "adapting" implemenation.
161: *
162: * @param members List of catalog handles.
163: *
164: * @return The list of wrapped handles.
165: */
166: protected List wrap(List members) {
167: List wrapped;
168: try {
169: wrapped = (List) members.getClass().newInstance();
170: } catch (Exception e) {
171: wrapped = new ArrayList();
172: }
173:
174: for (Iterator m = members.iterator(); m.hasNext();) {
175: Resolve member = (Resolve) m.next();
176: AdaptingResolve wrapper = wrap(member);
177: if (wrapper != null) {
178: wrapped.add(wrapper);
179: }
180: }
181:
182: return wrapped;
183: }
184:
185: /**
186: * Wraps a resove handle in an adapting resolve handle.
187: *
188: * <p>
189: * If <code>resolve</code> already extends {@link AdaptingResolve}, then it
190: * is not wrapped. This method supports the following "wraps":
191: * <ul>
192: * <li>{@link Catalog} -> {@link AdaptingCatalog}.
193: * <li>{@link Service} -> {@link AdaptingService}.
194: * <li>{@link GeoResource} -> {@link AdaptingGeoResource}.
195: * </ul>
196: * </p>
197: * @param resolve The catalog handle being wrapped in an adapting version
198: * of it.
199: *
200: * @return The adapting catalog handle, or null if <code>resolve</code> is
201: * not an instance of Catlaog,Serfvice,or GeoResource.
202: */
203: protected AdaptingResolve wrap(Resolve resolve) {
204: if (resolve instanceof AdaptingResolve) {
205: return (AdaptingResolve) resolve;
206: }
207:
208: if (resolve instanceof Catalog) {
209: return new AdaptingCatalog((Catalog) resolve, finder);
210: }
211:
212: if (resolve instanceof Service) {
213: return new AdaptingService((Service) resolve, finder);
214: }
215:
216: if (resolve instanceof GeoResource) {
217: return new AdaptingGeoResource((GeoResource) resolve,
218: finder);
219: }
220:
221: return null;
222: }
223:
224: public final boolean canResolve(Class adaptee) {
225: if (finder.find(this , adaptee) != null)
226: return true;
227:
228: return resolve.canResolve(adaptee);
229: }
230:
231: public final Object resolve(Class adaptee, ProgressListener monitor)
232: throws IOException {
233:
234: //check the cache
235: Key key = new Key(resolve, adaptee);
236: if (adapterCache.containsKey(key)) {
237: return adapterCache.get(key);
238: }
239:
240: ResolveAdapterFactory factory = finder.find(this , adaptee);
241: if (factory != null) {
242: if (factory instanceof AdaptingResolveAware) {
243: ((AdaptingResolveAware) factory)
244: .setAdaptingResolve(this );
245: }
246: Object adapter = factory.adapt(resolve, adaptee, monitor);
247: if (adapter != null) {
248: adapterCache.put(key, adapter);
249: return adapter;
250: }
251: }
252:
253: if (resolve.canResolve(adaptee)) {
254: return resolve.resolve(adaptee, monitor);
255: }
256:
257: return null;
258: }
259:
260: public synchronized final Resolve parent(ProgressListener monitor)
261: throws IOException {
262:
263: Resolve rParent = resolve.parent(monitor);
264:
265: // update the parent cahce if
266: // 1. the cache is null
267: // OR
268: // 2. the cached parents underling resolve does not match rParent
269: if (parent == null
270: || !Utilities.equals(parent.resolve, rParent)) {
271: parent = wrap(rParent);
272: }
273:
274: return parent;
275: }
276:
277: public Status getStatus() {
278: return resolve.getStatus();
279: }
280:
281: public Throwable getMessage() {
282: return resolve.getMessage();
283: }
284:
285: public URI getIdentifier() {
286: return resolve.getIdentifier();
287: }
288:
289: public void addListener(ResolveChangeListener listener)
290: throws UnsupportedOperationException {
291: resolve.addListener(listener);
292: }
293:
294: public void removeListener(ResolveChangeListener listener) {
295: resolve.removeListener(listener);
296: }
297:
298: public void fire(ResolveChangeEvent event) {
299: resolve.fire(event);
300: }
301: }
|