001 /** 002 * Licensed to the Apache Software Foundation (ASF) under one or more 003 * contributor license agreements. See the NOTICE file distributed with 004 * this work for additional information regarding copyright ownership. 005 * The ASF licenses this file to You under the Apache License, Version 2.0 006 * (the "License"); you may not use this file except in compliance with 007 * the License. You may obtain a copy of the License at 008 * 009 * http://www.apache.org/licenses/LICENSE-2.0 010 * 011 * Unless required by applicable law or agreed to in writing, software 012 * distributed under the License is distributed on an "AS IS" BASIS, 013 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 014 * See the License for the specific language governing permissions and 015 * limitations under the License. 016 */ 017 package org.apache.xbean.server.main; 018 019 import java.util.Map; 020 import java.util.Collections; 021 import java.util.Iterator; 022 023 import org.apache.xbean.kernel.Kernel; 024 import org.apache.xbean.kernel.KernelFactory; 025 import org.apache.xbean.kernel.ServiceName; 026 import org.apache.xbean.kernel.StringServiceName; 027 import org.apache.xbean.kernel.StaticServiceFactory; 028 029 /** 030 * KernelMain is the standard entry point class used for a server. It will initalize a kernel with a set of services 031 * and can optional hold the thread of execution until the kernel or virtual machine is destroyed. 032 * 033 * @org.apache.xbean.XBean namespace="http://xbean.apache.org/schemas/server" element="kernel-main" 034 * description="Standard entry point for a kernel based server." 035 * 036 * @author Dain Sundstrom 037 * @version $Id$ 038 * @since 2.0 039 */ 040 public class KernelMain implements Main { 041 private static final String DEFAULT_KERNEL_NAME = "xbean"; 042 043 private Kernel kernel; 044 private ClassLoader classLoader; 045 private Map services = Collections.EMPTY_MAP; 046 private boolean daemon = true; 047 private Main next; 048 049 /** 050 * Gets the kernel that will be initialized in the main method. If the kernel is null, a new kernel will be created 051 * and initialized in the main method. 052 * @return the kernel that will be initialized in the main method 053 */ 054 public Kernel getKernel() { 055 return kernel; 056 } 057 058 /** 059 * Sets the kernel to be initialized in the main method. 060 * @param kernel the kernel to initialize in the main method 061 */ 062 public void setKernel(Kernel kernel) { 063 this.kernel = kernel; 064 } 065 066 /** 067 * Gets the class loader which is used as the thread context class loader during the main method. 068 * @return the class loader which is used as the thread context class loader during the main method 069 */ 070 public ClassLoader getClassLoader() { 071 return classLoader; 072 } 073 074 /** 075 * Sets the class loader to use as the thread context class loader during the main method. 076 * @param classLoader the class loader to use as the thread context class loader during the main method 077 */ 078 public void setClassLoader(ClassLoader classLoader) { 079 this.classLoader = classLoader; 080 } 081 082 /** 083 * Gets the services to be registered with the kernel during the main method. 084 * @return the services to be mounted added to the kernel during the main method 085 */ 086 public Map getServices() { 087 return services; 088 } 089 090 /** 091 * Sets the services to be registered with the kernel during the main method. 092 * @param services the services to be registered with the kernel during the main method 093 */ 094 public void setServices(Map services) { 095 this.services = services; 096 } 097 098 /** 099 * Determines if the main method should hold the thread until the kernel is destroyed. 100 * @return true if the main method should hold the thread until the kernel is destroyed; false otherwise 101 */ 102 public boolean isDaemon() { 103 return daemon; 104 } 105 106 /** 107 * Sets the main method to hold the thread until the kernel is destroyed. 108 * @param daemon true if the main method should hold the thread until the kernel is destroyed 109 */ 110 public void setDaemon(boolean daemon) { 111 this.daemon = daemon; 112 } 113 114 /** 115 * Gets the next main to call after the kernel has been initialized, but before destroying the kernel. 116 * @return the next main to call after the kernel has been initialized 117 */ 118 public Main getNext() { 119 return next; 120 } 121 122 /** 123 * Sets the next main to call after the kernel has been initialized. 124 * @param next the next main to call after the kernel has been initialized 125 */ 126 public void setNext(Main next) { 127 this.next = next; 128 } 129 130 /** 131 * Registers the services with the kernel, calls the next main, optionally holds the thread until the kernel is 132 * destroyed, and then destroys the kernel. 133 * @param args the arguments passed the next main 134 */ 135 public void main(String[] args) { 136 if (classLoader == null) { 137 classLoader = Thread.currentThread().getContextClassLoader(); 138 } 139 140 ClassLoader oldClassLoader = Thread.currentThread().getContextClassLoader(); 141 Thread.currentThread().setContextClassLoader(classLoader); 142 try { 143 // create a default kernel if necessary 144 if (kernel == null) { 145 kernel = KernelFactory.newInstance().createKernel(DEFAULT_KERNEL_NAME); 146 } 147 148 boolean failed = false; 149 try { 150 // bind the bootstrap services 151 for (Iterator iterator = services.entrySet().iterator(); iterator.hasNext();) { 152 Map.Entry entry = (Map.Entry) iterator.next(); 153 String name = (String) entry.getKey(); 154 Object service = entry.getValue(); 155 156 try { 157 ServiceName serviceName = new StringServiceName(name); 158 kernel.registerService(serviceName, new StaticServiceFactory(service, classLoader)); 159 kernel.startService(serviceName); 160 } catch (Exception e) { 161 throw new FatalStartupError("Unable to bind bootstrap service '" + name + "' into the kernel", e); 162 } 163 } 164 165 // if we have a child main class call it 166 if (next != null) { 167 next.main(args); 168 } 169 170 // if we are a daemon we wait here until the server stops 171 if (daemon) { 172 // add our shutdown hook 173 Runtime.getRuntime().addShutdownHook(new DestroyKernelThread(kernel)); 174 175 // wait for the kernel to be destroyed 176 kernel.waitForDestruction(); 177 } 178 } catch (RuntimeException e) { 179 failed = true; 180 throw e; 181 } catch (Error e) { 182 failed = true; 183 throw e; 184 } finally { 185 try { 186 kernel.destroy(); 187 } catch (Exception e) { 188 // if we are not alredy throwing an exception, throw a new exception 189 if (!failed) { 190 throw new FatalStartupError("Exception while shutting down kernel", e); 191 } 192 } 193 } 194 } finally { 195 Thread.currentThread().setContextClassLoader(oldClassLoader); 196 } 197 } 198 199 public void destroy() { 200 if( kernel!=null ) { 201 kernel.destroy(); 202 } 203 } 204 205 private static class DestroyKernelThread extends Thread { 206 private final Kernel kernel; 207 208 private DestroyKernelThread(Kernel kernel) { 209 super("Destroy Kernel Shutdown Hook"); 210 this.kernel = kernel; 211 } 212 213 public void run() { 214 kernel.destroy(); 215 } 216 } 217 218 }