Difference between revisions of "SMILA/Documentation/HowTo/How to implement an agent"

From Eclipsepedia

Jump to: navigation, search
(New page: This page explains how to implement an Agent and add its functionality to SMILA. == Prepare bundle and manifest == * C...)
 
Line 197: Line 197:
  
 
* Implement your agent in a new class extending <tt>org.eclipse.smila.connectivity.framework.AbstractAgent</tt>.
 
* Implement your agent in a new class extending <tt>org.eclipse.smila.connectivity.framework.AbstractAgent</tt>.
* more info soon ...
+
** this base class already provides implementations for all interface methods except for method <tt>run()</tt> of interface <tt>Runnable</tt>
 +
** you should use the following code snippet as a template for the run method. It already includes checking if the agent was stopped as well as error handling. You only have to fill in the agent business logic.
 +
<source lang="java">
 +
/**
 +
* {@inheritDoc}
 +
*
 +
* @see java.lang.Runnable#run()
 +
*/
 +
public void run() {
 +
    try {
 +
      while (!isStopThread()) {
 +
 
 +
        // fille in the agent business logic
 +
 
 +
      } // while
 +
    } catch (Throwable t) {
 +
      getAgentState().setLastError(t);
 +
      getAgentState().setState(AgentThreadState.Aborted);
 +
      throw new RuntimeException(t);
 +
    } finally {
 +
      try {
 +
        stopThread();
 +
      } catch (Exception e) {
 +
        throw new RuntimeException(e);
 +
      }
 +
    }
 +
}
 +
</source>
 +
* inside your business logic you will have to create new <tt>Id</tt> and <tt>Record</tt> objects. You are encouraged to use the utility classes <tt>ConnectivityIdFactory</tt> and <tt>ConnectivityHashFactory</tt> to create Ids and hashes using your agent configuration. To send add or delete request use method <tt>getControllerCallback()</tt> provided by <tt>org.eclipse.smila.connectivity.framework.AbstractAgent</tt> to get a callback reference to the AgentController. For example
 +
<source lang="java">
 +
// add records
 +
Record[] records = {...}; // first the agent has to create some records
 +
getControllerCallback().add(records);
 +
 
 +
// delete ids
 +
Id[] ids = {...}; // first the agent has to create some ids
 +
getControllerCallback().delete(ids);
 +
</source>
 
* Integrate your new agent bundle into the build process: Refer to the page [[SMILA/Development_Guidelines/How to integrate new bundle into build process|How to integrate new bundle into build process]] for further instructions.
 
* Integrate your new agent bundle into the build process: Refer to the page [[SMILA/Development_Guidelines/How to integrate new bundle into build process|How to integrate new bundle into build process]] for further instructions.
  

Revision as of 06:25, 7 May 2009

This page explains how to implement an Agent and add its functionality to SMILA.

Contents

Prepare bundle and manifest

  • Create a new bundle that will contain your agent. Follow the instructions on How to create a bundle and use the prefix org.eclipse.smila.connectivity.framework.agent for the name of your project.
  • Edit the manifest file and add the following packages to the Import-Package section.
    • com.sun.xml.bind.v2;version="2.1.6"
    • javax.xml.bind;version="2.1.0"
    • javax.xml.bind.annotation;version="2.1.0"
    • javax.xml.bind.annotation.adapters;version="2.1.0"
    • javax.xml.stream;version="1.0.1"
    • org.apache.commons.logging;version="1.0.4"
    • org.eclipse.smila.connectivity;version="0.5.0"
    • org.eclipse.smila.connectivity.framework;version="0.5.0"
    • org.eclipse.smila.connectivity.framework.schema;version="0.5.0"
    • org.eclipse.smila.connectivity.framework.schema.config;version="0.5.0"
    • org.eclipse.smila.connectivity.framework.schema.config.interfaces;version="0.5.0"
    • org.eclipse.smila.connectivity.framework.schema.tools;version="0.5.0"
    • org.eclipse.smila.connectivity.framework.util;version="0.5.0"
    • org.eclipse.smila.datamodel.record;version="0.5.0"
  • you will have to add additional packages to fill you agent with business logic !

Prepare DataSourceConnect schema and classes

  • create an additional source folder code/gen to contain the generated schema sources
    • Right-click your bundle and click New > Source Folder.
    • Enter "code/gen" as the folder name.
    • edit build.properties and add folder code/gen to the source folders.
source.. = code/src/,\
           code/gen/
