001 /** 002 * Licensed to the Apache Software Foundation (ASF) under one or more 003 * contributor license agreements. See the NOTICE file distributed with 004 * this work for additional information regarding copyright ownership. 005 * The ASF licenses this file to You under the Apache License, Version 2.0 006 * (the "License"); you may not use this file except in compliance with 007 * the License. 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 018 package org.apache.geronimo.kernel.config; 019 020 import java.io.File; 021 import java.io.IOException; 022 import java.net.MalformedURLException; 023 import java.net.URL; 024 import java.util.ArrayList; 025 import java.util.Collection; 026 import java.util.Collections; 027 import java.util.HashMap; 028 import java.util.Iterator; 029 import java.util.LinkedHashMap; 030 import java.util.LinkedHashSet; 031 import java.util.List; 032 import java.util.ListIterator; 033 import java.util.Map; 034 import java.util.Set; 035 import java.util.HashSet; 036 037 import javax.management.MalformedObjectNameException; 038 import javax.management.ObjectName; 039 040 import org.apache.commons.logging.Log; 041 import org.apache.commons.logging.LogFactory; 042 import org.apache.geronimo.gbean.AbstractName; 043 import org.apache.geronimo.gbean.AbstractNameQuery; 044 import org.apache.geronimo.gbean.GBeanData; 045 import org.apache.geronimo.gbean.GBeanInfo; 046 import org.apache.geronimo.gbean.GBeanInfoBuilder; 047 import org.apache.geronimo.gbean.GBeanLifecycle; 048 import org.apache.geronimo.gbean.ReferencePatterns; 049 import org.apache.geronimo.kernel.GBeanAlreadyExistsException; 050 import org.apache.geronimo.kernel.GBeanNotFoundException; 051 import org.apache.geronimo.kernel.Naming; 052 import org.apache.geronimo.kernel.classloader.JarFileClassLoader; 053 import org.apache.geronimo.kernel.repository.Artifact; 054 import org.apache.geronimo.kernel.repository.Dependency; 055 import org.apache.geronimo.kernel.repository.Environment; 056 import org.apache.geronimo.kernel.repository.ImportType; 057 import org.apache.geronimo.kernel.repository.MissingDependencyException; 058 059 /** 060 * A Configuration represents a collection of runnable services that can be 061 * loaded into a Geronimo Kernel and brought online. The primary components in 062 * a Configuration are a codebase, represented by a collection of URLs that 063 * is used to locate classes, and a collection of GBean instances that define 064 * its state. 065 * <p/> 066 * The persistent attributes of the Configuration are: 067 * <ul> 068 * <li>its unique configId used to identify this specific config</li> 069 * <li>the configId of a parent Configuration on which this one is dependent</li> 070 * <li>a List<URI> of code locations (which may be absolute or relative to a baseURL)</li> 071 * <li>a byte[] holding the state of the GBeans instances in Serialized form</li> 072 * </ul> 073 * When a configuration is started, it converts the URIs into a set of absolute 074 * URLs by resolving them against the specified baseURL (this would typically 075 * be the root of the CAR file which contains the configuration) and then 076 * constructs a ClassLoader for that codebase. That ClassLoader is then used 077 * to de-serialize the persisted GBeans, ensuring the GBeans can be recycled 078 * as necessary. Once the GBeans have been restored, they are brought online 079 * by registering them with the MBeanServer. 080 * <p/> 081 * A dependency on the Configuration is created for every GBean it loads. As a 082 * result, a startRecursive() operation on the configuration will result in 083 * a startRecursive() for all the GBeans it contains. Similarly, if the 084 * Configuration is stopped then all of its GBeans will be stopped as well. 085 * 086 * @version $Rev:385718 $ $Date: 2008-10-21 14:44:05 +0000 (Tue, 21 Oct 2008) $ 087 */ 088 public class Configuration implements GBeanLifecycle, ConfigurationParent { 089 private static final Log log = LogFactory.getLog(Configuration.class); 090 091 /** 092 * Converts an Artifact to an AbstractName for a configuration. Does not 093 * validate that this is a reasonable or resolved Artifact, or that it 094 * corresponds to an actual Configuration. 095 */ 096 public static AbstractName getConfigurationAbstractName(Artifact configId) throws InvalidConfigException { 097 return new AbstractName(configId, Collections.singletonMap("configurationName", configId.toString()), getConfigurationObjectName(configId)); 098 } 099 100 public static boolean isConfigurationObjectName(ObjectName name) { 101 return name.getDomain().equals("geronimo.config") && name.getKeyPropertyList().size() == 1 && name.getKeyProperty("name") != null; 102 } 103 104 public static Artifact getConfigurationID(ObjectName objectName) { 105 if (isConfigurationObjectName(objectName)) { 106 String name = ObjectName.unquote(objectName.getKeyProperty("name")); 107 return Artifact.create(name); 108 } else { 109 throw new IllegalArgumentException("ObjectName " + objectName + " is not a Configuration name"); 110 } 111 } 112 113 private static ObjectName getConfigurationObjectName(Artifact configId) throws InvalidConfigException { 114 try { 115 return new ObjectName("geronimo.config:name=" + ObjectName.quote(configId.toString())); 116 } catch (MalformedObjectNameException e) { 117 throw new InvalidConfigException("Could not construct object name for configuration", e); 118 } 119 } 120 121 /** 122 * The artifact id for this configuration. 123 */ 124 private final Artifact id; 125 126 /** 127 * The registered abstractName for this configuraion. 128 */ 129 private final AbstractName abstractName; 130 131 /** 132 * Defines the environment requred for this configuration. 133 */ 134 private final Environment environment; 135 136 /** 137 * Used to resolve dependecies and paths 138 */ 139 private final ConfigurationResolver configurationResolver; 140 141 /** 142 * Parent configurations used for class loader. 143 */ 144 private final List<Configuration> classParents = new ArrayList<Configuration>(); 145 146 /** 147 * Parent configuations used for service resolution. 148 */ 149 private final List<Configuration> serviceParents = new ArrayList<Configuration>(); 150 151 /** 152 * All service parents depth first 153 */ 154 private final List<Configuration> allServiceParents = new ArrayList<Configuration>(); 155 156 /** 157 * Artifacts added to the class loader (non-configuation artifacts). 158 */ 159 private final LinkedHashSet<Artifact> dependencies = new LinkedHashSet<Artifact>(); 160 161 /** 162 * The GBeanData objects by ObjectName 163 */ 164 private final Map<AbstractName, GBeanData> gbeans = new LinkedHashMap<AbstractName, GBeanData>(); 165 166 /** 167 * The classloader used to load the child GBeans contained in this configuration. 168 */ 169 private final MultiParentClassLoader configurationClassLoader; 170 171 /** 172 * The relative class path (URI) of this configuation. 173 */ 174 private final LinkedHashSet<String> classPath; 175 176 /** 177 * Naming system used when generating a name for a new gbean 178 */ 179 private final Naming naming; 180 181 /** 182 * Environment, classpath, gbeans and other data for this configuration. 183 */ 184 private ConfigurationData configurationData; 185 186 /** 187 * The nested configurations of this configuration. 188 */ 189 List<Configuration> children = new ArrayList<Configuration>(); 190 191 /** 192 * The parent of this configuration; 193 */ 194 private Configuration parent = null; 195 196 /** 197 * Only used to allow declaration as a reference. 198 */ 199 public Configuration() { 200 id = null; 201 abstractName = null; 202 environment = null; 203 classPath = null; 204 configurationResolver = null; 205 configurationClassLoader = null; 206 naming = null; 207 } 208 209 /** 210 * Creates a configuration. 211 * @param parents parents of this configuation (not ordered) 212 * @param configurationData the module type, environment and classpath of the configuration 213 * @param configurationResolver used to resolve dependecies and paths 214 */ 215 public Configuration(Collection<Configuration> parents, 216 ConfigurationData configurationData, 217 ConfigurationResolver configurationResolver, 218 ManageableAttributeStore attributeStore) throws MissingDependencyException, MalformedURLException, NoSuchConfigException, InvalidConfigException { 219 if (parents == null) parents = Collections.EMPTY_SET; 220 if (configurationData == null) throw new NullPointerException("configurationData is null"); 221 if (configurationResolver == null) throw new NullPointerException("configurationResolver is null"); 222 223 this.configurationData = configurationData; 224 this.environment = configurationData.getEnvironment(); 225 this.configurationResolver = configurationResolver; 226 this.classPath = new LinkedHashSet<String>(configurationData.getClassPath()); 227 this.naming = configurationData.getNaming(); 228 229 this.id = environment.getConfigId(); 230 abstractName = getConfigurationAbstractName(id); 231 232 // 233 // Transitively resolve all the dependencies in the environment 234 // 235 List<Dependency> transitiveDependencies = configurationResolver.resolveTransitiveDependencies(parents, environment.getDependencies()); 236 237 // 238 // Process transtive dependencies splitting it into classParents, serviceParents and artifactDependencies 239 // 240 Map<Artifact, Configuration> parentsById = new HashMap<Artifact, Configuration>(); 241 for (Configuration configuration : parents) { 242 Artifact id = configuration.getId(); 243 parentsById.put(id, configuration); 244 } 245 246 for (Dependency dependency : transitiveDependencies) { 247 Artifact artifact = dependency.getArtifact(); 248 if (parentsById.containsKey(artifact)) { 249 Configuration parent = parentsById.get(artifact); 250 if (dependency.getImportType() == ImportType.CLASSES || dependency.getImportType() == ImportType.ALL) { 251 classParents.add(parent); 252 } 253 if (dependency.getImportType() == ImportType.SERVICES || dependency.getImportType() == ImportType.ALL) { 254 serviceParents.add(parent); 255 } 256 } else if (dependency.getImportType() == ImportType.SERVICES) { 257 throw new IllegalStateException("Could not find parent " + artifact + " in the parents collection"); 258 } else { 259 dependencies.add(artifact); 260 } 261 } 262 263 try { 264 // 265 // Build the configuration class loader 266 // 267 configurationClassLoader = createConfigurationClasssLoader(parents, environment, classPath); 268 269 // 270 // Get all service parents in depth first order 271 // 272 273 addDepthFirstServiceParents(this, allServiceParents, new HashSet<Artifact>()); 274 275 // 276 // Deserialize the GBeans in the configurationData 277 // 278 Collection<GBeanData> gbeans = configurationData.getGBeans(configurationClassLoader); 279 if (attributeStore != null) { 280 gbeans = attributeStore.applyOverrides(id, gbeans, configurationClassLoader); 281 } 282 for (GBeanData gbeanData : gbeans) { 283 this.gbeans.put(gbeanData.getAbstractName(), gbeanData); 284 } 285 286 // 287 // Create child configurations 288 // 289 LinkedHashSet<Configuration> childParents = new LinkedHashSet<Configuration>(parents); 290 childParents.add(this); 291 for (Iterator iterator = configurationData.getChildConfigurations().entrySet().iterator(); iterator.hasNext();) { 292 Map.Entry entry = (Map.Entry) iterator.next(); 293 String moduleName = (String) entry.getKey(); 294 ConfigurationData childConfigurationData = (ConfigurationData) entry.getValue(); 295 Configuration childConfiguration = new Configuration(childParents, childConfigurationData, configurationResolver.createChildResolver(moduleName), attributeStore); 296 childConfiguration.parent = this; 297 children.add(childConfiguration); 298 } 299 } catch (RuntimeException e) { 300 shutdown(); 301 throw e; 302 } catch (Error e) { 303 shutdown(); 304 throw e; 305 } catch (MissingDependencyException e) { 306 shutdown(); 307 throw e; 308 } catch (MalformedURLException e) { 309 shutdown(); 310 throw e; 311 } catch (NoSuchConfigException e) { 312 shutdown(); 313 throw e; 314 } catch (InvalidConfigException e) { 315 shutdown(); 316 throw e; 317 } 318 } 319 320 private MultiParentClassLoader createConfigurationClasssLoader(Collection<Configuration> parents, Environment environment, LinkedHashSet<String> classPath) throws MalformedURLException, MissingDependencyException, NoSuchConfigException { 321 // create the URL list 322 URL[] urls = buildClassPath(classPath); 323 324 // parents 325 ClassLoader[] parentClassLoaders; 326 if (parents.size() == 0 && classParents.size() == 0) { 327 // no explicit parent set, so use the class loader of this class as 328 // the parent... this class should be in the root geronimo classloader, 329 // which is normally the system class loader but not always, so be safe 330 parentClassLoaders = new ClassLoader[] {getClass().getClassLoader()}; 331 } else { 332 parentClassLoaders = new ClassLoader[classParents.size()]; 333 for (ListIterator iterator = classParents.listIterator(); iterator.hasNext();) { 334 Configuration configuration = (Configuration) iterator.next(); 335 parentClassLoaders[iterator.previousIndex()] = configuration.getConfigurationClassLoader(); 336 } 337 } 338 339 // hidden classes 340 Set<String> hiddenClassesSet = environment.getHiddenClasses(); 341 String[] hiddenClasses = hiddenClassesSet.toArray(new String[hiddenClassesSet.size()]); 342 343 // we need to propagate the non-overrideable classes from parents 344 LinkedHashSet<String> nonOverridableSet = new LinkedHashSet<String>(environment.getNonOverrideableClasses()); 345 for (Configuration parent : classParents) { 346 347 Environment parentEnvironment = parent.getEnvironment(); 348 nonOverridableSet.addAll(parentEnvironment.getNonOverrideableClasses()); 349 } 350 String[] nonOverridableClasses = nonOverridableSet.toArray(new String[nonOverridableSet.size()]); 351 352 if (log.isDebugEnabled()) { 353 StringBuffer buf = new StringBuffer("ClassLoader structure for configuration ").append(id).append("\n"); 354 buf.append("Parent configurations:\n"); 355 for (Configuration configuration : classParents) { 356 buf.append(" ").append(configuration.getId()).append("\n"); 357 } 358 buf.append("ClassPath:\n"); 359 for (URL url : urls) { 360 buf.append(" ").append(url).append("\n"); 361 } 362 log.debug(buf.toString()); 363 } 364 365 // The JarFileClassLoader was created to address a locking problem seen only on Windows platforms. 366 // It carries with it a slight performance penalty that needs to be addressed. Rather than make 367 // *nix OSes carry this burden we'll engage the JarFileClassLoader for Windows or if the user 368 // specifically requests it. We'll look more at this issue in the future. 369 boolean useJarFileClassLoader = false; 370 if (System.getProperty("Xorg.apache.geronimo.JarFileClassLoader") == null) { 371 useJarFileClassLoader = System.getProperty("os.name").startsWith("Windows"); 372 } else { 373 useJarFileClassLoader = Boolean.getBoolean("Xorg.apache.geronimo.JarFileClassLoader"); 374 } 375 if (useJarFileClassLoader) { 376 return new JarFileClassLoader(environment.getConfigId(), 377 urls, 378 parentClassLoaders, 379 environment.isInverseClassLoading(), 380 hiddenClasses, 381 nonOverridableClasses); 382 } else { 383 return new MultiParentClassLoader(environment.getConfigId(), 384 urls, 385 parentClassLoaders, 386 environment.isInverseClassLoading(), 387 hiddenClasses, 388 nonOverridableClasses); 389 } 390 } 391 392 private void addDepthFirstServiceParents(Configuration configuration, List<Configuration> ancestors, Set<Artifact> ids) { 393 if (!ids.contains(configuration.getId())) { 394 ancestors.add(configuration); 395 ids.add(configuration.getId()); 396 for (Configuration parent : configuration.getServiceParents()) { 397 addDepthFirstServiceParents(parent, ancestors, ids); 398 } 399 } 400 } 401 402 private URL[] buildClassPath(LinkedHashSet<String> classPath) throws MalformedURLException, MissingDependencyException, NoSuchConfigException { 403 List<URL> urls = new ArrayList<URL>(); 404 for (Artifact artifact : dependencies) { 405 File file = configurationResolver.resolve(artifact); 406 urls.add(file.toURL()); 407 } 408 if (classPath != null) { 409 for (String pattern : classPath) { 410 Set<URL> matches = configurationResolver.resolve(pattern); 411 for (URL url : matches) { 412 urls.add(url); 413 } 414 } 415 } 416 return urls.toArray(new URL[urls.size()]); 417 } 418 419 /** 420 * Return the unique Id 421 * @return the unique Id 422 */ 423 public Artifact getId() { 424 return id; 425 } 426 427 /** 428 * Gets the unique name of this configuration within the kernel. 429 * @return the unique name of this configuration 430 */ 431 public String getObjectName() { 432 try { 433 return getConfigurationObjectName(id).getCanonicalName(); 434 } catch (InvalidConfigException e) { 435 throw new AssertionError(e); 436 } 437 } 438 439 public AbstractName getAbstractName() { 440 return abstractName; 441 } 442 443 /** 444 * Gets the parent configurations used for class loading. 445 * @return the parents of this configuration used for class loading 446 */ 447 public List<Configuration> getClassParents() { 448 return classParents; 449 } 450 451 /** 452 * Gets the parent configurations used for service resolution. 453 * @return the parents of this configuration used for service resolution 454 */ 455 public List<Configuration> getServiceParents() { 456 return serviceParents; 457 } 458 459 /** 460 * Gets the artifact dependencies of this configuration. 461 * @return the artifact dependencies of this configuration 462 */ 463 public LinkedHashSet<Artifact> getDependencies() { 464 return dependencies; 465 } 466 467 /** 468 * Gets the declaration of the environment in which this configuration runs. 469 * @return the environment of this configuration 470 */ 471 public Environment getEnvironment() { 472 return environment; 473 } 474 475 /** 476 * This is used by the configuration manager to restart an existing configuation. 477 * Do not modify the configuration data. 478 * @return the configuration data for this configuration; do not modify 479 */ 480 ConfigurationData getConfigurationData() { 481 return configurationData; 482 } 483 484 public File getConfigurationDir() { 485 return configurationData.getConfigurationDir(); 486 } 487 488 /** 489 * @deprecated this is only exposed temporarily for configuration manager 490 */ 491 public ConfigurationResolver getConfigurationResolver() { 492 return configurationResolver; 493 } 494 495 /** 496 * Gets the relative class path (URIs) of this configuration. 497 * @return the relative class path of this configuation 498 */ 499 public List<String> getClassPath() { 500 return new ArrayList<String>(classPath); 501 } 502 503 public void addToClassPath(String pattern) throws IOException { 504 if (!classPath.contains(pattern)) { 505 try { 506 Set<URL> matches = configurationResolver.resolve(pattern); 507 for (URL url : matches) { 508 configurationClassLoader.addURL(url); 509 } 510 classPath.add(pattern); 511 } catch (Exception e) { 512 throw (IOException)new IOException("Unable to extend classpath with " + pattern).initCause(e); 513 } 514 } 515 } 516 517 /** 518 * Gets the type of the configuration (WAR, RAR et cetera) 519 * @return Type of the configuration. 520 */ 521 public ConfigurationModuleType getModuleType() { 522 return configurationData.getModuleType(); 523 } 524 525 /** 526 * Gets the time at which this configuration was created (or deployed). 527 * @return the time at which this configuration was created (or deployed) 528 */ 529 public long getCreated() { 530 return configurationData.getCreated(); 531 } 532 533 /** 534 * Gets the class loader for this configuration. 535 * @return the class loader for this configuration 536 */ 537 public ClassLoader getConfigurationClassLoader() { 538 return configurationClassLoader; 539 } 540 541 /** 542 * Gets the nested configurations of this configuration. That is, the 543 * configurations within this one as a WAR can be within an EAR; not 544 * including wholly separate configurations that just depend on this 545 * one as a parent. 546 * 547 * @return the nested configuration of this configuration 548 */ 549 public List<Configuration> getChildren() { 550 return Collections.unmodifiableList(children); 551 } 552 553 /** 554 * Gets the configurations owned by this configuration. This is only used for cascade-uninstall. 555 * @return the configurations owned by this configuration 556 */ 557 public Set<Artifact> getOwnedConfigurations() { 558 return configurationData.getOwnedConfigurations(); 559 } 560 561 /** 562 * Gets an unmodifiable collection of the GBeanDatas for the GBeans in this configuration. 563 * @return the GBeans in this configuration 564 */ 565 public Map<AbstractName, GBeanData> getGBeans() { 566 return Collections.unmodifiableMap(gbeans); 567 } 568 569 /** 570 * Determines of this configuration constains the specified GBean. 571 * @param gbean the name of the GBean 572 * @return true if this configuration contains the specified GBean; false otherwise 573 */ 574 public synchronized boolean containsGBean(AbstractName gbean) { 575 return gbeans.containsKey(gbean); 576 } 577 578 /** 579 * Gets the enclosing configuration of this one (e.g. the EAR for a WAR), 580 * or null if it has none. 581 * @return enclosing configuration, if any 582 */ 583 public Configuration getEnclosingConfiguration() { 584 return parent; 585 } 586 587 public synchronized AbstractName addGBean(String name, GBeanData gbean) throws GBeanAlreadyExistsException { 588 AbstractName abstractName = gbean.getAbstractName(); 589 if (abstractName != null) { 590 throw new IllegalArgumentException("gbean already has an abstract name: " + abstractName); 591 } 592 593 String j2eeType = gbean.getGBeanInfo().getJ2eeType(); 594 if (j2eeType == null) j2eeType = "GBean"; 595 abstractName = naming.createRootName(id, name, j2eeType); 596 gbean.setAbstractName(abstractName); 597 598 if (gbeans.containsKey(abstractName)) { 599 throw new GBeanAlreadyExistsException(gbean.getAbstractName().toString()); 600 } 601 gbeans.put(abstractName, gbean); 602 return abstractName; 603 } 604 605 public synchronized void addGBean(GBeanData gbean) throws GBeanAlreadyExistsException { 606 if (gbeans.containsKey(gbean.getAbstractName())) { 607 throw new GBeanAlreadyExistsException(gbean.getAbstractName().toString()); 608 } 609 gbeans.put(gbean.getAbstractName(), gbean); 610 } 611 612 public synchronized void removeGBean(AbstractName name) throws GBeanNotFoundException { 613 if (!gbeans.containsKey(name)) { 614 throw new GBeanNotFoundException(name); 615 } 616 gbeans.remove(name); 617 } 618 619 public AbstractName findGBean(AbstractNameQuery pattern) throws GBeanNotFoundException { 620 if (pattern == null) throw new NullPointerException("pattern is null"); 621 return findGBean(Collections.singleton(pattern)); 622 } 623 624 public GBeanData findGBeanData(AbstractNameQuery pattern) throws GBeanNotFoundException { 625 if (pattern == null) throw new NullPointerException("pattern is null"); 626 return findGBeanData(Collections.singleton(pattern)); 627 } 628 629 public AbstractName findGBean(ReferencePatterns referencePatterns) throws GBeanNotFoundException { 630 if (referencePatterns == null) throw new NullPointerException("referencePatterns is null"); 631 if (referencePatterns.isResolved()) { 632 return referencePatterns.getAbstractName(); 633 } 634 635 // check the local config 636 Set<AbstractNameQuery> patterns = referencePatterns.getPatterns(); 637 return findGBean(patterns); 638 } 639 640 public AbstractName findGBean(Set<AbstractNameQuery> patterns) throws GBeanNotFoundException { 641 if (patterns == null) throw new NullPointerException("patterns is null"); 642 return findGBeanData(patterns).getAbstractName(); 643 } 644 645 public GBeanData findGBeanData(Set<AbstractNameQuery> patterns) throws GBeanNotFoundException { 646 if (patterns == null) throw new NullPointerException("patterns is null"); 647 Set<GBeanData> result = findGBeanDatas(this, patterns); 648 if (result.size() > 1) { 649 throw new GBeanNotFoundException("More than one match to referencePatterns in local configuration", patterns, mapToNames(result)); 650 } else if (result.size() == 1) { 651 return (GBeanData) result.iterator().next(); 652 } 653 654 // search all parents 655 for (Configuration configuration : allServiceParents) { 656 result.addAll(findGBeanDatas(configuration, patterns)); 657 658 } 659 // if we already found a match we have an ambiguous query 660 if (result.size() > 1) { 661 List<AbstractName> names = new ArrayList<AbstractName>(result.size()); 662 for (GBeanData gBeanData : result) { 663 names.add(gBeanData.getAbstractName()); 664 } 665 throw new GBeanNotFoundException("More than one match to referencePatterns in parent configurations: " + names.toString(), patterns, mapToNames(result)); 666 } 667 668 if (result.isEmpty()) { 669 throw new GBeanNotFoundException("No matches for referencePatterns", patterns, null); 670 } 671 672 return result.iterator().next(); 673 } 674 675 private Set<AbstractName> mapToNames(Set<GBeanData> datas) { 676 Set<AbstractName> names = new HashSet<AbstractName>(datas.size()); 677 for (GBeanData gBeanData: datas) { 678 names.add(gBeanData.getAbstractName()); 679 } 680 return names; 681 } 682 683 public LinkedHashSet<AbstractName> findGBeans(AbstractNameQuery pattern) { 684 if (pattern == null) throw new NullPointerException("pattern is null"); 685 return findGBeans(Collections.singleton(pattern)); 686 } 687 688 public LinkedHashSet<AbstractName> findGBeans(ReferencePatterns referencePatterns) { 689 if (referencePatterns == null) throw new NullPointerException("referencePatterns is null"); 690 if (referencePatterns.getAbstractName() != null) { 691 // this pattern is already resolved 692 LinkedHashSet<AbstractName> result = new LinkedHashSet<AbstractName>(); 693 result.add(referencePatterns.getAbstractName()); 694 return result; 695 } 696 697 // check the local config 698 Set<AbstractNameQuery> patterns = referencePatterns.getPatterns(); 699 return findGBeans(patterns); 700 } 701 702 public LinkedHashSet<AbstractName> findGBeans(Set<AbstractNameQuery> patterns) { 703 if (patterns == null) throw new NullPointerException("patterns is null"); 704 LinkedHashSet<GBeanData> datas = findGBeanDatas(patterns); 705 LinkedHashSet<AbstractName> result = new LinkedHashSet<AbstractName>(datas.size()); 706 for (GBeanData gBeanData : datas) { 707 result.add(gBeanData.getAbstractName()); 708 } 709 710 return result; 711 } 712 713 public LinkedHashSet<GBeanData> findGBeanDatas(Set<AbstractNameQuery> patterns) { 714 if (patterns == null) throw new NullPointerException("patterns is null"); 715 LinkedHashSet<GBeanData> datas = findGBeanDatas(this, patterns); 716 717 // search all parents 718 for (Configuration configuration : allServiceParents) { 719 Set<GBeanData> match = findGBeanDatas(configuration, patterns); 720 datas.addAll(match); 721 } 722 return datas; 723 } 724 725 /** 726 * Find the gbeanDatas matching the patterns in this configuration only, ignoring parents. 727 * 728 * @param configuration configuration to look in 729 * @param patterns patterns to look for 730 * @return set of gbeandatas matching one of the patterns from this configuration only, not including parents. 731 */ 732 public LinkedHashSet<GBeanData> findGBeanDatas(Configuration configuration, Set<AbstractNameQuery> patterns) { 733 LinkedHashSet<GBeanData> result = new LinkedHashSet<GBeanData>(); 734 735 Set<Map.Entry<AbstractName, GBeanData>> gbeanNames = configuration.getGBeans().entrySet(); 736 for (AbstractNameQuery abstractNameQuery : patterns) { 737 Artifact queryArtifact = abstractNameQuery.getArtifact(); 738 739 // Does this query apply to this configuration 740 if (queryArtifact == null || queryArtifact.matches(configuration.getId())) { 741 742 // Search the GBeans 743 for (Map.Entry<AbstractName, GBeanData> entry : gbeanNames) { 744 AbstractName abstractName = entry.getKey(); 745 GBeanData gbeanData = entry.getValue(); 746 if (abstractNameQuery.matches(abstractName, gbeanData.getGBeanInfo().getInterfaces())) { 747 result.add(gbeanData); 748 } 749 } 750 } 751 } 752 return result; 753 } 754 755 public void doStart() throws Exception { 756 log.debug("Started configuration " + id); 757 } 758 759 public synchronized void doStop() throws Exception { 760 log.debug("Stopping configuration " + id); 761 shutdown(); 762 763 } 764 765 public void doFail() { 766 log.debug("Failed configuration " + id); 767 shutdown(); 768 } 769 770 private void shutdown() { 771 for (Configuration configuration : children) { 772 configuration.shutdown(); 773 } 774 775 // clear references to GBeanDatas 776 gbeans.clear(); 777 778 // destroy the class loader 779 if (configurationClassLoader != null) { 780 configurationClassLoader.destroy(); 781 } 782 } 783 784 public static final GBeanInfo GBEAN_INFO; 785 786 static { 787 GBeanInfoBuilder infoFactory = GBeanInfoBuilder.createStatic(Configuration.class);//does not use jsr-77 naming 788 infoFactory.addReference("Parents", Configuration.class); 789 infoFactory.addAttribute("configurationData", ConfigurationData.class, true, false); 790 infoFactory.addAttribute("configurationResolver", ConfigurationResolver.class, true); 791 infoFactory.addAttribute("managedAttributeStore", ManageableAttributeStore.class, true); 792 793 infoFactory.addInterface(Configuration.class); 794 795 infoFactory.setConstructor(new String[]{ 796 "Parents", 797 "configurationData", 798 "configurationResolver", 799 "managedAttributeStore" 800 }); 801 802 GBEAN_INFO = infoFactory.getBeanInfo(); 803 } 804 805 public static GBeanInfo getGBeanInfo() { 806 return GBEAN_INFO; 807 } 808 }