You are viewing a plain text version of this content. The canonical link for it is here.
Posted to dev@turbine.apache.org by sg...@apache.org on 2005/04/07 13:39:09 UTC
cvs commit: jakarta-turbine-fulcrum/yaafi/src/test shutdown.txt TestComponentConfig.xml TestRoleConfig.xml
sgoeschl 2005/04/07 04:39:09
Modified: yaafi/xdocs changes.xml index.xml navigation.xml
yaafi/xdocs/services index.xml
yaafi/src/java/org/apache/fulcrum/yaafi/service/reconfiguration
ReconfigurationEntry.java
yaafi/src/test TestComponentConfig.xml TestRoleConfig.xml
Added: yaafi/xdocs/services shutdownservice.xml
yaafi/src/java/org/apache/fulcrum/yaafi/service/shutdown
Shutdown.java ShutdownEntry.java
ShutdownService.java ShutdownServiceImpl.java
yaafi/src/test shutdown.txt
Log:
Added ShutdownService
Revision Changes Path
1.9 +6 -0 jakarta-turbine-fulcrum/yaafi/xdocs/changes.xml
Index: changes.xml
===================================================================
RCS file: /home/cvs/jakarta-turbine-fulcrum/yaafi/xdocs/changes.xml,v
retrieving revision 1.8
retrieving revision 1.9
diff -u -r1.8 -r1.9
--- changes.xml 31 Mar 2005 12:16:57 -0000 1.8
+++ changes.xml 7 Apr 2005 11:39:09 -0000 1.9
@@ -7,6 +7,12 @@
<body>
<release version="1.0.4-dev" date="as in CVS">
+ <action dev="sgoeschl" type="add">
+ Added a Shutdown service to dispose the YAAFI container
+ </action>
+ <action dev="sgoeschl" type="fix">
+ Updated Turbine integration found in the 'contrib' directory
+ </action>
<action dev="sgoeschl" type="fix">
Updated CLI to make it fit for one of our products
</action>
1.6 +2 -1 jakarta-turbine-fulcrum/yaafi/xdocs/index.xml
Index: index.xml
===================================================================
RCS file: /home/cvs/jakarta-turbine-fulcrum/yaafi/xdocs/index.xml,v
retrieving revision 1.5
retrieving revision 1.6
diff -u -r1.5 -r1.6
--- index.xml 2 Mar 2005 09:42:05 -0000 1.5
+++ index.xml 7 Apr 2005 11:39:09 -0000 1.6
@@ -44,7 +44,8 @@
<li>a light-weight Avalon container only depending an the Avalone Framwork libraries</li>
<li>a container which can run components written for ECM, Fortress, Phoenix and Merlin</li>
<li>ability to be embedded in other Avalon containers such as Phoenix</li>
- <li>support for automatic reconfiguration for the whole container or individual services</li>
+ <li>support for automatic reconfiguration for the whole Avalon container or individual services</li>
+ <li>support for automatic shotdown of the whole Avalon container</li>
<li>support for early or on-demand initialization</li>
<li>support for encrypted configuration files</li>
</ul>
1.6 +1 -0 jakarta-turbine-fulcrum/yaafi/xdocs/navigation.xml
Index: navigation.xml
===================================================================
RCS file: /home/cvs/jakarta-turbine-fulcrum/yaafi/xdocs/navigation.xml,v
retrieving revision 1.5
retrieving revision 1.6
diff -u -r1.5 -r1.6
--- navigation.xml 2 Mar 2005 09:42:05 -0000 1.5
+++ navigation.xml 7 Apr 2005 11:39:09 -0000 1.6
@@ -22,6 +22,7 @@
<item name="ServiceManagerService" href="/services/servicemanagerservice.html"/>
<item name="SystemPropertyService" href="/services/systempropertyservice.html"/>
<item name="ReconfigurationService" href="/services/reconfigurationservice.html"/>
+ <item name="ShutdownService" href="/services/shutdownservice.html"/>
</item>
<item name="Specification" href="/specification/index.html" collapse="true">
<item name="Container Configuration" href="/specification/container.html"/>
1.3 +6 -0 jakarta-turbine-fulcrum/yaafi/xdocs/services/index.xml
Index: index.xml
===================================================================
RCS file: /home/cvs/jakarta-turbine-fulcrum/yaafi/xdocs/services/index.xml,v
retrieving revision 1.2
retrieving revision 1.3
diff -u -r1.2 -r1.3
--- index.xml 16 Feb 2005 11:22:35 -0000 1.2
+++ index.xml 7 Apr 2005 11:39:09 -0000 1.3
@@ -39,6 +39,12 @@
Automatic reconfiguration after changes of the configuration file
</td>
</tr>
+ <tr>
+ <td><a href="shutdownservice.html">ShutdownService</a></td>
+ <td>
+ Automatic shutdown after changes of an arbitrary configuration file
+ </td>
+ </tr>
</table>
</p>
1.1 jakarta-turbine-fulcrum/yaafi/xdocs/services/shutdownservice.xml
Index: shutdownservice.xml
===================================================================
<?xml version="1.0"?>
<document>
<properties>
<title>ShutdownService</title>
<author email="siegfried.goeschl@it20one.at">Siegfried Goeschl</author>
</properties>
<body>
<section name="Overview">
<p>
This service uses a background thread to monitor a resource. A
resource is loaded by using a resource name and an InputStreamLocator.
The a SHA-1 hashcode is derived and compared to the previous hashcode.
If a change is detected the container is disposed, either by
terminating all active threads or by calling System.exit(). This
service allows to shutdown a long-running application by writing
a timestamp into a file therefore avoiding any additional network
support.
</p>
</section>
<section name="Configuration">
<subsection name="Role Configuration">
<source>
<![CDATA[
<role
name="org.apache.fulcrum.yaafi.service.shutdown.ShutdownService"
shorthand="ShutdownService"
default-class="org.apache.fulcrum.yaafi.service.shutdown.ShutdownServiceImpl"
early-init="true"
description="Monitors a resource to force a disposal of the Avalon container"
/>
]]>
</source>
</subsection>
<subsection name="Example Component Configuration">
<p>
The following configuration checks every 5 seconds
if the files have changed. Changing "shutdown.txt"
forces a disposable of the container and invoking
System.exit() afterwards
</p>
<source>
<![CDATA[
<ShutdownService interval="5000">
<entry>
<location>./src/test/shutdown.txt</location>
<useSystemExit>true</useSystemExit>
</entry>
</ShutdownService>
]]>
</source>
</subsection>
</section>
</body>
</document>
1.2 +1 -1 jakarta-turbine-fulcrum/yaafi/src/java/org/apache/fulcrum/yaafi/service/reconfiguration/ReconfigurationEntry.java
Index: ReconfigurationEntry.java
===================================================================
RCS file: /home/cvs/jakarta-turbine-fulcrum/yaafi/src/java/org/apache/fulcrum/yaafi/service/reconfiguration/ReconfigurationEntry.java,v
retrieving revision 1.1
retrieving revision 1.2
diff -u -r1.1 -r1.2
--- ReconfigurationEntry.java 1 Mar 2005 10:43:02 -0000 1.1
+++ ReconfigurationEntry.java 7 Apr 2005 11:39:09 -0000 1.2
@@ -119,7 +119,7 @@
}
catch(Exception e)
{
- String msg = "The ReconfigurationService encountered an internal error";
+ String msg = "The ShutdownService encountered an internal error";
this.getLogger().error(msg,e);
return false;
}
1.1 jakarta-turbine-fulcrum/yaafi/src/java/org/apache/fulcrum/yaafi/service/shutdown/Shutdown.java
Index: Shutdown.java
===================================================================
package org.apache.fulcrum.yaafi.service.shutdown;
/*
* Copyright 2004 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.
*/
import org.apache.avalon.framework.activity.Disposable;
/**
* This class process the shutdown notification from the JVM.
*
* @author <a href="mailto:siegfried.goeschl@it20one.at">Siegfried Goeschl</a>
*/
public class Shutdown implements Runnable
{
/** The service manager tobe disposed */
private Disposable disposable;
/** use System.exit() to shutdown the JVM */
private boolean useSystemExit;
/**
* Constructor
* @param disposable The service manager to be disposed
*/
public Shutdown( Disposable disposable, boolean useSystemExit )
{
this.disposable = disposable;
this.useSystemExit = useSystemExit;
}
/**
* @see java.lang.Runnable#run()
*/
public void run()
{
try
{
this.disposable.dispose();
}
catch (Throwable t)
{
t.printStackTrace();
}
this.disposable = null;
if( this.useSystemExit )
{
System.exit(0);
}
}
}
1.1 jakarta-turbine-fulcrum/yaafi/src/java/org/apache/fulcrum/yaafi/service/shutdown/ShutdownEntry.java
Index: ShutdownEntry.java
===================================================================
package org.apache.fulcrum.yaafi.service.shutdown;
/*
* Copyright 2004 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.
*/
import java.io.ByteArrayOutputStream;
import java.io.File;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.security.MessageDigest;
import org.apache.avalon.framework.logger.Logger;
import org.apache.fulcrum.yaafi.framework.util.InputStreamLocator;
/**
* Monitors a resource and checks if it has changed
*
* @author <a href="mailto:siegfried.goeschl@it20one.at">Siegfried Goeschl</a>
*/
public class ShutdownEntry
{
/** the location to monitor for changes */
private String location;
/** the last message digest of the location */
private byte[] digest;
/** the locator to load the monitored resource */
private InputStreamLocator locator;
/** keep a notice for the very first invocation */
private boolean isFirstInvocation;
/** the logger to be used */
private Logger logger;
/** use System.exit() to shutdown the JVM */
private boolean useSystemExit;
/**
* Constructor
*
* @param logger the logger to use
* @param applicationDir the home directory of the application
* @param location the location to monitor for changes
* @param useSystemExit use System.exit() on shutdown
*/
public ShutdownEntry( Logger logger, File applicationDir, String location, boolean useSystemExit )
{
this.isFirstInvocation = true;
this.useSystemExit = useSystemExit;
this.location = location;
this.locator = new InputStreamLocator( applicationDir );
this.logger = logger;
}
/**
* Has the monitored location changed?
*/
public boolean hasChanged()
{
boolean result = false;
InputStream is = null;
byte[] currDigest = null;
try
{
// get a grip on our resource
is = this.locate();
if( is == null )
{
String msg = "Unable to find the following resource : " + this.getLocation();
this.getLogger().warn(msg);
}
else
{
// calculate a SHA-1 digest
currDigest = this.getDigest(is);
is.close();
is = null;
if( this.isFirstInvocation() == true )
{
isFirstInvocation = false;
this.getLogger().debug( "Storing SHA-1 digest of " + this.getLocation() );
this.setDigest( currDigest );
}
else
{
if( equals( this.digest, currDigest ) == false )
{
this.getLogger().debug( "The following resource has changed : " + this.getLocation() );
this.setDigest( currDigest );
result = true;
}
}
}
return result;
}
catch(Exception e)
{
String msg = "The ShutdownService encountered an internal error";
this.getLogger().error(msg,e);
return false;
}
finally
{
if( is != null )
{
try
{
is.close();
}
catch (Exception e)
{
String msg = "Can't close the InputStream during error recovery";
this.getLogger().error(msg,e);
}
}
}
}
/**
* @return Returns the useSystemExit.
*/
public boolean isUseSystemExit()
{
return useSystemExit;
}
/**
* @return Returns the isFirstInvocation.
*/
private boolean isFirstInvocation()
{
return isFirstInvocation;
}
/**
* @return Returns the location.
*/
private String getLocation()
{
return location;
}
/**
* @return Returns the locator.
*/
private InputStreamLocator getLocator()
{
return locator;
}
/**
* Creates an InputStream
*/
public InputStream locate() throws IOException
{
return this.getLocator().locate(this.getLocation());
}
/**
* Creates a message digest
*/
private byte[] getDigest( InputStream is )
throws Exception
{
byte[] result = null;
byte[] content = null;
ByteArrayOutputStream baos = new ByteArrayOutputStream();
copy( is, baos );
content = baos.toByteArray();
baos.close();
MessageDigest sha1 = MessageDigest.getInstance( "SHA1" );
sha1.update( content );
result = sha1.digest();
return result;
}
/**
* @param digest The digest to set.
*/
private void setDigest(byte [] digest)
{
this.digest = digest;
}
/**
* Compares two byte[] for equality
*/
private static boolean equals(byte[] lhs, byte[] rhs)
{
if( lhs == rhs )
{
return true;
}
else if( lhs.length != rhs.length )
{
return false;
}
else
{
for( int i=0; i<lhs.length; i++ )
{
if( lhs[i] != rhs[i] )
{
return false;
}
}
}
return true;
}
/**
* Pumps the input stream to the output stream.
*
* @param is the source input stream
* @param os the target output stream
* @throws IOException the copying failed
*/
private static void copy( InputStream is, OutputStream os )
throws IOException
{
byte[] buf = new byte[1024];
int n = 0;
int total = 0;
while ((n = is.read(buf)) > 0)
{
os.write(buf, 0, n);
total += n;
}
is.close();
os.flush();
os.close();
}
/**
* @return Returns the logger.
*/
private Logger getLogger()
{
return logger;
}
}
1.1 jakarta-turbine-fulcrum/yaafi/src/java/org/apache/fulcrum/yaafi/service/shutdown/ShutdownService.java
Index: ShutdownService.java
===================================================================
package org.apache.fulcrum.yaafi.service.shutdown;
/*
* Copyright 2004 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.
*/
/**
* Monitors a resource for shutting down the Avalon container
*
* @author <a href="mailto:siegfried.goeschl@it20one.at">Siegfried Goeschl</a>
*/
public interface ShutdownService
{
// This interface doesn't exposes any other methods
}
1.1 jakarta-turbine-fulcrum/yaafi/src/java/org/apache/fulcrum/yaafi/service/shutdown/ShutdownServiceImpl.java
Index: ShutdownServiceImpl.java
===================================================================
package org.apache.fulcrum.yaafi.service.shutdown;
/*
* Copyright 2004 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.
*/
import java.io.File;
import java.security.MessageDigest;
import org.apache.avalon.framework.activity.Disposable;
import org.apache.avalon.framework.activity.Initializable;
import org.apache.avalon.framework.activity.Startable;
import org.apache.avalon.framework.configuration.Configuration;
import org.apache.avalon.framework.configuration.ConfigurationException;
import org.apache.avalon.framework.configuration.Reconfigurable;
import org.apache.avalon.framework.context.Context;
import org.apache.avalon.framework.context.ContextException;
import org.apache.avalon.framework.context.Contextualizable;
import org.apache.avalon.framework.logger.AbstractLogEnabled;
import org.apache.avalon.framework.service.ServiceException;
import org.apache.avalon.framework.service.ServiceManager;
import org.apache.avalon.framework.service.Serviceable;
/**
* Monitors the componentConfiguration.xml and triggers a reconfiguration
* if the content of the component configuration file has changed.
*
* @author <a href="mailto:siegfried.goeschl@it20one.at">Siegfried Goeschl</a>
*/
public class ShutdownServiceImpl
extends AbstractLogEnabled
implements ShutdownService, Serviceable, Contextualizable,
Reconfigurable, Initializable, Runnable, Startable, Disposable
{
/** the interval between two checks in ms */
private int interval;
/** shall the worker thread terminate immediately */
private boolean terminateNow;
/** the worker thread polling the resource */
private Thread workerThread;
/** the ServiceManager to use */
private ServiceManager serviceManager;
/** the application directory */
private File applicationDir;
/** our own and only shutdown entry */
private ShutdownEntry shutdownEntry;
/////////////////////////////////////////////////////////////////////////
// Avalon Service Lifecycle Implementation
/////////////////////////////////////////////////////////////////////////
/**
* Constructor
*/
public ShutdownServiceImpl()
{
this.terminateNow = false;
}
/**
* @see org.apache.avalon.framework.service.Serviceable#service(org.apache.avalon.framework.service.ServiceManager)
*/
public void service(ServiceManager manager) throws ServiceException
{
this.serviceManager = manager;
}
/**
* @see org.apache.avalon.framework.context.Contextualizable#contextualize(org.apache.avalon.framework.context.Context)
*/
public void contextualize(Context context) throws ContextException
{
this.applicationDir = (File) context.get("urn:avalon:home");
}
/**
* @see org.apache.avalon.framework.configuration.Configurable#configure(org.apache.avalon.framework.configuration.Configuration)
*/
public void configure(Configuration configuration) throws ConfigurationException
{
// limit to minimum interval of 1 second
this.interval = Math.max( configuration.getAttributeAsInteger("interval",5000), 1000 );
this.getLogger().debug( "Monitoring the resources every " + this.interval + " ms" );
if( configuration.getChild("entry",false) != null )
{
Configuration shutdownConfig = configuration.getChild("entry");
String shutdownEntryLocation = shutdownConfig.getChild("location").getValue();
this.shutdownEntry = new ShutdownEntry(
this.getLogger(),
this.applicationDir,
shutdownEntryLocation,
shutdownConfig.getChild("useSystemExit").getValueAsBoolean(false)
);
this.getLogger().debug( "Using a shutdown entry : " + shutdownEntryLocation );
}
else
{
this.shutdownEntry = null;
this.getLogger().debug( "No shutdown entry defined" );
}
}
/**
* @see org.apache.avalon.framework.activity.Initializable#initialize()
*/
public void initialize() throws Exception
{
// request a SHA-1 to make sure that it is supported
MessageDigest.getInstance( "SHA1" );
// check that the ServiceManager inplements Disposable
if( (this.serviceManager instanceof Disposable) == false )
{
String msg = "The ServiceManager instance does not implement Disposable?!";
throw new IllegalArgumentException( msg );
}
// create the worker thread polling the target
this.workerThread = new Thread( this, "ShutdownService" );
}
/**
* @see org.apache.avalon.framework.activity.Startable#start()
*/
public void start() throws Exception
{
this.getLogger().debug( "Starting worker thread ..." );
this.workerThread.start();
}
/**
* @see org.apache.avalon.framework.activity.Startable#stop()
*/
public void stop() throws Exception
{
this.getLogger().debug( "Stopping worker thread ..." );
this.terminateNow = true;
this.workerThread.interrupt();
this.workerThread.join( 10000 );
}
/**
* @see org.apache.avalon.framework.activity.Disposable#dispose()
*/
public void dispose()
{
this.terminateNow = false;
this.applicationDir = null;
this.workerThread = null;
this.serviceManager = null;
}
/**
* @see org.apache.avalon.framework.configuration.Reconfigurable#reconfigure(org.apache.avalon.framework.configuration.Configuration)
*/
public void reconfigure(Configuration configuration)
throws ConfigurationException
{
this.configure(configuration);
}
/////////////////////////////////////////////////////////////////////////
// Service interface implementation
/////////////////////////////////////////////////////////////////////////
/**
* @see java.lang.Runnable#run()
*/
public void run()
{
while( this.terminateNow == false )
{
if( this.hasShutdownEntry() && this.getShutdownEntry().hasChanged() )
{
if( this.serviceManager instanceof Disposable )
{
if( this.getShutdownEntry().isUseSystemExit() )
{
this.getLogger().warn( "Forcing a shutdown using System.exit() ..." );
}
else
{
this.getLogger().warn( "Forcing a shutdown ..." );
}
// create a demon thread to shutdown the container
Shutdown shutdown = new Shutdown(
(Disposable) this.serviceManager,
this.getShutdownEntry().isUseSystemExit()
);
Thread shutdownThread = new Thread( shutdown, "ShutdownServiceThread" );
shutdownThread.setDaemon(true);
shutdownThread.start();
}
}
}
}
/////////////////////////////////////////////////////////////////////////
// Service implementation
/////////////////////////////////////////////////////////////////////////
/**
* @return Returns the shutdownEntry.
*/
private ShutdownEntry getShutdownEntry()
{
return this.shutdownEntry;
}
/**
* @return Is a shutdown entry defined?
*/
private boolean hasShutdownEntry()
{
return ( this.shutdownEntry != null ? true : false );
}
}
1.4 +11 -0 jakarta-turbine-fulcrum/yaafi/src/test/TestComponentConfig.xml
Index: TestComponentConfig.xml
===================================================================
RCS file: /home/cvs/jakarta-turbine-fulcrum/yaafi/src/test/TestComponentConfig.xml,v
retrieving revision 1.3
retrieving revision 1.4
diff -u -r1.3 -r1.4
--- TestComponentConfig.xml 1 Mar 2005 10:53:04 -0000 1.3
+++ TestComponentConfig.xml 7 Apr 2005 11:39:09 -0000 1.4
@@ -21,6 +21,17 @@
<service name="org.apache.fulcrum.yaafi.service.systemproperty.SystemPropertyService"/>
</services>
</entry>
+ <shutdown>
+ <location>./src/test/shutdown.txt</location>
+ <useSystemExit>false</useSystemExit>
+ </shutdown>
</ReconfigurationService>
+
+ <ShutdownService interval="5000">
+ <entry>
+ <location>./src/test/shutdown.txt</location>
+ <useSystemExit>true</useSystemExit>
+ </entry>
+ </ShutdownService>
</componentConfig>
\ No newline at end of file
1.5 +9 -0 jakarta-turbine-fulcrum/yaafi/src/test/TestRoleConfig.xml
Index: TestRoleConfig.xml
===================================================================
RCS file: /home/cvs/jakarta-turbine-fulcrum/yaafi/src/test/TestRoleConfig.xml,v
retrieving revision 1.4
retrieving revision 1.5
diff -u -r1.4 -r1.5
--- TestRoleConfig.xml 1 Mar 2005 10:53:04 -0000 1.4
+++ TestRoleConfig.xml 7 Apr 2005 11:39:09 -0000 1.5
@@ -28,6 +28,15 @@
description="Monitors the componentConfiguration.xml to reconfigure YAAFI"
/>
<role
+ name="org.apache.fulcrum.yaafi.service.shutdown.ShutdownService"
+ shorthand="ShutdownService"
+ default-class="org.apache.fulcrum.yaafi.service.shutdown.ShutdownServiceImpl"
+ early-init="true"
+ component-type="avalon"
+ component-flavour="yaafi"
+ description="Monitors a resource to force a disposal of the Avalon container"
+ />
+ <role
name="org.apache.fulcrum.yaafi.TestComponent"
shorthand="test"
default-class="org.apache.fulcrum.yaafi.TestComponentImpl"
1.1 jakarta-turbine-fulcrum/yaafi/src/test/shutdown.txt
<<Binary file>>
---------------------------------------------------------------------
To unsubscribe, e-mail: turbine-dev-unsubscribe@jakarta.apache.org
For additional commands, e-mail: turbine-dev-help@jakarta.apache.org