- From: Anselm Baird_Smith <abaird@www43.inria.fr>
- Date: Thu, 14 Nov 1996 13:37:38 +0100 (MET)
- To: www-jigsaw@w3.org
If everything is ok, you should be able to do the following: a) Install the attached file in Jigsaw/src/classes/w3c/jigsaw/contrib/CheckpointResource.java b) Compile that class c) Install it into your URL space (typically in /Admin) This resource will checkpoint your configuration every N seconds. Note that this is roughly tested code, and not all features are implemented (prop and log flush). Problems: - Unless you access it, it will not start (so you really have to GET /Admin/checkpoint for it to start) - If the resource gets unloaded for some reason, it will not start up again. These are two serious problems, my intent is: a) For the first problem, maintain a list of resources that are to be loaded at startup time, ie, have a httpd property giving the name of a file consisting of a list of resource URL. After init, Jigsaw will look them up (which as a side effect will load them into memory) - This is I guess, what Alex suggested this morning. b) The second problem is more complicated, it requires some API changes to be able, for a resource to reject a notifyUnload. Unless I find something better, I will probably make notifyUnload return a boolean, if false, the resource will *not* be unloaded. Alternative is to add a new API in w3c.jigsaw.resources.Resource, eg: public boolean isUnloadable() which would return true by default, before deciding to unload a resource, a resource store would invoke that method and behalf according to the result. Alternative allows for backward compatibility, but I guess no one have played with notifyUnload yet (?) (drawback of alternative is that notifyUnload is no longer atomic, which might be a problem...) Criticisms, advices and opinions on these problems most welcome. Anselm. // CheckpointResource.java // $Id$ // (c) COPYRIGHT MIT and INRIA, 1996. // please first read the full copyright statement in file COPYRIGHT.HTML package w3c.jigsaw.contrib; import w3c.www.http.*; import w3c.jigsaw.http.*; import w3c.jigsaw.resources.*; import w3c.jigsaw.html.*; import java.util.*; /** * A resource that will checkpoint the configuration at regular intervals. * This resource will make sure that current configuration is backed up to * disk at regular (configurable) intervals. * <p>The webmaster can customize what part of the configuration is to be * backed up through boolean attributes. */ public class CheckpointResource extends FilteredResource implements Runnable { /** * Attribute index - Backup interval, in seconds. */ protected static int ATTR_INTERVAL = -1; /** * Attribute index - The priority of the flusher thread. */ protected static int ATTR_PRIORITY = -1; /** * Attribute index - Should we flush the logs too ? */ protected static int ATTR_FLUSHLOG = -1; /** * Attrbute index - Should we save the properties too ? */ protected static int ATTR_FLUSHPROPS = -1; /** * Attribute index - Should we save the configuration ? */ protected static int ATTR_FLUSHCONFIG = -1; static { Class c = null; Attribute a = null; try { c = Class.forName("w3c.jigsaw.contrib.CheckpointResource"); } catch (Exception ex) { ex.printStackTrace(); System.exit(1); } // Register the interval attribute: a = new IntegerAttribute("interval" , new Integer(60) , Attribute.EDITABLE); ATTR_INTERVAL = AttributeRegistry.registerAttribute(c, a); // Register the flusher thread priority a = new IntegerAttribute("thread-priority" , new Integer(2) , Attribute.EDITABLE); ATTR_PRIORITY = AttributeRegistry.registerAttribute(c, a); // Register the flushlog boolean property: a = new BooleanAttribute("flush-logs" , Boolean.FALSE , Attribute.EDITABLE); ATTR_FLUSHLOG = AttributeRegistry.registerAttribute(c, a); // Register the flush properties property: a = new BooleanAttribute("flush-properties" , Boolean.FALSE , Attribute.EDITABLE); ATTR_FLUSHPROPS = AttributeRegistry.registerAttribute(c, a); // Register the flush configuration property: a = new BooleanAttribute("flush-configuration" , Boolean.TRUE , Attribute.EDITABLE); ATTR_FLUSHCONFIG = AttributeRegistry.registerAttribute(c, a); } /** * Our thread, if one is currently attached. */ protected Thread thread = null; /** * Last date at which we checkpointed the configuration */ protected Date checkpoint = null; /** * Is our attached thread still alive ? */ protected boolean alive = false; /** * Start the thread for this object, only if needed. */ protected synchronized void activate() { if (getFlushLog() || getFlushProperties() || getFlushConfiguration()) { if (getInterval() > 0) { alive = true; if (thread == null) { thread = new Thread(this); thread.setName("checkpointer"); thread.setPriority(getPriority()); thread.start(); return; } else { return; } } } // The thread should not be running any more, stop and kill it: if ( thread != null ) { alive = false; thread.stop(); thread = null; } return; } /** * Force our attached thread to stop. */ protected synchronized void stop() { alive = false; thread = null; notify(); } /** * Get the sync interval. * @return An integer number of seconds, or <strong>-1</strong> if * undefined. */ public int getInterval() { return getInt(ATTR_INTERVAL, -1); } /** * Get the priority for our attached thread. * @return An integer priority for the thread, which defaults to * <strong>2</strong> if undefined. */ public int getPriority() { return getInt(ATTR_PRIORITY, 2); } /** * Get the flush log flag. * @return A boolean, <strong>true</strong> if the log is to be flushed at * each refresh interval, <strong>false</strong> otherwise. */ public boolean getFlushLog() { return getBoolean(ATTR_FLUSHLOG, false); } /** * Get the flush properties flag. * @return A boolean, <strong>true</strong> if the properties are to be * flushed, <strong>false</strong> otherwise. */ public boolean getFlushProperties() { return getBoolean(ATTR_FLUSHPROPS, false); } /** * Get the flush configuration flag. * @return A boolean, <strong>true</strong> oif the configuration is to be * flushed at each interval, <strong>false</strong> otherwise. */ public boolean getFlushConfiguration() { return getBoolean(ATTR_FLUSHCONFIG, true); } /** * This resource is being unloaded. * Unloading that object will also stop the thread. However, there is * a bug here, since if the resource gets unloaded for some reason, it * will not be able to wakeup itself at next checkpoint time. */ public void notifyUnload() { stop(); super.notifyUnload(); } /** * We are attached a thread, now it's time to performt the job. */ public void run() { httpd server = getServer(); int interval = -1; try { while ( alive ) { // Are we still alive ? interval = getInterval(); alive = ((getFlushLog() || getFlushProperties() || getFlushConfiguration()) && (interval > 0 )); if ( ! alive ) break; // Wait for something to do: synchronized(this) { try { wait(interval*1000); } catch (InterruptedException ex) { } } // Do what is to be done: if (alive && getFlushConfiguration() ) server.checkpoint(); checkpoint = new Date(); } } catch (Exception ex) { String msg = (getClass().getName() + "@" + getURL() +": exception while running \"" + ex.getMessage() + "\". Stopped."); server.errlog(msg); } finally { thread = null; } } /** * Get the content of that resources. * Will display some usefull commands to start/stop the attached thread * @param request The request to handle. * @exception HTTPException If request processing failed. */ public Reply get(Request request) throws HTTPException { String query = request.getQueryString(); if ( query != null ) { if ( query.equals("start") ) { // Start the thread if needed activate(); } else if (query.equals("stop") ) { // Stop the thread stop(); } } // Emit output: HtmlGenerator g = new HtmlGenerator("CheckpointResource"); g.append("<h1>CheckpointResource status</h1>"); g.append("<p>Checkpoint is currently " , ((thread == null) ? " stopped " : "running") , "."); g.append("<hr>You can:<p><dl>"); g.append("<dt><a href=\"" , getURL() , "?start\">start</a><dd>Start the checkpointer."); g.append("<dt><a href=\"" , getURL() , "?stop\">stop</a><dd>Stop the checkpointer."); g.append("</dl><hr>Last checkpoint at <strong>" , ((checkpoint == null) ? "no checkpoint run yet" : checkpoint.toString()) , "</strong>."); Reply reply = createDefaultReply(request, HTTP.OK); reply.setStream(g); return reply; } /** * Activate the checkpointer at initialization time. * @poaram values Default attribute values. */ public void initialize(Object values[]) { super.initialize(values); activate(); } }
Received on Thursday, 14 November 1996 07:37:42 UTC