output.. = code/bin/


  • create schema definition
    • create a folder schema in your bundle
    • create file schemas\MYAGENTDataSourceConnectionConfigSchema.xsd to contain the XSD schema for the agent configuration based on the abstract XSD schema "RootDataSourceConnectionConfigSchema"
    • therin you have to provide definitions of "Process" and "Attribute" nodes for agent specific information
    • the following code snippet can be used as a template
<xs:schema elementFormDefault="qualified" attributeFormDefault="unqualified" xmlns:xs="http://www.w3.org/2001/XMLSchema">
  <xs:redefine schemaLocation="../../org.eclipse.smila.connectivity.framework.schema/schemas/RootDataSourceConnectionConfigSchema.xsd">
    <xs:complexType name="Process">
      <xs:annotation>
        <xs:documentation>Process Specification</xs:documentation>
      </xs:annotation>
      <xs:complexContent>
        <xs:extension base="Process">
 
    	  <\!--define agent specific process here -->
 
        </xs:extension>
      </xs:complexContent>
    </xs:complexType>
    <xs:complexType name="Attribute">
      <xs:complexContent>
        <xs:extension base="Attribute">
 
    	  <\!--define agent specific attributes here -->
 
        </xs:extension>
      </xs:complexContent>
    </xs:complexType>
  </xs:redefine>
</xs:schema>
  • create JAXB mapping
    • create file schemas\MYAGENTDataSourceConnectionConfigSchema.jxb to contain the JAXB mappings used for generating configuration classes.
    • Here is an example for the MockAgent JXB file you can use as a template, just rename the "schemaLocation" and "package name":
<jxb:bindings version="1.0" 
  xmlns:jxb="http://java.sun.com/xml/ns/jaxb" 
  xmlns:xs="http://www.w3.org/2001/XMLSchema" 
>  
  <jxb:bindings schemaLocation="MockDataSourceConnectionConfigSchema.xsd" node="/xs:schema">
    <jxb:schemaBindings>
      <jxb:package name="org.eclipse.smila.connectivity.framework.agent.mock.messages"/>
    </jxb:schemaBindings>    
    <jxb:globalBindings>
      <jxb:javaType name="java.util.Date" xmlType="xs:dateTime" printMethod="org.eclipse.smila.connectivity.framework.schema.tools.SimpleDateFormatter.print" parseMethod="org.eclipse.smila.connectivity.framework.schema.tools.SimpleDateFormatter.parse"/>
      <jxb:javaType name="org.eclipse.smila.connectivity.framework.schema.config.MimeTypeAttributeType" xmlType="MimeTypeAttributeType" parseMethod="org.eclipse.smila.connectivity.framework.schema.config.MimeTypeAttributeType.fromValue" printMethod="org.eclipse.smila.connectivity.framework.schema.config.MimeTypeAttributeType.toValue"/>
      <jxb:serializable uid="1"/>
    </jxb:globalBindings>
  </jxb:bindings>
</jxb:bindings>


  • Add a schema location reference in the plug-in implementation
    • Create a new class (DataSourceConnectionConfigPluginImpl) which implements the interface DataSourceConnectionConfigPlugin.
    • Use the method String getSchemaLocation() to return "schemas/MYAGENTDataSourceConnectionConfigSchema.xsd".
    • Use the method String getMessagesPackage() to return package name"org.eclipse.smila.connectivity.framework.agent.MYAGENT.messages".

Here is an example implementation for the MockAgent you can use as a template:

package org.eclipse.smila.connectivity.framework.agent.mock;
 
import org.eclipse.smila.connectivity.framework.schema.DataSourceConnectionConfigPlugin;
 
/**
 * The Class DataSourceConnectionConfigPluginImpl.
 */
public class DataSourceConnectionConfigPluginImpl implements DataSourceConnectionConfigPlugin {
 
  /**
   * {@inheritDoc}
   * 
   * @see org.eclipse.smila.connectivity.framework.schema.DataSourceConnectionConfigPlugin#getSchemaLocation()
   */
  public String getSchemaLocation() {
    return "schemas/MockDataSourceConnectionConfigSchema.xsd";
  }
 
  /**
   * {@inheritDoc}
   * 
   * @see org.eclipse.smila.connectivity.framework.schema.DataSourceConnectionConfigPlugin#getMessagesPackage()
   */
  public String getMessagesPackage() {
    return "org.eclipse.smila.connectivity.framework.agent.mock.messages";
  }
 
}
  • create new file plugin.xml
    • define the extension for org.eclipse.smila.connectivity.framework.schema.extension, using the bundle name as ID and NAME.
    • set the schema class to your implmenetation of interface DataSourceConnectionConfigPlugin
    • Here is an example for the MockAgent plugin.xml file you can use as a template:
