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: private static final Log LOG = LogFactory
050: .getLog(RegistryBuilder.class);
051:
052: static {
053: if (!LOG.isErrorEnabled()) {
054: System.err
055: .println("********************************************************************************");
056: System.err
057: .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 *");
058: System.err
059: .println("* ---------------------------------------------------------------------------- *");
060: System.err
061: .println("* Logging is not enabled for org.apache.hivemind.impl.RegistryBuilder. *");
062: System.err
063: .println("* Errors during HiveMind module descriptor parsing and validation may not be *");
064: System.err
065: .println("* logged. This may result in difficult-to-trace runtime exceptions, if there *");
066: System.err
067: .println("* are errors in any of your module descriptors. You should enable error *");
068: System.err
069: .println("* logging for the org.apache.hivemind and hivemind loggers. *");
070: System.err
071: .println("********************************************************************************");
072: }
073: }
074:
075: /**
076: * Delegate used for handling errors.
077: */
078:
079: private ErrorHandler _errorHandler;
080:
081: /**
082: * RegistryAssembly used by the module descriptor parser(s).
083: */
084:
085: private RegistryAssemblyImpl _registryAssembly;
086:
087: /**
088: * A set of all {@link ModuleDescriptorProvider} objects used to construct the Registry.
089: *
090: * @since 1.1
091: */
092:
093: private Set _moduleDescriptorProviders;
094:
095: /**
096: * Contains most of the logic for actually creating the registry.
097: *
098: * @since 1.1
099: */
100:
101: private RegistryInfrastructureConstructor _constructor;
102:
103: public RegistryBuilder() {
104: this (new DefaultErrorHandler());
105: }
106:
107: public RegistryBuilder(ErrorHandler handler) {
108: _errorHandler = handler;
109:
110: _registryAssembly = new RegistryAssemblyImpl();
111:
112: _moduleDescriptorProviders = new HashSet();
113:
114: _constructor = new RegistryInfrastructureConstructor(handler,
115: LOG, _registryAssembly);
116: }
117:
118: /**
119: * Adds a {@link ModuleDescriptorProvider} as a source for
120: * {@link ModuleDescriptor module descriptors} to this RegistryBuilder. Adding the same provider
121: * instance multiple times has no effect.
122: *
123: * @since 1.1
124: */
125: public void addModuleDescriptorProvider(
126: ModuleDescriptorProvider provider) {
127: _moduleDescriptorProviders.add(provider);
128: }
129:
130: /**
131: * This first loads all modules provided by the ModuleDescriptorProvider, then resolves all the
132: * contributions, then constructs and returns the Registry.
133: */
134: public Registry constructRegistry(Locale locale) {
135: for (Iterator i = _moduleDescriptorProviders.iterator(); i
136: .hasNext();) {
137: ModuleDescriptorProvider provider = (ModuleDescriptorProvider) i
138: .next();
139:
140: processModuleDescriptorProvider(provider);
141: }
142:
143: // Process any deferred operations. Post processing is added by
144: // both the parser and the registry constructor.
145:
146: _registryAssembly.performPostProcessing();
147:
148: RegistryInfrastructure infrastructure = _constructor
149: .constructRegistryInfrastructure(locale);
150:
151: infrastructure.startup();
152:
153: return new RegistryImpl(infrastructure);
154: }
155:
156: private void processModuleDescriptorProvider(
157: ModuleDescriptorProvider provider) {
158: List descriptors = provider.getModuleDescriptors(_errorHandler);
159:
160: Iterator i = descriptors.iterator();
161: while (i.hasNext()) {
162: ModuleDescriptor md = (ModuleDescriptor) i.next();
163:
164: _constructor.addModuleDescriptor(md);
165: }
166: }
167:
168: /**
169: * Adds a default module descriptor provider to this <code>RegistryBuilder</code>. A default
170: * module descriptor provider is merely a {@link XmlModuleDescriptorProvider} constructed with a
171: * {@link DefaultClassResolver}.
172: *
173: * @since 1.1
174: */
175: public void addDefaultModuleDescriptorProvider() {
176: addModuleDescriptorProvider(new XmlModuleDescriptorProvider(
177: new DefaultClassResolver()));
178: }
179:
180: /**
181: * Constructs a default registry based on just the modules visible to the thread context class
182: * loader (this is sufficient is the majority of cases), and using the default locale. If you
183: * have different error handling needs, or wish to pick up HiveMind module deployment
184: * descriptors for non-standard locations, you must create a RegistryBuilder instance yourself.
185: *
186: * @see #addDefaultModuleDescriptorProvider()
187: */
188: public static Registry constructDefaultRegistry() {
189: RegistryBuilder builder = new RegistryBuilder();
190: builder.addDefaultModuleDescriptorProvider();
191: return builder.constructRegistry(Locale.getDefault());
192: }
193:
194: }
|