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