![]() |
![]() |
|
|
Developing an Event Adapter
Event adapters propagate information from an EIS into the Application Integration environment. These types of adapters can be described as publishers of information. On the Application Integration integration platform, all event adapters perform the following three functions:
The Application Integration implements the aspects of these three functions that are generic across all event adapters. You only need to focus on the EIS specific aspects of your adapter.
This section contains information on the following subjects:
Event Adapters in the Runtime Environment
The behavior of an Event in the runtime environment is depicted in Figure 7-1.
Figure 7-1 Event Adapters in the Runtime Environment
The Flow of Events
Figure 7-2 outlines the steps required to develop an Event Adapter.
Figure 7-2 Event Adapter Flow of Events
Step 1: Development Considerations
These are the items you need to consider before commencing with event adapter development. The Adapter Setup Worksheet will provide much of this information. See Adapter Setup Worksheet.
You need to identify what exactly comprises the event:
Next, you need to decide which method of data extraction will be used:
Use the pull method when your adapter needs to poll the EIS to determine a change-of-state. Use a push event when you want to implement an event generation that works more like a publish/subscribe model.
Step 2: Configuring the Development Environment
This step describes the processes you must complete to prepare your computer for adapter development.
Step 2a: Set up the File Structure
The file structure necessary to build an event adapter is the same as that required for service adapters. See "Step 2a: Set up the File Structure" in "Developing a Service Adapter."
Step 2b: Assign the Adapter Logical Name
Next, you need to assign the adapter's logical name. By convention, this name is comprised of the vendor name, the type of EIS connected to the adapter, and the version number of the EIS and is expressed as vendor_EIS-type_EIS version. For example, BEA_WLS_SAMPLE_ADK, where:
Step 2c: Set Up the Build Process
The Application Integration employs a build process based upon Ant, a 100% pure Java-based build tool. For more information on Ant, please see Ant-Based Build Process. For more information on using Ant, see http://jakarta.apache.org/ant/index.html.
The sample adapter shipped with BEA WebLogic Application Integration (located in <WLAI_HOME>\dev\bin\ sample) contains the file build.xml. This is the Ant build file for the sample adapter. It contains the tasks needed to build a J2EE-compliant adapter. Running the GenerateAdapterTemplate utility to clone a development tree for your adapter creates a build.xml file specifically for that adapter. This will free you from having to customize the sample build.xml and will ensure that the code is correct. For information on using the GenerateAdapterTemplate utility, see Creating a Custom Development Environment.
For more information on the build process, see Step 2c: Setting Up the Build Process in Developing a Service Adapter.
Step 2d: Create the Message Bundle
Any message destined for the end-user should be placed in a message bundle. The message bundle is simply a .properties text file that contains key=value pairs that allow you to internationalize messages. When a locale and national language are specified at runtime, the contents of the message is interpreted, based upon the key=value pair, and the message is presented to the user in the correct language for his or her locale.
For instructions on creating a message bundle, please refer to the JavaSoft tutorial on internationalization at:
http://java.sun.com/docs/books/tutorial/i18n/index.html
Step 2e: Configure Logging
The final step in configuring your development environment is to configure logging. Before you begin, read more about logging in "Concepts." Logging is accomplished using the logging tool log4j, developed as part of the Apache Jakarta project. For information on using this tool, please see The ADK Logging Toolkit.
Create an Event Generation Logging Category
For event adapters, you will need to create a logging category specifically for event generation (for more information on logging categories, see Message Categories). Edit the logging configuration file for the specific adapter (adapter_logical_name.xml in the /src/ directory for that adapter) by adding the following line:
Listing 7-1 Sample Code Creating an Event Generation Logging Category
<category name='BEA_WLS_SAMPLE_ADK.EventGenerator' class='com.bea. logging.LogCategory'>
</category>
By not setting any specific parameters for this category, it will inherit all of the parent category's property settings. In this example, the parent category is BEA_WLS_SAMPLE_ADK.
Step 3: Implementing the Adapter
Implementing an event adapter is a two-step process. You need to:
This section shows you how to accomplish these tasks.
Step 3a: Create an EventGenerator
The event generation provides adapter with a mechanism to either receive notification from an EIS or poll an EIS for the specific occurrence of an event. The event generation provided by the BEA WebLogic Application Integration engine is very powerful in that a single EventGenerator can support multiple types of events. An event type is defined by the configuration properties for an event.
Typically event properties are defined by the properties associated with an event at designtime. When configuring an event adapter, the adapter may have one or more web pages that it uses to collect event properties. These properties are saved with the application view Descriptor and passed back to the event at runtime. The Application Integration engine uses the properties and the source application view to determine how to route back to the listeners. For instance, two separate deployments of the same EventGenerator with identical properties will result in only a single IEventDefinition being created by the Application Integration engine. Whereas, a single IEventDefinition will be created for every deployment of a single event adapter where the properties are different. It is the responsibility of the EventGenerator to determine which IEventDefinition to use in the routing process. This is typically done based on property values and specific event occurrences.
The IEventDefinition objects are used by your implementation of the EventGenerator to route specific events back to their listener. As discussed before, the Application Integration engine will create IEventDefinition objects for deployed application views containing events. You will use the IEventDefinition objects to extract specific properties regarding the deployment of an application view, or to access schema and routing objects. You need to employ these attributes when routing an event.
How the Data Extraction Mechanism is Implemented
Application Integration supports two mechanisms for data extraction:
The "Pull" Mechanism
The mechanism relies on a polling technique to determine if an event has taken place. To implement a Pull scenario you must derive your EventGenerator from the AbstractPullEventGenerator in the com.bea.adapter.event package.
Note: adk-eventgenerator.jar file must be included in your .war make file. adk-eventgenerator.jar contains the ADK base classes required to implement an EventGenerator.
The ADK supplies several abstract methods in the AbstractPullEventGenerator that you must override in your implementation. These methods are described in Table 7-1.
The "Push" Mechanism
The Push scenario uses notification to trigger the routing of an event. To implement the Push scenario you must derive your EventGenerator from the AbstractPushEventGenerator class in the com.bea.adapter.event package. There are several other supporting classes included in the event package. These classes are described in Table 7-2.
Note: adk-eventgenerator.jar must be included in your .war make file. adk-eventgenerator.jar contains the Application Integration base classes required to implement an EventGenerator.
How the EventGenerator is Implemented
An EventGenerator implementation typically follows this flow of control:
The following is a series of code samples that implement an EventGenerator with a Pull mechanism.
Listing 7-2 shows the class declaration for the sample adapter's (Pull) EventGenerator.
Note: The AbstractPullEventGenerator implements a "run-able" interface; that is, it's a thread.
Listing 7-2 Sample Code Implementing a Pull Data Extraction Mechanism
public class EventGenerator
extends AbstractPullEventGenerator
Sample EventGenerator
Listing 7-3 shows the simple constructor for an EventGenerator. You must invoke the parent's constructor so that the parent's members get initialized correctly. The listing then shows how the doInit() method receives configuration information from the map variable and validates the parameters. The sample contains any parameters associated with the EventGenerator at designtime.
Listing 7-3 Sample Constructor for an EventGenerator
public EventGenerator()
{
super();
}
protected void doInit(Map map)
throws java.lang.Exception
{
ILogger logger = getLogger();
m_strUserName = (String)map.get("UserName");
if (m_strUserName == null || m_strUserName.length() == 0)
{
String strErrorMsg = logger.getI18NMessage("event_generator_no_UserName");
logger.error(strErrorMsg);
throw new IllegalStateException(strErrorMsg);
}
m_strPassword = (String)map.get("Password");
if (m_strPassword == null || m_strPassword.length() == 0)
{
String strErrorMsg = logger.getI18NMessage ("event_generator_no_Password");
logger.error(strErrorMsg);
throw new IllegalStateException(strErrorMsg);
}
postEvents() is called from the run method of our parent class, as shown in Listing 7-4. This method polls the EIS to determine when a new event occurs. This method will be invoked at a fixed interval, which is defined in the web.xml file for the EventRouter.
Listing 7-4 Sample Code Implementation of the postEvents() Method
*/ protected void postEvents(IEventRouter router)
throws java.lang.Exception
{
ILogger logger = getLogger();
// TODO: a real adapter would need to call into the EIS to
// determine ifany new events occured since the last time this
// method was invoked. For the sake of example, we'll just post
// a single event every time this method gets invoked...The
// event data will be the current time on the
// system formatted according to the event definition...we'll
// look for several event types...
Iterator eventTypesIterator = getEventTypes();
if (eventTypesIterator.hasNext())
{
do
{
// The event router is still interested in this type of event
IEventDefinition eventDef = (IEventDefinition) eventTypesIterator.next();
logger.debug("Generating event for " + eventDef.getName());
// Create a default event (just blank/default data)
IEvent event = eventDef.createDefaultEvent();
// Get the format for the event
java.util.Map eventPropertyMap = eventDef.getPropertySet();
String strFormat = (String)eventPropertyMap.get("Format");
if( logger.isDebugEnabled() )
logger.debug("Format for event type '"+eventDef. getName()+"' is '"+strFormat+"'");
java.text.SimpleDateFormat sdf =
new java.text.SimpleDateFormat(strFormat);
IDocument payload = event.getPayload();
payload.setStringInFirst("/SystemTime", sdf.format(new Date()));
// let's log an audit message for this...
try
{
logger.audit(toString() + ": postEvents >>> posting event ["+payload.toXML()+"] to router");
}
catch (Exception exc)
{
logger.warn(exc);
}
// This call actually posts the event to the IEventRouter
router.postEvent(event);
} while (eventTypesIterator.hasNext());
}
}// end of postEvents
A real adapter would need to call into the EIS to determine if any new events occurred since the last time this method was invoked. You can see a concrete example of this in the DBMS adapter included with the ADK. Refer to the postEvent() method in DbmsEventGeneratorWorker.java, which is in:
<WLAI_HOME>dev/dbms/com/bea/adapter/dbms/event/
Adding New Event Types
setupNewTypes() gets called during refresh to handle any new event types. This allows us to perform any setup we need to handle a new type. The parent class has already sanity-checked the listOfNewTypes() and logged it; so you don't need to do that here.
Listing 7-5 Sample Code Showing the Template for setupNewTypes()
protected void setupNewTypes(java.util.List listOfNewTypes)
{
Iterator iter = listOfNewTypes.iterator();
while (iter.hasNext())
{
IEventDefinition eventType = (IEventDefinition)iter.next();
}
}
Removing Event Types for Application Views that are Undeployed
removeDeadTypes() is called during refresh to handle any event types for application views that have been undeployed. You will need to perform a cleanup process to ensure that this event type is no longer handled, such as closing resources needed to handle this specific event type. Listing 7-6 shows how removeDeadTypes() is implemented.
Listing 7-6 Sample Code Showing the Template for removeDeadTypes()
protected void removeDeadTypes(java.util.List listOfDeadTypes)
{
Iterator iter = listOfDeadTypes.iterator();
while (iter.hasNext())
{
IEventDefinition eventType = (IEventDefinition)iter.next();
Removing Resources
Finally, doCleanUpOnQuit() gets called when the EventGenerator is shutting down, This method removes any resources allocated during event processing. The sample adapter stubs in this method. The template for implementing this method is shown in Listing 7-7.
Listing 7-7 Sample Code Showing doCleanUpOnQuit() Method Call
protected void doCleanUpOnQuit()
throws java.lang.Exception
{
ILogger logger = getLogger();
logger.debug(this.toString() + ": doCleanUpOnQuit");
}
}
Step 3b: Implement the Data Transformation Method
Data transformation is the process of taking data from the EIS and transforming it into an XML schema that can be read by the application server. For each event, a schema will define what the XML output looks like. This is accomplished by using the SOM and Document class libraries. The following code listings show the data transformation sequence:
Listing 7-8 Sample Code for Transforming EIS Data into XML Schema
SOMSchema schema = new SOMSchema();
SOMElement root = new SOMElement("SENDINPUT");
SOMComplexType mailType = new SOMComplexType();
root.setType(mailType);
SOMSequence sequence = mailType.addSequence();
SOMElement to = new SOMElement("TO");
to.setMinOccurs("1");
to.setMaxOccurs("unbounded");
sequence.add(to);
SOMElement from = new SOMElement("FROM");
from.setMinOccurs("1");
from.setMaxOccurs("1");
sequence.add(from);
SOMElement cc = new SOMElement("CC");
cc.setMinOccurs("1");
cc.setMaxOccurs("unbounded");
sequence.add(cc);
SOMElement bcc = new SOMElement("BCC");
bcc.setMinOccurs("1");
bcc.setMaxOccurs("unbounded");
sequence.add(bcc);
SOMElement subject = new SOMElement("SUBJECT");
subject.setMinOccurs("1");
subject.setMaxOccurs("1");
sequence.add(bcc);
SOMElement body = new SOMElement("BODY");
if (template == null)
{ body.setMinOccurs("1");
body.setMaxOccurs("1");
}else
{ Iterator iter = template.getTags();
if (iter.hasNext())
{ SOMComplexType bodyComplex = new SOMComplexType();
body.setType(bodyComplex);
SOMAll all = new SOMAll();
while (iter.hasNext())
{ SOMElement eNew = new SOMElement((String)iter.next());
all.add(eNew);
}//endwhile
bodyComplex.setGroup(all);
}//endif
}//endif
sequence.add(body);
schema.addElement(root);
Listing 7-9 XML Schema Created by Code in Listing 7-8
<xsd:schema xmlns:xsd="http://www.w3.org/2001/XMLSchema">
<xsd:element name="SENDINPUT">
<xsd:complexType>
<xsd:sequence>
<xsd:element name="TO" maxOccurs="unbounded" type="xsd: string"/>
<xsd:element name="FROM" type="xsd:string"/>
<xsd:element name="CC" maxOccurs="unbounded" type= "xsd:string"/>
<xsd:element name="BCC" maxOccurs="unbounded" type= "xsd:string"/>
<xsd:element name="BCC" maxOccurs="unbounded" type= "xsd:string"/>
<xsd:element name="BODY" type="xsd:string"/>
</xsd:sequence>
</xsd:complexType>
</xsd:element>
Listing 7-10 Valid XML Document Created by Schema in Listing 7-9
</xsd:schema>
<?xml version="1.0"?>
<!DOCTYPE SENDINPUT>
<SENDINPUT>
<TO/>
<FROM/>
<CC/>
<BCC/>
<BCC/>
<BODY/>
</SENDINPUT> <xsd:schema xmlns:xsd="http://www.w3.org/2001/XMLSchema">
Step 4. Deploying the Adapter
To deploy the event adapter, you need to deploy the EventGenerator on a J2EE servlet engine outside of the BEA WebLogic Application Integration engine. To do this, you need to bundle the EventGenerator as a web application, WEB-INF/web.xml. Rather than create this file from scratch, we recommend that you use the GenerateAdapterTemplate utility to clone and customize a development environment for your adapter. Running this utility will modify the web.xml file in the sample adapter for use with the adapter you are developing. For more information on using GenerateAdapterTemplate, see Creating a Custom Development Environment.
Add EventRouterServlet to .war File
The EventRouter is a .war file used to deploy your EventGenerator and is required for any adapter supporting events. It will be the URL that you will use in the design-time interface to deploy the event adapter. Because it is a .war file, it requires an associated web.xml file for deployment.
The EventRouterServlet is responsible for initializing and starting the Application Integration event process. The web.xml file contains initialization parameters for the EventRouterServlet, some of which are shown in Table 7-11.
Listing 7-11 EventRouterServlet Element of web.xml
<servlet>
<servlet-name>EventRouterServlet</servlet-name>
<description>Provides access to event router within WLAI</description>
<servlet-class>com.bea.wlai.event.EventRouterServlet</servlet-class>
<!-- Or jsp-file -->
<init-param>
<param-name>eventGeneratorClassName</param-name>
<param-value>email.event.PullEventGenerator</param-value>
<description>The fully qualified class name of the IEventGenerator implementation class</description>
</init-param>
<init-param>
<param-name>wlsUserID</param-name>
<param-value>system</param-value>
<description>The user id on the WLAI server that this event router will talk to to get schemas, etc.</description>
</init-param>
<init-param>
<param-name>wlsPassword</param-name>
<param-value>weblogic</param-value>
<description>The password for wlsUserID</description>
</init-param>
.
.
.
<load-on-startup>1</load-on-startup>
</servlet>
You need to assign values to several initialization parameters prior to creating the EventRouter. These parameters are described in Table 7-3.
The web.xml file also contains servlet directives and security constraints. Refer to the WebLogic documentation for a description of these attributes.
Create the EventRouter .war file
To make the EventRouter .war file you must include the following .jar files in your .war file:
Also add any other .jar file upon which your EventGenerator is dependent. These are specified in the <eventrouter> target in the build.xml file, as shown in Listing 7-12.
Listing 7-12 Adding .jar Files to the eventrouter Target of build.xml
<target name='eventrouter_war' depends='jar,eventrouter_jar'>
<delete file='${LIB_DIR}/${EVENTROUTER_WAR_FILE}'/>
<delete dir='${SRC_DIR}/eventrouter/WEB-INF/lib'/>
<war warfile='${LIB_DIR}/${EVENTROUTER_WAR_FILE} 'webxml='${SRC_DIR}/eventrouter/WEB-INF/web.xml'>
<fileset dir='${PROJECT_DIR}' includes='version_info.xml'/>
<fileset dir='${SRC_DIR}/eventrouter' excludes='WEB-INF/ web.xml'/>
<lib dir='${LIB_DIR}' includes='${JAR_FILE}, ${EVENTROUTER_JAR_FILE}'/>
<lib dir='${WLAI_LIB_DIR}' includes='adk.jar,adk- eventgenerator.jar,bea.jar,logtoolkit.jar,wlai-common.jar,wlai-ejb-client.jar,wlai-eventrouter.jar,wlai-servlet-client.jar,xmltoolkit.jar'/>
<lib dir='${RESOURCE_DIR}/log4j' includes='log4j.jar'/>
</war>
</target>
Step 5: Testing the Adapter
You can test the adapter by using the adapter test harness provided with the Application Integration. See Step 6: Testing the Adapter in Developing a Service Adapter for a complete description of this tool and instructions for using it.
![]() |
![]() |
![]() |
|
Copyright © 2001 BEA Systems, Inc. All rights reserved.
|