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: 2009-02-16 18:20:58 +0800 (Mon, 16 Feb 2009) $
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 * Manageable Attribute Store containing overrides to this configuration.
198 */
199 private ManageableAttributeStore attributeStore = null;
200
201 /**
202 * Only used to allow declaration as a reference.
203 */
204 public Configuration() {
205 id = null;
206 abstractName = null;
207 environment = null;
208 classPath = null;
209 configurationResolver = null;
210 configurationClassLoader = null;
211 naming = null;
212 }
213
214 /**
215 * Creates a configuration.
216 * @param parents parents of this configuation (not ordered)
217 * @param configurationData the module type, environment and classpath of the configuration
218 * @param configurationResolver used to resolve dependecies and paths
219 */
220 public Configuration(Collection<Configuration> parents,
221 ConfigurationData configurationData,
222 ConfigurationResolver configurationResolver,
223 ManageableAttributeStore attributeStore) throws MissingDependencyException, MalformedURLException, NoSuchConfigException, InvalidConfigException {
224 if (parents == null) parents = Collections.EMPTY_SET;
225 if (configurationData == null) throw new NullPointerException("configurationData is null");
226 if (configurationResolver == null) throw new NullPointerException("configurationResolver is null");
227
228 this.configurationData = configurationData;
229 this.environment = configurationData.getEnvironment();
230 this.configurationResolver = configurationResolver;
231 this.classPath = new LinkedHashSet<String>(configurationData.getClassPath());
232 this.naming = configurationData.getNaming();
233 this.attributeStore = attributeStore;
234 this.id = environment.getConfigId();
235 abstractName = getConfigurationAbstractName(id);
236
237 //
238 // Transitively resolve all the dependencies in the environment
239 //
240 List<Dependency> transitiveDependencies = configurationResolver.resolveTransitiveDependencies(parents, environment.getDependencies());
241
242 //
243 // Process transtive dependencies splitting it into classParents, serviceParents and artifactDependencies
244 //
245 Map<Artifact, Configuration> parentsById = new HashMap<Artifact, Configuration>();
246 for (Configuration configuration : parents) {
247 Artifact id = configuration.getId();
248 parentsById.put(id, configuration);
249 }
250
251 for (Dependency dependency : transitiveDependencies) {
252 Artifact artifact = dependency.getArtifact();
253 if (parentsById.containsKey(artifact)) {
254 Configuration parent = parentsById.get(artifact);
255 if (dependency.getImportType() == ImportType.CLASSES || dependency.getImportType() == ImportType.ALL) {
256 classParents.add(parent);
257 }
258 if (dependency.getImportType() == ImportType.SERVICES || dependency.getImportType() == ImportType.ALL) {
259 serviceParents.add(parent);
260 }
261 } else if (dependency.getImportType() == ImportType.SERVICES) {
262 throw new IllegalStateException("Could not find parent " + artifact + " in the parents collection");
263 } else {
264 dependencies.add(artifact);
265 }
266 }
267
268 try {
269 //
270 // Build the configuration class loader
271 //
272 configurationClassLoader = createConfigurationClasssLoader(parents, environment, classPath);
273
274 //
275 // Get all service parents in depth first order
276 //
277
278 addDepthFirstServiceParents(this, allServiceParents, new HashSet<Artifact>());
279
280 //
281 // Deserialize the GBeans in the configurationData
282 //
283 Collection<GBeanData> gbeans = configurationData.getGBeans(configurationClassLoader);
284 if (attributeStore != null) {
285 gbeans = attributeStore.applyOverrides(id, gbeans, configurationClassLoader);
286 }
287 for (GBeanData gbeanData : gbeans) {
288 this.gbeans.put(gbeanData.getAbstractName(), gbeanData);
289 }
290
291 //
292 // Create child configurations
293 //
294 LinkedHashSet<Configuration> childParents = new LinkedHashSet<Configuration>(parents);
295 childParents.add(this);
296 for (Iterator iterator = configurationData.getChildConfigurations().entrySet().iterator(); iterator.hasNext();) {
297 Map.Entry entry = (Map.Entry) iterator.next();
298 String moduleName = (String) entry.getKey();
299 ConfigurationData childConfigurationData = (ConfigurationData) entry.getValue();
300 Configuration childConfiguration = new Configuration(childParents, childConfigurationData, configurationResolver.createChildResolver(moduleName), attributeStore);
301 childConfiguration.parent = this;
302 children.add(childConfiguration);
303 }
304 } catch (RuntimeException e) {
305 shutdown();
306 throw e;
307 } catch (Error e) {
308 shutdown();
309 throw e;
310 } catch (MissingDependencyException e) {
311 shutdown();
312 throw e;
313 } catch (MalformedURLException e) {
314 shutdown();
315 throw e;
316 } catch (NoSuchConfigException e) {
317 shutdown();
318 throw e;
319 } catch (InvalidConfigException e) {
320 shutdown();
321 throw e;
322 }
323 }
324
325 private MultiParentClassLoader createConfigurationClasssLoader(Collection<Configuration> parents, Environment environment, LinkedHashSet<String> classPath) throws MalformedURLException, MissingDependencyException, NoSuchConfigException {
326 // create the URL list
327 URL[] urls = buildClassPath(classPath);
328
329 // parents
330 ClassLoader[] parentClassLoaders;
331 if (parents.size() == 0 && classParents.size() == 0) {
332 // no explicit parent set, so use the class loader of this class as
333 // the parent... this class should be in the root geronimo classloader,
334 // which is normally the system class loader but not always, so be safe
335 parentClassLoaders = new ClassLoader[] {getClass().getClassLoader()};
336 } else {
337 parentClassLoaders = new ClassLoader[classParents.size()];
338 for (ListIterator iterator = classParents.listIterator(); iterator.hasNext();) {
339 Configuration configuration = (Configuration) iterator.next();
340 parentClassLoaders[iterator.previousIndex()] = configuration.getConfigurationClassLoader();
341 }
342 }
343
344 // hidden classes
345 Set<String> hiddenClassesSet = environment.getHiddenClasses();
346 String[] hiddenClasses = hiddenClassesSet.toArray(new String[hiddenClassesSet.size()]);
347
348 // we need to propagate the non-overrideable classes from parents
349 LinkedHashSet<String> nonOverridableSet = new LinkedHashSet<String>(environment.getNonOverrideableClasses());
350 for (Configuration parent : classParents) {
351
352 Environment parentEnvironment = parent.getEnvironment();
353 nonOverridableSet.addAll(parentEnvironment.getNonOverrideableClasses());
354 }
355 String[] nonOverridableClasses = nonOverridableSet.toArray(new String[nonOverridableSet.size()]);
356
357 if (log.isDebugEnabled()) {
358 StringBuffer buf = new StringBuffer("ClassLoader structure for configuration ").append(id).append("\n");
359 buf.append("Parent configurations:\n");
360 for (Configuration configuration : classParents) {
361 buf.append(" ").append(configuration.getId()).append("\n");
362 }
363 buf.append("ClassPath:\n");
364 for (URL url : urls) {
365 buf.append(" ").append(url).append("\n");
366 }
367 log.debug(buf.toString());
368 }
369
370 // The JarFileClassLoader was created to address a locking problem seen only on Windows platforms.
371 // It carries with it a slight performance penalty that needs to be addressed. Rather than make
372 // *nix OSes carry this burden we'll engage the JarFileClassLoader for Windows or if the user
373 // specifically requests it. We'll look more at this issue in the future.
374 boolean useJarFileClassLoader = false;
375 if (System.getProperty("Xorg.apache.geronimo.JarFileClassLoader") == null) {
376 useJarFileClassLoader = System.getProperty("os.name").startsWith("Windows");
377 } else {
378 useJarFileClassLoader = Boolean.getBoolean("Xorg.apache.geronimo.JarFileClassLoader");
379 }
380 if (useJarFileClassLoader) {
381 return new JarFileClassLoader(environment.getConfigId(),
382 urls,
383 parentClassLoaders,
384 environment.isInverseClassLoading(),
385 hiddenClasses,
386 nonOverridableClasses);
387 } else {
388 return new MultiParentClassLoader(environment.getConfigId(),
389 urls,
390 parentClassLoaders,
391 environment.isInverseClassLoading(),
392 hiddenClasses,
393 nonOverridableClasses);
394 }
395 }
396
397 private void addDepthFirstServiceParents(Configuration configuration, List<Configuration> ancestors, Set<Artifact> ids) {
398 if (!ids.contains(configuration.getId())) {
399 ancestors.add(configuration);
400 ids.add(configuration.getId());
401 for (Configuration parent : configuration.getServiceParents()) {
402 addDepthFirstServiceParents(parent, ancestors, ids);
403 }
404 }
405 }
406
407 private URL[] buildClassPath(LinkedHashSet<String> classPath) throws MalformedURLException, MissingDependencyException, NoSuchConfigException {
408 List<URL> urls = new ArrayList<URL>();
409 for (Artifact artifact : dependencies) {
410 File file = configurationResolver.resolve(artifact);
411 urls.add(file.toURL());
412 }
413 if (classPath != null) {
414 for (String pattern : classPath) {
415 Set<URL> matches = configurationResolver.resolve(pattern);
416 for (URL url : matches) {
417 urls.add(url);
418 }
419 }
420 }
421 return urls.toArray(new URL[urls.size()]);
422 }
423
424 /**
425 * Return the unique Id
426 * @return the unique Id
427 */
428 public Artifact getId() {
429 return id;
430 }
431
432 /**
433 * Gets the unique name of this configuration within the kernel.
434 * @return the unique name of this configuration
435 */
436 public String getObjectName() {
437 try {
438 return getConfigurationObjectName(id).getCanonicalName();
439 } catch (InvalidConfigException e) {
440 throw new AssertionError(e);
441 }
442 }
443
444 public AbstractName getAbstractName() {
445 return abstractName;
446 }
447
448 /**
449 * Gets the parent configurations used for class loading.
450 * @return the parents of this configuration used for class loading
451 */
452 public List<Configuration> getClassParents() {
453 return classParents;
454 }
455
456 /**
457 * Gets the parent configurations used for service resolution.
458 * @return the parents of this configuration used for service resolution
459 */
460 public List<Configuration> getServiceParents() {
461 return serviceParents;
462 }
463
464 /**
465 * Gets the artifact dependencies of this configuration.
466 * @return the artifact dependencies of this configuration
467 */
468 public LinkedHashSet<Artifact> getDependencies() {
469 return dependencies;
470 }
471
472 /**
473 * Gets the declaration of the environment in which this configuration runs.
474 * @return the environment of this configuration
475 */
476 public Environment getEnvironment() {
477 return environment;
478 }
479
480 /**
481 * This is used by the configuration manager to restart an existing configuation.
482 * Do not modify the configuration data.
483 * @return the configuration data for this configuration; do not modify
484 */
485 ConfigurationData getConfigurationData() {
486 return configurationData;
487 }
488
489 public File getConfigurationDir() {
490 return configurationData.getConfigurationDir();
491 }
492
493 /**
494 * @deprecated this is only exposed temporarily for configuration manager
495 */
496 public ConfigurationResolver getConfigurationResolver() {
497 return configurationResolver;
498 }
499
500 /**
501 * Gets the relative class path (URIs) of this configuration.
502 * @return the relative class path of this configuation
503 */
504 public List<String> getClassPath() {
505 return new ArrayList<String>(classPath);
506 }
507
508 public void addToClassPath(String pattern) throws IOException {
509 if (!classPath.contains(pattern)) {
510 try {
511 Set<URL> matches = configurationResolver.resolve(pattern);
512 for (URL url : matches) {
513 configurationClassLoader.addURL(url);
514 }
515 classPath.add(pattern);
516 } catch (Exception e) {
517 throw (IOException)new IOException("Unable to extend classpath with " + pattern).initCause(e);
518 }
519 }
520 }
521
522 /**
523 * Gets the type of the configuration (WAR, RAR et cetera)
524 * @return Type of the configuration.
525 */
526 public ConfigurationModuleType getModuleType() {
527 return configurationData.getModuleType();
528 }
529
530 /**
531 * Gets the time at which this configuration was created (or deployed).
532 * @return the time at which this configuration was created (or deployed)
533 */
534 public long getCreated() {
535 return configurationData.getCreated();
536 }
537
538 /**
539 * Gets the class loader for this configuration.
540 * @return the class loader for this configuration
541 */
542 public ClassLoader getConfigurationClassLoader() {
543 return configurationClassLoader;
544 }
545
546 /**
547 * Gets the nested configurations of this configuration. That is, the
548 * configurations within this one as a WAR can be within an EAR; not
549 * including wholly separate configurations that just depend on this
550 * one as a parent.
551 *
552 * @return the nested configuration of this configuration
553 */
554 public List<Configuration> getChildren() {
555 return Collections.unmodifiableList(children);
556 }
557
558 /**
559 * Gets the configurations owned by this configuration. This is only used for cascade-uninstall.
560 * @return the configurations owned by this configuration
561 */
562 public Set<Artifact> getOwnedConfigurations() {
563 return configurationData.getOwnedConfigurations();
564 }
565
566 /**
567 * Gets an unmodifiable collection of the GBeanDatas for the GBeans in this configuration.
568 * @return the GBeans in this configuration
569 */
570 public Map<AbstractName, GBeanData> getGBeans() {
571 return Collections.unmodifiableMap(gbeans);
572 }
573
574 /**
575 * Determines of this configuration constains the specified GBean.
576 * @param gbean the name of the GBean
577 * @return true if this configuration contains the specified GBean; false otherwise
578 */
579 public synchronized boolean containsGBean(AbstractName gbean) {
580 return gbeans.containsKey(gbean);
581 }
582
583 /**
584 * Gets the enclosing configuration of this one (e.g. the EAR for a WAR),
585 * or null if it has none.
586 * @return enclosing configuration, if any
587 */
588 public Configuration getEnclosingConfiguration() {
589 return parent;
590 }
591
592 /**
593 * Gets the manageable attribute store for this configuration.
594 * This is used in the configuration manager to apply overrides
595 * @return
596 */
597 ManageableAttributeStore getManageableAttributeStore(){
598 return attributeStore;
599 }
600
601 public synchronized AbstractName addGBean(String name, GBeanData gbean) throws GBeanAlreadyExistsException {
602 AbstractName abstractName = gbean.getAbstractName();
603 if (abstractName != null) {
604 throw new IllegalArgumentException("gbean already has an abstract name: " + abstractName);
605 }
606
607 String j2eeType = gbean.getGBeanInfo().getJ2eeType();
608 if (j2eeType == null) j2eeType = "GBean";
609 abstractName = naming.createRootName(id, name, j2eeType);
610 gbean.setAbstractName(abstractName);
611
612 if (gbeans.containsKey(abstractName)) {
613 throw new GBeanAlreadyExistsException(gbean.getAbstractName().toString());
614 }
615 gbeans.put(abstractName, gbean);
616 return abstractName;
617 }
618
619 public synchronized void addGBean(GBeanData gbean) throws GBeanAlreadyExistsException {
620 if (gbeans.containsKey(gbean.getAbstractName())) {
621 throw new GBeanAlreadyExistsException(gbean.getAbstractName().toString());
622 }
623 gbeans.put(gbean.getAbstractName(), gbean);
624 }
625
626 public synchronized void removeGBean(AbstractName name) throws GBeanNotFoundException {
627 if (!gbeans.containsKey(name)) {
628 throw new GBeanNotFoundException(name);
629 }
630 gbeans.remove(name);
631 }
632
633 public AbstractName findGBean(AbstractNameQuery pattern) throws GBeanNotFoundException {
634 if (pattern == null) throw new NullPointerException("pattern is null");
635 return findGBean(Collections.singleton(pattern));
636 }
637
638 public GBeanData findGBeanData(AbstractNameQuery pattern) throws GBeanNotFoundException {
639 if (pattern == null) throw new NullPointerException("pattern is null");
640 return findGBeanData(Collections.singleton(pattern));
641 }
642
643 public AbstractName findGBean(ReferencePatterns referencePatterns) throws GBeanNotFoundException {
644 if (referencePatterns == null) throw new NullPointerException("referencePatterns is null");
645 if (referencePatterns.isResolved()) {
646 return referencePatterns.getAbstractName();
647 }
648
649 // check the local config
650 Set<AbstractNameQuery> patterns = referencePatterns.getPatterns();
651 return findGBean(patterns);
652 }
653
654 public AbstractName findGBean(Set<AbstractNameQuery> patterns) throws GBeanNotFoundException {
655 if (patterns == null) throw new NullPointerException("patterns is null");
656 return findGBeanData(patterns).getAbstractName();
657 }
658
659 public GBeanData findGBeanData(Set<AbstractNameQuery> patterns) throws GBeanNotFoundException {
660 if (patterns == null) throw new NullPointerException("patterns is null");
661 Set<GBeanData> result = findGBeanDatas(this, patterns);
662 if (result.size() > 1) {
663 throw new GBeanNotFoundException("More than one match to referencePatterns in local configuration", patterns, mapToNames(result));
664 } else if (result.size() == 1) {
665 return (GBeanData) result.iterator().next();
666 }
667
668 // search all parents
669 for (Configuration configuration : allServiceParents) {
670 result.addAll(findGBeanDatas(configuration, patterns));
671
672 }
673 // if we already found a match we have an ambiguous query
674 if (result.size() > 1) {
675 List<AbstractName> names = new ArrayList<AbstractName>(result.size());
676 for (GBeanData gBeanData : result) {
677 names.add(gBeanData.getAbstractName());
678 }
679 throw new GBeanNotFoundException("More than one match to referencePatterns in parent configurations: " + names.toString(), patterns, mapToNames(result));
680 }
681
682 if (result.isEmpty()) {
683 throw new GBeanNotFoundException("No matches for referencePatterns", patterns, null);
684 }
685
686 return result.iterator().next();
687 }
688
689 private Set<AbstractName> mapToNames(Set<GBeanData> datas) {
690 Set<AbstractName> names = new HashSet<AbstractName>(datas.size());
691 for (GBeanData gBeanData: datas) {
692 names.add(gBeanData.getAbstractName());
693 }
694 return names;
695 }
696
697 public LinkedHashSet<AbstractName> findGBeans(AbstractNameQuery pattern) {
698 if (pattern == null) throw new NullPointerException("pattern is null");
699 return findGBeans(Collections.singleton(pattern));
700 }
701
702 public LinkedHashSet<AbstractName> findGBeans(ReferencePatterns referencePatterns) {
703 if (referencePatterns == null) throw new NullPointerException("referencePatterns is null");
704 if (referencePatterns.getAbstractName() != null) {
705 // this pattern is already resolved
706 LinkedHashSet<AbstractName> result = new LinkedHashSet<AbstractName>();
707 result.add(referencePatterns.getAbstractName());
708 return result;
709 }
710
711 // check the local config
712 Set<AbstractNameQuery> patterns = referencePatterns.getPatterns();
713 return findGBeans(patterns);
714 }
715
716 public LinkedHashSet<AbstractName> findGBeans(Set<AbstractNameQuery> patterns) {
717 if (patterns == null) throw new NullPointerException("patterns is null");
718 LinkedHashSet<GBeanData> datas = findGBeanDatas(patterns);
719 LinkedHashSet<AbstractName> result = new LinkedHashSet<AbstractName>(datas.size());
720 for (GBeanData gBeanData : datas) {
721 result.add(gBeanData.getAbstractName());
722 }
723
724 return result;
725 }
726
727 public LinkedHashSet<GBeanData> findGBeanDatas(Set<AbstractNameQuery> patterns) {
728 if (patterns == null) throw new NullPointerException("patterns is null");
729 LinkedHashSet<GBeanData> datas = findGBeanDatas(this, patterns);
730
731 // search all parents
732 for (Configuration configuration : allServiceParents) {
733 Set<GBeanData> match = findGBeanDatas(configuration, patterns);
734 datas.addAll(match);
735 }
736 return datas;
737 }
738
739 /**
740 * Find the gbeanDatas matching the patterns in this configuration only, ignoring parents.
741 *
742 * @param configuration configuration to look in
743 * @param patterns patterns to look for
744 * @return set of gbeandatas matching one of the patterns from this configuration only, not including parents.
745 */
746 public LinkedHashSet<GBeanData> findGBeanDatas(Configuration configuration, Set<AbstractNameQuery> patterns) {
747 LinkedHashSet<GBeanData> result = new LinkedHashSet<GBeanData>();
748
749 Set<Map.Entry<AbstractName, GBeanData>> gbeanNames = configuration.getGBeans().entrySet();
750 for (AbstractNameQuery abstractNameQuery : patterns) {
751 Artifact queryArtifact = abstractNameQuery.getArtifact();
752
753 // Does this query apply to this configuration
754 if (queryArtifact == null || queryArtifact.matches(configuration.getId())) {
755
756 // Search the GBeans
757 for (Map.Entry<AbstractName, GBeanData> entry : gbeanNames) {
758 AbstractName abstractName = entry.getKey();
759 GBeanData gbeanData = entry.getValue();
760 if (abstractNameQuery.matches(abstractName, gbeanData.getGBeanInfo().getInterfaces())) {
761 result.add(gbeanData);
762 }
763 }
764 }
765 }
766 return result;
767 }
768
769 public void doStart() throws Exception {
770 log.debug("Started configuration " + id);
771 }
772
773 public synchronized void doStop() throws Exception {
774 log.debug("Stopping configuration " + id);
775 shutdown();
776
777 }
778
779 public void doFail() {
780 log.debug("Failed configuration " + id);
781 shutdown();
782 }
783
784 private void shutdown() {
785 for (Configuration configuration : children) {
786 configuration.shutdown();
787 }
788
789 // clear references to GBeanDatas
790 gbeans.clear();
791
792 // destroy the class loader
793 if (configurationClassLoader != null) {
794 configurationClassLoader.destroy();
795 }
796 }
797
798 public static final GBeanInfo GBEAN_INFO;
799
800 static {
801 GBeanInfoBuilder infoFactory = GBeanInfoBuilder.createStatic(Configuration.class);//does not use jsr-77 naming
802 infoFactory.addReference("Parents", Configuration.class);
803 infoFactory.addAttribute("configurationData", ConfigurationData.class, true, false);
804 infoFactory.addAttribute("configurationResolver", ConfigurationResolver.class, true);
805 infoFactory.addAttribute("managedAttributeStore", ManageableAttributeStore.class, true);
806
807 infoFactory.addInterface(Configuration.class);
808
809 infoFactory.setConstructor(new String[]{
810 "Parents",
811 "configurationData",
812 "configurationResolver",
813 "managedAttributeStore"
814 });
815
816 GBEAN_INFO = infoFactory.getBeanInfo();
817 }
818
819 public static GBeanInfo getGBeanInfo() {
820 return GBEAN_INFO;
821 }
822 }