<plugin>
   <extension
         id="org.eclipse.smila.connectivity.framework.agent.mock"
         name="org.eclipse.smila.connectivity.framework.agent.mock"
         point="org.eclipse.smila.connectivity.framework.schema.extension">
      <schema
            class="org.eclipse.smila.connectivity.framework.agent.mock.DataSourceConnectionConfigPluginImpl">
      </schema>
   </extension>
</plugin>


  • Compile schema into JAXB classes by using ant
    • create a new file build.xml to contain JXB build information
    • Launch ant -Dlib.dir=../lib from a cmd console to create the java files or to see any error messages.
    • Use the following template as the content for file build.xml and rename the property value accordingly:
<project name="sub-build" default="compile-schema-and-decorate" basedir=".">
 
  <property name="schema.name" value="MYAGENTDataSourceConnectionConfigSchema" />
 
  <import file="../SMILA.builder/xjc/build.xml" />
 
</project>


Note: If you rename the schema file name, make sure to update the following locations:

  • Plug-in implementation classes
  • MYAGENTDataSourceConnectionConfigSchema.jxb (it also should be renamed with the same name as schema)
  • build.xml

OSGi and Declarative Service requirements

  • It is not required to implement a BundleActivator.
  • Create the top level folder OSGI-INF.
  • Create a Component Description file in OSGI-INF. You can name the file as you like, but it is good practice to name it like the agent. Therein you have to provide a unique component name, it should be the same as the agent's class name. Then you have to provide your implementation class and the service interface class, which is always org.eclipse.smila.connectivity.framework.Agent. Here is an example for the MockAgent component description file you can use as a teemplate:
<component name="MockAgent" immediate="false" factory="AgentFactory">
    <implementation class="org.eclipse.smila.connectivity.framework.agent.mock.MockAgent" />
    <service>
         <provide interface="org.eclipse.smila.connectivity.framework.Agent"/>
    </service>    
</component>
  • Add a Service-Component entry to your manifest file, e.g.:
Service-Component: OSGI-INF/mockagent.xml
  • Open build.properties and change the binary build: Add the folders OSGI-INF and schemas as well as the file plugin.xml.
bin.includes = META-INF/,\
               .,\
               plugin.xml,\
               schemas/,\
               OSGI-INF/


Implement your agent

  • Implement your agent in a new class extending org.eclipse.smila.connectivity.framework.AbstractAgent.
    • this base class already provides implementations for all interface methods except for method run() of interface Runnable
    • you should use the following code snippet as a template for the run method. It already includes checking if the agent was stopped as well as error handling. You only have to fill in the agent business logic.
/**
 * {@inheritDoc}
 * 
 * @see java.lang.Runnable#run()
 */
public void run() {
    try {
      while (!isStopThread()) {
 
        // fille in the agent business logic
 
      } // while
    } catch (Throwable t) {
      getAgentState().setLastError(t);
      getAgentState().setState(AgentThreadState.Aborted);
      throw new RuntimeException(t);
    } finally {
      try {
        stopThread();
      } catch (Exception e) {
        throw new RuntimeException(e);
      }
    }
}
  • inside your business logic you will have to create new Id and Record objects. You are encouraged to use the utility classes ConnectivityIdFactory and ConnectivityHashFactory to create Ids and hashes using your agent configuration. To send add or delete request use method getControllerCallback() provided by org.eclipse.smila.connectivity.framework.AbstractAgent to get a callback reference to the AgentController. For example
// add records
Record[] records = {...}; // first the agent has to create some records
getControllerCallback().add(records);
 
// delete ids
Id[] ids = {...}; // first the agent has to create some ids
getControllerCallback().delete(ids);

[optional]

  • Create a JUnit test bundle for this agent e.g. org.eclipse.smila.connectivity.framework.agent.mock.test.
  • Integrate your test bundle into the build process: Refer to the page How to integrate test bundle into build process) for further instructions.

Run your agent

Running SMILA in eclipse

  • Open the Run dialog, switch to the configuration page of Bundles, select your bundle and set the parameter Default Auto-Start to true.
  • Launch SMILA.launch.

Running SMILA application

  • Insert your bundle , e.g. org.eclipse.smila.connectivity.framework.agent.mock@4:start, to the config.ini file.
  • Launch SMILA by calling either SMILA.exe or eclipse.exe -console