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