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