| /******************************************************************************* |
| * Licensed to the Apache Software Foundation (ASF) under one |
| * or more contributor license agreements. See the NOTICE file |
| * distributed with this work for additional information |
| * regarding copyright ownership. The ASF licenses this file |
| * to you under the Apache License, Version 2.0 (the |
| * "License"); you may not use this file except in compliance |
| * with the License. You may obtain a copy of the License at |
| * |
| * http://www.apache.org/licenses/LICENSE-2.0 |
| * |
| * Unless required by applicable law or agreed to in writing, |
| * software distributed under the License is distributed on an |
| * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY |
| * KIND, either express or implied. See the License for the |
| * specific language governing permissions and limitations |
| * under the License. |
| *******************************************************************************/ |
| package org.ofbiz.base.container; |
| |
| import java.io.PrintWriter; |
| import java.io.StringWriter; |
| import java.net.URL; |
| import java.util.Collection; |
| import java.util.Enumeration; |
| import java.util.LinkedList; |
| import java.util.List; |
| import java.util.Map; |
| |
| import org.ofbiz.base.component.ComponentConfig; |
| import org.ofbiz.base.start.Config; |
| import org.ofbiz.base.start.StartupException; |
| import org.ofbiz.base.start.StartupLoader; |
| import org.ofbiz.base.util.Debug; |
| import org.ofbiz.base.util.StringUtil; |
| import org.ofbiz.base.util.UtilValidate; |
| |
| /** |
| * An object that loads containers (background processes). |
| * |
| * <p>Normally, instances of this class are created by OFBiz startup code, and |
| * client code should not create instances of this class. Client code is |
| * responsible for making sure containers are shut down properly. </p> |
| * |
| */ |
| public class ContainerLoader implements StartupLoader { |
| |
| public static final String module = ContainerLoader.class.getName(); |
| |
| private String configFile = null; |
| private final List<Container> loadedContainers = new LinkedList<Container>(); |
| private boolean unloading = false; |
| private boolean loaded = false; |
| |
| /** |
| * @see org.ofbiz.base.start.StartupLoader#load(Config, String[]) |
| */ |
| @Override |
| public synchronized void load(Config config, String args[]) throws StartupException { |
| if (this.loaded || this.unloading) { |
| return; |
| } |
| this.loadedContainers.clear(); |
| // get this loader's configuration file |
| this.configFile = config.containerConfig; |
| |
| List<String> loaders = null; |
| for (Map loaderMap: config.loaders) { |
| if (module.equals(loaderMap.get("class"))) { |
| loaders = StringUtil.split((String)loaderMap.get("profiles"), ","); |
| } |
| } |
| |
| Debug.logInfo("[Startup] Loading containers from " + configFile + " for loaders " + loaders, module); |
| Collection<ContainerConfig.Container> containers = null; |
| try { |
| containers = ContainerConfig.getContainers(configFile); |
| } catch (ContainerException e) { |
| throw new StartupException(e); |
| } |
| for (ContainerConfig.Container containerCfg : containers) { |
| if (this.unloading) { |
| return; |
| } |
| boolean matchingLoaderFound = false; |
| if (UtilValidate.isEmpty(containerCfg.loaders) && UtilValidate.isEmpty(loaders)) { |
| matchingLoaderFound = true; |
| } else { |
| for (String loader: loaders) { |
| if (UtilValidate.isEmpty(containerCfg.loaders) || containerCfg.loaders.contains(loader)) { |
| matchingLoaderFound = true; |
| break; |
| } |
| } |
| } |
| if (matchingLoaderFound) { |
| Debug.logInfo("Loading container: " + containerCfg.name, module); |
| Container tmpContainer = loadContainer(containerCfg, args); |
| this.loadedContainers.add(tmpContainer); |
| Debug.logInfo("Loaded container: " + containerCfg.name, module); |
| } |
| } |
| if (this.unloading) { |
| return; |
| } |
| |
| List<ContainerConfig.Container> containersDefinedInComponents = ComponentConfig.getAllContainers(); |
| for (ContainerConfig.Container containerCfg: containersDefinedInComponents) { |
| boolean matchingLoaderFound = false; |
| if (UtilValidate.isEmpty(containerCfg.loaders) && UtilValidate.isEmpty(loaders)) { |
| matchingLoaderFound = true; |
| } else { |
| for (String loader: loaders) { |
| if (UtilValidate.isEmpty(containerCfg.loaders) || containerCfg.loaders.contains(loader)) { |
| matchingLoaderFound = true; |
| break; |
| } |
| } |
| } |
| if (matchingLoaderFound) { |
| Debug.logInfo("Loading component's container: " + containerCfg.name, module); |
| Container tmpContainer = loadContainer(containerCfg, args); |
| this.loadedContainers.add(tmpContainer); |
| Debug.logInfo("Loaded component's container: " + containerCfg.name, module); |
| } |
| } |
| // Get hot-deploy container configuration files |
| ClassLoader loader = Thread.currentThread().getContextClassLoader(); |
| Enumeration<URL> resources; |
| try { |
| resources = loader.getResources("hot-deploy-containers.xml"); |
| while (resources.hasMoreElements() && !this.unloading) { |
| URL xmlUrl = resources.nextElement(); |
| Debug.logInfo("Loading hot-deploy containers from " + xmlUrl, module); |
| Collection<ContainerConfig.Container> hotDeployContainers = ContainerConfig.getContainers(xmlUrl); |
| for (ContainerConfig.Container containerCfg : hotDeployContainers) { |
| if (this.unloading) { |
| return; |
| } |
| Container tmpContainer = loadContainer(containerCfg, args); |
| this.loadedContainers.add(tmpContainer); |
| } |
| } |
| } catch (Exception e) { |
| Debug.logError(e, "Could not load hot-deploy-containers.xml", module); |
| throw new StartupException(e); |
| } |
| loaded = true; |
| } |
| |
| private Container loadContainer(ContainerConfig.Container containerCfg, String[] args) throws StartupException { |
| // load the container class |
| ClassLoader loader = Thread.currentThread().getContextClassLoader(); |
| if (loader == null) { |
| Debug.logWarning("Unable to get context classloader; using system", module); |
| loader = ClassLoader.getSystemClassLoader(); |
| } |
| Class<?> containerClass = null; |
| try { |
| containerClass = loader.loadClass(containerCfg.className); |
| } catch (ClassNotFoundException e) { |
| throw new StartupException("Cannot locate container class", e); |
| } |
| if (containerClass == null) { |
| throw new StartupException("Component container class not loaded"); |
| } |
| |
| // create a new instance of the container object |
| Container containerObj = null; |
| try { |
| containerObj = (Container) containerClass.newInstance(); |
| } catch (InstantiationException e) { |
| throw new StartupException("Cannot create " + containerCfg.name, e); |
| } catch (IllegalAccessException e) { |
| throw new StartupException("Cannot create " + containerCfg.name, e); |
| } catch (ClassCastException e) { |
| throw new StartupException("Cannot create " + containerCfg.name, e); |
| } |
| |
| if (containerObj == null) { |
| throw new StartupException("Unable to create instance of component container"); |
| } |
| |
| // initialize the container object |
| try { |
| containerObj.init(args, containerCfg.name, configFile); |
| } catch (ContainerException e) { |
| throw new StartupException("Cannot init() " + containerCfg.name, e); |
| } catch (java.lang.AbstractMethodError e) { |
| throw new StartupException("Cannot init() " + containerCfg.name, e); |
| } |
| |
| return containerObj; |
| } |
| |
| private void printThreadDump() { |
| Thread currentThread = Thread.currentThread(); |
| ThreadGroup group = currentThread.getThreadGroup(); |
| while (group.getParent() != null) { |
| group = group.getParent(); |
| } |
| Thread threadArr[] = new Thread[1000]; |
| group.enumerate(threadArr); |
| |
| StringWriter writer = new StringWriter(); |
| PrintWriter out = new PrintWriter(writer); |
| out.println("Thread dump:"); |
| for (Thread t: threadArr) { |
| if (t != null) { |
| ThreadGroup g = t.getThreadGroup(); |
| out.println("Thread: " + t.getName() + " [" + t.getId() + "] @ " + (g != null ? g.getName() : "[none]") + " : " + t.getPriority() + " [" + t.getState().name() + "]"); |
| out.println("--- Alive: " + t.isAlive() + " Daemon: " + t.isDaemon()); |
| for (StackTraceElement stack: t.getStackTrace()) { |
| out.println("### " + stack.toString()); |
| } |
| } |
| } |
| Debug.logInfo(writer.toString(), module); |
| } |
| |
| /** |
| * @see org.ofbiz.base.start.StartupLoader#start() |
| */ |
| @Override |
| public synchronized void start() throws StartupException { |
| if (!this.loaded || this.unloading) { |
| throw new IllegalStateException("start() called on unloaded containers"); |
| } |
| Debug.logInfo("[Startup] Starting containers...", module); |
| // start each container object |
| for (Container container: this.loadedContainers) { |
| if (this.unloading) { |
| return; |
| } |
| Debug.logInfo("Starting container " + container.getName(), module); |
| try { |
| container.start(); |
| } catch (ContainerException e) { |
| throw new StartupException("Cannot start() " + container.getClass().getName(), e); |
| } catch (java.lang.AbstractMethodError e) { |
| throw new StartupException("Cannot start() " + container.getClass().getName(), e); |
| } |
| Debug.logInfo("Started container " + container.getName(), module); |
| } |
| } |
| |
| /** |
| * @see org.ofbiz.base.start.StartupLoader#unload() |
| */ |
| @Override |
| public void unload() throws StartupException { |
| if (!this.unloading) { |
| this.unloading = true; |
| synchronized (this) { |
| Debug.logInfo("Shutting down containers", module); |
| if (Debug.verboseOn()) { |
| printThreadDump(); |
| } |
| // shutting down in reverse order |
| for (int i = this.loadedContainers.size(); i > 0; i--) { |
| Container container = this.loadedContainers.get(i-1); |
| Debug.logInfo("Stopping container " + container.getName(), module); |
| try { |
| container.stop(); |
| } catch (ContainerException e) { |
| Debug.logError(e, module); |
| } |
| Debug.logInfo("Stopped container " + container.getName(), module); |
| } |
| } |
| } |
| } |
| } |