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