001: /*
002: * GeoTools - OpenSource mapping toolkit
003: * http://geotools.org
004: * (C) 2005-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; either
009: * version 2.1 of the License, or (at your option) any later version.
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.factory;
017:
018: // J2SE dependencies
019: import java.util.*;
020:
021: // JUnit dependencies
022: import junit.framework.Test;
023: import junit.framework.TestCase;
024: import junit.framework.TestSuite;
025:
026: // Geotools dependencies
027: import org.geotools.resources.LazySet;
028:
029: /**
030: * Tests {@link FactoryRegistry} implementation.
031: *
032: * @source $URL: http://svn.geotools.org/geotools/tags/2.4.1/modules/library/metadata/src/test/java/org/geotools/factory/FactoryRegistryTest.java $
033: * @version $Id: FactoryRegistryTest.java 27848 2007-11-12 13:10:32Z desruisseaux $
034: * @author Martin Desruisseaux
035: */
036: public final class FactoryRegistryTest extends TestCase {
037: /**
038: * Run the suite from the command line.
039: */
040: public static void main(String[] args) {
041: org.geotools.util.logging.Logging.GEOTOOLS
042: .forceMonolineConsoleOutput();
043: junit.textui.TestRunner.run(suite());
044: }
045:
046: /**
047: * Returns the test suite.
048: */
049: public static Test suite() {
050: return new TestSuite(FactoryRegistryTest.class);
051: }
052:
053: /**
054: * Constructs a test case.
055: */
056: public FactoryRegistryTest(final String testName) {
057: super (testName);
058: }
059:
060: /**
061: * Ensures that class {@link Hints} is loaded before {@link DummyFactory}.
062: * It is not needed for normal execution, but Maven seems to mess with class loaders.
063: */
064: protected void setUp() {
065: assertNotNull(Hints.DATUM_FACTORY.toString());
066: }
067:
068: /**
069: * Creates the factory registry to test. The tests performed in this method are more
070: * J2SE tests than Geotools implementation tests. We basically just ensure that we
071: * have setup the service registry properly.
072: * <br><br>
073: * Factories are specified in arguments as {@link Factory} objects in order to avoid
074: * the {@link DummyClass} to be initialized before {@link Hints}. This is not a problem
075: * for normal execution, but Maven seems to mess with class loaders.
076: *
077: * @param creator {@code true} if the registry should be an instance of {@link FactoryCreator}.
078: */
079: private FactoryRegistry getRegistry(final boolean creator,
080: final Factory factory1, final Factory factory2,
081: final Factory factory3) {
082: final FactoryRegistry registry;
083: if (creator) {
084: registry = new FactoryCreator(Collections
085: .singleton(DummyFactory.class));
086: } else {
087: registry = new FactoryRegistry(Collections
088: .singleton(DummyFactory.class));
089: }
090: registry.registerServiceProvider(factory1);
091: registry.registerServiceProvider(factory2);
092: registry.registerServiceProvider(factory3);
093: assertTrue(registry.setOrdering(DummyFactory.class,
094: (DummyFactory) factory1, (DummyFactory) factory2));
095: assertTrue(registry.setOrdering(DummyFactory.class,
096: (DummyFactory) factory2, (DummyFactory) factory3));
097: assertTrue(registry.setOrdering(DummyFactory.class,
098: (DummyFactory) factory1, (DummyFactory) factory3));
099: final List factories = new ArrayList(new LazySet(registry
100: .getServiceProviders(DummyFactory.class, null, null)));
101: assertTrue(factories.contains(factory1));
102: assertTrue(factories.contains(factory2));
103: assertTrue(factories.contains(factory3));
104: assertTrue(factories.indexOf(factory1) < factories
105: .indexOf(factory2));
106: assertTrue(factories.indexOf(factory2) < factories
107: .indexOf(factory3));
108: return registry;
109: }
110:
111: /**
112: * Tests the {@link FactoryRegistry#getProvider} method.
113: * Note that the tested method do not create any new factory.
114: * If no registered factory matching the hints is found, an exception is expected.
115: * <br><br>
116: * Three factories are initially registered: factory #1, #2 and #3.
117: *
118: * Factory #1 has no dependency.
119: * Factory #2 uses factory #1.
120: * Factory #3 uses factory #2, which implies an indirect dependency to factory #1.
121: *
122: * Additionnaly, factory #1 uses a KEY_INTERPOLATION hint.
123: */
124: public void testGetProvider() {
125: final Hints.Key key = DummyFactory.DUMMY_FACTORY;
126: final DummyFactory factory1 = new DummyFactory.Example1();
127: final DummyFactory factory2 = new DummyFactory.Example2();
128: final DummyFactory factory3 = new DummyFactory.Example3();
129: final FactoryRegistry registry = getRegistry(false, factory1,
130: factory2, factory3);
131: Hints hints;
132: DummyFactory factory;
133: // ------------------------------------------------
134: // PART 1: SIMPLE HINT (not a Factory hint)
135: // ------------------------------------------------
136: /*
137: * No hints. The fist factory should be selected.
138: */
139: hints = null;
140: factory = (DummyFactory) registry.getServiceProvider(
141: DummyFactory.class, null, hints, key);
142: assertSame("No preferences; should select the first factory. ",
143: factory1, factory);
144: /*
145: * A hint compatible with one of our factories. Factory #1 declares explicitly that it uses
146: * a bilinear interpolation, which is compatible with user's hints. All other factories are
147: * indifferent. Since factory #1 is the first one in the list, it should be selected.
148: */
149: hints = new Hints(Hints.KEY_INTERPOLATION,
150: Hints.VALUE_INTERPOLATION_BILINEAR);
151: factory = (DummyFactory) registry.getServiceProvider(
152: DummyFactory.class, null, hints, key);
153: assertSame("First factory matches; it should be selected. ",
154: factory1, factory);
155: /*
156: * A hint incompatible with all our factories. Factory #1 is the only one to defines
157: * explicitly a KEY_INTERPOLATION hint, but all other factories depend on factory #1
158: * either directly (factory #2) or indirectly (factory #3, which depends on #2).
159: */
160: hints = new Hints(Hints.KEY_INTERPOLATION,
161: Hints.VALUE_INTERPOLATION_BICUBIC);
162: try {
163: factory = (DummyFactory) registry.getServiceProvider(
164: DummyFactory.class, null, hints, key);
165: fail("Found factory " + factory
166: + ", while the hint should have been rejected.");
167: } catch (FactoryNotFoundException exception) {
168: // This is the expected exception. Continue...
169: }
170: /*
171: * Add a new factory implementation, and try again with exactly the same hints
172: * than the previous test. This time, the new factory should be selected since
173: * this one doesn't have any dependency toward factory #1.
174: */
175: final DummyFactory factory4 = new DummyFactory.Example4();
176: registry.registerServiceProvider(factory4);
177: assertTrue(registry.setOrdering(DummyFactory.class, factory1,
178: factory4));
179: factory = (DummyFactory) registry.getServiceProvider(
180: DummyFactory.class, null, hints, key);
181: assertSame("The new factory should be selected. ", factory4,
182: factory);
183:
184: // ----------------------------
185: // PART 2: FACTORY HINT
186: // ----------------------------
187: /*
188: * Trivial case: user gives explicitly a factory instance.
189: */
190: DummyFactory explicit = new DummyFactory.Example3();
191: hints = new Hints(DummyFactory.DUMMY_FACTORY, explicit);
192: factory = (DummyFactory) registry.getServiceProvider(
193: DummyFactory.class, null, hints, key);
194: assertSame(
195: "The user-specified factory should have been selected. ",
196: explicit, factory);
197: /*
198: * User specifies the expected implementation class rather than an instance.
199: */
200: hints = new Hints(DummyFactory.DUMMY_FACTORY,
201: DummyFactory.Example2.class);
202: factory = (DummyFactory) registry.getServiceProvider(
203: DummyFactory.class, null, hints, key);
204: assertSame("Factory of class #2 were requested. ", factory2,
205: factory);
206: /*
207: * Same as above, but with classes specified in an array. The 'Date.class' element is just
208: * a dummy value for testing the search a little bit further than the first element.
209: */
210: hints = new Hints(DummyFactory.DUMMY_FACTORY, new Class[] {
211: Date.class, DummyFactory.Example3.class,
212: DummyFactory.Example2.class });
213: factory = (DummyFactory) registry.getServiceProvider(
214: DummyFactory.class, null, hints, key);
215: assertSame("Factory of class #3 were requested. ", factory3,
216: factory);
217: /*
218: * The following hint should be ignored by factory #1, since this factory doesn't have
219: * any dependency to the INTERNAL_FACTORY hint. Since factory #1 is first in the ordering,
220: * it should be selected.
221: */
222: hints = new Hints(DummyFactory.INTERNAL_FACTORY,
223: DummyFactory.Example2.class);
224: factory = (DummyFactory) registry.getServiceProvider(
225: DummyFactory.class, null, hints, key);
226: assertSame("Expected factory #1. ", factory1, factory);
227: /*
228: * If the user really wants some factory that do have a dependency to factory #2, he should
229: * specifies in a DUMMY_FACTORY hint the implementation classes (or a common super-class or
230: * interface) that do care about the INTERNAL_FACTORY hint. Note that this extra step should
231: * not be a big deal in most real application, because:
232: *
233: * 1) Either all implementations have this dependency (for example it would be
234: * unusual to see a DatumAuthorityFactory without a DatumFactory dependency);
235: *
236: * 2) or the user really know the implementation he wants (for example if he specifies a
237: * JTS CoordinateSequenceFactory, he probably wants to use the JTS GeometryFactory).
238: *
239: * In the particular case of this test suite, this extra step would not be needed
240: * neither if factory #1 was last in the ordering rather than first.
241: */
242: final Hints implementations = new Hints(
243: DummyFactory.DUMMY_FACTORY, new Class[] {
244: DummyFactory.Example2.class,
245: DummyFactory.Example3.class });
246: /*
247: * Now search NOT for factory #1, but rather for a factory using #1 internally.
248: * This is the case of factory #2.
249: */
250: hints = new Hints(DummyFactory.INTERNAL_FACTORY,
251: DummyFactory.Example1.class);
252: hints.add(implementations);
253: factory = (DummyFactory) registry.getServiceProvider(
254: DummyFactory.class, null, hints, key);
255: assertSame("Expected a factory using #1 internally. ",
256: factory2, factory);
257: }
258:
259: /**
260: * Tests the {@link FactoryCreator#getProvider} method.
261: * This test tries again the cases that was expected to throws an exception in
262: * {@link #testGetProvider}. But now, those cases are expected to creates automatically
263: * new factory instances instead of throwing an exception.
264: */
265: public void testCreateProvider() {
266: final Hints.Key key = DummyFactory.DUMMY_FACTORY;
267: final DummyFactory factory1 = new DummyFactory.Example1();
268: final DummyFactory factory2 = new DummyFactory.Example2();
269: final DummyFactory factory3 = new DummyFactory.Example3();
270: final FactoryRegistry registry = getRegistry(true, factory1,
271: factory2, factory3);
272: Hints hints;
273: DummyFactory factory;
274: /*
275: * Same tests than above (at least some of them).
276: * See comments in 'testGetProvider()' for explanation.
277: */
278: hints = new Hints(Hints.KEY_INTERPOLATION,
279: Hints.VALUE_INTERPOLATION_BILINEAR);
280: factory = (DummyFactory) registry.getServiceProvider(
281: DummyFactory.class, null, hints, key);
282: assertSame("First factory matches; it should be selected. ",
283: factory1, factory);
284:
285: hints = new Hints(DummyFactory.DUMMY_FACTORY,
286: DummyFactory.Example2.class);
287: factory = (DummyFactory) registry.getServiceProvider(
288: DummyFactory.class, null, hints, key);
289: assertSame("Factory of class #2 were requested. ", factory2,
290: factory);
291: /*
292: * The following case was throwing an exception in testGetProvider(). It should fails again
293: * here, but for a different reason. FactoryCreator is unable to creates automatically a new
294: * factory instance, since we gave no implementation hint and no registered factory have a
295: * constructor expecting a Hints argument.
296: */
297: hints = new Hints(Hints.KEY_INTERPOLATION,
298: Hints.VALUE_INTERPOLATION_BICUBIC);
299: try {
300: factory = (DummyFactory) registry.getServiceProvider(
301: DummyFactory.class, null, hints, key);
302: fail("Found or created factory " + factory
303: + ", while it should not have been allowed.");
304: } catch (FactoryNotFoundException exception) {
305: // This is the expected exception. Continue...
306: }
307: /*
308: * Register a DummyFactory with a constructor expecting a Hints argument, and try again
309: * with the same hints. Now it should creates a new factory instance, because we are using
310: * FactoryCreator instead of FactoryRegistry and an appropriate constructor is found.
311: * Note that an AssertionFailedError should be thrown if the no-argument constructor of
312: * Example5 is invoked, since the constructor with a Hints argument should have priority.
313: */
314: final DummyFactory factory5 = new DummyFactory.Example5(null);
315: registry.registerServiceProvider(factory5);
316: assertTrue(registry.setOrdering(DummyFactory.class, factory1,
317: factory5));
318: factory = (DummyFactory) registry.getServiceProvider(
319: DummyFactory.class, null, hints, key);
320: assertSame(
321: "An instance of Factory #5 should have been created.",
322: factory5.getClass(), factory.getClass());
323: assertNotSame(
324: "A NEW instance of Factory #5 should have been created",
325: factory5, factory);
326: /*
327: * Tries again with a class explicitly specified as an implementation hint.
328: * It doesn't matter if this class is registered or not.
329: */
330: hints.put(DummyFactory.DUMMY_FACTORY,
331: DummyFactory.Example4.class);
332: factory = (DummyFactory) registry.getServiceProvider(
333: DummyFactory.class, null, hints, key);
334: assertEquals(
335: "An instance of Factory #4 should have been created.",
336: DummyFactory.Example4.class, factory.getClass());
337: }
338: }
|