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.builder;
19  
20  import java.net.URI;
21  import java.util.concurrent.ConcurrentHashMap;
22  import java.util.concurrent.ConcurrentMap;
23  
24  import org.apache.commons.discovery.ResourceNameIterator;
25  import org.apache.commons.discovery.resource.ClassLoaders;
26  import org.apache.commons.discovery.resource.names.DiscoverServiceNames;
27  import org.apache.commons.logging.Log;
28  import org.apache.commons.logging.LogFactory;
29  
30  /**
31   * POMBuilder finder.
32   *
33   * @author Rodrigo Ruiz
34   */
35  public final class POMBuilderFinder {
36  
37    /**
38     * Class logger.
39     */
40    private static final Log LOG = LogFactory.getLog(POMBuilderFinder.class);
41  
42    /**
43     * Builder map initial capacity.
44     */
45    private static final int INITIAL_CAPACITY = 5;
46  
47    /**
48     * Builder map load factor.
49     */
50    private static final float LOAD_FACTOR = 0.75f;
51  
52    /**
53     * Builder map concurrency level.
54     */
55    private static final int CONCURRENCY_LEVEL = 2;
56  
57    /**
58     * Builder map.
59     */
60    private static final ConcurrentMap<Class<?>, POMBuilder<?>> TYPE_REGISTRY;
61  
62    /**
63     * Builder map.
64     */
65    private static final ConcurrentMap<URI, POMBuilder<?>> URI_REGISTRY;
66  
67    static {
68      TYPE_REGISTRY = new ConcurrentHashMap<Class<?>, POMBuilder<?>>(
69        INITIAL_CAPACITY, LOAD_FACTOR, CONCURRENCY_LEVEL);
70  
71      URI_REGISTRY = new ConcurrentHashMap<URI, POMBuilder<?>>(
72          INITIAL_CAPACITY, LOAD_FACTOR, CONCURRENCY_LEVEL);
73  
74      // Discover builder implementations
75      ClassLoaders loaders = new ClassLoaders();
76      loaders.put(Thread.currentThread().getContextClassLoader());
77      DiscoverServiceNames dsn = new DiscoverServiceNames(loaders);
78  
79      ResourceNameIterator it = dsn.findResourceNames(POMBuilder.class.getName());
80      while (it.hasNext()) {
81        String name = it.nextResourceName();
82        try {
83          Class<?> c = Class.forName(name);
84          if (POMBuilder.class.isAssignableFrom(c)) {
85            POMBuilder<?> builder = (POMBuilder<?>)c.newInstance();
86            // Builders are found in class-path order, so the first instance
87            // found is "the right one". To ensure this order is honoured, we
88            // set the override parameter to "false"
89            register(builder, false);
90          }
91          // CHECKSTYLE:OFF
92        } catch (Exception e) {
93          // CHECKSTYLE:ON
94          LOG.warn("Could not load builder '" + name + "'", e);
95        }
96      }
97    }
98  
99    /**
100    * Creates an instance.
101    */
102   private POMBuilderFinder() { }
103 
104   /**
105    * Manually registers a builder, so it is available through the finder.
106    *
107    * @param builder The builder instance to register
108    */
109   public static void register(POMBuilder<?> builder) {
110     register(builder, true);
111   }
112 
113   /**
114    * Registers a builder instance.
115    *
116    * @param builder   The builder instance to register
117    * @param override  Whether to override previous registry entries or not
118    */
119   private static void register(POMBuilder<?> builder, boolean override) {
120     if (builder == null) {
121       return;
122     }
123 
124     Class<?> modelClass = builder.getModelType();
125     if (modelClass != null) {
126       if (override) {
127         TYPE_REGISTRY.put(modelClass, builder);
128       } else {
129         TYPE_REGISTRY.putIfAbsent(modelClass, builder);
130       }
131     }
132     URI modelURI = builder.getURI();
133     if (modelURI != null) {
134       if (override) {
135         URI_REGISTRY.put(modelURI, builder);
136       } else {
137         URI_REGISTRY.putIfAbsent(modelURI, builder);
138       }
139     }
140   }
141 
142   /**
143    * Gets a builder for the specified model type.
144    *
145    * @param c The model type
146    * @param <T> Used for return value type checking
147    * @return A builder for the specified model type, or null if none found
148    */
149   @SuppressWarnings("unchecked")
150   public static <T> POMBuilder<T> findBuilderFor(Class<T> c) {
151     return (POMBuilder<T>)TYPE_REGISTRY.get(c);
152   }
153 
154   /**
155    * Gets a builder by its URI id.
156    *
157    * @param uri The builder id
158    * @return The builder, or null if none found
159    */
160   public static POMBuilder<?> findBuilderByURI(URI uri) {
161     return URI_REGISTRY.get(uri);
162   }
163 }