View Javadoc

1   /*
2    Copyright (C) 2007 Grid Systems, S.A.
3   
4    This library is free software; you can redistribute it and/or
5    modify it under the terms of the GNU Lesser General Public
6    License as published by the Free Software Foundation; either
7    version 2.1 of the License, or (at your option) any later version.
8   
9    This library is distributed in the hope that it will be useful,
10   but WITHOUT ANY WARRANTY; without even the implied warranty of
11   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
12   Lesser General Public License for more details.
13  
14   You should have received a copy of the GNU Lesser General Public
15   License along with this library; if not, write to the Free Software
16   Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301 USA
17  */
18  package nextgrid.api.pom;
19  
20  import java.net.URI;
21  import java.net.URISyntaxException;
22  import java.util.concurrent.ConcurrentHashMap;
23  import java.util.concurrent.ConcurrentMap;
24  
25  import org.apache.commons.discovery.ResourceNameIterator;
26  import org.apache.commons.discovery.resource.ClassLoaders;
27  import org.apache.commons.discovery.resource.names.DiscoverServiceNames;
28  import org.apache.commons.logging.Log;
29  import org.apache.commons.logging.LogFactory;
30  
31  /**
32   * GroundingFactory Finder.
33   *
34   * @author Rodrigo Ruiz
35   */
36  public final class GroundingFactoryFinder {
37  
38    /**
39     * Class logger.
40     */
41    private static final Log LOG = LogFactory.getLog(GroundingFactoryFinder.class);
42  
43    /**
44     * Factory map initial capacity.
45     */
46    private static final int INITIAL_CAPACITY = 5;
47  
48    /**
49     * Factory map load factor.
50     */
51    private static final float LOAD_FACTOR = 0.75f;
52  
53    /**
54     * Factory map concurrency level.
55     */
56    private static final int CONCURRENCY_LEVEL = 2;
57  
58    /**
59     * Factory map.
60     */
61    private static final ConcurrentMap<URI, GroundingFactory> REGISTRY;
62  
63    static {
64      REGISTRY = new ConcurrentHashMap<URI, GroundingFactory>(
65        INITIAL_CAPACITY, LOAD_FACTOR, CONCURRENCY_LEVEL);
66  
67      // Discover builder implementations
68      ClassLoaders loaders = new ClassLoaders();
69      loaders.put(Thread.currentThread().getContextClassLoader());
70      DiscoverServiceNames dsn = new DiscoverServiceNames(loaders);
71  
72      ResourceNameIterator it = dsn.findResourceNames(GroundingFactory.class.getName());
73      while (it.hasNext()) {
74        String name = it.nextResourceName();
75        try {
76          Class<?> c = Class.forName(name);
77          if (GroundingFactory.class.isAssignableFrom(c)) {
78            GroundingFactory factory = (GroundingFactory)c.newInstance();
79            // Builders are found in class-path order, so the first instance
80            // found is "the right one". To ensure this order is honoured, we
81            // set the override parameter to "false"
82            register(factory, false);
83          }
84          // CHECKSTYLE:OFF
85        } catch (Exception e) {
86          // CHECKSTYLE:ON
87          LOG.warn("Could not load builder '" + name + "'", e);
88        }
89      }
90    }
91  
92    /**
93     * Creates an instance.
94     */
95    private GroundingFactoryFinder() { }
96  
97    /**
98     * Manually registers a factory, so it is available through the finder.
99     *
100    * @param factory The factory instance to register
101    */
102   public static void register(GroundingFactory factory) {
103     register(factory, true);
104   }
105 
106   /**
107    * Registers a factory instance.
108    *
109    * @param factory   The factory instance to register
110    * @param override  Whether to override previous registry entries or not
111    */
112   private static void register(GroundingFactory factory, boolean override) {
113     if (factory == null) {
114       return;
115     }
116 
117     URI type = factory.getType();
118     if (override) {
119       REGISTRY.put(type, factory);
120     } else {
121       REGISTRY.putIfAbsent(type, factory);
122     }
123   }
124 
125   /**
126    * Gets a factory for the specified model type.
127    *
128    * @param type The factory type
129    * @return A factory for the specified grounding type, or null if none found
130    */
131   public static GroundingFactory findFactory(URI type) {
132     return REGISTRY.get(type);
133   }
134 
135   /**
136    * Gets a factory for the specified model type.
137    *
138    * @param type The factory type
139    * @return A factory for the specified grounding type, or null if none found
140    */
141   public static GroundingFactory findFactory(String type) {
142     if (type == null) {
143       return null;
144     }
145 
146     try {
147       return findFactory(new URI(type));
148     } catch (URISyntaxException e) {
149       e.printStackTrace();
150       return null;
151     }
152   }
153 
154   /**
155    * Gets a list of all available Grounding types.
156    *
157    * @return An array of Grounding type URIs
158    */
159   public URI[] getAvailableTypes() {
160     return REGISTRY.keySet().toArray(new URI[REGISTRY.size()]);
161   }
162 }