Statistics
| Revision:

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

History | View | Annotate | Download (7.45 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.lang.reflect.InvocationTargetException;
23
import java.util.Collection;
24
import java.util.Iterator;
25

    
26
import javax.imageio.spi.ServiceRegistry;
27

    
28
import org.geotools.resources.Utilities;
29

    
30

    
31
/**
32
 * A {@linkplain FactoryRegistry factory registry} capable to creates factories if no appropriate
33
 * instance was found in the registry.
34
 * <p>
35
 * Factory created "on the fly" are not cached; all invocation to
36
 * {@link #getServiceProvider getServiceProvider(...)} will creates them again if no registered
37
 * factory matches the requirements ({@linkplain javax.imageio.spi.ServiceRegistry.Filter filter}
38
 * and/or {@linkplain Hints hints}).
39
 * </p>
40
 * <p>If caching is wanted, the instances to cache should be declared
41
 * likes all other services in the {@code META-INF/services/} directory. For the caching to be
42
 * effective, their no-argument constructor shall setup the factory with
43
 * {@linkplain Factory#getImplementationHints implementation hints} matching the hints that the
44
 * application is expected to ask for. It is preferable that such custom implementation
45
 * {@linkplain ServiceRegistry#setOrdering order} itself after the default implementations.
46
 * </p>
47
 * @version $Id: FactoryCreator.java 10627 2007-03-06 17:10:21Z caballero $
48
 * @author Martin Desruisseaux
49
 * @author Jody Garnett
50
 */
51
public class FactoryCreator extends FactoryRegistry {
52
    /**
53
     * The array of classes for searching the one-argument constructor.
54
     */
55
    private static final Class[] HINTS_ARGUMENT = new Class[] {Hints.class};
56

    
57
    /**
58
     * Constructs a new registry for the specified categories.
59
     *
60
     * @param categories The categories.
61
     */
62
    public FactoryCreator(final Collection categories) {
63
        super(categories);
64
    }
65

    
66
    /**
67
     * Returns a provider for the specified category, using the specified map of hints (if any).
68
     * If a provider matching the requirements is found in the registry, it is returned. Otherwise,
69
     * a new provider is created and returned. This creation step is the only difference between
70
     * this method and the {@linkplain FactoryRegistry#getServiceProvider super-class method}.
71
     *
72
     * @param  category The category to look for.
73
     * @param  filter   An optional filter, or {@code null} if none.
74
     * @param  hints    A {@linkplain Hints map of hints}, or {@code null} if none.
75
     * @return A factory for the specified category and hints (never {@code null}).
76
     * @throws FactoryNotFoundException if no factory was found, and the specified hints don't
77
     *         provide suffisient information for creating a new factory.
78
     * @throws FactoryRegistryException if the factory can't be created for some other reason.
79
     */
80
    public Object getServiceProvider(final Class category, final Filter filter, final Hints hints)
81
            throws FactoryRegistryException
82
    {
83
        final FactoryNotFoundException notFound;
84
        try {
85
            return super.getServiceProvider(category, filter, hints);
86
        } catch (FactoryNotFoundException exception) {
87
            // Will be rethrown later in case of failure to create the factory.
88
            notFound = exception;
89
        }
90
        /*
91
         * No existing factory found. Creates one using reflection.
92
         */
93
        if (hints != null) {
94
            final Hints.Key key = Hints.Key.getKeyForCategory(category);
95
            if (key != null) {
96
                final Object hint = hints.get(key);
97
                if (hint != null) {
98
                    final Class type;
99
                    if (hint instanceof Class[]) {
100
                        type = ((Class[]) hint)[0];
101
                        // Should not fails, since Hints.isCompatibleValue(Object)
102
                        // do not allows empty array.
103
                    } else {
104
                        type = (Class) hint;
105
                        // Should not fails, since non-class argument should
106
                        // have been accepted by 'getServiceProvider(...)'.
107
                    }
108
                    if (type!=null && category.isAssignableFrom(type)) {
109
                        return createServiceProvider(type, hints);
110
                    }
111
                }
112
            }
113
        }
114
        /*
115
         * No implementation hint provided. Search the first implementation
116
         * accepting a Hints argument. No-args constructor will be ignored.
117
         */
118
        for (final Iterator it=getServiceProviders(category); it.hasNext();) {
119
            final Class implementation = it.next().getClass();
120
            try {
121
                implementation.getConstructor(HINTS_ARGUMENT);
122
            } catch (NoSuchMethodException exception) {
123
                // No public constructor with the expected argument.
124
                continue;
125
            }
126
            return createServiceProvider(implementation, hints);
127
        }
128
        throw notFound;
129
    }
130

    
131
    /**
132
     * Creates a new instance of the specified factory using the specified hints.
133
     * The default implementation try to instantiate the given implementation class
134
     * the first of the following constructor found:
135
     * <ul>
136
     *   <li>Constructor with a single {@link Hints} argument.</li>
137
     *   <li>No-argument constructor.</li>
138
     * </ul>
139
     *
140
     * @param  implementation The factory class to instantiate.
141
     * @param  hints The implementation hints.
142
     * @return The factory.
143
     * @throws FactoryRegistryException if the factory creation failed.
144
     */
145
    protected Object createServiceProvider(final Class implementation, final Hints hints)
146
            throws FactoryRegistryException
147
    {
148
        Throwable cause;
149
        try {
150
            try {
151
                return implementation.getConstructor(HINTS_ARGUMENT).newInstance(new Object[]{hints});
152
            } catch (NoSuchMethodException exception) {
153
                // Constructor do not exists or is not public. We will fallback on the no-arg one.
154
            }
155
            try {
156
                return implementation.getConstructor((Class[])null).newInstance((Object[])null);
157
            } catch (NoSuchMethodException exception) {
158
                cause = exception; // No constructor accessible
159
            }
160
        } catch (IllegalAccessException exception) {
161
            cause = exception; // constructor is not public (should not happen)
162
        } catch (InstantiationException exception) {
163
            cause = exception; // The class is abstract
164
        } catch (InvocationTargetException exception) {
165
            cause = exception.getCause(); // Exception in constructor
166
        }
167
        // TODO: localize
168
        throw new FactoryRegistryException("Can't creates \"" +
169
                Utilities.getShortName(implementation) + "\" factory.", cause);
170
    }
171
}