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