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