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.system.main;
019    
020    import java.io.File;
021    import java.io.FileInputStream;
022    import java.io.IOException;
023    import java.util.ArrayList;
024    import java.util.LinkedHashSet;
025    import java.util.List;
026    import java.util.Properties;
027    import java.util.Set;
028    
029    import org.apache.commons.logging.Log;
030    import org.apache.commons.logging.LogFactory;
031    import org.apache.geronimo.cli.daemon.DaemonCLParser;
032    import org.apache.geronimo.common.DeploymentException;
033    import org.apache.geronimo.common.GeronimoEnvironment;
034    import org.apache.geronimo.crypto.EncryptionManager;
035    import org.apache.geronimo.gbean.AbstractName;
036    import org.apache.geronimo.gbean.AbstractNameQuery;
037    import org.apache.geronimo.gbean.GBeanInfo;
038    import org.apache.geronimo.gbean.GBeanInfoBuilder;
039    import org.apache.geronimo.kernel.Kernel;
040    import org.apache.geronimo.kernel.config.ConfigurationManager;
041    import org.apache.geronimo.kernel.config.ConfigurationUtil;
042    import org.apache.geronimo.kernel.config.DebugLoggingLifecycleMonitor;
043    import org.apache.geronimo.kernel.config.InvalidConfigException;
044    import org.apache.geronimo.kernel.config.LifecycleMonitor;
045    import org.apache.geronimo.kernel.config.PersistentConfigurationList;
046    import org.apache.geronimo.kernel.repository.Artifact;
047    import org.apache.geronimo.kernel.util.Main;
048    import org.apache.geronimo.system.serverinfo.DirectoryUtils;
049    
050    
051    /**
052     * @version $Rev:385659 $ $Date: 2007-03-07 14:40:07 +1100 (Wed, 07 Mar 2007) $
053     */
054    public class EmbeddedDaemon implements Main {
055        private static final Log log = LogFactory.getLog(EmbeddedDaemon.class);
056    
057        protected final Kernel kernel;
058        private StartupMonitor monitor;
059        private LifecycleMonitor lifecycleMonitor;
060        private List<Artifact> configs = new ArrayList<Artifact>();
061        static String KEYSTORE_TRUSTSTORE_PASSWORD_FILE = "org.apache.geronimo.keyStoreTrustStorePasswordFile";
062        static String DEFAULT_TRUSTSTORE_KEYSTORE_LOCATION = "/var/security/keystores/geronimo-default";
063        static String GERONIMO_HOME = "org.apache.geronimo.home.dir";
064        static String DEFAULT_KEYSTORE_TRUSTSTORE_PASSWORD_FILE = System.getProperty(GERONIMO_HOME)
065                + "/var/config/config-substitutions.properties";
066    
067        public EmbeddedDaemon(Kernel kernel) {
068            this.kernel = kernel;
069        }
070    
071        public int execute(Object opaque) {
072            if (!(opaque instanceof DaemonCLParser)) {
073                throw new IllegalArgumentException("Argument type is [" + opaque.getClass() + "]; expected [" + DaemonCLParser.class + "]");
074            }
075            DaemonCLParser parser = (DaemonCLParser) opaque;
076            initializeMonitor(parser);
077            initializeOverride(parser);
078            initializeSecure(parser);
079    
080            long start = System.currentTimeMillis();
081    
082            System.out.println("Booting Geronimo Kernel (in Java " + System.getProperty("java.version") + ")...");
083            System.out.flush();
084    
085            // Perform initialization tasks common with the various Geronimo environments
086            GeronimoEnvironment.init();
087    
088            monitor.systemStarting(start);
089            return doStartup();
090        }
091    
092        protected void initializeSecure(DaemonCLParser parser)
093        {
094            if(parser.isSecure()){
095                try {
096                    Properties props = new Properties();
097    
098                    String keyStorePassword = null;
099                    String trustStorePassword = null;
100    
101                    FileInputStream fstream = new FileInputStream(System.getProperty(KEYSTORE_TRUSTSTORE_PASSWORD_FILE,
102                            DEFAULT_KEYSTORE_TRUSTSTORE_PASSWORD_FILE));
103                    props.load(fstream);
104    
105                    keyStorePassword = (String) EncryptionManager.decrypt(props.getProperty("keyStorePassword"));
106                    trustStorePassword = (String) EncryptionManager.decrypt(props.getProperty("trustStorePassword"));
107    
108                    fstream.close();
109    
110                    String value = System.getProperty("javax.net.ssl.keyStore", System.getProperty(GERONIMO_HOME)
111                            + DEFAULT_TRUSTSTORE_KEYSTORE_LOCATION);
112                    String value1 = System.getProperty("javax.net.ssl.trustStore", System.getProperty(GERONIMO_HOME)
113                            + DEFAULT_TRUSTSTORE_KEYSTORE_LOCATION);
114                    System.setProperty("javax.net.ssl.keyStore", value);
115                    System.setProperty("javax.net.ssl.trustStore", value1);
116                    System.setProperty("javax.net.ssl.keyStorePassword", keyStorePassword);
117                    System.setProperty("javax.net.ssl.trustStorePassword", trustStorePassword);
118                } 
119    
120                catch(IOException e)
121                {
122                    e.printStackTrace();
123                }
124            }
125        }
126        protected void initializeOverride(DaemonCLParser parser) {
127            String[] override = parser.getOverride();
128            if (null != override) {
129                for (String anOverride : override) {
130                    configs.add(Artifact.create(anOverride));
131                }
132            }
133        }
134    
135        protected void initializeMonitor(DaemonCLParser parser) {
136            if (parser.isVerboseInfo() || parser.isVerboseDebug() || parser.isVerboseTrace() || parser.isNoProgress()) {
137                monitor = new SilentStartupMonitor();
138            } else {
139                if (parser.isLongProgress()) {
140                    monitor = new LongStartupMonitor();
141                } else {
142                    monitor = new SimpleProgressBarStartupMonitor();
143                }
144            }
145            lifecycleMonitor = new DebugLoggingLifecycleMonitor(log);
146        }
147    
148        protected int doStartup() {
149            try {
150                // Check that the tmpdir exists - if not give friendly msg and exit
151                // since we allow it to be configured in geronimo.bat and geronimo.sh
152                // (since 1.0 release) the same way Tomcat allows it to be configured.
153                String tmpDir = System.getProperty("java.io.tmpdir");
154                if (tmpDir == null || (!(new File(tmpDir)).exists()) || (!(new File(tmpDir)).isDirectory())) {
155                    System.err.println("The java.io.tmpdir system property specifies a non-existent directory: " + tmpDir);
156                    return 1;
157                }
158    
159                // Determine the geronimo installation directory
160                File geronimoInstallDirectory = DirectoryUtils.getGeronimoInstallDirectory();
161                if (geronimoInstallDirectory == null) {
162                    System.err.println("Could not determine geronimo installation directory");
163                    return 1;
164                }
165    
166                int exitCode = initializeKernel();
167                if (0 != exitCode) {
168                    return exitCode;
169                }
170    
171                monitor.systemStarted(kernel);
172    
173                AbstractNameQuery query = new AbstractNameQuery(PersistentConfigurationList.class.getName());
174    
175                if (configs.isEmpty()) {
176                    // --override wasn't used (nothing explicit), see what was running before
177                    Set<AbstractName> configLists = kernel.listGBeans(query);
178                    for (AbstractName configListName : configLists) {
179                        try {
180                            configs.addAll((List<Artifact>) kernel.invoke(configListName, "restore"));
181                        } catch (IOException e) {
182                            System.err.println("Unable to restore last known configurations");
183                            e.printStackTrace();
184                            shutdownKernel();
185                            return 1;
186                        }
187                    }
188                }
189    
190                monitor.foundModules(configs.toArray(new Artifact[configs.size()]));
191    
192                // load the rest of the configurations
193                try {
194                    ConfigurationManager configurationManager = ConfigurationUtil.getConfigurationManager(kernel);
195                    try {
196                        List<Artifact> unloadedConfigs = new ArrayList(configs);
197                        int unloadedConfigsCount;
198                        do {
199                            unloadedConfigsCount = unloadedConfigs.size();
200                            LinkedHashSet<Artifact> sorted = configurationManager.sort(unloadedConfigs, lifecycleMonitor);
201                            for (Artifact configID : sorted) {
202                                monitor.moduleLoading(configID);
203                                configurationManager.loadConfiguration(configID, lifecycleMonitor);
204                                monitor.moduleLoaded(configID);
205                                monitor.moduleStarting(configID);
206                                configurationManager.startConfiguration(configID, lifecycleMonitor);
207                                monitor.moduleStarted(configID);
208                            }
209                        } while (unloadedConfigsCount > unloadedConfigs.size());
210                        if (!unloadedConfigs.isEmpty()) {
211                            throw new InvalidConfigException("Could not locate configs to start: " + unloadedConfigs);
212                        }
213                        // the server has finished loading the persistent configuration so inform the gbean
214                        AbstractNameQuery startedQuery = new AbstractNameQuery(ServerStatus.class.getName());
215                        Set<AbstractName> statusBeans = kernel.listGBeans(startedQuery);
216                        for (AbstractName statusName : statusBeans) {
217                            ServerStatus status = (ServerStatus) kernel.getGBean(statusName);
218                            if (status != null) {
219                                status.setServerStarted(true);
220                            }
221                        }
222                    } finally {
223                        ConfigurationUtil.releaseConfigurationManager(kernel, configurationManager);
224                    }
225                } catch (Exception e) {
226                    //Exception caught when starting configurations, starting kernel shutdown
227                    monitor.serverStartFailed(e);
228                    shutdownKernel();
229                    return 1;
230                }
231    
232                // Tell every persistent configuration list that the kernel is now fully started
233                Set<AbstractName> configLists = kernel.listGBeans(query);
234                for (AbstractName configListName : configLists) {
235                    kernel.setAttribute(configListName, "kernelFullyStarted", Boolean.TRUE);
236                }
237    
238                // Startup sequence is finished
239                monitor.startupFinished();
240                monitor = null;
241    
242                // capture this thread until the kernel is ready to exit
243                while (kernel.isRunning()) {
244                    try {
245                        synchronized (kernel) {
246                            kernel.wait();
247                        }
248                    } catch (InterruptedException e) {
249                        // continue
250                    }
251                }
252            } catch (Exception e) {
253                if (monitor != null) {
254                    monitor.serverStartFailed(e);
255                }
256                e.printStackTrace();
257                return 1;
258            }
259            return 0;
260        }
261    
262        protected void shutdownKernel() {
263            try {
264                kernel.shutdown();
265            } catch (Exception e1) {
266                System.err.println("Exception caught during kernel shutdown");
267                e1.printStackTrace();
268            }
269        }
270    
271        protected int initializeKernel() throws Exception {
272            return 0;
273        }
274    
275        public static final GBeanInfo GBEAN_INFO;
276    
277        static {
278            GBeanInfoBuilder infoFactory = GBeanInfoBuilder.createStatic(EmbeddedDaemon.class, "EmbeddedDaemon");
279            infoFactory.addAttribute("kernel", Kernel.class, false);
280            infoFactory.setConstructor(new String[]{"kernel"});
281            GBEAN_INFO = infoFactory.getBeanInfo();
282        }
283    
284        public static GBeanInfo getGBeanInfo() {
285            return GBEAN_INFO;
286        }
287    
288    }