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