svn-gvsig-desktop / trunk / libraries / libFMap / src / com / iver / cit / gvsig / fmap / core / gt2 / factory / FactoryRegistry.java @ 2943
History | View | Annotate | Download (25.8 KB)
1 |
/*
|
---|---|
2 |
* Geotools 2 - OpenSource mapping toolkit
|
3 |
* (C) 2005, Geotools Project Managment Committee (PMC)
|
4 |
*
|
5 |
* This library is free software; you can redistribute it and/or
|
6 |
* modify it under the terms of the GNU Lesser General Public
|
7 |
* License as published by the Free Software Foundation; either
|
8 |
* version 2.1 of the License, or (at your option) any later version.
|
9 |
*
|
10 |
* This library is distributed in the hope that it will be useful,
|
11 |
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
12 |
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
13 |
* Lesser General Public License for more details.
|
14 |
*
|
15 |
* You should have received a copy of the GNU Lesser General Public
|
16 |
* License along with this library; if not, write to the Free Software
|
17 |
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
18 |
*/
|
19 |
package com.iver.cit.gvsig.fmap.core.gt2.factory; |
20 |
|
21 |
// J2SE dependencies
|
22 |
import java.util.ArrayList; |
23 |
import java.util.Collection; |
24 |
import java.util.Comparator; |
25 |
import java.util.HashSet; |
26 |
import java.util.Iterator; |
27 |
import java.util.List; |
28 |
import java.util.Map; |
29 |
import java.util.Set; |
30 |
import java.util.logging.Level; |
31 |
import java.util.logging.LogRecord; |
32 |
import java.util.logging.Logger; |
33 |
|
34 |
import javax.imageio.spi.ServiceRegistry; |
35 |
|
36 |
import org.geotools.resources.Utilities; |
37 |
|
38 |
|
39 |
/**
|
40 |
* A registry for factories, organized by categories (usualy by <strong>interface</strong>).
|
41 |
* <p>
|
42 |
* For example <code>{@link org.opengis.referencing.crs.CRSFactory}.class</code> is a category,
|
43 |
* and <code>{@link org.opengis.referencing.operation.MathTransformFactory}.class</code>
|
44 |
* is an other category.
|
45 |
* </p>
|
46 |
* <p>
|
47 |
* For each category, implementations are registered in a file placed in the
|
48 |
* {@code META-INF/services/} directory, as specified in the {@link ServiceRegistry}
|
49 |
* javadoc. Those files are usually bundled into the JAR file distributed by the vendor.
|
50 |
* If the same {@code META-INF/services/} file appears many time in different JARs,
|
51 |
* they are processed as if their content were merged.
|
52 |
* </p>
|
53 |
* <p>
|
54 |
* Example use: <pre><code>
|
55 |
* Set categories = Collections.singleton(new Class[] {MathTransformProvider.class});
|
56 |
* FactoryRegistry registry = new FactoryRegistry(categories);
|
57 |
*
|
58 |
* // get the providers
|
59 |
* Iterator providers = registry.getProviders(MathTransformProvider.class)
|
60 |
* </code></pre>
|
61 |
* </p>
|
62 |
* <p>
|
63 |
* <strong>NOTE: This class is not thread safe</strong>. Users are responsable
|
64 |
* for synchronisation. This is usually done in an utility class wrapping this
|
65 |
* service registry (e.g. {@link org.geotools.referencing.FactoryFinder}).
|
66 |
* </p>
|
67 |
* @version $Id: FactoryRegistry.java 2943 2005-09-22 11:27:52Z fjp $
|
68 |
* @author Martin Desruisseaux
|
69 |
* @author Richard Gould
|
70 |
* @author Jody Garnett
|
71 |
*
|
72 |
* @see org.geotools.referencing.FactoryFinder
|
73 |
*/
|
74 |
public class FactoryRegistry extends ServiceRegistry { |
75 |
/**
|
76 |
* Filters only the factories that are {@linkplain OptionalFactory#isReady ready}.
|
77 |
*/
|
78 |
private static final Filter FILTER = new Filter() { |
79 |
public boolean filter(final Object provider) { |
80 |
return !(provider instanceof OptionalFactory) || ((OptionalFactory) provider).isReady(); |
81 |
} |
82 |
}; |
83 |
|
84 |
/**
|
85 |
* Constructs a new registry for the specified categories.
|
86 |
*
|
87 |
* @param categories The categories.
|
88 |
*/
|
89 |
public FactoryRegistry(final Collection categories) { |
90 |
// TODO: remove the cast when we will be allowed to compile for J2SE 1.5.
|
91 |
super((Iterator) categories.iterator()); |
92 |
} |
93 |
|
94 |
/**
|
95 |
* Returns the providers in the registry for the specified category. Providers that are
|
96 |
* not {@linkplain OptionalFactory#isReady ready} will be ignored. This method will
|
97 |
* {@linkplain #scanForPlugins scan for plugins} the first time it is invoked for the
|
98 |
* given category.
|
99 |
*
|
100 |
* @param category The category to look for. Must be an interface class
|
101 |
* (not the actual implementation class).
|
102 |
* @return Factories ready to use for the specified category.
|
103 |
*/
|
104 |
public Iterator getServiceProviders(final Class category) { |
105 |
Iterator iterator = getServiceProviders(category, FILTER, true); |
106 |
if (!iterator.hasNext()) {
|
107 |
/*
|
108 |
* No plugin. This method is probably invoked the first time for the specified
|
109 |
* category, otherwise we should have found at least the Geotools implementation.
|
110 |
* Scans the plugin now, but for this category only.
|
111 |
*/
|
112 |
for (final Iterator it=getClassLoaders().iterator(); it.hasNext();) { |
113 |
scanForPlugins((ClassLoader) it.next(), category);
|
114 |
} |
115 |
iterator = getServiceProviders(category, FILTER, true);
|
116 |
} |
117 |
return iterator;
|
118 |
} |
119 |
|
120 |
/**
|
121 |
* Returns the first provider in the registry for the specified category, using the specified
|
122 |
* map of hints (if any). This method may {@linkplain #scanForPlugins scan for plugins} the
|
123 |
* first time it is invoked. Except as a result of this scan, no new provider instance is
|
124 |
* created by the default implementation of this method. The {@link FactoryCreator} class
|
125 |
* change this behavior however.
|
126 |
*
|
127 |
* @param category The category to look for. Must be an interface class
|
128 |
* (not the actual implementation class).
|
129 |
* @param filter An optional filter, or {@code null} if none. This is used for example in
|
130 |
* order to select the first factory for some {@linkplain
|
131 |
* org.opengis.referencing.AuthorityFactory#getAuthority authority}.
|
132 |
* @param hints A {@linkplain Hints map of hints}, or {@code null} if none.
|
133 |
* @return A factory {@linkplain OptionalFactory#isReady ready} to use for the specified
|
134 |
* category and hints. The returns type is {@code Object} instead of {@link Factory}
|
135 |
* because the factory implementation doesn't need to be a Geotools one.
|
136 |
* @throws FactoryNotFoundException if no factory was found for the specified category, filter
|
137 |
* and hints.
|
138 |
* @throws FactoryRegistryException if a factory can't be returned for some othe reason.
|
139 |
*
|
140 |
* @see #getServiceProviders
|
141 |
* @see FactoryCreator#getServiceProvider
|
142 |
*/
|
143 |
public Object getServiceProvider(final Class category, final Filter filter, final Hints hints) |
144 |
throws FactoryRegistryException
|
145 |
{ |
146 |
Class implementation = null; |
147 |
if (hints!=null && !hints.isEmpty()) { |
148 |
final Hints.Key key = Hints.Key.getKeyForCategory(category);
|
149 |
if (key != null) { |
150 |
final Object hint = hints.get(key); |
151 |
if (category.isInstance(hint)) {
|
152 |
/*
|
153 |
* The factory implementation was given explicitly by the user.
|
154 |
* Nothing to do; we are done.
|
155 |
*/
|
156 |
return hint;
|
157 |
} |
158 |
if (hint instanceof Class[]) { |
159 |
/*
|
160 |
* The user accepts many implementation classes. Tries all of them in the
|
161 |
* preference order given by the user. The last class will be tried using
|
162 |
* the "normal" path (oustide the loop) in order to get the error message
|
163 |
* in case of failure.
|
164 |
*/
|
165 |
final Class[] types = (Class[]) hint; |
166 |
for (int i=0; i<types.length-1; i++) { |
167 |
Object candidate = getServiceProvider(category, types[i], filter, hints);
|
168 |
if (candidate != null) { |
169 |
return candidate;
|
170 |
} |
171 |
} |
172 |
if (types.length != 0) { |
173 |
implementation = types[types.length-1]; // Last try to be done below. |
174 |
} |
175 |
} else {
|
176 |
implementation = (Class) hint;
|
177 |
} |
178 |
} |
179 |
} |
180 |
final Object candidate = getServiceProvider(category, implementation, filter, hints); |
181 |
if (candidate != null) { |
182 |
return candidate;
|
183 |
} |
184 |
// TODO: provides localized messages.
|
185 |
final String message; |
186 |
if (implementation == null) { |
187 |
message = "No factory found for category \"" + Utilities.getShortName(category) + "\"."; |
188 |
} else {
|
189 |
message = "No factory found for implementation \"" +
|
190 |
Utilities.getShortName(implementation) +"\"."; |
191 |
} |
192 |
throw new FactoryNotFoundException(message); |
193 |
} |
194 |
|
195 |
/**
|
196 |
* Search the first implementation in the registery matching the specified conditions.
|
197 |
* This method do not creates new instance if no matching factory is found.
|
198 |
*
|
199 |
* @param category The category to look for. Must be an interface class.
|
200 |
* @param implementation The desired class for the implementation, or {@code null} if none.
|
201 |
* @param filter An optional filter, or {@code null} if none.
|
202 |
* @param hints A {@linkplain Hints map of hints}, or {@code null} if none.
|
203 |
* @return A factory for the specified category and hints, or {@code null} if none.
|
204 |
*/
|
205 |
private Object getServiceProvider(final Class category, final Class implementation, |
206 |
final Filter filter, final Hints hints) |
207 |
{ |
208 |
for (final Iterator it=getServiceProviders(category); it.hasNext();) { |
209 |
final Object candidate = it.next(); |
210 |
if (filter!=null && !filter.filter(candidate)) { |
211 |
continue;
|
212 |
} |
213 |
if (implementation!=null && !implementation.isInstance(candidate)) { |
214 |
continue;
|
215 |
} |
216 |
if (hints != null) { |
217 |
if (candidate instanceof Factory) { |
218 |
if (!isAcceptable((Factory) candidate, hints, null)) { |
219 |
continue;
|
220 |
} |
221 |
} |
222 |
if (!isAcceptable(candidate, hints)) {
|
223 |
continue;
|
224 |
} |
225 |
} |
226 |
return candidate;
|
227 |
} |
228 |
return null; |
229 |
} |
230 |
|
231 |
/**
|
232 |
* Returns {@code true} is the specified {@code factory} meets the requirements specified by a
|
233 |
* map of {@code hints}.
|
234 |
*
|
235 |
* @param factory The factory to checks.
|
236 |
* @param hints The user requirements.
|
237 |
* @param alreadyDone Should be {@code null} except on recursive calls (for internal use only).
|
238 |
* @return {@code true} if the {@code factory} meets the user requirements.
|
239 |
*/
|
240 |
private boolean isAcceptable(final Factory factory, final Hints hints, Set alreadyDone) { |
241 |
for (final Iterator it=factory.getImplementationHints().entrySet().iterator(); it.hasNext();) { |
242 |
final Map.Entry entry = (Map.Entry) it.next(); |
243 |
final Object value = entry.getValue(); |
244 |
final Object expected = hints.get(entry.getKey()); |
245 |
if (expected != null) { |
246 |
/*
|
247 |
* We have found a hint that matter. Check if the
|
248 |
* available factory meets the user's criterions.
|
249 |
*/
|
250 |
if (expected instanceof Class) { |
251 |
if (!((Class) expected).isInstance(value)) { |
252 |
return false; |
253 |
} |
254 |
} else if (expected instanceof Class[]) { |
255 |
final Class[] types = (Class[]) expected; |
256 |
int i=0; |
257 |
do if (i >= types.length) return false; |
258 |
while (!types[i++].isInstance(value));
|
259 |
} else if (!expected.equals(value)) { |
260 |
return false; |
261 |
} |
262 |
} |
263 |
// User check (overridable).
|
264 |
if (!isAcceptable(value, hints)) {
|
265 |
return false; |
266 |
} |
267 |
/*
|
268 |
* Check recursively in factory depencies, if any. The 'alreadyDone' set is a safety
|
269 |
* against cyclic dependencies, in order to protect ourself against never-ending loops.
|
270 |
*/
|
271 |
if (value instanceof Factory) { |
272 |
if (alreadyDone == null) { |
273 |
alreadyDone = new HashSet(); |
274 |
} |
275 |
if (!alreadyDone.contains(value)) {
|
276 |
alreadyDone.add(factory); |
277 |
if (!isAcceptable((Factory) value, hints, alreadyDone)) {
|
278 |
return false; |
279 |
} |
280 |
} |
281 |
} |
282 |
} |
283 |
return true; |
284 |
} |
285 |
|
286 |
/**
|
287 |
* Returns {@code true} if the specified {@code provider} meets the requirements specified by a
|
288 |
* map of {@code hints}. This method is invoked automatically when the {@code provider} is known
|
289 |
* to meets standard requirements.
|
290 |
* <br><br>
|
291 |
* The default implementation always returns {@code true}. Override this method if
|
292 |
* more checks are needed, typically for non-Geotools implementation. For example a
|
293 |
* JTS geometry factory finder may overrides this method in order to check if a
|
294 |
* {@link com.vividsolutions.jts.geom.GeometryFactory} uses the required
|
295 |
* {@link com.vividsolutions.jts.geom.CoordinateSequenceFactory}.
|
296 |
*
|
297 |
* @param provider The provider to checks.
|
298 |
* @param hints The user requirements.
|
299 |
* @return {@code true} if the {@code provider} meets the user requirements.
|
300 |
*/
|
301 |
protected boolean isAcceptable(final Object provider, final Hints hints) { |
302 |
return true; |
303 |
} |
304 |
|
305 |
/**
|
306 |
* Returns all class loaders to be used for scanning plugins. Current implementation
|
307 |
* returns the following class loaders:
|
308 |
*
|
309 |
* <ul>
|
310 |
* <li>{@linkplain Class#getClassLoader This object class loader}</li>
|
311 |
* <li>{@linkplain Thread#getContextClassLoader The thread context class loader}</li>
|
312 |
* <li>{@linkplain ClassLoader#getSystemClassLoader The system class loader}</li>
|
313 |
* </ul>
|
314 |
*
|
315 |
* The actual number of class loaders may be smaller if redundancies was found.
|
316 |
* If some more classloaders should be scanned, they shall be added into the code
|
317 |
* of this method.
|
318 |
*/
|
319 |
public final Set getClassLoaders() { |
320 |
final Set loaders = new HashSet(); |
321 |
for (int i=0; i<4; i++) { |
322 |
final ClassLoader loader; |
323 |
try {
|
324 |
switch (i) {
|
325 |
case 0: loader = getClass().getClassLoader(); break; |
326 |
case 1: loader = FactoryRegistry.class.getClassLoader(); break; |
327 |
case 2: loader = Thread.currentThread().getContextClassLoader(); break; |
328 |
case 3: loader = ClassLoader.getSystemClassLoader(); break; |
329 |
// Add any supplementary class loaders here, if needed.
|
330 |
default: throw new AssertionError(i); // Should never happen. |
331 |
} |
332 |
} catch (SecurityException exception) { |
333 |
// We are not allowed to get a class loader.
|
334 |
// Continue; some other class loader may be available.
|
335 |
continue;
|
336 |
} |
337 |
loaders.add(loader); |
338 |
} |
339 |
/*
|
340 |
* We now have a set of class loaders with duplicated object already removed
|
341 |
* (e.g. system classloader == context classloader). However, we may still
|
342 |
* have an other form of redundancie. A class loader may be the parent of an
|
343 |
* other one. Try to remove those dependencies.
|
344 |
*/
|
345 |
final ClassLoader[] asArray = (ClassLoader[]) loaders.toArray(new ClassLoader[loaders.size()]); |
346 |
for (int i=0; i<asArray.length; i++) { |
347 |
ClassLoader loader = asArray[i];
|
348 |
try {
|
349 |
while ((loader=loader.getParent()) != null) { |
350 |
loaders.remove(loader); |
351 |
} |
352 |
} catch (SecurityException exception) { |
353 |
// We are not allowed to fetch the parent class loader.
|
354 |
// Ignore (some redundancies may remains).
|
355 |
} |
356 |
} |
357 |
if (loaders.isEmpty()) {
|
358 |
Logger.getLogger("org.geotools.factory").warning("No class loaders available"); |
359 |
} |
360 |
return loaders;
|
361 |
} |
362 |
|
363 |
/**
|
364 |
* Scans for factory plug-ins on the application class path. This method is
|
365 |
* needed because the application class path can theoretically change, or
|
366 |
* additional plug-ins may become available. Rather than re-scanning the
|
367 |
* classpath on every invocation of the API, the class path is scanned
|
368 |
* automatically only on the first invocation. Clients can call this
|
369 |
* method to prompt a re-scan. Thus this method need only be invoked by
|
370 |
* sophisticated applications which dynamically make new plug-ins
|
371 |
* available at runtime.
|
372 |
*/
|
373 |
public void scanForPlugins() { |
374 |
final Set loaders = getClassLoaders(); |
375 |
for (final Iterator categories=getCategories(); categories.hasNext();) { |
376 |
final Class category = (Class) categories.next(); |
377 |
for (final Iterator it=loaders.iterator(); it.hasNext();) { |
378 |
final ClassLoader loader = (ClassLoader) it.next(); |
379 |
scanForPlugins(loader, category); |
380 |
} |
381 |
} |
382 |
} |
383 |
|
384 |
/**
|
385 |
* Scans for factory plug-ins of the given category.
|
386 |
*
|
387 |
* @param loader The class loader to use.
|
388 |
* @param category The category to scan for plug-ins.
|
389 |
*
|
390 |
* @todo localize log and error messages.
|
391 |
*/
|
392 |
private void scanForPlugins(final ClassLoader loader, final Class category) { |
393 |
final Iterator factories = ServiceRegistry.lookupProviders(category, loader); |
394 |
final String lineSeparator = System.getProperty("line.separator", "\n"); |
395 |
final StringBuffer message = new StringBuffer(); |
396 |
message.append("Scan for '");
|
397 |
message.append(Utilities.getShortName(category));
|
398 |
message.append("' implementations:");
|
399 |
boolean newServices = false; |
400 |
while (factories.hasNext()) {
|
401 |
Object factory = factories.next();
|
402 |
final Class factoryClass = factory.getClass(); |
403 |
/*
|
404 |
* If the factory implements more than one interface and an instance were
|
405 |
* already registered, reuse the same instance instead of duplicating it.
|
406 |
*/
|
407 |
final Object replacement = getServiceProviderByClass(factoryClass); |
408 |
if (replacement != null) { |
409 |
factory = replacement; |
410 |
} |
411 |
if (registerServiceProvider(factory, category)) {
|
412 |
/*
|
413 |
* The factory is now registered. Add it to the message to be logged
|
414 |
* at the end of this method. We log all factories together in order
|
415 |
* to produces only one log entry, since some registration (e.g.
|
416 |
* MathTransformProviders) may be quite extensive.
|
417 |
*/
|
418 |
message.append(lineSeparator); |
419 |
message.append(" Register ");
|
420 |
message.append(factoryClass.getName()); |
421 |
newServices = true;
|
422 |
} |
423 |
} |
424 |
/*
|
425 |
* If a system property was setup, load the class (if not already registered)
|
426 |
* and move it in front of any other factory. This is done for compatibility
|
427 |
* with legacy FactoryFinder implementation.
|
428 |
*/
|
429 |
try {
|
430 |
final String classname = System.getProperty(category.getName()); |
431 |
if (classname != null) try { |
432 |
final Class factoryClass = loader.loadClass(classname); |
433 |
Object factory = getServiceProviderByClass(factoryClass);
|
434 |
if (factory == null) try { |
435 |
factory = factoryClass.newInstance(); |
436 |
if (registerServiceProvider(factory, category)) {
|
437 |
message.append(lineSeparator); |
438 |
message.append(" Register ");
|
439 |
message.append(factoryClass.getName()); |
440 |
message.append(" from system property");
|
441 |
newServices = true;
|
442 |
} |
443 |
} catch (IllegalAccessException exception) { |
444 |
// TODO: localize
|
445 |
throw new FactoryRegistryException("Can't create factory for the \"" + |
446 |
classname + "\" system property.", exception);
|
447 |
} catch (InstantiationException exception) { |
448 |
// TODO: localize
|
449 |
throw new FactoryRegistryException("Can't create factory for the \"" + |
450 |
classname + "\" system property.", exception);
|
451 |
} |
452 |
/*
|
453 |
* Put this factory in front of every other factories (including the ones loaded
|
454 |
* in previous class loaders, which is why we don't inline this ordering in the
|
455 |
* above loop). Note: if some factories were not yet registered, they will not
|
456 |
* be properly ordered. Since this code exists more for compatibility reasons
|
457 |
* than as a commited API, we ignore this short comming for now.
|
458 |
*/
|
459 |
for (final Iterator it=getServiceProviders(category, false); it.hasNext();) { |
460 |
final Object other = it.next(); |
461 |
if (other != factory) {
|
462 |
setOrdering(category, factory, other); |
463 |
} |
464 |
} |
465 |
} catch (ClassNotFoundException exception) { |
466 |
// The class has not been found, maybe because we are not using the appropriate
|
467 |
// class loader. Ignore (do not thrown an exception), in order to give a chance
|
468 |
// to the caller to invokes this method again with a different class loader.
|
469 |
} |
470 |
} catch (SecurityException exception) { |
471 |
// We are not allowed to read property, probably
|
472 |
// because we are running in an applet. Ignore...
|
473 |
} |
474 |
/*
|
475 |
* Log the list of registered factories.
|
476 |
*/
|
477 |
if (newServices) {
|
478 |
final LogRecord record = new LogRecord(Level.CONFIG, message.toString()); |
479 |
record.setSourceClassName(FactoryRegistry.class.getName()); |
480 |
record.setSourceMethodName("scanForPlugins");
|
481 |
Logger.getLogger("org.opengis.factory").log(record); |
482 |
} |
483 |
} |
484 |
|
485 |
/**
|
486 |
* Set pairwise ordering between all services according a comparator. Calls to
|
487 |
* <code>{@linkplain Comparator#compare compare}(factory1, factory2)</code> should returns:
|
488 |
* <ul>
|
489 |
* <li>{@code -1} if {@code factory1} is preferred to {@code factory2}</li>
|
490 |
* <li>{@code +1} if {@code factory2} is preferred to {@code factory1}</li>
|
491 |
* <li>{@code 0} if there is no preferred order between {@code factory1} and
|
492 |
* {@code factory2}</li>
|
493 |
* </ul>
|
494 |
*
|
495 |
* @param category The category to set ordering.
|
496 |
* @param comparator The comparator to use for ordering.
|
497 |
* @return {@code true} if at least one ordering setting has been modified as a consequence
|
498 |
* of this call.
|
499 |
*/
|
500 |
public boolean setOrdering(final Class category, final Comparator comparator) { |
501 |
boolean set = false; |
502 |
final List previous = new ArrayList(); |
503 |
for (final Iterator it=getServiceProviders(category, false); it.hasNext();) { |
504 |
final Object f1 = it.next(); |
505 |
for (int i=previous.size(); --i>=0;) { |
506 |
final Object f2 = previous.get(i); |
507 |
final int c; |
508 |
try {
|
509 |
c = comparator.compare(f1, f2); |
510 |
} catch (ClassCastException exception) { |
511 |
/*
|
512 |
* This exception is expected if the user-supplied comparator follows strictly
|
513 |
* the java.util.Comparator specification and has determined that it can't
|
514 |
* compare the supplied factories. From ServiceRegistry point of view, it just
|
515 |
* means that the ordering between those factories will stay undeterminated.
|
516 |
*/
|
517 |
continue;
|
518 |
} |
519 |
if (c > 0) { |
520 |
set |= setOrdering(category, f1, f2); |
521 |
} else if (c < 0) { |
522 |
set |= setOrdering(category, f2, f1); |
523 |
} |
524 |
} |
525 |
previous.add(f1); |
526 |
} |
527 |
return set;
|
528 |
} |
529 |
|
530 |
/**
|
531 |
* Sets or unsets a pairwise ordering between all services meeting a criterion. For example
|
532 |
* in the CRS framework ({@link org.geotools.referencing.FactoryFinder}), this is used for
|
533 |
* setting ordering between all services provided by two vendors, or for two authorities.
|
534 |
* If one or both services are not currently registered, or if the desired ordering is
|
535 |
* already set/unset, nothing happens and false is returned.
|
536 |
*
|
537 |
* @param base The base category. Only categories {@linkplain Class#isAssignableFrom
|
538 |
* assignable} to {@code base} will be processed.
|
539 |
* @param set {@code true} for setting the ordering, or {@code false} for unsetting.
|
540 |
* @param service1 filter for the preferred service.
|
541 |
* @param service2 filter for the service to which {@code service1} is preferred.
|
542 |
*/
|
543 |
public boolean setOrdering(final Class base, |
544 |
final boolean set, |
545 |
final Filter service1, |
546 |
final Filter service2) |
547 |
{ |
548 |
boolean done = false; |
549 |
for (final Iterator categories=getCategories(); categories.hasNext();) { |
550 |
final Class category = (Class) categories.next(); |
551 |
if (base.isAssignableFrom(category)) {
|
552 |
Object impl1 = null; |
553 |
Object impl2 = null; |
554 |
for (final Iterator it=getServiceProviders(category); it.hasNext();) { |
555 |
final Object factory = it.next(); |
556 |
if (service1.filter(factory)) impl1 = factory;
|
557 |
if (service2.filter(factory)) impl2 = factory;
|
558 |
if (impl1!=null && impl2!=null && impl1!=impl2) { |
559 |
if (set) done |= setOrdering(category, impl1, impl2);
|
560 |
else done |= unsetOrdering(category, impl1, impl2);
|
561 |
} |
562 |
} |
563 |
} |
564 |
} |
565 |
return done;
|
566 |
} |
567 |
} |