blob: 150a488dde260cfdfe70dfe46fef0b1ac41aef4f [file] [log] [blame]
<?xml version="1.0"?>
<!--
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.
-->
<document>
<properties>
<title>Fulcrum YAAFI Avalon Container 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 also known as
<a href="../lifecycle/index.html">Avalon Lifecycle
Management Specification</a>. Finding the right interface might be
challenge in the beginning but it is not an unsurmountable task.
Our service needs access to the logging infrastructure, to the
component configuration and needs to tell the Avalon Service
Container that it is reconfigurable. To make things more
interesting we want to dump the updated system properties into
the temp directory of the application during service initialization.
<source><![CDATA[
public class SystemPropertyServiceImpl
extends AbstractLogEnabled
implements SystemPropertyService, Reconfigurable, Contextualizable, Initializable
{
// here comes the implementation ...
}
]]></source>
</p>
<p>
Our service derives 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>
<p>
The information about the application context is provided by
the "Contextualizable" interface while the service initialization
needs the "Initializable" interface.
</p>
</subsection>
<subsection name="Accessing the Avalon Context">
<p>
The <a href="../specification/context.html">Avalon Context </a>contains
environment settings such as the current working directory, the
temporary directory or the name of the service.
<source><![CDATA[
public void contextualize(Context context) throws ContextException
{
this.tempDir = (File) context.get("urn:avalon:temp");
}
]]></source>
</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="Service Initialization ">
<p>
Since we have done most of our work already we use the
service initialization to dump the current system properties
into the temporary directory.
<source><![CDATA[
public void initialize() throws Exception
{
FileOutputStream fos = new FileOutputStream( new File(this.tempDir,"system.properties") );
System.getProperties().store( fos, "system.properties" );
fos.flush();
fos.close();
}
]]></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>
Below you find your first 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, Contextualizable, Initializable
{
/** the Avalon temp directory */
private File tempDir;
/**
* @see org.apache.avalon.framework.context.Contextualizable#contextualize(org.apache.avalon.framework.context.Context)
*/
public void contextualize(Context context) throws ContextException
{
this.tempDir = (File) context.get("urn:avalon:temp");
}
/**
* @see org.apache.avalon.framework.configuration.Configurable#configure(org.apache.avalon.framework.configuration.Configuration)
*/
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 );
}
}
/**
* @see org.apache.avalon.framework.activity.Initializable#initialize()
*/
public void initialize() throws Exception
{
FileOutputStream fos = new FileOutputStream( new File(this.tempDir,"system.properties") );
System.getProperties().store( fos, "system.properties" );
fos.flush();
fos.close();
}
/**
* @see org.apache.avalon.framework.configuration.Reconfigurable#reconfigure(org.apache.avalon.framework.configuration.Configuration)
*/
public void reconfigure(Configuration configuration)
throws ConfigurationException
{
this.configure(configuration);
}
}
]]></source>
</p>
</subsection>
</section>
</body>
</document>