/* * Copyright 2000-2001,2004 The Apache Software Foundation. * * Licensed 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.apache.jetspeed.services.daemonfactory; import java.util.Collection; import java.util.Hashtable; import java.util.Iterator; import java.util.Vector; import javax.servlet.ServletConfig; import org.apache.jetspeed.daemon.Daemon; import org.apache.jetspeed.daemon.DaemonConfig; import org.apache.jetspeed.daemon.DaemonContext; import org.apache.jetspeed.daemon.DaemonEntry; import org.apache.jetspeed.daemon.DaemonException; import org.apache.jetspeed.daemon.DaemonNotFoundException; import org.apache.jetspeed.daemon.DaemonThread; import org.apache.jetspeed.services.logging.JetspeedLogFactoryService; import org.apache.jetspeed.services.logging.JetspeedLogger; import org.apache.jetspeed.services.resources.JetspeedResources; import org.apache.turbine.services.TurbineBaseService; /** * * @author <a href="mailto:burton@apache.org">Kevin A. Burton</a> * @author <a href="mailto:sgala@hisitech.com">Santiago Gala</a> */ public class JetspeedDaemonFactoryService extends TurbineBaseService implements DaemonFactoryService { /** * Static initialization of the logger for this class */ private static final JetspeedLogger logger = JetspeedLogFactoryService .getLogger(JetspeedDaemonFactoryService.class.getName()); // BEGIN define the keys for various/default Daemons public final static String FEEDDAEMON_KEY = "org.apache.jetspeed.daemon.impl.FeedDaemon"; public final static String DISKCACHEDAEMON_KEY = "org.apache.jetspeed.daemon.impl.DiskCacheDaemon"; public final static String BADURLMANAGERDAEMON_KEY = "org.apache.jetspeed.daemon.impl.BadURLManagerDaemon"; // END private DaemonContext context = null; /** * Stores mappings of DaemonEntry -> DaemonThreads */ protected Hashtable daemons = new Hashtable(); protected Hashtable threads = new Hashtable(); private DaemonEntry[] entries = null; /** * Late init. Don't return control until early init says we're done. */ public void init() { logger.info("Late init for DaemonFactory called"); while (!getInit()) { try { Thread.sleep(500); } catch (InterruptedException ie) { logger.info("DaemonFactory service: Waiting for init()..."); } } } /** * Perform initialization of the DaemonFactory. Note that this should return * right away so that processing can continue (IE thread off everything) */ public synchronized void init(ServletConfig config) { // already initialized if (getInit()) return; logger.info("Early init for DaemonFactory called..."); this.context = new DaemonContext(); // init daemons from config file Vector raw = JetspeedResources.getVector(JetspeedResources.DAEMON_ENTRY); this.entries = new DaemonEntry[raw.size()]; for (int i = 0; i < raw.size(); ++i) { String name = (String) raw.elementAt(i); String classname = JetspeedResources.getString("daemon." + name + ".classname"); long interval = JetspeedResources.getLong("daemon." + name + ".interval"); boolean onstartup = JetspeedResources.getBoolean("daemon." + name + ".onstartup"); entries[i] = new DaemonEntry(name, interval, classname, onstartup); } setInit(true); logger.info("Early init for DaemonFactory done"); // Finish by starting requested Daemons... this.start(); } /** * <p> * Starts any daemons that need processing. * </p> * * <p> * This should be called right after init() so that any daemons that need to * be started will be. If you need to do any per-daemon initialization then do * so before calling start() * </p> */ public void start() { logger.info("DaemonFactory: Starting up necessary daemons."); // get all the entries.. DaemonEntry[] entries = this.getDaemonEntries(); for (int i = 0; i < entries.length; ++i) { // create Daemon threads for them and pa if (entries[i].onStartup()) { start(entries[i]); } } } /** * Starts a daemon entry * * @param entry */ private void start(DaemonEntry entry) { logger.info("DaemonFactory: start(): starting daemon -> " + entry.getName()); DaemonThread dt = new DaemonThread(entry); this.threads.put(entry, dt); dt.start(); } /** * Stop all daemon thread * * @param entry */ public void stop() { logger.info("DaemonFactory: stop(): stop all daemons"); try { super.shutdown(); Collection threadsValues = threads.values(); Iterator threadsiter = threadsValues.iterator(); while (threadsiter.hasNext()) { Object obj = threadsiter.next(); // ((DaemonThread) obj).stopThread(); ((DaemonThread) obj).interrupt(); } threads.clear(); daemons.clear(); Collection daemonsValues = daemons.values(); Iterator daemonsIter = daemonsValues.iterator(); while (daemonsIter.hasNext()) { Object obj = daemonsIter.next(); Daemon daemon = (Daemon) this.daemons.get(obj.getClass()); daemon.wait(); } } catch (Exception e) { logger.error("Error instantiating DaemonThread", e); } } /** * Allows a Daemon to define its Thread priority through a factory. The Thread * that this object should return should be an implementation of itself. */ public Daemon getDaemon(DaemonEntry entry) throws DaemonException { // FIX ME: before instantiating a daemon ... find out if it is already setup Daemon daemon = (Daemon) this.daemons.get(entry); if (daemon != null) { return daemon; } else { logger.info("Creating daemon: " + entry.getName()); } try { daemon = (Daemon) Class.forName(entry.getClassname()).newInstance(); DaemonConfig dc = new DaemonConfig(); daemon.init(dc, entry); this.daemons.put(entry, daemon); return daemon; } catch (ClassNotFoundException e) { logger.error("Exception", e); throw new DaemonException("daemon not found: " + e.getMessage()); } catch (InstantiationException e) { logger.error("Exception", e); throw new DaemonException("couldn't instantiate daemon: " + e.getMessage()); } catch (IllegalAccessException e) { logger.error("Exception", e); throw new DaemonException(e.getMessage()); } } /** * Get a daemon with the given classname. * * @see #getDaemon( DaemonEntry entry ) */ public Daemon getDaemon(String classname) throws DaemonException { DaemonEntry[] entries = this.getDaemonEntries(); for (int i = 0; i < entries.length; ++i) { if (entries[i].getClassname().equals(classname)) { return getDaemon(entries[i]); } } throw new DaemonException("daemon not found: " + classname); } /** */ public DaemonContext getDaemonContext() { return this.context; } /** * Kicks of processing of a Daemon. Does the same thing as getDaemon() but * also creates a thread and runs the daemon. */ public void process(DaemonEntry entry) throws DaemonException { DaemonThread dt = (DaemonThread) this.threads.get(entry); if (dt == null) { start(entry); dt = (DaemonThread) this.threads.get(entry); } // FIX ME: get the status of this daemon before kicking it off again. int status = this.getStatus(entry); if (status != Daemon.STATUS_PROCESSING && status != Daemon.STATUS_UNKNOWN && dt != null) { // tell this thread to stop waiting and process immediately synchronized (dt) { dt.notify(); } } if (dt != null && dt.isAlive() == false) { dt.start(); } } /** */ public int getStatus(DaemonEntry entry) { try { Daemon daemon = this.getDaemon(entry); return daemon.getStatus(); } catch (DaemonException e) { logger.error("Exception", e); return Daemon.STATUS_UNKNOWN; } } /** * Get the last known result of the given DaemonEntry's processing */ public int getResult(DaemonEntry entry) { try { Daemon daemon = this.getDaemon(entry); return daemon.getResult(); } catch (DaemonException e) { logger.error("Exception", e); return Daemon.RESULT_UNKNOWN; } } /** * Get the last known message of the given DaemonEntry's processing */ public String getMessage(DaemonEntry entry) { try { Daemon daemon = this.getDaemon(entry); return daemon.getMessage(); } catch (DaemonException e) { logger.error("Exception", e); return null; } } /** * Get the current known DaemonEntries within the DaemonFactory */ public DaemonEntry[] getDaemonEntries() { return this.entries; } /** * Given the name of a DaemonEntry... get it from the DaemonFactory */ public DaemonEntry getDaemonEntry(String name) throws DaemonNotFoundException { DaemonEntry[] entries = this.getDaemonEntries(); for (int i = 0; i < entries.length; ++i) { if (entries[i].getName().equals(name)) { return entries[i]; } } throw new DaemonNotFoundException("Could not find daemon named: " + name); } }