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    package org.apache.geronimo.kernel.config;
018    
019    import java.io.IOException;
020    import java.util.ArrayList;
021    import java.util.Collection;
022    import java.util.Collections;
023    import java.util.HashSet;
024    import java.util.Iterator;
025    import java.util.LinkedHashMap;
026    import java.util.LinkedHashSet;
027    import java.util.List;
028    import java.util.ListIterator;
029    import java.util.Map;
030    import java.util.Set;
031    
032    import org.apache.commons.logging.Log;
033    import org.apache.commons.logging.LogFactory;
034    import org.apache.geronimo.gbean.AbstractName;
035    import org.apache.geronimo.gbean.GBeanInfo;
036    import org.apache.geronimo.gbean.GBeanInfoBuilder;
037    import org.apache.geronimo.kernel.management.State;
038    import org.apache.geronimo.kernel.repository.Artifact;
039    import org.apache.geronimo.kernel.repository.ArtifactResolver;
040    import org.apache.geronimo.kernel.repository.Dependency;
041    import org.apache.geronimo.kernel.repository.Environment;
042    import org.apache.geronimo.kernel.repository.ImportType;
043    import org.apache.geronimo.kernel.repository.MissingDependencyException;
044    import org.apache.geronimo.kernel.repository.Repository;
045    import org.apache.geronimo.kernel.repository.Version;
046    
047    /**
048     * @version $Rev: 557026 $ $Date: 2007-07-17 14:56:15 -0400 (Tue, 17 Jul 2007) $
049     */
050    public class SimpleConfigurationManager implements ConfigurationManager {
051        protected static final Log log = LogFactory.getLog(SimpleConfigurationManager.class);
052        protected final Collection stores;
053        private final ArtifactResolver artifactResolver;
054        protected final Map configurations = new LinkedHashMap();
055        protected final ConfigurationModel configurationModel = new ConfigurationModel();
056        protected final Collection repositories;
057        protected final Collection watchers;
058    
059        /**
060         * When this is not null, it points to the "new" configuration that is
061         * part of an in-process reload operation.  This configuration will
062         * definitely be loaded, but might not be started yet.  It shold never be
063         * populated outside the scope of a reload operation.
064         */
065        private Configuration reloadingConfiguration;
066    
067    
068        public SimpleConfigurationManager(Collection stores, ArtifactResolver artifactResolver, Collection repositories) {
069            this(stores, artifactResolver, repositories, Collections.EMPTY_SET);
070        }
071        
072        public SimpleConfigurationManager(Collection stores, ArtifactResolver artifactResolver, Collection repositories, Collection watchers) {
073            if (stores == null) stores = Collections.EMPTY_SET;
074            if (repositories == null) repositories = Collections.EMPTY_SET;
075            if (watchers == null) watchers = Collections.EMPTY_SET;
076    
077            this.stores = stores;
078            this.artifactResolver = artifactResolver;
079            this.repositories = repositories;
080            this.watchers = watchers;
081        }
082    
083        public synchronized boolean isInstalled(Artifact configId) {
084            if(!configId.isResolved()) {
085                throw new IllegalArgumentException("Artifact "+configId+" is not fully resolved");
086            }
087            List storeSnapshot = getStoreList();
088            for (int i = 0; i < storeSnapshot.size(); i++) {
089                ConfigurationStore store = (ConfigurationStore) storeSnapshot.get(i);
090                if(store.containsConfiguration(configId)) {
091                    return true;
092                }
093            }
094            return false;
095        }
096    
097        public synchronized boolean isLoaded(Artifact configId) {
098            if(!configId.isResolved()) {
099                throw new IllegalArgumentException("Artifact "+configId+" is not fully resolved");
100            }
101            if(reloadingConfiguration != null && reloadingConfiguration.getId().equals(configId)) {
102                return true;
103            }
104            return configurationModel.isLoaded(configId);
105        }
106    
107        public synchronized boolean isRunning(Artifact configId) {
108            if(!configId.isResolved()) {
109                throw new IllegalArgumentException("Artifact "+configId+" is not fully resolved");
110            }
111            return configurationModel.isStarted(configId);
112        }
113    
114        public Artifact[] getInstalled(Artifact query) {
115            Artifact[] all = artifactResolver.queryArtifacts(query);
116            List configs = new ArrayList();
117            for (int i = 0; i < all.length; i++) {
118                Artifact artifact = all[i];
119                if(isConfiguration(artifact)) {
120                    configs.add(artifact);
121                }
122            }
123            if(configs.size() == all.length) {
124                return all;
125            }
126            return (Artifact[]) configs.toArray(new Artifact[configs.size()]);
127        }
128    
129        public Artifact[] getLoaded(Artifact query) {
130            return configurationModel.getLoaded(query);
131        }
132    
133        public Artifact[] getRunning(Artifact query) {
134            return configurationModel.getStarted(query);
135        }
136    
137    
138        public List listStores() {
139            List storeSnapshot = getStoreList();
140            List result = new ArrayList(storeSnapshot.size());
141            for (int i = 0; i < storeSnapshot.size(); i++) {
142                ConfigurationStore store = (ConfigurationStore) storeSnapshot.get(i);
143                result.add(store.getAbstractName());
144            }
145            return result;
146        }
147    
148        public ConfigurationStore[] getStores() {
149            List storeSnapshot = getStoreList();
150            return (ConfigurationStore[]) storeSnapshot.toArray(new ConfigurationStore[storeSnapshot.size()]);
151        }
152    
153        public Collection getRepositories() {
154            return repositories;
155        }
156    
157        public List listConfigurations() {
158            List storeSnapshot = getStoreList();
159            List list = new ArrayList();
160            for (int i = 0; i < storeSnapshot.size(); i++) {
161                ConfigurationStore store = (ConfigurationStore) storeSnapshot.get(i);
162                list.addAll(listConfigurations(store));
163            }
164            return list;
165        }
166    
167        public ConfigurationStore getStoreForConfiguration(Artifact configId) {
168            if(!configId.isResolved()) {
169                throw new IllegalArgumentException("Artifact "+configId+" is not fully resolved");
170            }
171            List storeSnapshot = getStoreList();
172            for (int i = 0; i < storeSnapshot.size(); i++) {
173                ConfigurationStore store = (ConfigurationStore) storeSnapshot.get(i);
174                if(store.containsConfiguration(configId)) {
175                    return store;
176                }
177            }
178            return null;
179        }
180    
181        public List listConfigurations(AbstractName storeName) throws NoSuchStoreException {
182            List storeSnapshot = getStoreList();
183            for (int i = 0; i < storeSnapshot.size(); i++) {
184                ConfigurationStore store = (ConfigurationStore) storeSnapshot.get(i);
185                if (storeName.equals(store.getAbstractName())) {
186                    return listConfigurations(store);
187                }
188            }
189            throw new NoSuchStoreException("No such store: " + storeName);
190        }
191    
192        private List listConfigurations(ConfigurationStore store) {
193            List list = store.listConfigurations();
194            for (ListIterator iterator = list.listIterator(); iterator.hasNext();) {
195                ConfigurationInfo configurationInfo = (ConfigurationInfo) iterator.next();
196                if (isRunning(configurationInfo.getConfigID())) {
197                    configurationInfo = new ConfigurationInfo(store.getAbstractName(),
198                            configurationInfo.getConfigID(),
199                            configurationInfo.getType(),
200                            configurationInfo.getCreated(),
201                            configurationInfo.getOwnedConfigurations(),
202                            configurationInfo.getChildConfigurations(),
203                            configurationInfo.getInPlaceLocation(),
204                            State.RUNNING);
205                } else {
206                    configurationInfo = new ConfigurationInfo(store.getAbstractName(),
207                            configurationInfo.getConfigID(),
208                            configurationInfo.getType(),
209                            configurationInfo.getCreated(),
210                            configurationInfo.getOwnedConfigurations(),
211                            configurationInfo.getChildConfigurations(),
212                            configurationInfo.getInPlaceLocation(),
213                            State.STOPPED);
214                }
215                iterator.set(configurationInfo);
216            }
217            return list;
218        }
219    
220        public boolean isConfiguration(Artifact artifact) {
221            if(!artifact.isResolved()) {
222                throw new IllegalArgumentException("Artifact "+artifact+" is not fully resolved");
223            }
224            synchronized (this) {
225                // if it is loaded, it is definitely a configuration
226                if (configurations.containsKey(artifact)) {
227                    return true;
228                }
229            }
230    
231            // see if any stores think it is a configuration
232            List storeSnapshot = getStoreList();
233            for (int i = 0; i < storeSnapshot.size(); i++) {
234                ConfigurationStore store = (ConfigurationStore) storeSnapshot.get(i);
235                if (store.containsConfiguration(artifact)) {
236                    return true;
237                }
238            }
239            return false;
240        }
241    
242        public synchronized Configuration getConfiguration(Artifact configurationId) {
243            if(!configurationId.isResolved()) {
244                throw new IllegalArgumentException("Artifact "+configurationId+" is not fully resolved");
245            }
246            if(reloadingConfiguration != null && reloadingConfiguration.getId().equals(configurationId)) {
247                return reloadingConfiguration;
248            }
249            return (Configuration) configurations.get(configurationId);
250        }
251    
252        public synchronized LifecycleResults loadConfiguration(Artifact configurationId) throws NoSuchConfigException, LifecycleException {
253            return loadConfiguration(configurationId, NullLifecycleMonitor.INSTANCE);
254        }
255    
256        public synchronized LifecycleResults loadConfiguration(Artifact configurationId, LifecycleMonitor monitor) throws NoSuchConfigException, LifecycleException {
257            if(!configurationId.isResolved()) {
258                throw new IllegalArgumentException("Artifact "+configurationId+" is not fully resolved");
259            }
260            if (isLoaded(configurationId)) {
261                // already loaded, so just mark the configuration as user loaded
262                load(configurationId);
263    
264                monitor.finished();
265                return new LifecycleResults();
266            }
267    
268            // load the ConfigurationData for the new configuration
269            ConfigurationData configurationData = null;
270            try {
271                configurationData = loadConfigurationData(configurationId, monitor);
272            } catch (Exception e) {
273                monitor.finished();
274                throw new LifecycleException("load", configurationId, e);
275            }
276    
277            // load the configuration
278            LifecycleResults results = loadConfiguration(configurationData, monitor);
279    
280            return results;
281        }
282    
283        public synchronized LifecycleResults loadConfiguration(ConfigurationData configurationData) throws NoSuchConfigException, LifecycleException {
284            return loadConfiguration(configurationData, NullLifecycleMonitor.INSTANCE);
285        }
286    
287        public synchronized LifecycleResults loadConfiguration(ConfigurationData configurationData, LifecycleMonitor monitor) throws NoSuchConfigException, LifecycleException {
288            Artifact id = configurationData.getId();
289            LifecycleResults results = new LifecycleResults();
290            if (!isLoaded(id)) {
291                // recursively load configurations from the new child to the parents
292                LinkedHashMap configurationsToLoad = new LinkedHashMap();
293                try {
294                    loadDepthFirst(configurationData, configurationsToLoad, monitor);
295                } catch (Exception e) {
296                    monitor.finished();
297                    throw new LifecycleException("load", id, e);
298                }
299    
300                // load and start the unloaded the gbean for each configuration (depth first)
301                Map actuallyLoaded = new LinkedHashMap(configurationsToLoad.size());
302                Artifact configurationId = null;
303                try {
304                    for (Iterator iterator = configurationsToLoad.entrySet().iterator(); iterator.hasNext();) {
305                        Map.Entry entry = (Map.Entry) iterator.next();
306                        configurationId = (Artifact) entry.getKey();
307                        UnloadedConfiguration unloadedConfiguration = (UnloadedConfiguration) entry.getValue();
308    
309                        monitor.loading(configurationId);
310                        Configuration configuration = load(unloadedConfiguration.getConfigurationData(), unloadedConfiguration.getResolvedParentIds(), actuallyLoaded);
311                        monitor.succeeded(configurationId);
312    
313                        actuallyLoaded.put(configurationId, configuration);
314                    }
315                } catch (Exception e) {
316                    monitor.failed(configurationId, e);
317    
318                    // there was a problem, so we need to unload all configurations that were actually loaded
319                    for (Iterator iterator = actuallyLoaded.values().iterator(); iterator.hasNext();) {
320                        Configuration configuration = (Configuration) iterator.next();
321                        unload(configuration);
322                    }
323    
324                    monitor.finished();
325                    throw new LifecycleException("load", id, e);
326                }
327    
328                // update the status of the loaded configurations
329                addNewConfigurationsToModel(actuallyLoaded);
330                results.setLoaded(actuallyLoaded.keySet());
331            }
332            load(id);
333            monitor.finished();
334            return results;
335        }
336    
337        protected void load(Artifact configurationId) throws NoSuchConfigException {
338            configurationModel.load(configurationId);
339        }
340    
341        protected Configuration load(ConfigurationData configurationData, LinkedHashSet resolvedParentIds, Map loadedConfigurations) throws InvalidConfigException {
342            Artifact configurationId = configurationData.getId();
343            try {
344                Collection parents = findParentConfigurations(resolvedParentIds, loadedConfigurations);
345    
346                Configuration configuration = new Configuration(parents, configurationData, new ConfigurationResolver(configurationData, repositories, artifactResolver), null);
347                configuration.doStart();
348                return configuration;
349            } catch (Exception e) {
350                throw new InvalidConfigException("Error starting configuration gbean " + configurationId, e);
351            }
352        }
353    
354        private Collection findParentConfigurations(LinkedHashSet resolvedParentIds, Map loadedConfigurations) throws InvalidConfigException {
355            LinkedHashMap parents = new LinkedHashMap();
356            for (Iterator iterator = resolvedParentIds.iterator(); iterator.hasNext();) {
357                Artifact resolvedArtifact = (Artifact) iterator.next();
358    
359                Configuration parent = null;
360                if (loadedConfigurations.containsKey(resolvedArtifact)) {
361                    parent = (Configuration) loadedConfigurations.get(resolvedArtifact);
362                } else if (isLoaded(resolvedArtifact)) {
363                    parent = getConfiguration(resolvedArtifact);
364                } else {
365                    throw new InvalidConfigException("Cound not find parent configuration: " + resolvedArtifact);
366                }
367    
368                parents.put(resolvedArtifact, parent);
369            }
370            return parents.values();
371        }
372    
373        private void addNewConfigurationsToModel(Map loadedConfigurations) throws NoSuchConfigException {
374            for (Iterator iterator = loadedConfigurations.values().iterator(); iterator.hasNext();) {
375                Configuration configuration = (Configuration) iterator.next();
376                addNewConfigurationToModel(configuration);
377            }
378        }
379    
380        protected void addNewConfigurationToModel(Configuration configuration) throws NoSuchConfigException {
381            configurationModel.addConfiguation(configuration.getId(),
382                    getConfigurationIds(getLoadParents(configuration)),
383                    getConfigurationIds(getStartParents(configuration)));
384            configurations.put(configuration.getId(), configuration);
385        }
386    
387        protected LinkedHashSet getLoadParents(Configuration configuration) {
388            LinkedHashSet loadParent = new LinkedHashSet(configuration.getClassParents());
389            for (Iterator iterator = configuration.getChildren().iterator(); iterator.hasNext();) {
390                Configuration childConfiguration = (Configuration) iterator.next();
391                LinkedHashSet childLoadParent = getLoadParents(childConfiguration);
392    
393                // remove this configuration from the parent Ids since it will cause an infinite loop
394                childLoadParent.remove(configuration);
395    
396                loadParent.addAll(childLoadParent);
397            }
398            return loadParent;
399        }
400    
401        protected LinkedHashSet getStartParents(Configuration configuration) {
402            LinkedHashSet startParent = new LinkedHashSet(configuration.getServiceParents());
403            for (Iterator iterator = configuration.getChildren().iterator(); iterator.hasNext();) {
404                Configuration childConfiguration = (Configuration) iterator.next();
405                LinkedHashSet childStartParent = getStartParents(childConfiguration);
406    
407                // remove this configuration from the parent Ids since it will cause an infinite loop
408                childStartParent.remove(configuration);
409    
410                startParent.addAll(childStartParent);
411            }
412            return startParent;
413        }
414    
415        private static LinkedHashSet getConfigurationIds(Collection configurations) {
416            LinkedHashSet configurationIds = new LinkedHashSet(configurations.size());
417            for (Iterator iterator = configurations.iterator(); iterator.hasNext();) {
418                Configuration configuration = (Configuration) iterator.next();
419                configurationIds.add(configuration.getId());
420            }
421            return configurationIds;
422        }
423    
424        private synchronized void loadDepthFirst(ConfigurationData configurationData, LinkedHashMap configurationsToLoad, LifecycleMonitor monitor) throws NoSuchConfigException, IOException, InvalidConfigException, MissingDependencyException {
425            // if this parent hasn't already been processed, iterate into the parent
426            Artifact configurationId = configurationData.getId();
427            if (!configurationsToLoad.containsKey(configurationId)) {
428                LinkedHashSet resolvedParentIds = resolveParentIds(configurationData);
429    
430                for (Iterator iterator = resolvedParentIds.iterator(); iterator.hasNext();) {
431                    Artifact parentId = (Artifact) iterator.next();
432                    // if this parent id hasn't already been loaded and is actually a configuration
433                    if (!isLoaded(parentId) && isConfiguration(parentId)) {
434                        ConfigurationData parentConfigurationData = loadConfigurationData(parentId, monitor);
435                        loadDepthFirst(parentConfigurationData, configurationsToLoad, monitor);
436                    }
437                }
438    
439                // depth first - all unloaded parents have been added, now add this configuration
440                configurationsToLoad.put(configurationId, new UnloadedConfiguration(configurationData, resolvedParentIds));
441            }
442        }
443    
444        private ConfigurationData loadConfigurationData(Artifact configurationId, LifecycleMonitor monitor) throws NoSuchConfigException, IOException, InvalidConfigException {
445            List storeSnapshot = getStoreList();
446    
447            monitor.addConfiguration(configurationId);
448            monitor.reading(configurationId);
449            for (int i = 0; i < storeSnapshot.size(); i++) {
450                ConfigurationStore store = (ConfigurationStore) storeSnapshot.get(i);
451                if (store.containsConfiguration(configurationId)) {
452                    ConfigurationData configurationData = store.loadConfiguration(configurationId);
453                    monitor.succeeded(configurationId);
454                    return configurationData;
455                }
456            }
457            NoSuchConfigException exception = new NoSuchConfigException(configurationId);
458            monitor.failed(configurationId, exception);
459            throw exception;
460        }
461    
462        private LinkedHashSet<Artifact> resolveParentIds(ConfigurationData configurationData) throws MissingDependencyException, InvalidConfigException {
463            Environment environment = configurationData.getEnvironment();
464    
465            LinkedHashSet<Artifact> parentIds = new LinkedHashSet<Artifact>();
466            List<Dependency> dependencies = new ArrayList<Dependency>(environment.getDependencies());
467            for (ListIterator<Dependency> iterator = dependencies.listIterator(); iterator.hasNext();) {
468                Dependency dependency = iterator.next();
469                Artifact resolvedArtifact = artifactResolver.resolveInClassLoader(dependency.getArtifact());
470                if (isConfiguration(resolvedArtifact)) {
471                    parentIds.add(resolvedArtifact);
472    
473                    // update the dependency list to contain the resolved artifact
474                    dependency = new Dependency(resolvedArtifact, dependency.getImportType());
475                    iterator.set(dependency);
476                } else if (dependency.getImportType() == ImportType.SERVICES) {
477                    // Service depdendencies require that the depdencency be a configuration
478                    throw new InvalidConfigException("Dependency does not have services: " + resolvedArtifact);
479                }
480            }
481    
482            for (Iterator iterator = configurationData.getChildConfigurations().values().iterator(); iterator.hasNext();) {
483                ConfigurationData childConfigurationData = (ConfigurationData) iterator.next();
484                LinkedHashSet<Artifact> childParentIds = resolveParentIds(childConfigurationData);
485                // remove this configuration's id from the parent Ids since it will cause an infinite loop
486                childParentIds.remove(configurationData.getId());
487                parentIds.addAll(childParentIds);
488            }
489            return parentIds;
490        }
491    
492        private static class UnloadedConfiguration {
493            private final ConfigurationData configurationData;
494            private final LinkedHashSet resolvedParentIds;
495    
496            public UnloadedConfiguration(ConfigurationData configurationData, LinkedHashSet resolvedParentIds) {
497                this.configurationData = configurationData;
498                this.resolvedParentIds = resolvedParentIds;
499            }
500    
501            public ConfigurationData getConfigurationData() {
502                return configurationData;
503            }
504    
505            public LinkedHashSet getResolvedParentIds() {
506                return resolvedParentIds;
507            }
508        }
509    
510        public synchronized LifecycleResults startConfiguration(Artifact id) throws NoSuchConfigException, LifecycleException {
511            return startConfiguration(id, NullLifecycleMonitor.INSTANCE);
512        }
513    
514        public synchronized LifecycleResults startConfiguration(Artifact id, LifecycleMonitor monitor) throws  NoSuchConfigException, LifecycleException {
515            if(!id.isResolved()) {
516                throw new IllegalArgumentException("Artifact "+id+" is not fully resolved");
517            }
518            LinkedHashSet unstartedConfigurations = configurationModel.start(id);
519    
520            addConfigurationsToMonitor(monitor, unstartedConfigurations);
521    
522            LifecycleResults results = new LifecycleResults();
523            Artifact configurationId = null;
524            try {
525                for (Iterator iterator = unstartedConfigurations.iterator(); iterator.hasNext();) {
526                    configurationId = (Artifact) iterator.next();
527                    Configuration configuration = getConfiguration(configurationId);
528    
529                    monitor.starting(configurationId);
530                    start(configuration);
531                    monitor.succeeded(configurationId);
532    
533                    results.addStarted(configurationId);
534                }
535            } catch (Exception e) {
536                monitor.failed(configurationId, e);
537                configurationModel.stop(id);
538    
539                for (Iterator iterator = results.getStarted().iterator(); iterator.hasNext();) {
540                    configurationId = (Artifact) iterator.next();
541                    Configuration configuration = getConfiguration(configurationId);
542                    monitor.stopping(configurationId);
543                    stop(configuration);
544                    monitor.succeeded(configurationId);
545                }
546                monitor.finished();
547                throw new LifecycleException("start", id, e);
548            }
549            monitor.finished();
550            return results;
551        }
552    
553        protected void start(Configuration configuration) throws Exception {
554            throw new UnsupportedOperationException();
555        }
556    
557        public synchronized LifecycleResults stopConfiguration(Artifact id) throws NoSuchConfigException {
558            return stopConfiguration(id, NullLifecycleMonitor.INSTANCE);
559        }
560    
561        public synchronized LifecycleResults stopConfiguration(Artifact id, LifecycleMonitor monitor) throws NoSuchConfigException {
562            if(!id.isResolved()) {
563                throw new IllegalArgumentException("Artifact "+id+" is not fully resolved");
564            }
565            LinkedHashSet stopList = configurationModel.stop(id);
566    
567            addConfigurationsToMonitor(monitor, stopList);
568    
569            LifecycleResults results = new LifecycleResults();
570            for (Iterator iterator = stopList.iterator(); iterator.hasNext();) {
571                Artifact configurationId = (Artifact) iterator.next();
572                Configuration configuration = getConfiguration(configurationId);
573    
574                monitor.stopping(configurationId);
575                stop(configuration);
576                monitor.succeeded(configurationId);
577    
578                results.addStopped(configurationId);
579            }
580    
581            monitor.finished();
582            return results;
583        }
584    
585        protected void stop(Configuration configuration) {
586            // Don't throw an exception because we call this from unload to be sure that all
587            // unloaded configurations are stopped first
588        }
589    
590        public synchronized LifecycleResults restartConfiguration(Artifact id) throws NoSuchConfigException, LifecycleException {
591            return restartConfiguration(id, NullLifecycleMonitor.INSTANCE);
592        }
593    
594        public synchronized LifecycleResults restartConfiguration(Artifact id, LifecycleMonitor monitor) throws NoSuchConfigException, LifecycleException {
595            if(!id.isResolved()) {
596                throw new IllegalArgumentException("Artifact "+id+" is not fully resolved");
597            }
598            // get a sorted list of configurations to restart
599            LinkedHashSet restartList = configurationModel.restart(id);
600    
601            addConfigurationsToMonitor(monitor, restartList);
602    
603            // stop the configuations
604            LifecycleResults results = new LifecycleResults();
605            for (Iterator iterator = restartList.iterator(); iterator.hasNext();) {
606                Artifact configurationId = (Artifact) iterator.next();
607                Configuration configuration = getConfiguration(configurationId);
608                monitor.stopping(configurationId);
609                stop(configuration);
610                monitor.succeeded(configurationId);
611                results.addStopped(configurationId);
612            }
613    
614            // reverse the list
615            restartList = reverse(restartList);
616    
617            // restart the configurations
618            Set skip = new HashSet();
619            for (Iterator iterator = restartList.iterator(); iterator.hasNext();) {
620                Artifact configurationId = (Artifact) iterator.next();
621    
622                // skip the configurations that have alredy failed or are children of failed configurations
623                if (skip.contains(configurationId)) {
624                    continue;
625                }
626    
627                // try to start the configuation
628                try {
629                    Configuration configuration = getConfiguration(configurationId);
630                    monitor.starting(configurationId);
631                    start(configuration);
632                    monitor.succeeded(configurationId);
633                    results.addStarted(configurationId);
634                } catch (Exception e) {
635                    // the configuraiton failed to restart
636                    results.addFailed(configurationId, e);
637                    monitor.failed(configurationId, e);
638                    skip.add(configurationId);
639    
640                    // officially stop the configuration in the model (without gc)
641                    LinkedHashSet stopList = configurationModel.stop(configurationId, false);
642    
643                    // all of the configurations to be stopped must be in our restart list, or the model is corrupt
644                    if (!restartList.containsAll(stopList)) {
645                        throw new AssertionError("Configuration data model is corrupt.   You must restart your server.");
646                    }
647    
648                    // add the children of the failed configuration to the results as stopped
649                    for (Iterator iterator1 = stopList.iterator(); iterator1.hasNext();) {
650                        Artifact failedId = (Artifact) iterator1.next();
651    
652                        // if any of the failed configuration is in the restarted set, the model is
653                        // corrupt because we started a child before a parent
654                        if (results.wasStarted(failedId)) {
655                            throw new AssertionError("Configuration data model is corrupt.   You must restart your server.");
656                        }
657    
658                        skip.add(failedId);
659                    }
660                }
661            }
662    
663            monitor.finished();
664            if (!results.wasStarted(id)) {
665                throw new LifecycleException("restart", id, results);
666            }
667            return results;
668        }
669    
670        public synchronized LifecycleResults unloadConfiguration(Artifact id) throws NoSuchConfigException {
671            return unloadConfiguration(id, NullLifecycleMonitor.INSTANCE);
672        }
673    
674        public synchronized LifecycleResults unloadConfiguration(Artifact id, LifecycleMonitor monitor) throws NoSuchConfigException {
675            if(!id.isResolved()) {
676                throw new IllegalArgumentException("Artifact "+id+" is not fully resolved");
677            }
678            Set started = configurationModel.getStarted();
679            LinkedHashSet unloadList = configurationModel.unload(id);
680    
681            addConfigurationsToMonitor(monitor, unloadList);
682    
683            LifecycleResults results = new LifecycleResults();
684            for (Iterator iterator = unloadList.iterator(); iterator.hasNext();) {
685                Artifact configurationId = (Artifact) iterator.next();
686                Configuration configuration = getConfiguration(configurationId);
687    
688                // first make sure it is stopped
689                if (started.contains(configurationId)) {
690                    monitor.stopping(configurationId);
691                    stop(configuration);
692                    monitor.succeeded(configurationId);
693                    results.addStopped(configurationId);
694                } else {
695                    // call stop just to be sure the beans aren't running
696                    stop(configuration);
697                }
698    
699                // now unload it
700                monitor.unloading(configurationId);
701                unload(configuration);
702                monitor.succeeded(configurationId);
703                results.addUnloaded(configurationId);
704    
705                // clean up the model
706                removeConfigurationFromModel(configurationId);
707            }
708            monitor.finished();
709            return results;
710        }
711    
712        protected void removeConfigurationFromModel(Artifact configurationId) throws NoSuchConfigException {
713            if(configurationModel.containsConfiguration(configurationId)) {
714                configurationModel.removeConfiguration(configurationId);
715            }
716            configurations.remove(configurationId);
717        }
718    
719        protected void unload(Configuration configuration) {
720            try {
721                configuration.doStop();
722            } catch (Exception e) {
723                log.debug("Problem unloading config: " + configuration.getId(), e);
724            }
725        }
726    
727        public synchronized LifecycleResults reloadConfiguration(Artifact id) throws NoSuchConfigException, LifecycleException {
728            return reloadConfiguration(id, NullLifecycleMonitor.INSTANCE);
729        }
730    
731        public synchronized LifecycleResults reloadConfiguration(Artifact id, LifecycleMonitor monitor) throws NoSuchConfigException, LifecycleException {
732            return reloadConfiguration(id, id.getVersion(), monitor);
733        }
734    
735        public synchronized LifecycleResults reloadConfiguration(Artifact id, Version version) throws NoSuchConfigException, LifecycleException {
736            return reloadConfiguration(id, version, NullLifecycleMonitor.INSTANCE);
737        }
738    
739        public synchronized LifecycleResults reloadConfiguration(Artifact id, Version version, LifecycleMonitor monitor) throws NoSuchConfigException, LifecycleException {
740            if(!id.isResolved()) {
741                throw new IllegalArgumentException("Artifact "+id+" is not fully resolved");
742            }
743            Configuration configuration = getConfiguration(id);
744            if (configuration == null) { // The configuration to reload is not currently loaded
745                ConfigurationData data = null;
746                List storeSnapshot = getStoreList();
747                for (int i = 0; i < storeSnapshot.size(); i++) {
748                    ConfigurationStore store = (ConfigurationStore) storeSnapshot.get(i);
749                    if (store.containsConfiguration(id)) {
750                        try {
751                            data = store.loadConfiguration(id);
752                        } catch (Exception e) {
753                            log.warn("Unable to load existing configuration "+id+" from config store", e);
754                        }
755                    }
756                }
757                if(data == null) {
758                    throw new NoSuchConfigException(id);
759                }
760                UnloadedConfiguration existingUnloadedConfiguration = new UnloadedConfiguration(data, new LinkedHashSet());
761                Artifact newId = new Artifact(id.getGroupId(), id.getArtifactId(), version, id.getType());
762                ConfigurationData newData = null;
763                try {
764                    newData = loadConfigurationData(newId, monitor);
765                } catch (Exception e) {
766                    monitor.finished();
767                    throw new LifecycleException("reload", id, e);
768                }
769    
770                return reloadConfiguration(existingUnloadedConfiguration, newData, monitor);
771            } else { // The configuration to reload is loaded
772                ConfigurationData existingConfigurationData = configuration.getConfigurationData();
773                UnloadedConfiguration existingUnloadedConfiguration = new UnloadedConfiguration(existingConfigurationData, getResolvedParentIds(configuration));
774    
775                Artifact newId = new Artifact(id.getGroupId(), id.getArtifactId(), version, id.getType());
776    
777                // reload the ConfigurationData from a store
778                ConfigurationData configurationData = null;
779                try {
780                    configurationData = loadConfigurationData(newId, monitor);
781                } catch (Exception e) {
782                    monitor.finished();
783                    throw new LifecycleException("reload", id, e);
784                }
785    
786                return reloadConfiguration(existingUnloadedConfiguration, configurationData, monitor);
787            }
788        }
789    
790        public synchronized LifecycleResults reloadConfiguration(ConfigurationData configurationData) throws LifecycleException, NoSuchConfigException {
791            return reloadConfiguration(configurationData, NullLifecycleMonitor.INSTANCE);
792        }
793    
794        public synchronized LifecycleResults reloadConfiguration(ConfigurationData configurationData, LifecycleMonitor monitor) throws LifecycleException, NoSuchConfigException {
795            Configuration configuration = getConfiguration(configurationData.getId());
796            if (configuration == null) {
797                throw new NoSuchConfigException(configurationData.getId());
798            }
799            ConfigurationData existingConfigurationData = configuration.getConfigurationData();
800            UnloadedConfiguration existingUnloadedConfiguration = new UnloadedConfiguration(existingConfigurationData, getResolvedParentIds(configuration));
801            return reloadConfiguration(existingUnloadedConfiguration, configurationData, monitor);
802        }
803    
804        private boolean hasHardDependency(Artifact configurationId, ConfigurationData configurationData) {
805            for (Iterator iterator = configurationData.getEnvironment().getDependencies().iterator(); iterator.hasNext();) {
806                Dependency dependency = (Dependency) iterator.next();
807                Artifact artifact = dependency.getArtifact();
808                if (artifact.getVersion() != null && artifact.matches(configurationId)) {
809                    return true;
810                }
811            }
812    
813            for (Iterator iterator = configurationData.getChildConfigurations().values().iterator(); iterator.hasNext();) {
814                ConfigurationData childConfigurationData = (ConfigurationData) iterator.next();
815                if (hasHardDependency(configurationId, childConfigurationData)) {
816                    return true;
817                }
818            }
819            return false;
820        }
821    
822        // todo this method ignores garbage collection of configurations
823        private LifecycleResults reloadConfiguration(UnloadedConfiguration existingUnloadedConfiguration, ConfigurationData newConfigurationData, LifecycleMonitor monitor) throws LifecycleException, NoSuchConfigException {
824            boolean force = false;
825    
826            Artifact existingConfigurationId = existingUnloadedConfiguration.getConfigurationData().getId();
827            Artifact newConfigurationId = newConfigurationData.getId();
828    
829            //
830            // recursively load the new configuration; this will catch any new parents
831            //
832            LinkedHashMap newConfigurations = new LinkedHashMap();
833            try {
834                loadDepthFirst(newConfigurationData, newConfigurations, monitor);
835            } catch (Exception e) {
836                monitor.finished();
837                throw new LifecycleException("reload", newConfigurationId, e);
838            }
839    
840            //
841            // get a list of the started configuration, so we can restart them later
842            //
843            Set started = configurationModel.getStarted();
844    
845            //
846            // get a list of the child configurations that will need to reload
847            //
848            //   note: we are iterating in reverse order
849            LinkedHashMap existingParents = new LinkedHashMap();
850            LinkedHashMap reloadChildren = new LinkedHashMap();
851            for (Iterator iterator = reverse(configurationModel.reload(existingConfigurationId)).iterator(); iterator.hasNext();) {
852                Artifact configurationId = (Artifact) iterator.next();
853    
854                if (configurationId.equals(existingConfigurationId)) {
855                    continue;
856                }
857    
858                // if new configurations contains the child something we have a circular dependency
859                if (newConfigurations.containsKey(configurationId)) {
860                    throw new LifecycleException("reload", newConfigurationId,
861                            new IllegalStateException("Circular depenency between " + newConfigurationId + " and " + configurationId));
862                }
863    
864                Configuration configuration = getConfiguration(configurationId);
865                ConfigurationData configurationData = configuration.getConfigurationData();
866    
867                // save off the exising resolved parent ids in case we need to restore this configuration
868                LinkedHashSet existingParentIds = getResolvedParentIds(configuration);
869                existingParents.put(configurationId, existingParentIds);
870    
871                // check that the child doen't have a hard dependency on the old configuration
872                LinkedHashSet resolvedParentIds = null;
873                if (hasHardDependency(existingConfigurationId, configurationData)) {
874                    if (force) {
875                        throw new LifecycleException("reload", newConfigurationId,
876                                new IllegalStateException("Existing configuration " + configurationId + " has a hard dependency on the current version of this configuration " + existingConfigurationId));
877                    }
878    
879                    // we leave the resolved parent ids null to signal that we should not reload the configuration
880                    resolvedParentIds = null;
881                } else {
882                    resolvedParentIds = new LinkedHashSet(existingParentIds);
883                    resolvedParentIds.remove(existingConfigurationId);
884                    resolvedParentIds.add(newConfigurationId);
885                }
886    
887                reloadChildren.put(configurationId, new UnloadedConfiguration(configurationData, resolvedParentIds));
888                monitor.addConfiguration(configurationId);
889            }
890    
891            //
892            // unload the children
893            //
894    
895            // note: we are iterating in reverse order
896            LifecycleResults results = new LifecycleResults();
897            for (Iterator iterator = reverse(reloadChildren).keySet().iterator(); iterator.hasNext();) {
898                Artifact configurationId = (Artifact) iterator.next();
899                Configuration configuration = getConfiguration(configurationId);
900    
901                // first make sure it is stopped
902                if (started.contains(configurationId)) {
903                    monitor.stopping(configurationId);
904                    stop(configuration);
905                    monitor.succeeded(configurationId);
906                    results.addStopped(configurationId);
907                } else {
908                    // call stop just to be sure the beans aren't running
909                    stop(configuration);
910                }
911    
912                // now unload it
913                monitor.unloading(configurationId);
914                unload(configuration);
915                monitor.succeeded(configurationId);
916                results.addUnloaded(configurationId);
917            }
918    
919            //
920            // unload the existing config
921            //
922            Configuration existingConfiguration = getConfiguration(existingConfigurationId);
923            if (started.contains(existingConfigurationId)) {
924                monitor.stopping(existingConfigurationId);
925                stop(existingConfiguration);
926                monitor.succeeded(existingConfigurationId);
927                results.addStopped(existingConfigurationId);
928            } else if(existingConfiguration != null) {
929                // call stop just to be sure the beans aren't running
930                stop(existingConfiguration);
931            }
932            if(existingConfiguration != null) {
933                monitor.unloading(existingConfigurationId);
934                unload(existingConfiguration);
935                monitor.succeeded(existingConfigurationId);
936                results.addUnloaded(existingConfigurationId);
937            }
938    
939            //
940            // load the new configurations
941            //
942            boolean reinstatedExisting = false;
943            /* reduce variable scope */ {
944                Map loadedParents = new LinkedHashMap();
945                Map startedParents = new LinkedHashMap();
946                Configuration newConfiguration = null;
947                Artifact configurationId = null;
948                try {
949                    //
950                    // load all of the new configurations
951                    //
952                    for (Iterator iterator = newConfigurations.entrySet().iterator(); iterator.hasNext();) {
953                        Map.Entry entry = (Map.Entry) iterator.next();
954                        configurationId = (Artifact) entry.getKey();
955                        UnloadedConfiguration unloadedConfiguration = (UnloadedConfiguration) entry.getValue();
956    
957                        monitor.loading(configurationId);
958                        Configuration configuration = load(unloadedConfiguration.getConfigurationData(), unloadedConfiguration.getResolvedParentIds(), loadedParents);
959                        monitor.succeeded(configurationId);
960    
961                        if (configurationId.equals(newConfigurationId)) {
962                            newConfiguration = configuration;
963                            reloadingConfiguration = configuration;
964                        } else {
965                            loadedParents.put(configurationId, configuration);
966                        }
967                    }
968    
969                    if (newConfiguration == null) {
970                        AssertionError cause = new AssertionError("Internal error: configuration was not load");
971                        results.addFailed(newConfigurationId, cause);
972                        throw new LifecycleException("reload", newConfigurationId, results);
973                    }
974    
975                    //
976                    // start the new configurations if the old one was running
977                    //
978                    if (started.contains(existingConfigurationId)) {
979    
980                        // determine which of the parents we need to start
981                        LinkedHashSet startList = new LinkedHashSet();
982                        for (Iterator iterator = getStartParents(newConfiguration).iterator(); iterator.hasNext();) {
983                            Configuration serviceParent = (Configuration) iterator.next();
984                            if (loadedParents.containsKey(serviceParent.getId())) {
985                                startList.add(serviceParent);
986                            }
987                        }
988    
989                        // start the new parents
990                        for (Iterator iterator = startList.iterator(); iterator.hasNext();) {
991                            Configuration startParent = (Configuration) iterator.next();
992                            monitor.starting(configurationId);
993                            start(startParent);
994                            monitor.succeeded(configurationId);
995    
996                            startedParents.put(configurationId, startParent);
997                        }
998    
999                        //  start the new configuration
1000                        monitor.starting(newConfigurationId);
1001                        start(newConfiguration);
1002                        monitor.succeeded(newConfigurationId);
1003                    }
1004    
1005                    //
1006                    // update the results
1007                    //
1008                    results.setLoaded(loadedParents.keySet());
1009                    results.addLoaded(newConfigurationId);
1010                    if (started.contains(existingConfigurationId)) {
1011                        results.setStarted(startedParents.keySet());
1012                        results.addStarted(newConfigurationId);
1013                    }
1014    
1015                    //
1016                    // update the model
1017                    //
1018    
1019                    // add all of the new configurations the model
1020                    addNewConfigurationsToModel(loadedParents);
1021    
1022                    // now ugrade the existing node in the model
1023                    if(configurationModel.containsConfiguration(existingConfigurationId)) {
1024                        configurationModel.upgradeConfiguration(existingConfigurationId,
1025                                newConfigurationId,
1026                                getConfigurationIds(getLoadParents(newConfiguration)),
1027                                getConfigurationIds(getStartParents(newConfiguration)));
1028                    } else {
1029                        configurationModel.addConfiguation(newConfigurationId,
1030                                getConfigurationIds(getLoadParents(newConfiguration)),
1031                                getConfigurationIds(getStartParents(newConfiguration)));
1032                        load(newConfigurationId);
1033                    }
1034    
1035                    // replace the configuraiton in he configurations map
1036                    configurations.remove(existingConfiguration);
1037                    configurations.put(newConfigurationId, newConfiguration);
1038    
1039                    // migrate the configuration settings
1040                    migrateConfiguration(existingConfigurationId, newConfigurationId, newConfiguration, started.contains(existingConfigurationId));
1041                } catch (Exception e) {
1042                    monitor.failed(configurationId, e);
1043                    results.addFailed(configurationId, e);
1044    
1045                    //
1046                    // stop and unload all configurations that were actually loaded
1047                    //
1048                    for (Iterator iterator = startedParents.values().iterator(); iterator.hasNext();) {
1049                        Configuration configuration = (Configuration) iterator.next();
1050                        stop(configuration);
1051                    }
1052                    for (Iterator iterator = loadedParents.values().iterator(); iterator.hasNext();) {
1053                        Configuration configuration = (Configuration) iterator.next();
1054                        unload(configuration);
1055                    }
1056    
1057                    // stop and unload the newConfiguration
1058                    if (newConfiguration != null) {
1059                        stop(newConfiguration);
1060                        unload(newConfiguration);
1061                    }
1062    
1063                    //
1064                    // atempt to reinstate the old configuation
1065                    //
1066                    Configuration configuration = null;
1067                    try {
1068                        configuration = load(existingUnloadedConfiguration.getConfigurationData(),
1069                                existingUnloadedConfiguration.getResolvedParentIds(),
1070                                Collections.EMPTY_MAP);
1071                        reloadingConfiguration = configuration;
1072                        // if the configuration was started before restart it
1073                        if (started.contains(existingConfigurationId)) {
1074                            start(configuration);
1075                            results.addStarted(existingConfigurationId);
1076                        }
1077    
1078                        // don't mark as loded until start completes as it may thorw an exception
1079                        results.addLoaded(existingConfigurationId);
1080    
1081                        configurations.put(existingConfigurationId, configuration);
1082    
1083                        reinstatedExisting = true;
1084                    } catch (Exception ignored) {
1085                        monitor.failed(existingConfigurationId, e);
1086    
1087                        // we tried our best
1088                        if (configuration != null) {
1089                            unload(configuration);
1090                        }
1091    
1092                        //
1093                        // cleanup the model
1094                        //
1095                        for (Iterator iterator = results.getUnloaded().iterator(); iterator.hasNext();) {
1096                            Artifact childId = (Artifact) iterator.next();
1097                            configurationModel.unload(childId);
1098                            removeConfigurationFromModel(childId);
1099                        }
1100    
1101                        throw new LifecycleException("reload", newConfigurationId, results);
1102                    }
1103                } finally {
1104                    reloadingConfiguration = null;
1105                }
1106            }
1107    
1108            //
1109            // reload as many child configurations as possible
1110            //
1111            Set skip = new HashSet();
1112            for (Iterator iterator = reloadChildren.entrySet().iterator(); iterator.hasNext();) {
1113                Map.Entry entry = (Map.Entry) iterator.next();
1114                Artifact configurationId = (Artifact) entry.getKey();
1115                UnloadedConfiguration unloadedConfiguration = (UnloadedConfiguration) entry.getValue();
1116    
1117                // skip the configurations that have alredy failed or are children of failed configurations
1118                if (skip.contains(configurationId)) {
1119                    continue;
1120                }
1121    
1122                // try to load the configuation
1123                Configuration configuration = null;
1124                try {
1125                    // get the correct resolved parent ids based on if we are loading with the new config id or the existing one
1126                    LinkedHashSet resolvedParentIds;
1127                    if (!reinstatedExisting) {
1128                        resolvedParentIds = unloadedConfiguration.getResolvedParentIds();
1129                    } else {
1130                        resolvedParentIds = (LinkedHashSet) existingParents.get(configurationId);
1131                    }
1132    
1133                    // if the resolved parent ids is null, then we are not supposed to reload this configuration
1134                    if (resolvedParentIds != null) {
1135                        monitor.loading(configurationId);
1136                        configuration = load(unloadedConfiguration.getConfigurationData(), resolvedParentIds, Collections.EMPTY_MAP);
1137                        reloadingConfiguration = configuration;
1138                        monitor.succeeded(configurationId);
1139    
1140    
1141                        // if the configuration was started before restart it
1142                        if (started.contains(configurationId)) {
1143                            monitor.starting(configurationId);
1144                            start(configuration);
1145                            monitor.succeeded(configurationId);
1146                            results.addStarted(configurationId);
1147                        }
1148    
1149                        // don't mark as loded until start completes as it may thow an exception
1150                        results.addLoaded(configurationId);
1151    
1152                        configurations.put(configurationId, configuration);
1153                    } else {
1154                        removeConfigurationFromModel(configurationId);
1155                    }
1156                } catch (Exception e) {
1157                    // the configuraiton failed to restart
1158                    results.addFailed(configurationId, e);
1159                    monitor.failed(configurationId, e);
1160                    skip.add(configurationId);
1161    
1162                    // unload the configuration if it was loaded and failed in start
1163                    if (configuration != null) {
1164                        unload(configuration);
1165                    }
1166    
1167                    // officially unload the configuration in the model (without gc)
1168                    LinkedHashSet unloadList = configurationModel.unload(configurationId, false);
1169                    configurationModel.removeConfiguration(configurationId);
1170    
1171                    // all of the configurations to be unloaded must be in our unloaded list, or the model is corrupt
1172                    if (!reloadChildren.keySet().containsAll(unloadList)) {
1173                        throw new AssertionError("Configuration data model is corrupt.   You must restart your server.");
1174                    }
1175    
1176                    // add the children of the failed configuration to the results as unloaded
1177                    for (Iterator iterator1 = unloadList.iterator(); iterator1.hasNext();) {
1178                        Artifact failedId = (Artifact) iterator1.next();
1179    
1180                        // if any of the failed configuration are in the reloaded set, the model is
1181                        // corrupt because we loaded a child before a parent
1182                        if (results.wasLoaded(failedId)) {
1183                            throw new AssertionError("Configuration data model is corrupt.   You must restart your server.");
1184                        }
1185    
1186                        skip.add(failedId);
1187                    }
1188                } finally {
1189                    reloadingConfiguration = null;
1190                }
1191            }
1192    
1193            //
1194            // If nothing failed, delete all the unloaded modules that weren't reloaded
1195            //
1196            if(!results.wasLoaded(existingConfigurationId) && !results.wasFailed(existingConfigurationId)) {
1197                try {
1198                    uninstallConfiguration(existingConfigurationId);
1199                } catch (IOException e) {
1200                    log.error("Unable to uninstall configuration "+existingConfigurationId, e);
1201                }
1202            }
1203    
1204            monitor.finished();
1205            if (results.wasFailed(newConfigurationId) || !results.wasLoaded(newConfigurationId)) {
1206                throw new LifecycleException("restart", newConfigurationId, results);
1207            }
1208            return results;
1209        }
1210    
1211        protected void migrateConfiguration(Artifact oldName, Artifact newName, Configuration configuration, boolean running) throws NoSuchConfigException {
1212        }
1213    
1214        private static LinkedHashSet getResolvedParentIds(Configuration configuration) {
1215            LinkedHashSet resolvedParentIds = new LinkedHashSet();
1216            for (Iterator iterator = configuration.getClassParents().iterator(); iterator.hasNext();) {
1217                Configuration classParent = (Configuration) iterator.next();
1218                resolvedParentIds.add(classParent.getId());
1219            }
1220            for (Iterator iterator = configuration.getServiceParents().iterator(); iterator.hasNext();) {
1221                Configuration serviceParent = (Configuration) iterator.next();
1222                resolvedParentIds.add(serviceParent.getId());
1223            }
1224            for (Iterator iterator = configuration.getChildren().iterator(); iterator.hasNext();) {
1225                Configuration child = (Configuration) iterator.next();
1226                resolvedParentIds.addAll(getResolvedParentIds(child));
1227            }
1228    
1229            return resolvedParentIds;
1230        }
1231    
1232        public synchronized void uninstallConfiguration(Artifact configurationId) throws IOException, NoSuchConfigException {
1233            if(!configurationId.isResolved()) {
1234                throw new IllegalArgumentException("Artifact "+configurationId+" is not fully resolved");
1235            }
1236            if (configurations.containsKey(configurationId)) {
1237                if(isRunning(configurationId)) {
1238                    stopConfiguration(configurationId);
1239                }
1240                if(isLoaded((configurationId))) {
1241                    unloadConfiguration(configurationId);
1242                }
1243            }
1244    
1245            uninstall(configurationId);
1246            List storeSnapshot = getStoreList();
1247            for (int i = 0; i < storeSnapshot.size(); i++) {
1248                ConfigurationStore store = (ConfigurationStore) storeSnapshot.get(i);
1249                if(store.containsConfiguration(configurationId)) {
1250                    store.uninstall(configurationId);
1251                }
1252            }
1253    
1254            removeConfigurationFromModel(configurationId);
1255            notifyWatchers(configurationId);
1256        }
1257    
1258        protected void uninstall(Artifact configurationId) {
1259            //child class can override this method
1260        }
1261    
1262        private void notifyWatchers(Artifact id) {
1263            for (Iterator it = watchers.iterator(); it.hasNext();) {
1264                DeploymentWatcher watcher = (DeploymentWatcher) it.next();
1265                watcher.undeployed(id);
1266            }
1267        }
1268    
1269        public ArtifactResolver getArtifactResolver() {
1270            return artifactResolver;
1271        }
1272    
1273        /**
1274         * this configuration manager never starts configurations.
1275         * @return false
1276         */
1277        public boolean isOnline() {
1278            return false;
1279        }
1280    
1281        public void setOnline(boolean online) {
1282        }
1283    
1284        private List getStoreList() {
1285            return new ArrayList(stores);
1286        }
1287    
1288        private static void addConfigurationsToMonitor(LifecycleMonitor monitor, LinkedHashSet configurations) {
1289            for (Iterator iterator = configurations.iterator(); iterator.hasNext();) {
1290                Artifact configurationId = (Artifact) iterator.next();
1291                monitor.addConfiguration(configurationId);
1292            }
1293        }
1294    
1295        private static LinkedHashSet reverse(LinkedHashSet set) {
1296            ArrayList reverseList = new ArrayList(set);
1297            Collections.reverse(reverseList);
1298            set = new LinkedHashSet(reverseList);
1299            return set;
1300        }
1301    
1302        private static LinkedHashMap reverse(LinkedHashMap map) {
1303            ArrayList reverseEntrySet = new ArrayList(map.entrySet());
1304            Collections.reverse(reverseEntrySet);
1305    
1306            map = new LinkedHashMap(reverseEntrySet.size());
1307            for (Iterator iterator = reverseEntrySet.iterator(); iterator.hasNext();) {
1308                Map.Entry entry = (Map.Entry) iterator.next();
1309                Object key = entry.getKey();
1310                Object value = entry.getValue();
1311                map.put(key, value);
1312            }
1313            return map;
1314        }
1315    
1316        public static final GBeanInfo GBEAN_INFO;
1317    
1318        static {
1319            GBeanInfoBuilder infoFactory = GBeanInfoBuilder.createStatic(SimpleConfigurationManager.class, "ConfigurationManager");
1320            infoFactory.addReference("Stores", ConfigurationStore.class, "ConfigurationStore");
1321            infoFactory.addReference("ArtifactResolver", ArtifactResolver.class, "ArtifactResolver");
1322            infoFactory.addReference("Repositories", Repository.class, "Repository");
1323            infoFactory.addReference("Watchers", DeploymentWatcher.class);
1324            infoFactory.addInterface(ConfigurationManager.class);
1325            infoFactory.setConstructor(new String[]{"Stores", "ArtifactResolver", "Repositories", "Watchers"});
1326            GBEAN_INFO = infoFactory.getBeanInfo();
1327        }
1328    
1329        public static GBeanInfo getGBeanInfo() {
1330            return GBEAN_INFO;
1331        }
1332    
1333    }