View Javadoc

1   /**
2    *
3    * Copyright 2003-2004 The Apache Software Foundation
4    *
5    *  Licensed under the Apache License, Version 2.0 (the "License");
6    *  you may not use this file except in compliance with the License.
7    *  You may obtain a copy of the License at
8    *
9    *     http://www.apache.org/licenses/LICENSE-2.0
10   *
11   *  Unless required by applicable law or agreed to in writing, software
12   *  distributed under the License is distributed on an "AS IS" BASIS,
13   *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14   *  See the License for the specific language governing permissions and
15   *  limitations under the License.
16   */
17  
18  package org.apache.geronimo.kernel.config;
19  
20  import java.io.File;
21  import java.io.IOException;
22  import java.net.MalformedURLException;
23  import java.net.URL;
24  import java.util.ArrayList;
25  import java.util.Collection;
26  import java.util.Collections;
27  import java.util.HashMap;
28  import java.util.Iterator;
29  import java.util.LinkedHashSet;
30  import java.util.List;
31  import java.util.ListIterator;
32  import java.util.Map;
33  import java.util.Set;
34  
35  import javax.management.MalformedObjectNameException;
36  import javax.management.ObjectName;
37  
38  import org.apache.commons.logging.Log;
39  import org.apache.commons.logging.LogFactory;
40  import org.apache.geronimo.gbean.AbstractName;
41  import org.apache.geronimo.gbean.AbstractNameQuery;
42  import org.apache.geronimo.gbean.GBeanData;
43  import org.apache.geronimo.gbean.GBeanInfo;
44  import org.apache.geronimo.gbean.GBeanInfoBuilder;
45  import org.apache.geronimo.gbean.GBeanLifecycle;
46  import org.apache.geronimo.gbean.ReferencePatterns;
47  import org.apache.geronimo.kernel.GBeanAlreadyExistsException;
48  import org.apache.geronimo.kernel.GBeanNotFoundException;
49  import org.apache.geronimo.kernel.Naming;
50  import org.apache.geronimo.kernel.classloader.JarFileClassLoader;
51  import org.apache.geronimo.kernel.repository.Artifact;
52  import org.apache.geronimo.kernel.repository.Dependency;
53  import org.apache.geronimo.kernel.repository.Environment;
54  import org.apache.geronimo.kernel.repository.ImportType;
55  import org.apache.geronimo.kernel.repository.MissingDependencyException;
56  
57  /**
58   * A Configuration represents a collection of runnable services that can be
59   * loaded into a Geronimo Kernel and brought online. The primary components in
60   * a Configuration are a codebase, represented by a collection of URLs that
61   * is used to locate classes, and a collection of GBean instances that define
62   * its state.
63   * <p/>
64   * The persistent attributes of the Configuration are:
65   * <ul>
66   * <li>its unique configId used to identify this specific config</li>
67   * <li>the configId of a parent Configuration on which this one is dependent</li>
68   * <li>a List<URI> of code locations (which may be absolute or relative to a baseURL)</li>
69   * <li>a byte[] holding the state of the GBeans instances in Serialized form</li>
70   * </ul>
71   * When a configuration is started, it converts the URIs into a set of absolute
72   * URLs by resolving them against the specified baseURL (this would typically
73   * be the root of the CAR file which contains the configuration) and then
74   * constructs a ClassLoader for that codebase. That ClassLoader is then used
75   * to de-serialize the persisted GBeans, ensuring the GBeans can be recycled
76   * as necessary. Once the GBeans have been restored, they are brought online
77   * by registering them with the MBeanServer.
78   * <p/>
79   * A dependency on the Configuration is created for every GBean it loads. As a
80   * result, a startRecursive() operation on the configuration will result in
81   * a startRecursive() for all the GBeans it contains. Similarly, if the
82   * Configuration is stopped then all of its GBeans will be stopped as well.
83   *
84   * @version $Rev:385718 $ $Date: 2006-11-06 02:28:54 -0800 (Mon, 06 Nov 2006) $
85   */
86  public class Configuration implements GBeanLifecycle, ConfigurationParent {
87      private static final Log log = LogFactory.getLog(Configuration.class);
88  
89      /**
90       * Converts an Artifact to an AbstractName for a configuration.  Does not
91       * validate that this is a reasonable or resolved Artifact, or that it
92       * corresponds to an actual Configuration.
93       */
94      public static AbstractName getConfigurationAbstractName(Artifact configId) throws InvalidConfigException {
95          return new AbstractName(configId, Collections.singletonMap("configurationName", configId.toString()), getConfigurationObjectName(configId));
96      }
97  
98      public static boolean isConfigurationObjectName(ObjectName name) {
99          return name.getDomain().equals("geronimo.config") && name.getKeyPropertyList().size() == 1 && name.getKeyProperty("name") != null;
100     }
101 
102     public static Artifact getConfigurationID(ObjectName objectName) {
103         if (isConfigurationObjectName(objectName)) {
104             String name = ObjectName.unquote(objectName.getKeyProperty("name"));
105             return Artifact.create(name);
106         } else {
107             throw new IllegalArgumentException("ObjectName " + objectName + " is not a Configuration name");
108         }
109     }
110 
111     private static ObjectName getConfigurationObjectName(Artifact configId) throws InvalidConfigException {
112         try {
113             return new ObjectName("geronimo.config:name=" + ObjectName.quote(configId.toString()));
114         } catch (MalformedObjectNameException e) {
115             throw new InvalidConfigException("Could not construct object name for configuration", e);
116         }
117     }
118 
119     /**
120      * The artifact id for this configuration.
121      */
122     private final Artifact id;
123 
124     /**
125      * The registered abstractName for this configuraion.
126      */
127     private final AbstractName abstractName;
128 
129     /**
130      * Defines the environment requred for this configuration.
131      */
132     private final Environment environment;
133 
134     /**
135      * Used to resolve dependecies and paths
136      */
137     private final ConfigurationResolver configurationResolver;
138 
139     /**
140      * Parent configurations used for class loader.
141      */
142     private final List classParents = new ArrayList();
143 
144     /**
145      * Parent configuations used for service resolution.
146      */
147     private final List serviceParents = new ArrayList();
148 
149     /**
150      * All service parents depth first
151      */
152     private final List allServiceParents = new ArrayList();
153 
154     /**
155      * Artifacts added to the class loader (non-configuation artifacts).
156      */
157     private final LinkedHashSet dependencies = new LinkedHashSet();
158 
159     /**
160      * The GBeanData objects by ObjectName
161      */
162     private final Map gbeans = new HashMap();
163 
164     /**
165      * The classloader used to load the child GBeans contained in this configuration.
166      */
167     private final MultiParentClassLoader configurationClassLoader;
168 
169     /**
170      * The relative class path (URI) of this configuation.
171      */
172     private final LinkedHashSet classPath;
173 
174     /**
175      * Naming system used when generating a name for a new gbean
176      */
177     private final Naming naming;
178 
179     /**
180      * Environment, classpath, gbeans and other data for this configuration.
181      */
182     private ConfigurationData configurationData;
183 
184     /**
185      * The nested configurations of this configuration.
186      */
187     List children = new ArrayList();
188 
189     /**
190      * The parent of this configuration;
191      */
192     private Configuration parent = null;
193 
194     /**
195      * Only used to allow declaration as a reference.
196      */
197     public Configuration() {
198         id = null;
199         abstractName = null;
200         environment = null;
201         classPath = null;
202         configurationResolver = null;
203         configurationClassLoader = null;
204         naming = null;
205     }
206 
207     /**
208      * Creates a configuration.
209      * @param parents parents of this configuation (not ordered)
210      * @param configurationData the module type, environment and classpath of the configuration
211      * @param configurationResolver used to resolve dependecies and paths
212      */
213     public Configuration(Collection parents,
214             ConfigurationData configurationData,
215             ConfigurationResolver configurationResolver,
216             ManageableAttributeStore attributeStore) throws MissingDependencyException, MalformedURLException, NoSuchConfigException, InvalidConfigException {
217         if (parents == null) parents = Collections.EMPTY_SET;
218         if (configurationData == null) throw new NullPointerException("configurationData is null");
219         if (configurationResolver == null) throw new NullPointerException("configurationResolver is null");
220 
221         this.configurationData = configurationData;
222         this.environment = configurationData.getEnvironment();
223         this.configurationResolver = configurationResolver;
224         this.classPath = new LinkedHashSet(configurationData.getClassPath());
225         this.naming = configurationData.getNaming();
226 
227         this.id = environment.getConfigId();
228         abstractName = getConfigurationAbstractName(id);
229 
230         //
231         // Transitively resolve all the dependencies in the environment
232         //
233         List transtiveDependencies = configurationResolver.resolveTransitiveDependencies(parents, environment.getDependencies());
234 
235         //
236         // Process transtive dependencies splitting it into classParents, serviceParents and artifactDependencies
237         //
238         Map parentsById = new HashMap();
239         for (Iterator iterator = parents.iterator(); iterator.hasNext();) {
240             Configuration configuration = (Configuration) iterator.next();
241             Artifact id = configuration.getId();
242             parentsById.put(id, configuration);
243         }
244 
245         for (Iterator iterator = transtiveDependencies.iterator(); iterator.hasNext();) {
246             Dependency dependency = (Dependency) iterator.next();
247             Artifact artifact = dependency.getArtifact();
248             if (parentsById.containsKey(artifact)) {
249                 Configuration parent = (Configuration) 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             addDepthFirstServiceParents(this, allServiceParents);
273 
274             //
275             // Deserialize the GBeans in the configurationData
276             //
277             Collection gbeans = configurationData.getGBeans(configurationClassLoader);
278             if (attributeStore != null) {
279                 gbeans = attributeStore.applyOverrides(id, gbeans, configurationClassLoader);
280             }
281             for (Iterator iterator = gbeans.iterator(); iterator.hasNext();) {
282                 GBeanData gbeanData = (GBeanData) iterator.next();
283                 this.gbeans.put(gbeanData.getAbstractName(), gbeanData);
284             }
285 
286             //
287             // Create child configurations
288             //
289             LinkedHashSet childParents = new LinkedHashSet(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 parents, Environment environment, LinkedHashSet 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 hiddenClassesSet = environment.getHiddenClasses();
341         String[] hiddenClasses = (String[]) hiddenClassesSet.toArray(new String[hiddenClassesSet.size()]);
342 
343         // we need to propagate the non-overrideable classes from parents
344         LinkedHashSet nonOverridableSet = new LinkedHashSet();
345         for (Iterator iterator = classParents.iterator(); iterator.hasNext();) {
346             Configuration parent = (Configuration) iterator.next();
347 
348             Environment parentEnvironment = parent.getEnvironment();
349             nonOverridableSet.addAll(parentEnvironment.getNonOverrideableClasses());
350         }
351         String[] nonOverridableClasses = (String[]) nonOverridableSet.toArray(new String[nonOverridableSet.size()]);
352 
353         if (log.isDebugEnabled()) {
354             StringBuffer buf = new StringBuffer("ClassLoader structure for configuration ").append(id).append("\n");
355             buf.append("Parent configurations:\n");
356             for (Iterator iterator = classParents.iterator(); iterator.hasNext();) {
357                 Configuration configuration = (Configuration) iterator.next();
358                 buf.append("     ").append(configuration.getId()).append("\n");
359             }
360             buf.append("ClassPath:\n");
361             for (int i = 0; i < urls.length; i++) {
362                 URL url = urls[i];
363                 buf.append("     ").append(url).append("\n");
364             }
365             log.debug(buf.toString());
366         }
367 
368         if (Boolean.getBoolean("Xorg.apache.geronimo.OldClassLoader")) {
369             return new MultiParentClassLoader(environment.getConfigId(),
370                     urls,
371                     parentClassLoaders,
372                     environment.isInverseClassLoading(),
373                     hiddenClasses,
374                     nonOverridableClasses);
375         } else {
376             return new JarFileClassLoader(environment.getConfigId(),
377                     urls,
378                     parentClassLoaders,
379                     environment.isInverseClassLoading(),
380                     hiddenClasses,
381                     nonOverridableClasses);
382         }
383     }
384 
385     private void addDepthFirstServiceParents(Configuration configuration, List ancestors) {
386         ancestors.add(configuration);
387         for (Iterator parents = configuration.getServiceParents().iterator(); parents.hasNext();) {
388             Configuration parent = (Configuration) parents.next();
389             addDepthFirstServiceParents(parent, ancestors);
390         }
391     }
392 
393     private URL[] buildClassPath(LinkedHashSet classPath) throws MalformedURLException, MissingDependencyException, NoSuchConfigException {
394         List urls = new ArrayList();
395         for (Iterator i = dependencies.iterator(); i.hasNext();) {
396             Artifact artifact = (Artifact) i.next();
397             File file = configurationResolver.resolve(artifact);
398             urls.add(file.toURL());
399         }
400         if (classPath != null) {
401             for (Iterator i = classPath.iterator(); i.hasNext();) {
402                 String pattern = (String) i.next();
403                 Set matches = configurationResolver.resolve(pattern);
404                 for (Iterator iterator = matches.iterator(); iterator.hasNext();) {
405                     URL url = (URL) iterator.next();
406                     urls.add(url);
407                 }
408             }
409         }
410         return (URL[]) urls.toArray(new URL[urls.size()]);
411     }
412 
413     /**
414      * Return the unique Id
415      * @return the unique Id
416      */
417     public Artifact getId() {
418         return id;
419     }
420 
421     /**
422      * Gets the unique name of this configuration within the kernel.
423      * @return the unique name of this configuration
424      */
425     public String getObjectName() {
426         try {
427             return getConfigurationObjectName(id).getCanonicalName();
428         } catch (InvalidConfigException e) {
429             throw new AssertionError(e);
430         }
431     }
432 
433     public AbstractName getAbstractName() {
434         return abstractName;
435     }
436 
437     /**
438      * Gets the parent configurations used for class loading.
439      * @return the parents of this configuration used for class loading
440      */
441     public List getClassParents() {
442         return classParents;
443     }
444 
445     /**
446      * Gets the parent configurations used for service resolution.
447      * @return the parents of this configuration used for service resolution
448      */
449     public List getServiceParents() {
450         return serviceParents;
451     }
452 
453     /**
454      * Gets the artifact dependencies of this configuration.
455      * @return the artifact dependencies of this configuration
456      */
457     public LinkedHashSet getDependencies() {
458         return dependencies;
459     }
460 
461     /**
462      * Gets the declaration of the environment in which this configuration runs.
463      * @return the environment of this configuration
464      */
465     public Environment getEnvironment() {
466         return environment;
467     }
468 
469     /**
470      * This is used by the configuration manager to restart an existing configuation.
471      * Do not modify the configuation data.
472      * @return the configuation data for this configuration; do not modify
473      */
474     ConfigurationData getConfigurationData() {
475         return configurationData;
476     }
477 
478     /**
479      * @deprecated this is only exposed temporarily for configuration manager
480      */
481     public ConfigurationResolver getConfigurationResolver() {
482         return configurationResolver;
483     }
484 
485     /**
486      * Gets the relative class path (URIs) of this configuration.
487      * @return the relative class path of this configuation
488      */
489     public List getClassPath() {
490         return new ArrayList(classPath);
491     }
492 
493     public void addToClassPath(String pattern) throws IOException {
494         if (!classPath.contains(pattern)) {
495             try {
496                 Set matches = configurationResolver.resolve(pattern);
497                 for (Iterator iterator = matches.iterator(); iterator.hasNext();) {
498                     URL url = (URL) iterator.next();
499                     configurationClassLoader.addURL(url);
500                 }
501                 classPath.add(pattern);
502             } catch (Exception e) {
503                 throw new IOException("Unable to extend classpath with " + pattern);
504             }
505         }
506     }
507 
508     /**
509      * Gets the type of the configuration (WAR, RAR et cetera)
510      * @return Type of the configuration.
511      */
512     public ConfigurationModuleType getModuleType() {
513         return configurationData.getModuleType();
514     }
515 
516     /**
517      * Gets the time at which this configuration was created (or deployed).
518      * @return the time at which this configuration was created (or deployed)
519      */
520     public long getCreated() {
521         return configurationData.getCreated();
522     }
523 
524     /**
525      * Gets the class loader for this configuration.
526      * @return the class loader for this configuration
527      */
528     public ClassLoader getConfigurationClassLoader() {
529         return configurationClassLoader;
530     }
531 
532     /**
533      * Gets the nested configurations of this configuration.  That is, the
534      * configurations within this one as a WAR can be within an EAR; not
535      * including wholly separate configurations that just depend on this
536      * one as a parent.
537      * 
538      * @return the nested configuration of this configuration
539      */
540     public List getChildren() {
541         return Collections.unmodifiableList(children);
542     }
543 
544     /**
545      * Gets the configurations owned by this configuration.  This is only used for cascade-uninstall.
546      * @return the configurations owned by this configuration
547      */
548     public Set getOwnedConfigurations() {
549         return configurationData.getOwnedConfigurations();
550     }
551 
552     /**
553      * Gets an unmodifiable collection of the GBeanDatas for the GBeans in this configuration.
554      * @return the GBeans in this configuration
555      */
556     public Map getGBeans() {
557         return Collections.unmodifiableMap(gbeans);
558     }
559 
560     /**
561      * Determines of this configuration constains the specified GBean.
562      * @param gbean the name of the GBean
563      * @return true if this configuration contains the specified GBean; false otherwise
564      */
565     public synchronized boolean containsGBean(AbstractName gbean) {
566         return gbeans.containsKey(gbean);
567     }
568 
569     /**
570      * Gets the enclosing configuration of this one (e.g. the EAR for a WAR),
571      * or null if it has none.
572      */
573     public Configuration getEnclosingConfiguration() {
574         return parent;
575     }
576 
577     public synchronized AbstractName addGBean(String name, GBeanData gbean) throws GBeanAlreadyExistsException {
578         AbstractName abstractName = gbean.getAbstractName();
579         if (abstractName != null) {
580             throw new IllegalArgumentException("gbean already has an abstract name: " + abstractName);
581         }
582 
583         String j2eeType = gbean.getGBeanInfo().getJ2eeType();
584         if (j2eeType == null) j2eeType = "GBean";
585         abstractName = naming.createRootName(id, name, j2eeType);
586         gbean.setAbstractName(abstractName);
587 
588         if (gbeans.containsKey(abstractName)) {
589             throw new GBeanAlreadyExistsException(gbean.getAbstractName().toString());
590         }
591         gbeans.put(abstractName, gbean);
592         return abstractName;
593     }
594 
595     public synchronized void addGBean(GBeanData gbean) throws GBeanAlreadyExistsException {
596         if (gbeans.containsKey(gbean.getAbstractName())) {
597             throw new GBeanAlreadyExistsException(gbean.getAbstractName().toString());
598         }
599         gbeans.put(gbean.getAbstractName(), gbean);
600     }
601 
602     public synchronized void removeGBean(AbstractName name) throws GBeanNotFoundException {
603         if (!gbeans.containsKey(name)) {
604             throw new GBeanNotFoundException(name);
605         }
606         gbeans.remove(name);
607     }
608 
609     public AbstractName findGBean(AbstractNameQuery pattern) throws GBeanNotFoundException {
610         if (pattern == null) throw new NullPointerException("pattern is null");
611         return findGBean(Collections.singleton(pattern));
612     }
613 
614     public GBeanData findGBeanData(AbstractNameQuery pattern) throws GBeanNotFoundException {
615         if (pattern == null) throw new NullPointerException("pattern is null");
616         return findGBeanData(Collections.singleton(pattern));
617     }
618 
619     public AbstractName findGBean(ReferencePatterns referencePatterns) throws GBeanNotFoundException {
620         if (referencePatterns == null) throw new NullPointerException("referencePatterns is null");
621         if (referencePatterns.isResolved()) {
622             return referencePatterns.getAbstractName();
623         }
624 
625         // check the local config
626         Set patterns = referencePatterns.getPatterns();
627         return findGBean(patterns);
628     }
629 
630     public AbstractName findGBean(Set patterns) throws GBeanNotFoundException {
631         if (patterns == null) throw new NullPointerException("patterns is null");
632         return findGBeanData(patterns).getAbstractName();
633     }
634 
635     public GBeanData findGBeanData(Set patterns) throws GBeanNotFoundException {
636         if (patterns == null) throw new NullPointerException("patterns is null");
637         Set result = findGBeanDatas(this, patterns);
638         if (result.size() > 1) {
639             throw new GBeanNotFoundException("More than one match to referencePatterns", patterns);
640         } else if (result.size() == 1) {
641             return (GBeanData) result.iterator().next();
642         }
643 
644         // search all parents
645         for (Iterator iterator = allServiceParents.iterator(); iterator.hasNext();) {
646             Configuration configuration = (Configuration) iterator.next();
647             result.addAll(findGBeanDatas(configuration, patterns));
648 
649             // if we already found a match we have an ambiguous query
650             if (result.size() > 1) {
651                 List names = new ArrayList(result.size());
652                 for (Iterator iterator1 = result.iterator(); iterator1.hasNext();) {
653                     GBeanData gBeanData = (GBeanData) iterator1.next();
654                     names.add(gBeanData.getAbstractName());
655                 }
656                 throw new GBeanNotFoundException("More than one match to referencePatterns: " + names.toString(), patterns);
657             }
658         }
659 
660         if (result.isEmpty()) {
661             throw new GBeanNotFoundException("No matches for referencePatterns", patterns);
662         }
663 
664         return (GBeanData) result.iterator().next();
665     }
666 
667     public LinkedHashSet findGBeans(AbstractNameQuery pattern) {
668         if (pattern == null) throw new NullPointerException("pattern is null");
669         return findGBeans(Collections.singleton(pattern));
670     }
671 
672     public LinkedHashSet findGBeans(ReferencePatterns referencePatterns) {
673         if (referencePatterns == null) throw new NullPointerException("referencePatterns is null");
674         if (referencePatterns.getAbstractName() != null) {
675             // this pattern is already resolved
676             LinkedHashSet result = new LinkedHashSet();
677             result.add(referencePatterns.getAbstractName());
678             return result;
679         }
680 
681         // check the local config
682         Set patterns = referencePatterns.getPatterns();
683         return findGBeans(patterns);
684     }
685 
686     public LinkedHashSet findGBeans(Set patterns) {
687         if (patterns == null) throw new NullPointerException("patterns is null");
688         LinkedHashSet datas = findGBeanDatas(patterns);
689         LinkedHashSet result = new LinkedHashSet(datas.size());
690         for (Iterator iterator = datas.iterator(); iterator.hasNext();) {
691             GBeanData gBeanData = (GBeanData) iterator.next();
692             result.add(gBeanData.getAbstractName());
693         }
694 
695         return result;
696     }
697 
698     public LinkedHashSet findGBeanDatas(Set patterns) {
699         if (patterns == null) throw new NullPointerException("patterns is null");
700         LinkedHashSet datas = findGBeanDatas(this, patterns);
701 
702         // search all parents
703         for (Iterator iterator = allServiceParents.iterator(); iterator.hasNext();) {
704             Configuration configuration = (Configuration) iterator.next();
705             Set match = findGBeanDatas(configuration, patterns);
706             datas.addAll(match);
707         }
708         return datas;
709     }
710 
711     private LinkedHashSet findGBeanDatas(Configuration configuration, Set patterns) {
712         LinkedHashSet result = new LinkedHashSet();
713 
714         Set gbeanNames = configuration.getGBeans().entrySet();
715         for (Iterator abstractNameQueries = patterns.iterator(); abstractNameQueries.hasNext();) {
716             AbstractNameQuery abstractNameQuery =  (AbstractNameQuery) abstractNameQueries.next();
717             Artifact queryArtifact = abstractNameQuery.getArtifact();
718 
719             // Does this query apply to this configuration
720             if (queryArtifact == null || queryArtifact.matches(configuration.getId())) {
721 
722                 // Search the GBeans
723                 for (Iterator iterator = gbeanNames.iterator(); iterator.hasNext();) {
724                     Map.Entry entry = (Map.Entry) iterator.next();
725                     AbstractName abstractName = (AbstractName) entry.getKey();
726                     GBeanData gbeanData = (GBeanData) entry.getValue();
727                     if (abstractNameQuery.matches(abstractName, gbeanData.getGBeanInfo().getInterfaces())) {
728                         result.add(gbeanData);
729                     }
730                 }
731             }
732         }
733         return result;
734     }
735 
736     public void doStart() throws Exception {
737         log.debug("Started configuration " + id);
738     }
739 
740     public synchronized void doStop() throws Exception {
741         log.debug("Stopping configuration " + id);
742         shutdown();
743 
744     }
745 
746     public void doFail() {
747         log.debug("Failed configuration " + id);
748         shutdown();
749     }
750 
751     private void shutdown() {
752         for (Iterator iterator = children.iterator(); iterator.hasNext();) {
753             Configuration configuration = (Configuration) iterator.next();
754             configuration.shutdown();
755         }
756 
757         // clear references to GBeanDatas
758         gbeans.clear();
759 
760         // destroy the class loader
761         if (configurationClassLoader != null) {
762             configurationClassLoader.destroy();
763         }
764     }
765 
766     public static final GBeanInfo GBEAN_INFO;
767 
768     static {
769         GBeanInfoBuilder infoFactory = GBeanInfoBuilder.createStatic(Configuration.class);//does not use jsr-77 naming
770         infoFactory.addReference("Parents", Configuration.class);
771         infoFactory.addAttribute("configurationData", ConfigurationData.class, true, false);
772         infoFactory.addAttribute("configurationResolver", ConfigurationResolver.class, true);
773         infoFactory.addAttribute("managedAttributeStore", ManageableAttributeStore.class, true);
774 
775         infoFactory.addInterface(Configuration.class);
776 
777         infoFactory.setConstructor(new String[]{
778                 "Parents",
779                 "configurationData",
780                 "configurationResolver",
781                 "managedAttributeStore"
782         });
783 
784         GBEAN_INFO = infoFactory.getBeanInfo();
785     }
786 
787     public static GBeanInfo getGBeanInfo() {
788         return GBEAN_INFO;
789     }
790 }