xdocs/tutorial/step3.xml (199 lines of code) (raw):

<?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>