Statistics
| Revision:

root / trunk / libraries / libFMap / src / com / iver / cit / gvsig / fmap / core / gt2 / factory / FactoryFinder.java @ 10627

History | View | Annotate | Download (34.8 KB)

1
/*
2
 * Created on 12-may-2005
3
 *
4
 * gvSIG. Sistema de Informaci?n Geogr?fica de la Generalitat Valenciana
5
 * 
6
 * Copyright (C) 2004 IVER T.I. and Generalitat Valenciana.
7
 * 
8
 * This program is free software; you can redistribute it and/or
9
 * modify it under the terms of the GNU General Public License
10
 * as published by the Free Software Foundation; either version 2
11
 * of the License, or (at your option) any later version.
12
 *  
13
 * This program is distributed in the hope that it will be useful,
14
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
15
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
16
 * GNU General Public License for more details.
17
 * 
18
 * You should have received a copy of the GNU General Public License
19
 * along with this program; if not, write to the Free Software
20
 * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
21
 *  
22
 * For more information, contact:
23
 *
24
 *  Generalitat Valenciana
25
 *   Conselleria d'Infraestructures i Transport
26
 *   Av. Blasco Ib??ez, 50
27
 *   46010 VALENCIA
28
 *   SPAIN
29
 *
30
 *      +34 963862235
31
 *   gvsig@gva.es
32
 *      www.gvsig.gva.es
33
 * 
34
 *    or
35
 * 
36
 *   IVER T.I. S.A
37
 *   Salamanca 50
38
 *   46005 Valencia
39
 *   Spain
40
 * 
41
 *   +34 963163400
42
 *   dac@iver.es
43
 */
44
package com.iver.cit.gvsig.fmap.core.gt2.factory;
45

    
46

    
47
// J2SE direct dependencies
48
import java.io.IOException;
49
import java.io.Writer;
50
import java.util.Arrays;
51
import java.util.Iterator;
52
import java.util.Locale;
53
import java.util.NoSuchElementException;
54
import java.util.Set;
55

    
56
import javax.imageio.spi.RegisterableService;
57
import javax.imageio.spi.ServiceRegistry;
58

    
59
import org.geotools.io.TableWriter;
60
import org.geotools.referencing.CRS;
61
import org.geotools.resources.Arguments;
62
import org.geotools.resources.LazySet;
63
import org.geotools.resources.Utilities;
64
import org.opengis.metadata.citation.Citation;
65
import org.opengis.referencing.AuthorityFactory;
66
import org.opengis.referencing.Factory;
67
import org.opengis.referencing.crs.CRSAuthorityFactory;
68
import org.opengis.referencing.crs.CRSFactory;
69
import org.opengis.referencing.cs.CSAuthorityFactory;
70
import org.opengis.referencing.cs.CSFactory;
71
import org.opengis.referencing.datum.DatumAuthorityFactory;
72
import org.opengis.referencing.datum.DatumFactory;
73
import org.opengis.referencing.operation.CoordinateOperationFactory;
74
import org.opengis.referencing.operation.MathTransformFactory;
75

    
76

    
77
/**
78
 * Defines static methods used to access the application's default {@linkplain Factory
79
 * factory} implementation.
80
 *
81
 * <P>To declare a factory implementation, a services subdirectory is placed within the
82
 * <code>META-INF</code> directory that is present in every JAR file. This directory
83
 * contains a file for each factory interface that has one or more implementation classes
84
 * present in the JAR file. For example, if the JAR file contained a class named
85
 * <code>com.mycompany.DatumFactoryImpl</code> which implements the {@link DatumFactory}
86
 * interface, the JAR file would contain a file named:</P>
87
 *
88
 * <blockquote><pre>META-INF/services/org.opengis.referencing.datum.DatumFactory</pre></blockquote>
89
 *
90
 * <P>containing the line:</P>
91
 *
92
 * <blockquote><pre>com.mycompany.DatumFactoryImpl</pre></blockquote>
93
 *
94
 * <P>If the factory classes implements {@link RegisterableService}, it will be notified upon
95
 * registration and deregistration. Note that the factory classes should be lightweight and quick
96
 * to load. Implementations of these interfaces should avoid complex dependencies on other classes
97
 * and on native code. The usual pattern for more complex services is to register a lightweight
98
 * proxy for the heavyweight service.</P>
99
 *
100
 * <H2>Note on factory ordering in a multi-thread environment</H2>
101
 * <P>This class is thread-safe. However, calls to any {@link #setAuthorityOrdering} or
102
 * {@link #setVendorOrdering} methods have a system-wide effect. If two threads or two
103
 * applications need a different ordering, they shall manage their own instance of
104
 * {@link FactoryRegistry}. This {@code FactoryFinder} class is simply a convenience
105
 * wrapper around a {@code FactoryRegistry} instance.</P>
106
 *
107
 * @version $Id: FactoryFinder.java 10627 2007-03-06 17:10:21Z caballero $
108
 * @author Martin Desruisseaux
109
 */
