001    /**
002     *
003     * Copyright 2003-2004 The Apache Software Foundation
004     *
005     *  Licensed under the Apache License, Version 2.0 (the "License");
006     *  you may not use this file except in compliance with the License.
007     *  You may obtain a copy of the License at
008     *
009     *     http://www.apache.org/licenses/LICENSE-2.0
010     *
011     *  Unless required by applicable law or agreed to in writing, software
012     *  distributed under the License is distributed on an "AS IS" BASIS,
013     *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
014     *  See the License for the specific language governing permissions and
015     *  limitations under the License.
016     */
017    
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    
035    import javax.management.MalformedObjectNameException;
036    import javax.management.ObjectName;
037    
038    import org.apache.commons.logging.Log;
039    import org.apache.commons.logging.LogFactory;
040    import org.apache.geronimo.gbean.AbstractName;
041    import org.apache.geronimo.gbean.AbstractNameQuery;
042    import org.apache.geronimo.gbean.GBeanData;
043    import org.apache.geronimo.gbean.GBeanInfo;
044    import org.apache.geronimo.gbean.GBeanInfoBuilder;
045    import org.apache.geronimo.gbean.GBeanLifecycle;
046    import org.apache.geronimo.gbean.ReferencePatterns;
047    import org.apache.geronimo.kernel.GBeanAlreadyExistsException;
048    import org.apache.geronimo.kernel.GBeanNotFoundException;
049    import org.apache.geronimo.kernel.Naming;
050    import org.apache.geronimo.kernel.classloader.JarFileClassLoader;
051    import org.apache.geronimo.kernel.repository.Artifact;
052    import org.apache.geronimo.kernel.repository.Dependency;
053    import org.apache.geronimo.kernel.repository.Environment;
054    import org.apache.geronimo.kernel.repository.ImportType;
055    import org.apache.geronimo.kernel.repository.MissingDependencyException;
056    
057    /**
058     * A Configuration represents a collection of runnable services that can be
059     * loaded into a Geronimo Kernel and brought online. The primary components in
060     * a Configuration are a codebase, represented by a collection of URLs that
061     * is used to locate classes, and a collection of GBean instances that define
062     * its state.
063     * <p/>
064     * The persistent attributes of the Configuration are:
065     * <ul>
066     * <li>its unique configId used to identify this specific config</li>
067     * <li>the configId of a parent Configuration on which this one is dependent</li>
068     * <li>a List<URI> of code locations (which may be absolute or relative to a baseURL)</li>
069     * <li>a byte[] holding the state of the GBeans instances in Serialized form</li>
070     * </ul>
071     * When a configuration is started, it converts the URIs into a set of absolute
072     * URLs by resolving them against the specified baseURL (this would typically
073     * be the root of the CAR file which contains the configuration) and then
074     * constructs a ClassLoader for that codebase. That ClassLoader is then used
075     * to de-serialize the persisted GBeans, ensuring the GBeans can be recycled
076     * as necessary. Once the GBeans have been restored, they are brought online
077     * by registering them with the MBeanServer.
078     * <p/>
079     * A dependency on the Configuration is created for every GBean it loads. As a
080     * result, a startRecursive() operation on the configuration will result in
081     * a startRecursive() for all the GBeans it contains. Similarly, if the
082     * Configuration is stopped then all of its GBeans will be stopped as well.
083     *
084     * @version $Rev:385718 $ $Date: 2006-11-06 02:28:54 -0800 (Mon, 06 Nov 2006) $
085     */
086    public class Configuration implements GBeanLifecycle, ConfigurationParent {
087        private static final Log log = LogFactory.getLog(Configuration.class);
088    
089        /**
090         * Converts an Artifact to an AbstractName for a configuration.  Does not
091         * validate that this is a reasonable or resolved Artifact, or that it
092         * corresponds to an actual Configuration.
093         */
094        public static AbstractName getConfigurationAbstractName(Artifact configId) throws InvalidConfigException {
095            return new AbstractName(configId, Collections.singletonMap("configurationName", configId.toString()), getConfigurationObjectName(configId));
096        }
097    
098        public static boolean isConfigurationObjectName(ObjectName name) {
099            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    }