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 }