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: */package org.apache.openejb.server;
017:
018: import org.apache.openejb.loader.FileUtils;
019: import org.apache.openejb.loader.SystemInstance;
020: import org.apache.openejb.util.LogCategory;
021: import org.apache.openejb.util.Logger;
022: import org.apache.openejb.util.Messages;
023: import org.apache.openejb.spi.ContainerSystem;
024: import org.apache.openejb.assembler.classic.ServiceInfo;
025: import org.apache.openejb.assembler.classic.OpenEjbConfiguration;
026: import org.apache.xbean.finder.ResourceFinder;
027: import org.apache.xbean.recipe.ObjectRecipe;
028: import org.apache.xbean.recipe.Option;
029: import org.apache.xbean.recipe.MissingFactoryMethodException;
030:
031: import javax.naming.NamingException;
032: import javax.naming.Binding;
033: import javax.naming.NamingEnumeration;
034: import javax.resource.spi.ResourceAdapter;
035: import java.io.File;
036: import java.io.FileInputStream;
037: import java.io.FileOutputStream;
038: import java.io.IOException;
039: import java.net.InetAddress;
040: import java.util.ArrayList;
041: import java.util.Iterator;
042: import java.util.List;
043: import java.util.Map;
044: import java.util.Properties;
045: import java.util.Set;
046:
047: /**
048: * @version $Rev: 635148 $ $Date: 2008-03-08 19:09:07 -0800 $
049: * @org.apache.xbean.XBean element="serviceManager"
050: */
051: public class ServiceManager {
052:
053: static Messages messages = new Messages(
054: "org.apache.openejb.server.util.resources");
055: static Logger logger = Logger.getInstance(
056: LogCategory.OPENEJB_SERVER_REMOTE,
057: "org.apache.openejb.server.util.resources");
058:
059: private static ServiceManager manager;
060:
061: private static ServerService[] daemons;
062:
063: private boolean stop = false;
064:
065: public ServiceManager() {
066: }
067:
068: public static ServiceManager getManager() {
069: if (manager == null) {
070: manager = new ServiceManager();
071: }
072:
073: return manager;
074: }
075:
076: // Have properties files (like xinet.d) that specifies what daemons to
077: // Look into the xinet.d file structure again
078: // conf/server.d/
079: // admin.properties
080: // ejbd.properties
081: // webadmin.properties
082: // telnet.properties
083: // corba.properties
084: // soap.properties
085: // xmlrpc.properties
086: // httpejb.properties
087: // webejb.properties
088: // xmlejb.properties
089: // Each contains the class name of the daemon implamentation
090: // The port to use
091: // whether it's turned on
092:
093: // May be reusable elsewhere, move if another use occurs
094: public static class ServiceFinder {
095: private final ResourceFinder resourceFinder;
096: private ClassLoader classLoader;
097:
098: public ServiceFinder(String basePath) {
099: this (basePath, Thread.currentThread()
100: .getContextClassLoader());
101: }
102:
103: public ServiceFinder(String basePath, ClassLoader classLoader) {
104: this .resourceFinder = new ResourceFinder(basePath,
105: classLoader);
106: this .classLoader = classLoader;
107: }
108:
109: public Map mapAvailableServices(Class interfase)
110: throws IOException, ClassNotFoundException {
111: Map services = resourceFinder
112: .mapAvailableProperties(ServerService.class
113: .getName());
114:
115: for (Iterator iterator = services.entrySet().iterator(); iterator
116: .hasNext();) {
117: Map.Entry entry = (Map.Entry) iterator.next();
118: String name = (String) entry.getKey();
119: Properties properties = (Properties) entry.getValue();
120:
121: String className = properties.getProperty("className");
122: if (className == null) {
123: className = properties.getProperty("classname");
124: if (className == null) {
125: className = properties.getProperty("server");
126: }
127: }
128:
129: Class impl = classLoader.loadClass(className);
130:
131: properties.put(interfase, impl);
132: String rawProperties = resourceFinder
133: .findString(interfase.getName() + "/" + name);
134: properties.put(Properties.class, rawProperties);
135:
136: }
137: return services;
138: }
139: }
140:
141: public void init() throws Exception {
142: try {
143: org.apache.log4j.MDC.put("SERVER", "main");
144: InetAddress localhost = InetAddress.getLocalHost();
145: org.apache.log4j.MDC.put("HOST", localhost.getHostName());
146: } catch (Throwable e) {
147: }
148:
149: ServiceFinder serviceFinder = new ServiceFinder("META-INF/");
150:
151: Map availableServices = serviceFinder
152: .mapAvailableServices(ServerService.class);
153: List enabledServers = new ArrayList();
154:
155: OpenEjbConfiguration conf = SystemInstance.get().getComponent(
156: OpenEjbConfiguration.class);
157: for (Iterator iterator = availableServices.entrySet()
158: .iterator(); iterator.hasNext();) {
159: Map.Entry entry = (Map.Entry) iterator.next();
160: String serviceName = (String) entry.getKey();
161: Properties serviceProperties = (Properties) entry
162: .getValue();
163:
164: logger.debug("Processing ServerService(id=" + serviceName
165: + ")");
166:
167: overrideProperties(serviceName, serviceProperties);
168: serviceProperties.setProperty("name", serviceName);
169:
170: if (conf != null && conf.facilities != null) {
171: ServiceInfo info = new ServiceInfo();
172: info.className = ((Class) serviceProperties
173: .get(ServerService.class)).getName();
174: info.service = "ServerService";
175: info.id = serviceName;
176: info.properties = serviceProperties;
177: conf.facilities.services.add(info);
178: }
179:
180: boolean enabled = isEnabled(serviceProperties);
181:
182: logger.debug("Found ServerService(id=" + serviceName
183: + ", disabled=" + (!enabled) + ")");
184:
185: if (enabled) {
186:
187: Class serviceClass = (Class) serviceProperties
188: .get(ServerService.class);
189:
190: logger.debug("Creating ServerService(id=" + serviceName
191: + ")");
192:
193: try {
194: // Create Service
195: ServerService service = null;
196:
197: ObjectRecipe recipe = new ObjectRecipe(serviceClass);
198: try {
199: // Do not import. This class is not available in xbean-reflect-3.3
200: if (org.apache.xbean.recipe.ReflectionUtil
201: .findStaticFactory(serviceClass,
202: "createServerService", null,
203: null) != null) {
204: recipe = new ObjectRecipe(serviceClass,
205: "createServerService");
206: }
207: } catch (Throwable e) {
208: }
209:
210: recipe.allow(Option.CASE_INSENSITIVE_PROPERTIES);
211: recipe.allow(Option.IGNORE_MISSING_PROPERTIES);
212:
213: service = (ServerService) recipe
214: .create(serviceClass.getClassLoader());
215:
216: if (!(service instanceof SelfManaging)) {
217: service = new ServiceLogger(service);
218: service = new ServiceAccessController(service);
219: service = new ServiceDaemon(service);
220: }
221:
222: service.init(serviceProperties);
223: enabledServers.add(service);
224: } catch (Throwable t) {
225: logger.error("service.instantiation.err", t,
226: serviceClass.getName(), t.getClass()
227: .getName(), t.getMessage());
228: }
229: }
230:
231: }
232:
233: daemons = (ServerService[]) enabledServers
234: .toArray(new ServerService[] {});
235: }
236:
237: private void overrideProperties(String serviceName,
238: Properties serviceProperties) throws IOException {
239: FileUtils base = SystemInstance.get().getBase();
240:
241: // Override with file from conf dir
242: File conf = base.getDirectory("conf");
243: if (conf.exists()) {
244: File serviceConfig = new File(conf, serviceName
245: + ".properties");
246: if (serviceConfig.exists()) {
247: FileInputStream in = new FileInputStream(serviceConfig);
248: try {
249: serviceProperties.load(in);
250: } finally {
251: in.close();
252: }
253: } else {
254: FileOutputStream out = new FileOutputStream(
255: serviceConfig);
256: try {
257: String rawPropsContent = (String) serviceProperties
258: .get(Properties.class);
259: out.write(rawPropsContent.getBytes());
260: } finally {
261: out.close();
262: }
263: }
264: }
265:
266: // Override with system properties
267: String prefix = serviceName + ".";
268: Properties sysProps = new Properties(System.getProperties());
269: sysProps.putAll(SystemInstance.get().getProperties());
270: for (Iterator iterator1 = sysProps.entrySet().iterator(); iterator1
271: .hasNext();) {
272: Map.Entry entry1 = (Map.Entry) iterator1.next();
273: String key = (String) entry1.getKey();
274: Object value = entry1.getValue();
275: if (value instanceof String && key.startsWith(prefix)) {
276: key = key.replaceFirst(prefix, "");
277: serviceProperties.setProperty(key, (String) value);
278: }
279: }
280:
281: }
282:
283: private boolean isEnabled(Properties props) {
284: // if it should be started, continue
285: String disabled = props.getProperty("disabled", "");
286:
287: if (disabled.equalsIgnoreCase("yes")
288: || disabled.equalsIgnoreCase("true")) {
289: return false;
290: } else {
291: return true;
292: }
293: }
294:
295: public synchronized void start() throws ServiceException {
296: start(true);
297: }
298:
299: public synchronized void start(boolean block)
300: throws ServiceException {
301: boolean display = System.getProperty("openejb.nobanner") == null;
302:
303: if (display) {
304: System.out.println(" ** Starting Services **");
305: printRow("NAME", "IP", "PORT");
306: }
307:
308: for (int i = 0; i < daemons.length; i++) {
309: ServerService d = daemons[i];
310: try {
311: d.start();
312: if (display && d.getPort() != -1) {
313: printRow(d.getName(), d.getIP(), d.getPort() + "");
314: }
315: } catch (Exception e) {
316: logger.fatal("Service Start Failed: " + d.getName()
317: + " " + d.getIP() + " " + d.getPort() + ": "
318: + e.getMessage());
319: if (display) {
320: printRow(d.getName(), "----", "FAILED");
321: }
322: }
323: }
324: if (display) {
325: System.out.println("-------");
326: System.out.println("Ready!");
327: }
328: if (!block)
329: return;
330:
331: /*
332: * This will cause the user thread (the thread that keeps the
333: * vm alive) to go into a state of constant waiting.
334: * Each time the thread is woken up, it checks to see if
335: * it should continue waiting.
336: *
337: * To stop the thread (and the VM), just call the stop method
338: * which will set 'stop' to true and notify the user thread.
339: */
340: try {
341: while (!stop) {
342:
343: this .wait(Long.MAX_VALUE);
344: }
345: } catch (Throwable t) {
346: logger
347: .fatal("Unable to keep the server thread alive. Received exception: "
348: + t.getClass().getName()
349: + " : "
350: + t.getMessage());
351: }
352: logger.info("Stopping Remote Server");
353: }
354:
355: public synchronized void stop() throws ServiceException {
356: logger.info("Received stop signal");
357: stop = true;
358:
359: try {
360: ContainerSystem containerSystem = SystemInstance.get()
361: .getComponent(ContainerSystem.class);
362: NamingEnumeration<Binding> namingEnumeration = null;
363: try {
364: namingEnumeration = containerSystem.getJNDIContext()
365: .listBindings("java:openejb/resourceAdapter");
366: } catch (NamingException ignored) {
367: // no resource adapters were created
368: }
369: while (namingEnumeration != null
370: && namingEnumeration.hasMoreElements()) {
371: Binding binding = namingEnumeration.nextElement();
372: Object object = binding.getObject();
373: ResourceAdapter resourceAdapter = (ResourceAdapter) object;
374: try {
375: resourceAdapter.stop();
376: } catch (Exception e) {
377: logger.fatal("ResourceAdapter Shutdown Failed: "
378: + binding.getName(), e);
379: }
380: }
381: } catch (Throwable e) {
382: logger
383: .fatal(
384: "Unable to get ResourceAdapters from JNDI. Stop must be called on them for proper vm shutdown.",
385: e);
386: }
387:
388: for (int i = 0; i < daemons.length; i++) {
389: try {
390: daemons[i].stop();
391: } catch (ServiceException e) {
392: logger.fatal("Service Shutdown Failed: "
393: + daemons[i].getName() + ". Exception: "
394: + e.getMessage(), e);
395: }
396: }
397: notifyAll();
398: }
399:
400: private void printRow(String col1, String col2, String col3) {
401:
402: col1 += " ";
403: col1 = col1.substring(0, 20);
404:
405: col2 += " ";
406: col2 = col2.substring(0, 15);
407:
408: col3 += " ";
409: col3 = col3.substring(0, 6);
410:
411: StringBuffer sb = new StringBuffer(50);
412: sb.append(" ").append(col1);
413: sb.append(" ").append(col2);
414: sb.append(" ").append(col3);
415:
416: System.out.println(sb.toString());
417: }
418: }
|