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/05/09 19:52:50 UTC
cvs commit: jakarta-turbine-fulcrum/yaafi/xdocs/tutorial index.xml step1.xml step2.xml step3.xml step4.xml step5.xml
sgoeschl 2005/05/09 10:52:50
Modified: yaafi/xdocs changes.xml navigation.xml
Added: yaafi/xdocs/tutorial index.xml step1.xml step2.xml step3.xml
step4.xml step5.xml
Log:
Added a simple YAAFI tutorial
Revision Changes Path
1.12 +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.11
retrieving revision 1.12
diff -u -r1.11 -r1.12
--- changes.xml 9 May 2005 12:09:56 -0000 1.11
+++ changes.xml 9 May 2005 17:52:50 -0000 1.12
@@ -7,6 +7,12 @@
<body>
<release version="1.0.4-dev" date="as in CVS">
+ <action dev="sgoeschl" type="add">
+ Added a simple tutorial
+ </action>
+ <action dev="sgoeschl" type="fix">
+ Fixed bug in ShutdownService reslulting in excessive CPU usage.
+ </action>
<action dev="sgoeschl" type="update">
Improved the implementation of BaseServiceImpl
</action>
1.7 +7 -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.6
retrieving revision 1.7
diff -u -r1.6 -r1.7
--- navigation.xml 7 Apr 2005 11:39:09 -0000 1.6
+++ navigation.xml 9 May 2005 17:52:50 -0000 1.7
@@ -31,6 +31,13 @@
<item name="Avalon Context" href="/specification/context.html"/>
<item name="Lifecycle Contract" href="/specification/lifecycle.html"/>
</item>
+ <item name="Tutorial" href="/tutorial/index.html" collapse="true">
+ <item name="Step 1" href="/tutorial/step1.html"/>
+ <item name="Step 2" href="/tutorial/step2.html"/>
+ <item name="Step 3" href="/tutorial/step3.html"/>
+ <item name="Step 4" href="/tutorial/step4.html"/>
+ <item name="Step 5" href="/tutorial/step5.html"/>
+ </item>
<item name="Todo's" href="/todo.html"/>
</menu>
1.1 jakarta-turbine-fulcrum/yaafi/xdocs/tutorial/index.xml
Index: index.xml
===================================================================
<?xml version="1.0"?>
<document>
<properties>
<title>Avalon Service Tutorial</title>
<author email="siegfried.goeschl@it20one.at">Siegfried Goeschl</author>
</properties>
<body>
<section name="Avalon Service Tutorial">
<p>
This tutorial demonstrate how to write an Avalon service - in our
case an Avalon SystemProperty Service.
</p>
<subsection name="What We Want to Do?!">
<p>
The service will implement the following features
<ul>
<li>read the system properties to be set from the component configuration file</li>
<li>write some diagnostic output to the logfile</li>
<li>be reconfigurable without restarting the container</li>
</ul>
</p>
</subsection>
<subsection name="The Five Steps to Happiness">
<ul>
<li><a href="step1.html">The Role Configuration File</a></li>
<li><a href="step2.html">The Component Configuration File</a></li>
<li><a href="step3.html">Implementing an Avalon Service</a></li>
<li><a href="step4.html">Running an Avalon Service</a></li>
<li><a href="step5.html">Odds and Ends</a></li>
</ul>
</subsection>
</section>
</body>
</document>
1.1 jakarta-turbine-fulcrum/yaafi/xdocs/tutorial/step1.xml
Index: step1.xml
===================================================================
<?xml version="1.0"?>
<document>
<properties>
<title>Avalon Service Tutorial Step 1</title>
<author email="siegfried.goeschl@it20one.at">Siegfried Goeschl</author>
</properties>
<body>
<section name="The Role Configuration File">
<p>
The role configuration file is a XML file containing configuration
information for the Avalon Service Container.
</p>
<subsection name="Adding the Avalon SystemProperty Service">
<p>
The following information is needed by the Avalon Service Container to
manage our service
<table>
<tr>
<th>Entry</th>
<th>Descriptoin</th>
</tr>
<tr>
<td>name</td>
<td>The name to lookup the service usually the interface class name</td>
</tr>
<tr>
<td>shorthand</td>
<td>The shorthand to lookup the configuration in the Compontent Configuration</td>
</tr>
<tr>
<td>default-class</td>
<td>The implementation class of the service</td>
</tr>
</table>
<source><![CDATA[
<?xml version="1.0" encoding="UTF-8"?>
<role-list>
<role
name="org.apache.fulcrum.yaafi.service.systemproperty.SystemPropertyService"
shorthand="SystemPropertyService"
default-class="org.apache.fulcrum.yaafi.service.systemproperty.SystemPropertyServiceImpl"
/>
</role-list>
]]></source>
</p>
</subsection>
</section>
</body>
</document>
1.1 jakarta-turbine-fulcrum/yaafi/xdocs/tutorial/step2.xml
Index: step2.xml
===================================================================
<?xml version="1.0"?>
<document>
<properties>
<title>Avalon Service Tutorial Step 2</title>
<author email="siegfried.goeschl@it20one.at">Siegfried Goeschl</author>
</properties>
<body>
<section name="The Component Configuration File">
<p>
The component configuration file is a XML file containing configuration
information for the instantiated Avalone services.
</p>
<subsection name="Adding the Avalon SystemProperty Service">
<p>
For finding the right section of the component configuration file
the shorthand of the role configuration is used - in our case
"SystemPropertyService". Here we define a system property with the
name "FOO" and the value "BAR".
<source><![CDATA[
<?xml version="1.0" encoding="UTF-8"?>
<componentConfig>
<SystemPropertyService>
<property name="FOO">BAR</property>
</SystemPropertyService>
</componentConfig>
]]></source>
</p>
</subsection>
</section>
</body>
</document>
1.1 jakarta-turbine-fulcrum/yaafi/xdocs/tutorial/step3.xml
Index: step3.xml
===================================================================
<?xml version="1.0"?>
<document>
<properties>
<title>Avalon Service Tutorial Step 3</title>
<author email="siegfried.goeschl@it20one.at">Siegfried Goeschl</author>
</properties>
<body>
<section name="Implementing an Avalon Service">
<subsection name="Defining an Interface and an Implementation Class">
<p>
The evry first step is to define an interface and a corresponding implementation
class.
<ul>
<li>org.apache.fulcrum.yaafi.service.systemproperty.SystemPropertyService as interface</li>
<li>org.apache.fulcrum.yaafi.service.systemproperty.SystemPropertyServiceImpl as implementation class</li>
</ul>
</p>
</subsection>
<subsection name="Writing the interface">
<p>
The interface exposes only business methods and never ever one of the various Avalon
interfaces.
<source><![CDATA[
public interface SystemPropertyService
{
// This interface doesn't exposes any other methods
}
]]></source>
</p>
</subsection>
<subsection name="Chasing the Interfaces to Implement">
<p>
The Avalon Service Container interacts with an Avalon service through a bunch
of interfaces and finding the right one's might be challenge in the beginning. Our
service needs access to the logging infrastructure, to the component configuration
and needs to tell the Avalon Service Container that it is reconfigurable:
<source><![CDATA[
public class SystemPropertyServiceImpl
extends AbstractLogEnabled
implements SystemPropertyService, Reconfigurable
{
// here comes the implementation ...
}
]]></source>
</p>
<p>
Our service is deriving from "AbstractLogEnabled" which takes care of getting
access to the logger. The implementation class also implements the "Reconfigurable"
interface which tells the Avalon Service Container that the service implements
<ul>
<li>public void configure(Configuration configuration)</li>
<li>public void reconfigure(Configuration configuration)</li>
</ul>
</p>
</subsection>
<subsection name="Accessing the Component Configuration">
<p>
In the Role Configuration file we defined "SystemPropertyService" as shorthand for accessing
the Component Configuration. The Component Configuration we use is shown below
<source><![CDATA[
<SystemPropertyService>
<property name="FOO">BAR</property>
</SystemPropertyService>
]]></source>
</p>
<p>
Let's access the configuration to set the system properties - we get all childrem from
the configuration instance and process them. Each child consists of an attribute
containing the name and text for the value of the system property to be set. We also
write some diagnostic ouptut by requesting the logger instance from "AbstractLogEnabled".
<source><![CDATA[
public void configure(Configuration configuration) throws ConfigurationException
{
Configuration[] systemProperties = configuration.getChildren("property");
for( int i=0; i<systemProperties.length; i++ )
{
String key = systemProperties[i].getAttribute("name");
String value = systemProperties[i].getValue();
this.getLogger().debug( "Setting the value of " + key + " to " + value );
System.setProperty( key, value );
}
}
]]></source>
</p>
</subsection>
<subsection name="Implementing the Reconfiguration">
<p>
Making our service reconfigurable is simple. When the service is
reconfigured a new configuration instance is passed. We just reuse
the configure() method to reinitalize our service - that's it.
<source><![CDATA[
public void reconfigure(Configuration configuration) throws ConfigurationException
{
this.configure(configuration);
}
]]></source>
</p>
</subsection>
<subsection name="Putting it all together">
<p>
Here is our complete and fully functional Avalon service
<source><![CDATA[
public interface SystemPropertyService
{
// This interface doesn't exposes any other methods
}
public class SystemPropertyServiceImpl
extends AbstractLogEnabled
implements SystemPropertyService, Reconfigurable
{
public void configure(Configuration configuration) throws ConfigurationException
{
Configuration[] systemProperties = configuration.getChildren("property");
for( int i=0; i<systemProperties.length; i++ )
{
String key = systemProperties[i].getAttribute("name");
String value = systemProperties[i].getValue();
this.getLogger().debug( "Setting the value of " + key + " to " + value );
System.setProperty( key, value );
}
}
public void reconfigure(Configuration configuration) throws ConfigurationException
{
this.configure(configuration);
}
]]></source>
</p>
</subsection>
</section>
</body>
</document>
1.1 jakarta-turbine-fulcrum/yaafi/xdocs/tutorial/step4.xml
Index: step4.xml
===================================================================
<?xml version="1.0"?>
<document>
<properties>
<title>Avalon Service Tutorial Step 4</title>
<author email="siegfried.goeschl@it20one.at">Siegfried Goeschl</author>
</properties>
<body>
<section name="Running an Avalon Service">
<p>
Writing an Avalon service without running it is a rather
academic approach. The YAAFI container was born out of the need
to add infrastructure service to an existing web application.
Therefore there are many ways to skin the YAAFI cat
<ul>
<li>Using the org.apache.fulcrum.yaafi.framework.factory.ServiceContainerFactory</li>
<li>Using the org.apache.fulcrum.yaafi.cli.Main</li>
<li>Using another Avalon container</li>
</ul>
</p>
<subsection name="Using ServiceContainerFactory">
<p>
The easist way of getting it going is to define a container configuration
file as shown below. The file contains the location of the Avalon artifacts
to get the container and the services up and running.
<source><![CDATA[
<?xml version="1.0" encoding="UTF-8"?>
<fulcrum-yaafi>
<componentRoles>
<location>./tutorial/conf/componentRoles.xml</location>
</componentRoles>
<componentConfiguration>
<location>./tutorial/conf/componentConfig.xml</location>
</componentConfiguration>
<parameters>
<location>./tutorial/conf/parameters.properties</location>
</parameters>
</fulcrum-yaafi>
]]></source>
</p>
<p>
After writing the container configuration file you fire up
the factory to get an instance of the YAAFI container. Since
all of the optional configuration the YAAFI container uses
the default temp directory and a ConsoleLogger.
<source><![CDATA[
ServiceContainer container = null;
ServiceContainerConfiguration config = null;
config = new ServiceContainerConfiguration();
config.loadContainerConfiguration( "./tutorial/conf/containerConfiguration.xml" );
container = ServiceContainerFactory.create( config );
]]></source>
</p>
<p>
It is gooooooood practice to shutdown an Avalon container properly
to give the running Avalon service a chance to free any
resources
<source><![CDATA[
container.dispose();
]]></source>
</p>
</subsection>
<subsection name="Using Main">
<p>
This class helps to run a command line application based on the YAAFI
container. The following sample shows a more complex setup
<ul>
<li>uses a ConsoleLogger</li>
<li>sets "./temp" as the temporary directory to be used</li>
<li>loads a container configuration file from "./conf/containerConfiguration.xml</li>
<li>blocks the main thread until termination</li>
<li>installs a JVM shutdown hook to dispose the YAAFI container during JVM shutdown</li>
</ul>
<source><![CDATA[
public class Application implements Runnable
{
/** the YAAFI command line interface */
private Main cli;
public static void main( String[] args )
{
try
{
new Application(args).init().run();
}
catch( Throwable t )
{
String msg = "Execution of the server failed : " + t.getMessage();
System.err.println(msg);
}
}
public Application(String[] args)
{
this.cli = new Main(args);
}
protected Application init() throws Exception
{
// 1) initialize the YAAFI Main class
// 1.1) set the temp directory to be used
this.cli.setTempHome( "./tutorial/temp" );
// 1.2) set the container configuration to bootstrap the YAAFI container
this.cli.setContainerConfigValue( "./tutorial/conf/containerConfiguration.xml" );
// 1.3) block the main thread until the JVM is terminated
this.cli.setIsBlocking(true);
// 1.4) install a JVM shutdown hook to dispose the YAAFI container
this.cli.setHasShutdownHook(true);
// 2) initialize the logger
ConsoleLogger consoleLogger = new ConsoleLogger(ConsoleLogger.LEVEL_DEBUG);
this.cli.setLogger( consoleLogger );
return this;
}
public void run()
{
try
{
this.cli.initialize();
this.cli.getLogger().info( "The application is up and running ..." );
this.cli.onWait();
}
catch (Throwable t)
{
String msg = "Running the server failed due to : " + t.getMessage();
this.cli.getLogger().error(msg,t);
throw new RuntimeException(msg);
}
}
}
]]></source>
</p>
</subsection>
<subsection name="Using Another Avalon Container">
<p>
Emebdding YAAFI into another Avalon container might sound like
a no-brainer but YAAFI was successfully integrated as Avalon
service in the JAMES mail server using the Phoenix container.
The ugly truth behind it is the fact that Avalon services might
not be portable across different Avalon service containers which
definitely is a no-brainer.
</p>
<source><![CDATA[
<block name="fulcrum-yaafi" class="org.apache.fulcrum.yaafi.framework.container.ServiceContainerImpl" />
<fulcrum-yaafi>
<containerFlavour>phoenix</containerFlavour>
<componentRoles>
<location>../conf/componentRoles.xml</location>
</componentRoles>
<componentConfiguration>
<location>../conf/componentConfiguration.xml</location>
</componentConfiguration>
</fulcrum-yaafi>
]]></source>
</subsection>
</section>
</body>
</document>
1.1 jakarta-turbine-fulcrum/yaafi/xdocs/tutorial/step5.xml
Index: step5.xml
===================================================================
<?xml version="1.0"?>
<document>
<properties>
<title>Avalon Service Tutorial Step 4</title>
<author email="siegfried.goeschl@it20one.at">Siegfried Goeschl</author>
</properties>
<body>
<section name="Odds and Ends">
<subsection name="Setting Up A Logger">
<p>
The YAAFI container expects that you setup the logging facilty to be used.
The Avalon Service Framework provides wrappers for commonly used loggers such
as
<ul>
<li>JDK 1.4 logger</li>
<li>Log4J logger</li>
<li>LogKit logger</li>
<li>Console logger</li>
<li>Null logger</li>
</ul>
</p>
<p>
The following examples shows how to use a Log4J logger
<source><![CDATA[
Main cli = new Main(args)
String log4jConfig = cli.makeAbsolutePath( System.getProperty("log4j.configuration", "./conf/log4j.properties") );
PropertyConfigurator.configureAndWatch( log4jConfig, 2000 );
cli.setLogger( new Log4JLogger( Logger.getLogger("main") ) );
]]></source>
</p>
</subsection>
</section>
</body>
</document>
---------------------------------------------------------------------
To unsubscribe, e-mail: turbine-dev-unsubscribe@jakarta.apache.org
For additional commands, e-mail: turbine-dev-help@jakarta.apache.org