001    /**
002     *  Licensed to the Apache Software Foundation (ASF) under one or more
003     *  contributor license agreements.  See the NOTICE file distributed with
004     *  this work for additional information regarding copyright ownership.
005     *  The ASF licenses this file to You under the Apache License, Version 2.0
006     *  (the "License"); you may not use this file except in compliance with
007     *  the License.  You may obtain a copy of the License at
008     *
009     *     http://www.apache.org/licenses/LICENSE-2.0
010     *
011     *  Unless required by applicable law or agreed to in writing, software
012     *  distributed under the License is distributed on an "AS IS" BASIS,
013     *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
014     *  See the License for the specific language governing permissions and
015     *  limitations under the License.
016     */
017    
018    package org.apache.geronimo.kernel.config;
019    
020    import java.util.Collection;
021    import java.util.Collections;
022    import java.util.Iterator;
023    import java.util.LinkedHashSet;
024    import java.util.Map;
025    import java.util.Set;
026    
027    import org.apache.geronimo.gbean.AbstractName;
028    import org.apache.geronimo.gbean.AbstractNameQuery;
029    import org.apache.geronimo.gbean.GBeanData;
030    import org.apache.geronimo.gbean.GBeanInfo;
031    import org.apache.geronimo.gbean.GBeanInfoBuilder;
032    import org.apache.geronimo.gbean.GBeanLifecycle;
033    import org.apache.geronimo.gbean.InvalidConfigurationException;
034    import org.apache.geronimo.kernel.GBeanAlreadyExistsException;
035    import org.apache.geronimo.kernel.GBeanNotFoundException;
036    import org.apache.geronimo.kernel.InternalKernelException;
037    import org.apache.geronimo.kernel.Kernel;
038    import org.apache.geronimo.kernel.management.State;
039    import org.apache.geronimo.kernel.repository.Artifact;
040    import org.apache.geronimo.kernel.repository.ArtifactManager;
041    import org.apache.geronimo.kernel.repository.ArtifactResolver;
042    import org.apache.geronimo.kernel.repository.DefaultArtifactResolver;
043    
044    /**
045     * The standard non-editable ConfigurationManager implementation.  That is,
046     * you can save a lost configurations and stuff, but not change the set of
047     * GBeans included in a configuration.
048     *
049     * @version $Rev:386276 $ $Date: 2008-10-21 14:44:05 +0000 (Tue, 21 Oct 2008) $
050     * @see EditableConfigurationManager
051     */
052    public class KernelConfigurationManager extends SimpleConfigurationManager implements GBeanLifecycle {
053    
054        protected final Kernel kernel;
055        protected final ManageableAttributeStore attributeStore;
056        protected final PersistentConfigurationList configurationList;
057        private final ArtifactManager artifactManager;
058        protected final ClassLoader classLoader;
059        private final ShutdownHook shutdownHook;
060        private boolean online = true;
061    
062        public KernelConfigurationManager(Kernel kernel,
063                Collection stores,
064                ManageableAttributeStore attributeStore,
065                PersistentConfigurationList configurationList,
066                ArtifactManager artifactManager,
067                ArtifactResolver artifactResolver,
068                Collection repositories,
069                Collection watchers,
070                ClassLoader classLoader) {
071    
072            super(stores,
073                    createArtifactResolver(artifactResolver, artifactManager, repositories),
074                    repositories, watchers);
075    
076            this.kernel = kernel;
077            this.attributeStore = attributeStore;
078            this.configurationList = configurationList;
079            this.artifactManager = artifactManager;
080            this.classLoader = classLoader;
081    
082            shutdownHook = new ShutdownHook(kernel, configurationModel);
083        }
084    
085        private static ArtifactResolver createArtifactResolver(ArtifactResolver artifactResolver, ArtifactManager artifactManager, Collection repositories) {
086            if (artifactResolver != null) {
087                return artifactResolver;
088            }
089            return new DefaultArtifactResolver(artifactManager, repositories, null);
090        }
091    
092        public synchronized LifecycleResults loadConfiguration(Artifact configurationId) throws NoSuchConfigException, LifecycleException {
093            // todo hack for bootstrap deploy
094            AbstractName abstractName = null;
095            try {
096                abstractName = Configuration.getConfigurationAbstractName(configurationId);
097            } catch (InvalidConfigException e) {
098                throw new RuntimeException(e);
099            }
100            if (getConfiguration(configurationId) == null && kernel.isLoaded(abstractName)) {
101                try {
102                    Configuration configuration = (Configuration) kernel.getGBean(abstractName);
103                    addNewConfigurationToModel(configuration);
104                    configurationModel.load(configurationId);
105                    configurationModel.start(configurationId);
106                    return new LifecycleResults();
107                } catch (GBeanNotFoundException e) {
108                    // configuration was unloaded, just continue as normal
109                }
110            }
111    
112            return super.loadConfiguration(configurationId);
113        }
114    
115        protected void load(Artifact configurationId) throws NoSuchConfigException {
116            super.load(configurationId);
117            if (configurationList != null) {
118                configurationList.addConfiguration(configurationId);
119            }
120        }
121    
122        protected void migrateConfiguration(Artifact oldName, Artifact newName, Configuration configuration, boolean running) throws NoSuchConfigException {
123            super.migrateConfiguration(oldName, newName, configuration, running);
124            if (configurationList != null) {
125                configurationList.migrateConfiguration(oldName, newName, configuration);
126                if(running) {
127                    configurationList.startConfiguration(newName);
128                }
129            }
130        }
131    
132        protected Configuration load(ConfigurationData configurationData, LinkedHashSet resolvedParentIds, Map loadedConfigurations) throws InvalidConfigException {
133            Artifact configurationId = configurationData.getId();
134            AbstractName configurationName = Configuration.getConfigurationAbstractName(configurationId);
135            GBeanData gbeanData = new GBeanData(configurationName, Configuration.GBEAN_INFO);
136            gbeanData.setAttribute("configurationData", configurationData);
137            gbeanData.setAttribute("configurationResolver", new ConfigurationResolver(configurationData, repositories, getArtifactResolver()));
138            //TODO is this dangerous?
139            gbeanData.setAttribute("managedAttributeStore", attributeStore);
140    
141            // add parents to the parents reference collection
142            LinkedHashSet parentNames = new LinkedHashSet();
143            for (Iterator iterator = resolvedParentIds.iterator(); iterator.hasNext();) {
144                Artifact resolvedParentId = (Artifact) iterator.next();
145                AbstractName parentName = Configuration.getConfigurationAbstractName(resolvedParentId);
146                parentNames.add(parentName);
147            }
148            gbeanData.addDependencies(parentNames);
149            gbeanData.setReferencePatterns("Parents", parentNames);
150    
151            // load the configuration
152            try {
153                kernel.loadGBean(gbeanData, classLoader);
154            } catch (GBeanAlreadyExistsException e) {
155                throw new InvalidConfigException("Unable to load configuration gbean " + configurationId, e);
156            }
157    
158            // start the configuration and assure it started
159            Configuration configuration;
160            try {
161                kernel.startGBean(configurationName);
162                if (State.RUNNING_INDEX != kernel.getGBeanState(configurationName)) {
163                    String stateReason = kernel.getStateReason(configurationName);
164                    throw new InvalidConfigurationException("Configuration gbean failed to start " + configurationId + "\nreason: " + stateReason);
165                }
166    
167                // get the configuration
168                configuration = (Configuration) kernel.getGBean(configurationName);
169    
170                // declare the dependencies as loaded
171                if (artifactManager != null) {
172                    artifactManager.loadArtifacts(configurationId, configuration.getDependencies());
173                }
174    
175                log.debug("Loaded Configuration " + configurationName);
176            } catch (Exception e) {
177                unload(configurationId);
178                if (e instanceof InvalidConfigException) {
179                    throw (InvalidConfigException) e;
180                }
181                throw new InvalidConfigException("Error starting configuration gbean " + configurationId, e);
182            }
183            return configuration;
184        }
185    
186        public void start(Configuration configuration) throws InvalidConfigException {
187            if (online) {
188                ConfigurationUtil.startConfigurationGBeans(configuration.getAbstractName(), configuration, kernel);
189            }
190    
191            if (configurationList != null && configuration.getConfigurationData().isAutoStart()) {
192                configurationList.startConfiguration(configuration.getId());
193            }
194        }
195    
196        public boolean isOnline() {
197            return online;
198        }
199    
200        public void setOnline(boolean online) {
201            this.online = online;
202        }
203    
204        protected void stop(Configuration configuration) {
205            stopRecursive(configuration);
206            if (configurationList != null) {
207                configurationList.stopConfiguration(configuration.getId());
208            }
209        }
210    
211        private void stopRecursive(Configuration configuration) {
212            // stop all of the child configurations first
213            for (Iterator iterator = configuration.getChildren().iterator(); iterator.hasNext();) {
214                Configuration childConfiguration = (Configuration) iterator.next();
215                stopRecursive(childConfiguration);
216            }
217    
218            Collection gbeans = configuration.getGBeans().values();
219    
220            // stop the gbeans
221            for (Iterator iterator = gbeans.iterator(); iterator.hasNext();) {
222                GBeanData gbeanData = (GBeanData) iterator.next();
223                AbstractName gbeanName = gbeanData.getAbstractName();
224                try {
225                    kernel.stopGBean(gbeanName);
226                } catch (GBeanNotFoundException ignored) {
227                } catch (IllegalStateException ignored) {
228                } catch (InternalKernelException kernelException) {
229                    log.debug("Error cleaning up after failed start of configuration " + configuration.getId() + " gbean " + gbeanName, kernelException);
230                }
231            }
232    
233            // unload the gbeans
234            for (Iterator iterator = gbeans.iterator(); iterator.hasNext();) {
235                GBeanData gbeanData = (GBeanData) iterator.next();
236                AbstractName gbeanName = gbeanData.getAbstractName();
237                try {
238                    kernel.unloadGBean(gbeanName);
239                } catch (GBeanNotFoundException ignored) {
240                } catch (IllegalStateException ignored) {
241                } catch (InternalKernelException kernelException) {
242                    log.debug("Error cleaning up after failed start of configuration " + configuration.getId() + " gbean " + gbeanName, kernelException);
243                }
244            }
245        }
246    
247        protected void unload(Configuration configuration) {
248            Artifact configurationId = configuration.getId();
249            unload(configurationId);
250        }
251    
252        private void unload(Artifact configurationId) {
253            AbstractName configurationName;
254            try {
255                configurationName = Configuration.getConfigurationAbstractName(configurationId);
256            } catch (InvalidConfigException e) {
257                throw new AssertionError(e);
258            }
259    
260            if (artifactManager != null) {
261                artifactManager.unloadAllArtifacts(configurationId);
262            }
263    
264            // unload this configuration
265            try {
266                kernel.stopGBean(configurationName);
267            } catch (GBeanNotFoundException ignored) {
268                // Good
269            } catch (Exception stopException) {
270                log.warn("Unable to stop failed configuration: " + configurationId, stopException);
271            }
272    
273            try {
274                kernel.unloadGBean(configurationName);
275            } catch (GBeanNotFoundException ignored) {
276                // Good
277            } catch (Exception unloadException) {
278                log.warn("Unable to unload failed configuration: " + configurationId, unloadException);
279            }
280        }
281    
282        protected void uninstall(Artifact configurationId) {
283            if (configurationList != null) {
284                configurationList.removeConfiguration( configurationId );
285            }
286        }
287        
288        public void doStart() {
289            kernel.registerShutdownHook(shutdownHook);
290        }
291    
292        public void doStop() {
293            kernel.unregisterShutdownHook(shutdownHook);
294        }
295    
296        public void doFail() {
297            log.error("Cofiguration manager failed");
298        }
299    
300        private static class ShutdownHook implements Runnable {
301            private final Kernel kernel;
302            private final ConfigurationModel configurationModel;
303    
304            public ShutdownHook(Kernel kernel, ConfigurationModel configurationModel) {
305                this.kernel = kernel;
306                this.configurationModel = configurationModel;
307            }
308    
309            public void run() {
310                while (true) {
311                    Set configs = kernel.listGBeans(new AbstractNameQuery(Configuration.class.getName()));
312                    if (configs.isEmpty()) {
313                        return;
314                    }
315                    LinkedHashSet orderedConfigs = new LinkedHashSet();
316                    for (Iterator i = configs.iterator(); i.hasNext();) {
317                        AbstractName configName = (AbstractName) i.next();
318                        if (kernel.isLoaded(configName) && !orderedConfigs.contains(configName)) {
319                            LinkedHashSet startedChildren = configurationModel.getStartedChildren(configName.getArtifact());
320                            for (Iterator iterator = startedChildren.iterator(); iterator.hasNext();) {
321                                Artifact configurationId = (Artifact) iterator.next();
322                                Set childConfig = kernel.listGBeans(new AbstractNameQuery(configurationId, Collections.emptyMap() , Configuration.class.getName()));
323                                if (!childConfig.isEmpty()) {
324                                    AbstractName childConfigName = (AbstractName) childConfig.iterator().next();
325                                    if (!orderedConfigs.contains(childConfigName))
326                                        orderedConfigs.add(childConfigName);
327                                }
328                            }
329                            orderedConfigs.add(configName);
330                        }
331                    }
332    
333                    for (Iterator i = orderedConfigs.iterator(); i.hasNext();) {
334                        AbstractName configName = (AbstractName) i.next();
335                        try {
336                            kernel.stopGBean(configName);
337                        } catch (GBeanNotFoundException e) {
338                            // ignore
339                        } catch (InternalKernelException e) {
340                            log.warn("Could not stop configuration: " + configName, e);
341                        }
342                        try {
343                            kernel.unloadGBean(configName);
344                        } catch (GBeanNotFoundException e) {
345                            // ignore
346                        }
347                    }
348                }
349            }
350        }
351    
352        public static final GBeanInfo GBEAN_INFO;
353    
354        static {
355            GBeanInfoBuilder infoFactory = GBeanInfoBuilder.createStatic(KernelConfigurationManager.class, SimpleConfigurationManager.GBEAN_INFO, "ConfigurationManager");
356            infoFactory.addAttribute("kernel", Kernel.class, false);
357            infoFactory.addReference("AttributeStore", ManageableAttributeStore.class, ManageableAttributeStore.ATTRIBUTE_STORE);
358            infoFactory.addReference("PersistentConfigurationList", PersistentConfigurationList.class, PersistentConfigurationList.PERSISTENT_CONFIGURATION_LIST);
359            infoFactory.addReference("ArtifactManager", ArtifactManager.class, "ArtifactManager");
360            infoFactory.addAttribute("classLoader", ClassLoader.class, false);
361            infoFactory.addInterface(ConfigurationManager.class);
362            infoFactory.setConstructor(new String[]{"kernel", "Stores", "AttributeStore", "PersistentConfigurationList", "ArtifactManager", "ArtifactResolver", "Repositories", "Watchers", "classLoader"});
363            GBEAN_INFO = infoFactory.getBeanInfo();
364        }
365    
366        public static GBeanInfo getGBeanInfo() {
367            return GBEAN_INFO;
368        }
369    }