001 /** 002 * 003 * Copyright 2005 The Apache Software Foundation 004 * 005 * Licensed under the Apache License, Version 2.0 (the "License"); 006 * you may not use this file except in compliance with the License. 007 * You may obtain a copy of the License at 008 * 009 * http://www.apache.org/licenses/LICENSE-2.0 010 * 011 * Unless required by applicable law or agreed to in writing, software 012 * distributed under the License is distributed on an "AS IS" BASIS, 013 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 014 * See the License for the specific language governing permissions and 015 * limitations under the License. 016 */ 017 package org.apache.geronimo.kernel.config; 018 019 import java.io.IOException; 020 import java.io.InputStream; 021 import java.io.OutputStream; 022 import java.io.PrintWriter; 023 import java.io.File; 024 import java.net.URL; 025 import java.util.Collection; 026 import java.util.HashSet; 027 import java.util.Iterator; 028 import java.util.Set; 029 import java.util.List; 030 import java.util.Collections; 031 import java.util.ArrayList; 032 import java.util.Properties; 033 import java.util.Map; 034 import java.util.LinkedHashSet; 035 036 import org.apache.geronimo.gbean.AbstractName; 037 import org.apache.geronimo.gbean.AbstractNameQuery; 038 import org.apache.geronimo.gbean.GAttributeInfo; 039 import org.apache.geronimo.gbean.GBeanData; 040 import org.apache.geronimo.gbean.GReferenceInfo; 041 import org.apache.geronimo.gbean.InvalidConfigurationException; 042 import org.apache.geronimo.gbean.ReferencePatterns; 043 import org.apache.geronimo.kernel.GBeanAlreadyExistsException; 044 import org.apache.geronimo.kernel.GBeanNotFoundException; 045 import org.apache.geronimo.kernel.Kernel; 046 import org.apache.geronimo.kernel.ClassLoading; 047 import org.apache.geronimo.kernel.InternalKernelException; 048 import org.apache.geronimo.kernel.basic.BasicKernel; 049 import org.apache.geronimo.kernel.management.State; 050 import org.apache.geronimo.kernel.repository.Artifact; 051 import org.apache.commons.logging.Log; 052 import org.apache.commons.logging.LogFactory; 053 054 /** 055 * @version $Rev:386276 $ $Date: 2006-11-06 02:28:54 -0800 (Mon, 06 Nov 2006) $ 056 */ 057 public final class ConfigurationUtil { 058 private static final Log log = LogFactory.getLog(ConfigurationUtil.class); 059 private static final ConfigurationMarshaler configurationMarshaler; 060 061 static { 062 ConfigurationMarshaler marshaler = null; 063 String marshalerClass = System.getProperty("Xorg.apache.geronimo.kernel.config.Marshaler"); 064 if (marshalerClass != null) { 065 try { 066 marshaler = createConfigurationMarshaler(marshalerClass); 067 } catch (Exception e) { 068 log.error("Error creating configuration marshaler class " + marshalerClass , e); 069 } 070 } 071 072 // todo this code effectively makes the default format xstream 073 //if (marshaler == null) { 074 // try { 075 // marshaler = createConfigurationMarshaler("org.apache.geronimo.kernel.config.xstream.XStreamConfigurationMarshaler"); 076 // } catch (Throwable ignored) { 077 // } 078 //} 079 080 if (marshaler == null) { 081 marshaler = new SerializedConfigurationMarshaler(); 082 } 083 084 configurationMarshaler = marshaler; 085 } 086 087 public static ConfigurationMarshaler createConfigurationMarshaler(String marshalerClass) throws Exception { 088 ClassLoader classLoader = Thread.currentThread().getContextClassLoader(); 089 Class clazz = null; 090 if (classLoader != null) { 091 try { 092 clazz = ClassLoading.loadClass(marshalerClass, classLoader); 093 } catch (ClassNotFoundException ignored) { 094 // doesn't matter 095 } 096 } 097 if (clazz == null) { 098 classLoader = ConfigurationUtil.class.getClassLoader(); 099 try { 100 clazz = ClassLoading.loadClass(marshalerClass, classLoader); 101 } catch (ClassNotFoundException ignored) { 102 // doesn't matter 103 } 104 } 105 106 if (clazz != null) { 107 Object object = clazz.newInstance(); 108 if (object instanceof ConfigurationMarshaler) { 109 return (ConfigurationMarshaler) object; 110 } else { 111 log.warn("Configuration marshaler class is not an instance of ConfigurationMarshaler " + marshalerClass + ": using default configuration "); 112 } 113 } 114 return null; 115 } 116 117 private ConfigurationUtil() { 118 } 119 120 public static GBeanState newGBeanState(Collection gbeans) { 121 return configurationMarshaler.newGBeanState(gbeans); 122 } 123 124 public static AbstractName loadBootstrapConfiguration(Kernel kernel, InputStream in, ClassLoader classLoader) throws Exception { 125 ConfigurationData configurationData = readConfigurationData(in); 126 return loadBootstrapConfiguration(kernel, configurationData, classLoader); 127 } 128 129 public static AbstractName loadBootstrapConfiguration(Kernel kernel, ConfigurationData configurationData, ClassLoader classLoader) throws Exception { 130 if (kernel == null) throw new NullPointerException("kernel is null"); 131 if (configurationData == null) throw new NullPointerException("configurationData is null"); 132 if (classLoader == null) throw new NullPointerException("classLoader is null"); 133 134 // a bootstrap configuration can not have any dependencies 135 List dependencies = configurationData.getEnvironment().getDependencies(); 136 if (!dependencies.isEmpty()) { 137 configurationData.getEnvironment().setDependencies(Collections.EMPTY_SET); 138 // throw new InvalidConfigurationException("Booststrap configuration can not have dependendencies: " + dependencies); 139 } 140 141 // build the gbean data 142 Artifact configId = configurationData.getId(); 143 AbstractName abstractName = Configuration.getConfigurationAbstractName(configId); 144 GBeanData gbeanData = new GBeanData(abstractName, Configuration.GBEAN_INFO); 145 gbeanData.setAttribute("configurationData", configurationData); 146 gbeanData.setAttribute("configurationResolver", new ConfigurationResolver(configurationData, null, null)); 147 148 // load and start the gbean 149 kernel.loadGBean(gbeanData, classLoader); 150 kernel.startGBean(gbeanData.getAbstractName()); 151 152 Configuration configuration = (Configuration) kernel.getGBean(gbeanData.getAbstractName()); 153 154 // start the gbeans 155 startConfigurationGBeans(configuration.getAbstractName(), configuration, kernel); 156 157 ConfigurationManager configurationManager = getConfigurationManager(kernel); 158 configurationManager.loadConfiguration(configId); 159 return gbeanData.getAbstractName(); 160 } 161 162 public static void writeConfigurationData(ConfigurationData configurationData, OutputStream out) throws IOException { 163 configurationMarshaler.writeConfigurationData(configurationData, out); 164 } 165 166 public static ConfigurationData readConfigurationData(InputStream in) throws IOException, ClassNotFoundException { 167 return configurationMarshaler.readConfigurationData(in); 168 } 169 170 public static void writeConfigInfo(PrintWriter writer, ConfigurationData configurationData) { 171 writeConfigInfo("", writer, configurationData); 172 } 173 private static void writeConfigInfo(String prefix, PrintWriter writer, ConfigurationData configurationData) { 174 writer.println(prefix+"id=" + configurationData.getId()); 175 writer.println(prefix+"type=" + configurationData.getModuleType()); 176 writer.println(prefix+"created=" + configurationData.getCreated()); 177 Set ownedConfigurations = configurationData.getOwnedConfigurations(); 178 int i = 0; 179 for (Iterator iterator = ownedConfigurations.iterator(); iterator.hasNext();) { 180 Artifact ownedConfiguration = (Artifact) iterator.next(); 181 writer.println(prefix+"owned." + i++ + "=" + ownedConfiguration); 182 } 183 i = 0; 184 for (Iterator it = configurationData.getChildConfigurations().values().iterator(); it.hasNext(); i++) { 185 ConfigurationData data = (ConfigurationData) it.next(); 186 writeConfigInfo("child."+i+".", writer, data); 187 } 188 writer.flush(); 189 } 190 191 public static ConfigurationInfo readConfigurationInfo(InputStream in, AbstractName storeName, File inPlaceLocation) throws IOException { 192 Properties properties = new Properties(); 193 properties.load(in); 194 return readConfigurationInfo("", properties, storeName, inPlaceLocation); 195 } 196 private static ConfigurationInfo readConfigurationInfo(String prefix, Properties properties, AbstractName storeName, File inPlaceLocation) throws IOException { 197 String id = properties.getProperty(prefix+"id"); 198 Artifact configId = Artifact.create(id); 199 200 String type = properties.getProperty(prefix+"type"); 201 ConfigurationModuleType moduleType = ConfigurationModuleType.getByName(type); 202 if (moduleType == null) { 203 throw new IllegalArgumentException("Unknown module type: " + type); 204 } 205 206 String created = properties.getProperty(prefix+"created"); 207 long time; 208 try { 209 time = Long.parseLong(created); 210 } catch (NumberFormatException e) { 211 throw new IllegalArgumentException("Invalid created time: " + created); 212 } 213 214 LinkedHashSet ownedConfigurations = new LinkedHashSet(); 215 for (Iterator iterator = properties.entrySet().iterator(); iterator.hasNext();) { 216 Map.Entry entry = (Map.Entry) iterator.next(); 217 String name = (String) entry.getKey(); 218 if (name.startsWith(prefix+"owned.")) { 219 String value = (String) entry.getValue(); 220 Artifact ownedConfiguration = Artifact.create(value); 221 ownedConfigurations.add(ownedConfiguration); 222 } 223 } 224 LinkedHashSet childConfigurations = new LinkedHashSet(); 225 int test = 0; 226 while(true) { 227 String next = prefix+"child."+test+"."; 228 String value = properties.getProperty(next+".id"); 229 if(value == null) { 230 break; 231 } 232 childConfigurations.add(readConfigurationInfo(next, properties, storeName, inPlaceLocation)); 233 ++test; 234 } 235 236 return new ConfigurationInfo(storeName, configId, moduleType, time, ownedConfigurations, childConfigurations, inPlaceLocation); 237 } 238 239 /** 240 * Gets a reference or proxy to the ConfigurationManager running in the specified kernel. 241 * 242 * @return The ConfigurationManager 243 * @throws IllegalStateException Occurs if a ConfigurationManager cannot be identified 244 */ 245 public static ConfigurationManager getConfigurationManager(Kernel kernel) { 246 Set names = kernel.listGBeans(new AbstractNameQuery(ConfigurationManager.class.getName())); 247 for (Iterator iterator = names.iterator(); iterator.hasNext();) { 248 AbstractName abstractName = (AbstractName) iterator.next(); 249 if (!kernel.isRunning(abstractName)) { 250 iterator.remove(); 251 } 252 } 253 if (names.isEmpty()) { 254 throw new IllegalStateException("A Configuration Manager could not be found in the kernel"); 255 } 256 if (names.size() > 1) { 257 throw new IllegalStateException("More than one Configuration Manager was found in the kernel"); 258 } 259 AbstractName configurationManagerName = (AbstractName) names.iterator().next(); 260 return (ConfigurationManager) kernel.getProxyManager().createProxy(configurationManagerName, ConfigurationManager.class); 261 } 262 263 /** 264 * Gets a reference or proxy to an EditableConfigurationManager running in the specified kernel, if there is one. 265 * 266 * @return The EdtiableConfigurationManager, or none if there is not one available. 267 * @throws IllegalStateException Occurs if there are multiple EditableConfigurationManagers in the kernel. 268 */ 269 public static EditableConfigurationManager getEditableConfigurationManager(Kernel kernel) { 270 Set names = kernel.listGBeans(new AbstractNameQuery(EditableConfigurationManager.class.getName())); 271 for (Iterator iterator = names.iterator(); iterator.hasNext();) { 272 AbstractName abstractName = (AbstractName) iterator.next(); 273 if (!kernel.isRunning(abstractName)) { 274 iterator.remove(); 275 } 276 } 277 if (names.isEmpty()) { 278 return null; // may be one, just not editable 279 } 280 if (names.size() > 1) { 281 throw new IllegalStateException("More than one Configuration Manager was found in the kernel"); 282 } 283 AbstractName configurationManagerName = (AbstractName) names.iterator().next(); 284 return (EditableConfigurationManager) kernel.getProxyManager().createProxy(configurationManagerName, EditableConfigurationManager.class); 285 } 286 287 public static void releaseConfigurationManager(Kernel kernel, ConfigurationManager configurationManager) { 288 kernel.getProxyManager().destroyProxy(configurationManager); 289 } 290 291 static void preprocessGBeanData(AbstractName configurationName, Configuration configuration, GBeanData gbeanData) throws InvalidConfigException { 292 for (Iterator references = gbeanData.getReferencesNames().iterator(); references.hasNext();) { 293 String referenceName = (String) references.next(); 294 GReferenceInfo referenceInfo = gbeanData.getGBeanInfo().getReference(referenceName); 295 if (referenceInfo == null) { 296 throw new InvalidConfigException("No reference named " + referenceName + " in gbean " + gbeanData.getAbstractName()); 297 } 298 boolean isSingleValued = !referenceInfo.getProxyType().equals(Collection.class.getName()); 299 if (isSingleValued) { 300 ReferencePatterns referencePatterns = gbeanData.getReferencePatterns(referenceName); 301 AbstractName abstractName; 302 try { 303 abstractName = configuration.findGBean(referencePatterns); 304 } catch (GBeanNotFoundException e) { 305 throw new InvalidConfigException("Unable to resolve reference \"" + referenceName + "\" in gbean " + gbeanData.getAbstractName() + " to a gbean matching the pattern " + referencePatterns, e); 306 } 307 gbeanData.setReferencePatterns(referenceName, new ReferencePatterns(abstractName)); 308 } 309 } 310 311 Set newDependencies = new HashSet(); 312 for (Iterator dependencyIterator = gbeanData.getDependencies().iterator(); dependencyIterator.hasNext();) { 313 ReferencePatterns referencePatterns = (ReferencePatterns) dependencyIterator.next(); 314 AbstractName abstractName; 315 try { 316 abstractName = configuration.findGBean(referencePatterns); 317 } catch (GBeanNotFoundException e) { 318 throw new InvalidConfigException("Unable to resolve dependency in gbean " + gbeanData.getAbstractName(), e); 319 } 320 newDependencies.add(new ReferencePatterns(abstractName)); 321 } 322 gbeanData.setDependencies(newDependencies); 323 324 // If the GBean has a configurationBaseUrl attribute, set it 325 // todo Even though this is not used by the classloader, web apps still need this. WHY??? 326 GAttributeInfo attribute = gbeanData.getGBeanInfo().getAttribute("configurationBaseUrl"); 327 if (attribute != null && attribute.getType().equals("java.net.URL")) { 328 try { 329 Set set = configuration.getConfigurationResolver().resolve(""); 330 if (set.size() != 1) { 331 throw new AssertionError("Expected one match for pattern \".\", but got " + set.size() + " matches"); 332 } 333 URL baseURL = (URL) set.iterator().next(); 334 gbeanData.setAttribute("configurationBaseUrl", baseURL); 335 } catch (Exception e) { 336 throw new InvalidConfigException("Unable to set attribute named " + "configurationBaseUrl" + " in gbean " + gbeanData.getAbstractName(), e); 337 } 338 } 339 340 // add a dependency from the gbean to the configuration 341 gbeanData.addDependency(configurationName); 342 } 343 344 static void startConfigurationGBeans(AbstractName configurationName, Configuration configuration, Kernel kernel) throws InvalidConfigException { 345 List gbeans = new ArrayList(configuration.getGBeans().values()); 346 Collections.sort(gbeans, new GBeanData.PriorityComparator()); 347 348 List loaded = new ArrayList(gbeans.size()); 349 List started = new ArrayList(gbeans.size()); 350 351 try { 352 // register all the GBeans 353 for (Iterator iterator = gbeans.iterator(); iterator.hasNext();) { 354 GBeanData gbeanData = (GBeanData) iterator.next(); 355 356 // copy the gbeanData object as not to mutate the original 357 gbeanData = new GBeanData(gbeanData); 358 359 // preprocess the gbeanData (resolve references, set base url, declare dependency, etc.) 360 preprocessGBeanData(configurationName, configuration, gbeanData); 361 362 try { 363 kernel.loadGBean(gbeanData, configuration.getConfigurationClassLoader()); 364 loaded.add(gbeanData.getAbstractName()); 365 } catch (GBeanAlreadyExistsException e) { 366 throw new InvalidConfigException(e); 367 } 368 } 369 370 try { 371 // start the gbeans 372 for (Iterator iterator = gbeans.iterator(); iterator.hasNext();) { 373 GBeanData gbeanData = (GBeanData) iterator.next(); 374 AbstractName gbeanName = gbeanData.getAbstractName(); 375 kernel.startRecursiveGBean(gbeanName); 376 started.add(gbeanName); 377 } 378 379 // assure all of the gbeans are started 380 List unstarted = new ArrayList(); 381 for (Iterator iterator = gbeans.iterator(); iterator.hasNext();) { 382 GBeanData gbeanData = (GBeanData) iterator.next(); 383 AbstractName gbeanName = gbeanData.getAbstractName(); 384 if (State.RUNNING_INDEX != kernel.getGBeanState(gbeanName)) { 385 String stateReason = null; 386 if (kernel instanceof BasicKernel) { 387 stateReason = ((BasicKernel) kernel).getStateReason(gbeanName); 388 } 389 String name = gbeanName.toURI().getQuery(); 390 if (stateReason != null) { 391 unstarted.add("The service " + name + " did not start because " + stateReason); 392 } else { 393 unstarted.add("The service " + name + " did not start for an unknown reason"); 394 } 395 } 396 } 397 if (!unstarted.isEmpty()) { 398 StringBuffer message = new StringBuffer(); 399 message.append("Configuration ").append(configuration.getId()).append(" failed to start due to the following reasons:\n"); 400 for (Iterator iterator = unstarted.iterator(); iterator.hasNext();) { 401 String reason = (String) iterator.next(); 402 message.append(" ").append(reason).append("\n"); 403 } 404 throw new InvalidConfigurationException(message.toString()); 405 } 406 } catch (GBeanNotFoundException e) { 407 throw new InvalidConfigException(e); 408 } 409 410 for (Iterator iterator = configuration.getChildren().iterator(); iterator.hasNext();) { 411 Configuration childConfiguration = (Configuration) iterator.next(); 412 ConfigurationUtil.startConfigurationGBeans(configurationName, childConfiguration, kernel); 413 } 414 } catch (Throwable e) { 415 for (Iterator iterator = started.iterator(); iterator.hasNext();) { 416 AbstractName gbeanName = (AbstractName) iterator.next(); 417 try { 418 kernel.stopGBean(gbeanName); 419 } catch (GBeanNotFoundException ignored) { 420 } catch (IllegalStateException ignored) { 421 } catch (InternalKernelException kernelException) { 422 log.debug("Error cleaning up after failed start of configuration " + configuration.getId() + " gbean " + gbeanName, kernelException); 423 } 424 } 425 for (Iterator iterator = loaded.iterator(); iterator.hasNext();) { 426 AbstractName gbeanName = (AbstractName) iterator.next(); 427 try { 428 kernel.unloadGBean(gbeanName); 429 } catch (GBeanNotFoundException ignored) { 430 } catch (IllegalStateException ignored) { 431 } catch (InternalKernelException kernelException) { 432 log.debug("Error cleaning up after failed start of configuration " + configuration.getId() + " gbean " + gbeanName, kernelException); 433 } 434 } 435 if (e instanceof Error) { 436 throw (Error) e; 437 } 438 if (e instanceof InvalidConfigException) { 439 throw (InvalidConfigException) e; 440 } 441 throw new InvalidConfigException("Unknown start exception", e); 442 } 443 } 444 }