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    }