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