001 // Copyright 2004, 2005 The Apache Software Foundation
002 //
003 // Licensed under the Apache License, Version 2.0 (the "License");
004 // you may not use this file except in compliance with the License.
005 // You may obtain a copy of the License at
006 //
007 // http://www.apache.org/licenses/LICENSE-2.0
008 //
009 // Unless required by applicable law or agreed to in writing, software
010 // distributed under the License is distributed on an "AS IS" BASIS,
011 // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
012 // See the License for the specific language governing permissions and
013 // limitations under the License.
014
015 package org.apache.hivemind.impl;
016
017 import java.util.HashSet;
018 import java.util.Iterator;
019 import java.util.List;
020 import java.util.Locale;
021 import java.util.Set;
022
023 import org.apache.commons.logging.Log;
024 import org.apache.commons.logging.LogFactory;
025 import org.apache.hivemind.ErrorHandler;
026 import org.apache.hivemind.ModuleDescriptorProvider;
027 import org.apache.hivemind.Registry;
028 import org.apache.hivemind.internal.RegistryInfrastructure;
029 import org.apache.hivemind.parse.ModuleDescriptor;
030
031 /**
032 * Class used to build a {@link org.apache.hivemind.Registry} from individual
033 * {@link org.apache.hivemind.parse.ModuleDescriptor}. The descriptors are provided by the
034 * {@link ModuleDescriptorProvider}parameter passed to {@link #constructRegistry(Locale)} method.
035 * <p>
036 * A note about threadsafety: The assumption is that a single thread will access the RegistryBuilder
037 * at one time (typically, a startup class within some form of server or application). Code here and
038 * in many of the related classes is divided into construction-time logic and runtime logic. Runtime
039 * logic is synchronized and threadsafe. Construction-time logic is not threadsafe. Once the
040 * registry is fully constructed, it is not allowed to invoke those methods (though, at this time,
041 * no checks occur).
042 * <p>
043 * Runtime methods, such as {@link org.apache.hivemind.impl.ModuleImpl#getService(String, Class)}
044 * are fully threadsafe.
045 *
046 * @author Howard Lewis Ship
047 */
048 public final class RegistryBuilder
049 {
050 private static final Log LOG = LogFactory.getLog(RegistryBuilder.class);
051
052 static
053 {
054 if (!LOG.isErrorEnabled())
055 {
056 System.err
057 .println("********************************************************************************");
058 System.err
059 .println("* L O G G I N G C O N F I G U R A T I O N E R R O R *");
060 System.err
061 .println("* ---------------------------------------------------------------------------- *");
062 System.err
063 .println("* Logging is not enabled for org.apache.hivemind.impl.RegistryBuilder. *");
064 System.err
065 .println("* Errors during HiveMind module descriptor parsing and validation may not be *");
066 System.err
067 .println("* logged. This may result in difficult-to-trace runtime exceptions, if there *");
068 System.err
069 .println("* are errors in any of your module descriptors. You should enable error *");
070 System.err
071 .println("* logging for the org.apache.hivemind and hivemind loggers. *");
072 System.err
073 .println("********************************************************************************");
074 }
075 }
076
077 /**
078 * Delegate used for handling errors.
079 */
080
081 private ErrorHandler _errorHandler;
082
083 /**
084 * RegistryAssembly used by the module descriptor parser(s).
085 */
086
087 private RegistryAssemblyImpl _registryAssembly;
088
089 /**
090 * A set of all {@link ModuleDescriptorProvider} objects used to construct the Registry.
091 *
092 * @since 1.1
093 */
094
095 private Set _moduleDescriptorProviders;
096
097 /**
098 * Contains most of the logic for actually creating the registry.
099 *
100 * @since 1.1
101 */
102
103 private RegistryInfrastructureConstructor _constructor;
104
105 public RegistryBuilder()
106 {
107 this(new DefaultErrorHandler());
108 }
109
110 public RegistryBuilder(ErrorHandler handler)
111 {
112 _errorHandler = handler;
113
114 _registryAssembly = new RegistryAssemblyImpl();
115
116 _moduleDescriptorProviders = new HashSet();
117
118 _constructor = new RegistryInfrastructureConstructor(handler, LOG, _registryAssembly);
119 }
120
121 /**
122 * Adds a {@link ModuleDescriptorProvider} as a source for
123 * {@link ModuleDescriptor module descriptors} to this RegistryBuilder. Adding the same provider
124 * instance multiple times has no effect.
125 *
126 * @since 1.1
127 */
128 public void addModuleDescriptorProvider(ModuleDescriptorProvider provider)
129 {
130 _moduleDescriptorProviders.add(provider);
131 }
132
133 /**
134 * This first loads all modules provided by the ModuleDescriptorProvider, then resolves all the
135 * contributions, then constructs and returns the Registry.
136 */
137 public Registry constructRegistry(Locale locale)
138 {
139 for (Iterator i = _moduleDescriptorProviders.iterator(); i.hasNext();)
140 {
141 ModuleDescriptorProvider provider = (ModuleDescriptorProvider) i.next();
142
143 processModuleDescriptorProvider(provider);
144 }
145
146 // Process any deferred operations. Post processing is added by
147 // both the parser and the registry constructor.
148
149 _registryAssembly.performPostProcessing();
150
151 RegistryInfrastructure infrastructure = _constructor
152 .constructRegistryInfrastructure(locale);
153
154 infrastructure.startup();
155
156 return new RegistryImpl(infrastructure);
157 }
158
159 private void processModuleDescriptorProvider(ModuleDescriptorProvider provider)
160 {
161 List descriptors = provider.getModuleDescriptors(_errorHandler);
162
163 Iterator i = descriptors.iterator();
164 while (i.hasNext())
165 {
166 ModuleDescriptor md = (ModuleDescriptor) i.next();
167
168 _constructor.addModuleDescriptor(md);
169 }
170 }
171
172 /**
173 * Adds a default module descriptor provider to this <code>RegistryBuilder</code>. A default
174 * module descriptor provider is merely a {@link XmlModuleDescriptorProvider} constructed with a
175 * {@link DefaultClassResolver}.
176 *
177 * @since 1.1
178 */
179 public void addDefaultModuleDescriptorProvider()
180 {
181 addModuleDescriptorProvider(new XmlModuleDescriptorProvider(new DefaultClassResolver()));
182 }
183
184 /**
185 * Constructs a default registry based on just the modules visible to the thread context class
186 * loader (this is sufficient is the majority of cases), and using the default locale. If you
187 * have different error handling needs, or wish to pick up HiveMind module deployment
188 * descriptors for non-standard locations, you must create a RegistryBuilder instance yourself.
189 *
190 * @see #addDefaultModuleDescriptorProvider()
191 */
192 public static Registry constructDefaultRegistry()
193 {
194 RegistryBuilder builder = new RegistryBuilder();
195 builder.addDefaultModuleDescriptorProvider();
196 return builder.constructRegistry(Locale.getDefault());
197 }
198
199 }