110
public final class FactoryFinder {
111
    /**
112
     * The service registry for this manager.
113
     * Will be initialized only when first needed.
114
     */
115
    private static FactoryRegistry registry;
116

    
117
    /**
118
     * Do not allows any instantiation of this class.
119
     */
120
    private FactoryFinder() {
121
        // singleton
122
    }
123

    
124
    /**
125
     * Returns the service registry. The registry will be created the first
126
     * time this method is invoked.
127
     */
128
    private static FactoryRegistry getServiceRegistry() {
129
        assert Thread.holdsLock(FactoryFinder.class);
130
        if (registry == null) {
131
            registry = new FactoryCreator(Arrays.asList(new Class[] {
132
                    DatumFactory.class,
133
                    CSFactory.class,
134
                    CRSFactory.class,
135
                    DatumAuthorityFactory.class,
136
                    CSAuthorityFactory.class,
137
                    CRSAuthorityFactory.class,
138
                    MathTransformFactory.class,
139
                    CoordinateOperationFactory.class}));
140
        }
141
        return registry;
142
    }
143

    
144
    /**
145
     * Programmatic management of authority factories.
146
     * Needed for user managed, not plug-in managed, authority factory.
147
     * Also useful for test cases.
148
     *
149
     * @param authority The authority factory to add.
150
     */
151
    public static synchronized void addAuthorityFactory(final AuthorityFactory authority) {
152
        getServiceRegistry().registerServiceProvider(authority);
153
    }
154

    
155
    /**
156
     * Programmatic management of authority factories.
157
     *
158
     * @deprecated Renamed as {@link #addAuthorityFactory}.
159
     */
160
    public static void addAuthority(final AuthorityFactory authority) {
161
        addAuthorityFactory(authority);
162
    }
163

    
164
    /**
165
     * Programmatic management of authority factories.
166
     * Needed for user managed, not plug-in managed, authority factory.
167
     * Also useful for test cases.
168
     *
169
     * @param authority The authority factory to remove.
170
     */
171
    public static synchronized void removeAuthorityFactory(final AuthorityFactory authority) {
172
        getServiceRegistry().deregisterServiceProvider(authority);
173
    }
174

    
175
    /**
176
     * Programmatic management of authority factories.
177
     *
178
     * @deprecated Renamed as {@link #removeAuthorityFactory}.
179
     */
180
    public static void removeAuthority(final AuthorityFactory authority) {
181
        removeAuthorityFactory(authority);
182
    }
183

    
184
    /**
185
     * Returns the default implementation of {@link DatumFactory}. If no implementation is
186
     * registered, then this method throws an exception. If more than one implementation is
187
     * registered and an {@linkplain #setVendorOrdering ordering is set}, then the preferred
188
     * implementation is returned. Otherwise an arbitrary one is selected.
189
     *
190
     * @return First datum factory found.
191
     * @throws NoSuchElementException if no implementation was found for the
192
     *         {@link DatumFactory} interface.
193
     *
194
     * @deprecated Replaced by {@code getDatumFactory(null)}.
195
     */
196
    public static synchronized DatumFactory getDatumFactory() throws NoSuchElementException {
197
        return (DatumFactory) getServiceRegistry().getServiceProviders(DatumFactory.class).next();
198
    }
199

    
200
    /**
201
     * Returns the first implementation of {@link DatumFactory} matching the specified hints.
202
     * If no implementation matches, a new one is created if possible or an exception is thrown
203
     * otherwise. If more than one implementation is registered and an
204
     * {@linkplain #setVendorOrdering ordering is set}, then the preferred
205
     * implementation is returned. Otherwise an arbitrary one is selected.
206
     *
207
     * @param  hints An optional map of hints, or {@code null} if none.
208
     * @return The first datum factory that matches the supplied hints.
209
     * @throws FactoryRegistryException if no implementation was found or can be created for the
210
     *         {@link DatumFactory} interface.
211
     */
212
    public static synchronized DatumFactory getDatumFactory(final Hints hints) throws FactoryRegistryException {
213
        return (DatumFactory) getServiceRegistry().getServiceProvider(DatumFactory.class, null, hints);
214
    }
215

    
216
    /**
217
     * Returns a set of all available implementations for the {@link DatumFactory} interface.
218
     *
219
     * @return Set of available datum factory implementations.
220
     */
221
    public static synchronized Set getDatumFactories() {
222
        return new LazySet(getServiceRegistry().getServiceProviders(DatumFactory.class));
223
    }
224

    
225
    /**
226
     * Returns the default implementation of {@link CSFactory}. If no implementation is
227
     * registered, then this method throws an exception. If more than one implementation is
228
     * registered and an {@linkplain #setVendorOrdering ordering is set}, then the preferred
229
     * implementation is returned. Otherwise an arbitrary one is selected.
230
     *
231
     * @return The first coordinate system factory found.
232
     * @throws NoSuchElementException if no implementation was found for the
233
     *         {@link CSFactory} interface.
234
     *
235
     * @deprecated Replaced by {@code getCSFactory(null)}.
236
     */
237
    public static synchronized CSFactory getCSFactory() throws NoSuchElementException {
238
        return (CSFactory) getServiceRegistry().getServiceProviders(CSFactory.class).next();
239
    }
240

    
241
    /**
242
     * Returns the first implementation of {@link CSFactory} matching the specified hints.
243
     * If no implementation matches, a new one is created if possible or an exception is thrown
244
     * otherwise. If more than one implementation is registered and an
245
     * {@linkplain #setVendorOrdering ordering is set}, then the preferred
246
     * implementation is returned. Otherwise an arbitrary one is selected.
247
     *
248
     * @param  hints An optional map of hints, or {@code null} if none.
249
     * @return The first coordinate system factory that matches the supplied hints.
250
     * @throws FactoryRegistryException if no implementation was found or can be created for the
251
     *         {@link CSFactory} interface.
252
     */
253
    public static synchronized CSFactory getCSFactory(final Hints hints) throws FactoryRegistryException {
254
        return (CSFactory) getServiceRegistry().getServiceProvider(CSFactory.class, null, hints);
255
    }
256

    
257
    /**
258
     * Returns a set of all available implementations for the {@link CSFactory} interface.
259
     *
260
     * @return Set of available coordinate system factory implementations.
261
     */
262
    public static synchronized Set getCSFactories() {
263
        return new LazySet(getServiceRegistry().getServiceProviders(CSFactory.class));
264
    }
265

    
266
    /**
267
     * Returns the default implementation of {@link CRSFactory}. If no implementation is
268
     * registered, then this method throws an exception. If more than one implementation is
269
     * registered and an {@linkplain #setVendorOrdering ordering is set}, then the preferred
270
     * implementation is returned. Otherwise an arbitrary one is selected.
271
     *
272
     * @return The first coordinate reference system factory found.
273
     * @throws NoSuchElementException if no implementation was found for the
274
     *         {@link CRSFactory} interface.
275
     *
276
     * @deprecated Replaced by {@code getCRSFactory(null)}.
277
     */
278
    public static synchronized CRSFactory getCRSFactory() throws NoSuchElementException {
279
        return (CRSFactory) getServiceRegistry().getServiceProviders(CRSFactory.class).next();
280
    }
281

    
282
    /**
283
     * Returns the first implementation of {@link CRSFactory} matching the specified hints.
284
     * If no implementation matches, a new one is created if possible or an exception is thrown
285
     * otherwise. If more than one implementation is registered and an
286
     * {@linkplain #setVendorOrdering ordering is set}, then the preferred
287
     * implementation is returned. Otherwise an arbitrary one is selected.
288
     *
289
     * @param  hints An optional map of hints, or {@code null} if none.
290
     * @return The first coordinate reference system factory that matches the supplied hints.
291
     * @throws FactoryRegistryException if no implementation was found or can be created for the
292
     *         {@link CRSFactory} interface.
293
     */
294
    public static synchronized CRSFactory getCRSFactory(final Hints hints) throws FactoryRegistryException {
295
        return (CRSFactory) getServiceRegistry().getServiceProvider(CRSFactory.class, null, hints);
296
    }
297

    
298
    /**
299
     * Returns a set of all available implementations for the {@link CRSFactory} interface.
300
     *
301
     * @return Set of available coordinate reference system factory implementations.
302
     */
303
    public static synchronized Set getCRSFactories() {
304
        return new LazySet(getServiceRegistry().getServiceProviders(CRSFactory.class));
305
    }
306

    
307
    /**
308
     * Returns the first authority factory for the specified authority.
309
     *
310
     * @param  iterator The set of authority factories.
311
     * @param  authority The desired authority.
312
     * @return The factory for the specified authority.
313
     * @throws NoSuchElementException If no factory was found for the specified authority.
314
     *
315
     * @deprecated Replaced by filters.
316
     */
317
    private static AuthorityFactory next(final Iterator iterator, final String authority)
318
            throws NoSuchElementException
319
    {
320
        AuthorityFactory factory;
321
        do factory = (AuthorityFactory) iterator.next();
322
        while (!org.geotools.metadata.citation.Citation.titleMatches(factory.getAuthority(), authority));
323
        return factory;
324
    }
325

    
326
    /**
327
     * Returns the default implementation of {@link DatumAuthorityFactory}. If no implementation is
328
     * registered for the given authority, then this method throws an exception. If more than one
329
     * implementation is registered and an {@linkplain #setVendorOrdering ordering is set}, then
330
     * the preferred implementation is returned.
331
     *
332
     * @param  authority The desired authority (e.g. "EPSG").
333
     * @return First datum authority factory found.
334
     * @throws NoSuchElementException if no implementation was found for the
335
     *         {@link DatumAuthorityFactory} interface.
336
     *
337
     * @deprecated Replaced by {@code getDatumAuthorityFactory(authority, null)}.
338
     */
339
    public static synchronized DatumAuthorityFactory getDatumAuthorityFactory(final String authority)
340
            throws NoSuchElementException
341
    {
342
        return (DatumAuthorityFactory) next(getServiceRegistry().getServiceProviders(
343
                                            DatumAuthorityFactory.class), authority);
344
    }
345

    
346
    /**
347
     * Returns the first implementation of {@link DatumAuthorityFactory} matching the specified
348
     * hints. If no implementation matches, a new one is created if possible or an exception is
349
     * thrown otherwise. If more than one implementation is registered and an
350
     * {@linkplain #setVendorOrdering ordering is set}, then the preferred
351
     * implementation is returned. Otherwise an arbitrary one is selected.
352
     *
353
     * @param  authority The desired authority (e.g. "EPSG").
354
     * @param  hints An optional map of hints, or {@code null} if none.
355
     * @return The first datum authority factory that matches the supplied hints.
356
     * @throws FactoryRegistryException if no implementation was found or can be created for the
357
     *         {@link DatumAuthorityFactory} interface.
358
     */
359
    public static synchronized DatumAuthorityFactory getDatumAuthorityFactory(final String authority,
360
                                                                              final Hints  hints)
361
            throws FactoryRegistryException
362
    {
363
        return (DatumAuthorityFactory) getServiceRegistry().getServiceProvider(
364
                DatumAuthorityFactory.class, new AuthorityFilter(authority), hints);
365
    }
366

    
367
    /**
368
     * Returns a set of all available implementations for the {@link DatumAuthorityFactory}
369
     * interface.
370
     *
371
     * @return Set of available datum authority factory implementations.
372
     */
373
    public static synchronized Set getDatumAuthorityFactories() {
374
        return new LazySet(getServiceRegistry().getServiceProviders(DatumAuthorityFactory.class));
375
    }
376

    
377
    /**
378
     * Returns the default implementation of {@link CSAuthorityFactory}. If no implementation is
379
     * registered for the given authority, then this method throws an exception. If more than one
380
     * implementation is registered and an {@linkplain #setVendorOrdering ordering is set}, then
381
     * the preferred implementation is returned.
382
     *
383
     * @param  authority The desired authority (e.g. "EPSG").
384
     * @return First coordinate system authority factory found.
385
     * @throws NoSuchElementException if no implementation was found for the
386
     *         {@link CSAuthorityFactory} interface.
387
     *
388
     * @deprecated Replaced by {@code getCSAuthorityFactory(authority, null)}.
389
     */
390
    public static synchronized CSAuthorityFactory getCSAuthorityFactory(final String authority)
391
            throws NoSuchElementException
392
    {
393
        return (CSAuthorityFactory) next(getServiceRegistry().getServiceProviders(
394
                                         CSAuthorityFactory.class), authority);
395
    }
396

    
397
    /**
398
     * Returns the first implementation of {@link CSAuthorityFactory} matching the specified
399
     * hints. If no implementation matches, a new one is created if possible or an exception is
400
     * thrown otherwise. If more than one implementation is registered and an
401
     * {@linkplain #setVendorOrdering ordering is set}, then the preferred
402
     * implementation is returned. Otherwise an arbitrary one is selected.
403
     *
404
     * @param  authority The desired authority (e.g. "EPSG").
405
     * @param  hints An optional map of hints, or {@code null} if none.
406
     * @return The first coordinate system authority factory that matches the supplied hints.
407
     * @throws FactoryRegistryException if no implementation was found or can be created for the
408
     *         {@link CSAuthorityFactory} interface.
409
     */
410
    public static synchronized CSAuthorityFactory getCSAuthorityFactory(final String authority,
411
                                                                        final Hints  hints)
412
            throws FactoryRegistryException
413
    {
414
        return (CSAuthorityFactory) getServiceRegistry().getServiceProvider(
415
                CSAuthorityFactory.class, new AuthorityFilter(authority), hints);
416
    }
417

    
418
    /**
419
     * Returns a set of all available implementations for the {@link CSAuthorityFactory} interface.
420
     *
421
     * @return Set of available coordinate system authority factory implementations.
422
     */
423
    public static synchronized Set getCSAuthorityFactories() {
424
        return new LazySet(getServiceRegistry().getServiceProviders(CSAuthorityFactory.class));
425
    }
426

    
427
    /**
428
     * Returns the default implementation of {@link CRSAuthorityFactory}. If no implementation is
429
     * registered for the given authority, then this method throws an exception. If more than one
430
     * implementation is registered and an {@linkplain #setVendorOrdering ordering is set}, then
431
     * the preferred implementation is returned.
432
     *
433
     * @param  authority The desired authority (e.g. "EPSG").
434
     * @return First coordinate reference system authority factory found.
435
     * @throws NoSuchElementException if no implementation was found for the
436
     *         {@link CRSAuthorityFactory} interface.
437
     *
438
     * @deprecated Replaced by {@code getCRSAuthorityFactory(authority, null)}.
439
     */
440
    public static synchronized CRSAuthorityFactory getCRSAuthorityFactory(final String authority)
441
            throws NoSuchElementException
442
    {
443
        return (CRSAuthorityFactory) next(getServiceRegistry().getServiceProviders(
444
                                          CRSAuthorityFactory.class), authority);
445
    }
446

    
447
    /**
448
     * Returns the first implementation of {@link CRSAuthorityFactory} matching the specified
449
     * hints. If no implementation matches, a new one is created if possible or an exception is
450
     * thrown otherwise. If more than one implementation is registered and an
451
     * {@linkplain #setVendorOrdering ordering is set}, then the preferred
452
     * implementation is returned. Otherwise an arbitrary one is selected.
453
     *
454
     * @param  authority The desired authority (e.g. "EPSG").
455
     * @param  hints An optional map of hints, or {@code null} if none.
456
     * @return The first coordinate system authority factory that matches the supplied hints.
457
     * @throws FactoryRegistryException if no implementation was found or can be created for the
458
     *         {@link CRSAuthorityFactory} interface.
459
     */
460
    public static synchronized CRSAuthorityFactory getCRSAuthorityFactory(final String authority,
461
                                                                          final Hints  hints)
462
            throws FactoryRegistryException
463
    {
464
        return (CRSAuthorityFactory) getServiceRegistry().getServiceProvider(
465
                CRSAuthorityFactory.class, new AuthorityFilter(authority), hints);
466
    }
467
    
468
    /**
469
     * Returns a set of all available implementations for the {@link CRSAuthorityFactory} interface.
470
     * This set can be used to list the available codes known to all authorities.
471
     * In the event that the same code is understood by more then one authority
472
     * you will need to assume both are close enough, or make use of this set directly
473
     * rather than use the {@link CRS#decode} convenience method.
474
     */
475
    public static synchronized Set getCRSAuthorityFactories() {
476
        return new LazySet(getServiceRegistry().getServiceProviders(CRSAuthorityFactory.class));
477
    }
478

    
479
    /**
480
     * Returns the default implementation of {@link MathTransformFactory}. If no implementation
481
     * is registered, then this method throws an exception. If more than one implementation is
482
     * registered and an {@linkplain #setVendorOrdering ordering is set}, then the preferred
483
     * implementation is returned. Otherwise an arbitrary one is selected.
484
     *
485
     * @throws NoSuchElementException if no implementation was found for the
486
     *         {@link MathTransformFactory} interface.
487
     *
488
     * @deprecated Replaced by {@code getMathTransformFactory(null)}.
489
     */
490
    public static synchronized MathTransformFactory getMathTransformFactory() throws NoSuchElementException {
491
        return (MathTransformFactory) getServiceRegistry().getServiceProviders(MathTransformFactory.class).next();
492
    }
493

    
494
    /**
495
     * Returns the first implementation of {@link MathTransformFactory} matching the specified
496
     * hints. If no implementation matches, a new one is created if possible or an exception is
497
     * thrown otherwise. If more than one implementation is registered and an
498
     * {@linkplain #setVendorOrdering ordering is set}, then the preferred
499
     * implementation is returned. Otherwise an arbitrary one is selected.
500
     *
501
     * @param  hints An optional map of hints, or {@code null} if none.
502
     * @return The first math transform factory that matches the supplied hints.
503
     * @throws FactoryRegistryException if no implementation was found or can be created for the
504
     *         {@link MathTransformFactory} interface.
505
     */
506
    public static synchronized MathTransformFactory getMathTransformFactory(final Hints hints)
507
            throws FactoryRegistryException
508
    {
509
        return (MathTransformFactory) getServiceRegistry().getServiceProvider(
510
                MathTransformFactory.class, null, hints);
511
    }
512

    
513
    /**
514
     * Returns a set of all available implementations for the
515
     * {@link MathTransformFactory} interface.
516
     */
517
    public static synchronized Set getMathTransformFactories() {
518
        return new LazySet(getServiceRegistry().getServiceProviders(MathTransformFactory.class));
519
    }
520

    
521
    /**
522
     * Returns the default implementation of {@link CoordinateOperationFactory}. If no
523
     * implementation is registered, then this method throws an exception. If more than
524
     * one implementation is registered and an {@linkplain #setVendorOrdering ordering is set},
525
     * then the preferred implementation is returned. Otherwise an arbitrary one is selected.
526
     *
527
     * @throws NoSuchElementException if no implementation was found for the
528
     *         {@link CoordinateOperationFactory} interface.
529
     *
530
     * @deprecated Replaced by {@code getCoordinateOperationFactory(null)}.
531
     */
532
    public static synchronized CoordinateOperationFactory getCoordinateOperationFactory() throws NoSuchElementException {
533
        return (CoordinateOperationFactory) getServiceRegistry().getServiceProviders(CoordinateOperationFactory.class).next();
534
    }
535

    
536
    /**
537
     * Returns the first implementation of {@link CoordinateOperationFactory} matching the specified
538
     * hints. If no implementation matches, a new one is created if possible or an exception is
539
     * thrown otherwise. If more than one implementation is registered and an
540
     * {@linkplain #setVendorOrdering ordering is set}, then the preferred
541
     * implementation is returned. Otherwise an arbitrary one is selected.
542
     *
543
     * @param  hints An optional map of hints, or {@code null} if none.
544
     * @return The first coordinate operation factory that matches the supplied hints.
545
     * @throws FactoryRegistryException if no implementation was found or can be created for the
546
     *         {@link CoordinateOperationFactory} interface.
547
     */
548
    public static synchronized CoordinateOperationFactory getCoordinateOperationFactory(final Hints hints)
549
            throws FactoryRegistryException
550
    {
551
        return (CoordinateOperationFactory) getServiceRegistry().getServiceProvider(
552
                CoordinateOperationFactory.class, null, hints);
553
    }
554

    
555
    /**
556
     * Returns a set of all available implementations for the
557
     * {@link CoordinateOperationFactory} interface.
558
     */
559
    public static synchronized Set getCoordinateOperationFactories() {
560
        return new LazySet(getServiceRegistry().getServiceProviders(CoordinateOperationFactory.class));
561
    }
562

    
563
    /**
564
     * Sets a pairwise ordering between two vendors. If one or both vendors are not
565
     * currently registered, or if the desired ordering is already set, nothing happens
566
     * and <code>false</code> is returned.
567
     * <br><br>
568
     * The example below said that an ESRI implementation (if available) is
569
     * preferred over the Geotools one:
570
     *
571
     * <blockquote><code>FactoryFinder.setVendorOrdering("ESRI", "Geotools");</code></blockquote>
572
     *
573
     * @param  vendor1 The preferred vendor.
574
     * @param  vendor2 The vendor to which <code>vendor1</code> is preferred.
575
     * @return <code>true</code> if the ordering was set for at least one category.
576
     */
577
    public static boolean setVendorOrdering(final String vendor1, final String vendor2) {
578
        return getServiceRegistry().setOrdering(Factory.class, true,
579
                                                new VendorFilter(vendor1),
580
                                                new VendorFilter(vendor2));
581
    }
582

    
583
    /**
584
     * Unsets a pairwise ordering between two vendors. If one or both vendors are not
585
     * currently registered, or if the desired ordering is already unset, nothing happens
586
     * and <code>false</code> is returned.
587
     *
588
     * @param  vendor1 The preferred vendor.
589
     * @param  vendor2 The vendor to which <code>vendor1</code> is preferred.
590
     * @return <code>true</code> if the ordering was unset for at least one category.
591
     */
592
    public static boolean unsetVendorOrdering(final String vendor1, final String vendor2) {
593
        return getServiceRegistry().setOrdering(Factory.class, false,
594
                                                new VendorFilter(vendor1),
595
                                                new VendorFilter(vendor2));
596
    }
597

    
598
    /**
599
     * A filter for factories provided by a given vendor.
600
     */
601
    private static final class VendorFilter implements ServiceRegistry.Filter {
602
        /** The vendor to filter. */
603
        private final String vendor;
604

    
605
        /** Constructs a filter for the given vendor. */
606
        public VendorFilter(final String vendor) {
607
            this.vendor = vendor;
608
        }
609

    
610
        /** Returns <code>true</code> if the specified provider is built by the vendor. */
611
        public boolean filter(final Object provider) {
612
            return org.geotools.metadata.citation.Citation.titleMatches(
613
                    ((Factory)provider).getVendor(), vendor);
614
        }
615
    }
616

    
617
    /**
618
     * Sets a pairwise ordering between two authorities. If one or both authorities are not
619
     * currently registered, or if the desired ordering is already set, nothing happens
620
     * and <code>false</code> is returned.
621
     * <br><br>
622
     * The example below said that EPSG {@linkplain AuthorityFactory authority factories}
623
     * are preferred over ESRI ones:
624
     *
625
     * <blockquote><code>FactoryFinder.setAuthorityOrdering("EPSG", "ESRI");</code></blockquote>
626
     *
627
     * @param  authority1 The preferred authority.
628
     * @param  authority2 The authority to which <code>authority1</code> is preferred.
629
     * @return <code>true</code> if the ordering was set for at least one category.
630
     */
631
    public static boolean setAuthorityOrdering(final String authority1, final String authority2) {
632
        return getServiceRegistry().setOrdering(AuthorityFactory.class, true,
633
                                                new AuthorityFilter(authority1),
634
                                                new AuthorityFilter(authority2));
635
    }
636

    
637
    /**
638
     * Unsets a pairwise ordering between two authorities. If one or both authorities are not
639
     * currently registered, or if the desired ordering is already unset, nothing happens
640
     * and <code>false</code> is returned.
641
     *
642
     * @param  authority1 The preferred authority.
643
     * @param  authority2 The vendor to which <code>authority1</code> is preferred.
644
     * @return <code>true</code> if the ordering was unset for at least one category.
645
     */
646
    public static boolean unsetAuthorityOrdering(final String authority1, final String authority2) {
647
        return getServiceRegistry().setOrdering(AuthorityFactory.class, false,
648
                                                new AuthorityFilter(authority1),
649
                                                new AuthorityFilter(authority2));
650
    }
651

    
652
    /**
653
     * A filter for factories provided for a given authority.
654
     */
655
    private static final class AuthorityFilter implements ServiceRegistry.Filter {
656
        /** The authority to filter. */
657
        private final String authority;
658

    
659
        /** Constructs a filter for the given authority. */
660
        public AuthorityFilter(final String authority) {
661
            this.authority = authority;
662
        }
663

    
664
        /** Returns <code>true</code> if the specified provider is for the authority. */
665
        public boolean filter(final Object provider) {
666
            return org.geotools.metadata.citation.Citation.titleMatches(
667
                    ((AuthorityFactory)provider).getAuthority(), authority);
668
        }
669
    }
670

    
671
    /**
672
     * Scans for factory plug-ins on the application class path. This method is
673
     * needed because the application class path can theoretically change, or
674
     * additional plug-ins may become available. Rather than re-scanning the
675
     * classpath on every invocation of the API, the class path is scanned
676
     * automatically only on the first invocation. Clients can call this
677
     * method to prompt a re-scan. Thus this method need only be invoked by
678
     * sophisticated applications which dynamically make new plug-ins
679
     * available at runtime.
680
     */
681
    public static void scanForPlugins() {
682
        if (registry != null) {
683
            registry.scanForPlugins();
684
        }
685
    }
686

    
687
    /**
688
     * List all available factory implementations in a tabular format. For each factory interface,
689
     * the first implementation listed is the default one. This method provides a way to check the
690
     * state of a system, usually for debugging purpose.
691
     *
692
     * @param  out The output stream where to format the list.
693
     * @param  locale The locale for the list, or <code>null</code>.
694
     * @throws IOException if an error occurs while writting to <code>out</code>.
695
     *
696
     * @todo Localize the title line.
697
     */
698
    public static synchronized void listProviders(final Writer out, final Locale locale)
699
            throws IOException
700
    {
701
        getServiceRegistry().getServiceProviders(DatumFactory.class); // Force the initialization of ServiceRegistry
702
        final TableWriter table  = new TableWriter(out, " \u2502 ");
703
        table.setMultiLinesCells(true);
704
        table.writeHorizontalSeparator();
705
        table.write("Factory");
706
        table.nextColumn();
707
        table.write("Implementation(s)");
708
        table.writeHorizontalSeparator();
709
        for (final Iterator categories=getServiceRegistry().getCategories(); categories.hasNext();) {
710
            final Class category = (Class)categories.next();
711
            table.write(Utilities.getShortName(category));
712
            table.nextColumn();
713
            boolean first = true;
714
            for (final Iterator providers=getServiceRegistry().getServiceProviders(category); providers.hasNext();) {
715
                if (!first) {
716
                    table.write('\n');
717
                }
718
                first = false;
719
                final Factory provider = (Factory)providers.next();
720
                final Citation vendor = provider.getVendor();
721
                table.write(vendor.getTitle().toString(locale));
722
            }
723
            table.nextLine();
724
        }
725
        table.writeHorizontalSeparator();
726
        table.flush();
727
    }
728

    
729
    /**
730
     * Dump to the standard output stream a list of available factory implementations.
731
     * This method can be invoked from the command line. It provides a mean to verify
732
     * if some implementations were found in the classpath. The syntax is:
733
     * <BR>
734
     * <BLOCKQUOTE><CODE>
735
     * java org.geotools.referencing.FactoryFinder <VAR>&lt;options&gt;</VAR>
736
     * </CODE></BLOCKQUOTE>
737
     *
738
     * <P>where options are:</P>
739
     *
740
     * <TABLE CELLPADDING='0' CELLSPACING='0'>
741
     *   <TR><TD NOWRAP><CODE>-encoding</CODE> <VAR>&lt;code&gt;</VAR></TD>
742
     *       <TD NOWRAP>&nbsp;Set the character encoding</TD></TR>
743
     *   <TR><TD NOWRAP><CODE>-locale</CODE> <VAR>&lt;language&gt;</VAR></TD>
744
     *       <TD NOWRAP>&nbsp;Set the language for the output (e.g. "fr" for French)</TD></TR>
745
     * </TABLE>
746
     *
747
     * <P><strong>Note for Windows users:</strong> If the output contains strange
748
     * symbols, try to supply an "<code>-encoding</code>" argument. Example:</P>
749
     *
750
     * <blockquote><code>
751
     * java org.geotools.referencing.FactoryFinder -encoding Cp850
752
     * </code></blockquote>
753
     *
754
     * <P>The codepage number (850 in the previous example) can be obtained from the DOS
755
     * commande line using the "<code>chcp</code>" command with no arguments.
756
     * This <code>-encoding</code> argument need to be supplied only once.</P>
757
     *
758
     * @param args Command line arguments.
759
     */
760
    public static void main(String[] args) {
761
        final Arguments arguments = new Arguments(args);
762
        args = arguments.getRemainingArguments(0);
763
        try {
764
            listProviders(arguments.out, arguments.locale);
765
        } catch (Exception exception) {
766
            exception.printStackTrace(arguments.err);
767
        }
768
    }
769
}