14 Configuring Custom Adapters

This chapter describes how to implement and configure Oracle Complex Event Processing (Oracle CEP) adapters for converting data to and from event types, including how to implement adapters as event sources and event sinks and how to pass login credentials from an adapter.

14.1 Overview of Custom Adapters

One of the main roles of an adapter is to convert data coming from some channel, such as a market data feed, into Oracle CEP events. These events are then passed to other components in the application, such as processors. An adapter is usually the entry point to an Oracle CEP application. An adapter can also be the exit point of an application so that it receives events from an intermediate component, converts the data into something that an external application can read, and then sends it out.

"Foreign Exchange (FX) Example" in the Oracle Fusion Middleware Getting Started Guide for Oracle Complex Event Processing shows three adapters that read in data from currency data feeds and then pass the data, in the form of a specific event type, to the processors, which are the next components in the network.

You can create adapters of different types, depending on the format of incoming data and the technology you use in the adapter code to do the conversion. The most typical types of adapters are those that:

  • Use a data vendor API, such as Reuters, Wombat, or Bloomberg.

  • Convert incoming JMS messages using standard JMS APIs.

  • Use other messaging systems, such as TIBCO Rendezvous.

  • Use a socket connection to the customer's own data protocol.

Adapters are Java classes that implement specific Oracle CEP interfaces. You register the adapter classes in the EPN assembly file that describes your entire application.

You can optionally change the default configuration of the adapter, or even extend the configuration and add new configuration elements and attributes.

There are two ways to pass configuration data to the adapter; the method you chose depends on whether you want to dynamically change the configuration after deployment:

  • If you are not going to change the configuration data after the adapter is deployed, then you can configure the adapter in the EPN assembly file.

  • If, however, you do want to be able to dynamically change the configuration elements, then you should put this configuration in the adapter-specific component configuration file.

This section describes:

14.1.1 Custom Adapter Event Sources and Event Sinks

Adapters can be event sources, event sinks, or both. Event sources generate events, event sinks receive events.

14.1.1.1 Custom Adapters as Event Sources

You specify that an adapter component in your EPN is an event source by implementing the com.bea.wlevs.ede.api.StreamSource or RelationSource API.

The implementation class of a custom adapter that is an event source may be specified as private to the application or as an advertised OSGI service re-usable by other applications.

You register adapters in the EPN assembly file using the wlevs:adapter element. For example:

<wlevs:adapter id="myAdapterSource" class="com.acme.MySourceAdapter">
</wlevs:adapter>

In this example, the Java class MySourceAdapter.java implements the com.bea.wlevs.ede.api.StreamSource or RelationSource API.

For more information, see Section 14.2.1.1, "Implementing a Custom Adapter as an Event Source".

14.1.1.2 Custom Adapters as Event Sinks

The functionality of custom adapters as event sinks is very similar to that of event sources except that custom adapter event sinks must implement the com.bea.wlevs.ede.api.StreamSink or RelationSink API.

Event sinks are not active which means that if they implement the Runnable interface, Oracle CEP does not run them in a separate thread.

You reference event sinks in the EPN assembly file using the wlevs:listener element:

<wlevs:adapter id="myAdapterSink" class="com.acme.MySinkAdapter">
</wlevs:adapter>

<wlevs:channel id="myStream" >
    <wlevs:listener ref="myAdapterSink" />
</wlevs:channel>

In this example, the Java class MySinkAdapter.java implements the com.bea.wlevs.ede.api.StreamSink or RelationSink API.

For more information, see Section 14.2.1.2, "Implementing a Custom Adapter as an Event Sink".

14.1.2 Custom Adapter Factories

If your adapter is going to be used only by a single Oracle CEP application, then you do not need to create a factory. However, if multiple applications are going to use the same adapter, then you should also program a factory. In this case, every application gets its own instance of the adapter.

Adapter factories must implement the com.bea.wlevs.ede.api.Factory interface. This interface has a single method, create, that you implement to create an adapter or event bean instance.

You register factories in the EPN assembly file using the wlevs:factory element:

<wlevs:factory provider-name="myprovider" class="my.Implementation"/>

Note that if you need to specify service properties, then you must use the osgi:service element to register the factory.

14.1.3 Single and Multi-threaded Adapters

By default, an adapter is single-threaded. That is, an adapter uses a single thread to read messages from its data source.

When an adapter is single-threaded, event order is guaranteed.

To improve scalability, you can configure an adapter to use multiple threads to read from its data source. The simplest way to do this is to configure the adapter with a work manager. You can specify a dedicated work manager used only by the adapter or you can share a work manager amongst several components such as other adapters and Jetty.

When an adapter is multi-threaded, event order is not guaranteed.

For more information, see:

14.2 Implementing a Custom Adapter

You implement a custom adapter in a Java class that you create. To create this Java class, you can either:

For more information, see Section 14.1, "Overview of Custom Adapters".

14.2.1 How to Implement a Custom Adapter Manually

The following procedure describes the typical steps for manually creating a custom adapter.

Note:

The following procedure assumes that the custom adapter is bundled in the same application JAR file that contains the other components of the event network, such as the processor, streams, and business logic POJO. If you want to bundle the custom adapter in its own JAR file so that it can be shared among multiple applications, see Section 24.2.4.1, "How to Assemble a Custom Adapter in its Own Bundle."

To implement a custom adapter:

  1. Program the custom adapter Java class.

    If your custom adapter is an event source, see Section 14.2.1.1, "Implementing a Custom Adapter as an Event Source."

    If your custom adapter is an event sink, see Section 14.2.1.2, "Implementing a Custom Adapter as an Event Sink."

    If your custom adapter is both an event source and event sink, then see both sections.

    If your custom adapter must authenticate itself with a data feed provider, see Section 14.3, "Passing Login Credentials from an Adapter to a Data Feed Provider."

  2. Optionally program a factory class.

    You only need to do this if many applications are going to use the custom adapter.

    See Section 14.2.2, "Implementing a Custom Adapter Factory."

  3. Optionally extend the component configuration of the custom adapter if the default component configuration is not adequate.

    See Chapter 19, "Extending Component Configuration."

  4. Configure the custom adapter.

    For more information, see:

14.2.1.1 Implementing a Custom Adapter as an Event Source

This section describes how to create a custom adapter that acts as an event source because it receives incoming data and generates events that it sends to the next component in the EPN.

The inbound custom adapter class typically reads the stream of incoming data, such as from a market data feed, converts it into an Oracle CEP event type that is understood by the rest of the application, and sends the event to the next component in the network.

The following example shows the custom adapter class of the Spatial sample; see the explanation after the example for coding guidelines that correspond to the Java code in bold.

package com.oracle.cep.sample.spatial;
 
import java.io.BufferedReader;
import java.io.File;
import java.io.FileReader;
 
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
 
import com.bea.wlevs.ede.api.EventProperty;
import com.bea.wlevs.ede.api.EventRejectedException;
import com.bea.wlevs.ede.api.EventType;
import com.bea.wlevs.ede.api.EventTypeRepository;
import com.bea.wlevs.ede.api.RunnableBean;
import com.bea.wlevs.ede.api.StreamSender;
import com.bea.wlevs.ede.api.StreamSink;
import com.bea.wlevs.ede.api.StreamSource;
import com.bea.wlevs.util.Service;
import java.lang.RuntimeException;
 
import oracle.spatial.geometry.JGeometry;
import com.oracle.cep.cartridge.spatial.Geometry;
 
public class BusStopAdapter implements RunnableBean, StreamSource, StreamSink
{
  private final static String APP_NAME              = "spatial_sample";
...
  private String              m_eventTypeName;
  private EventType           m_eventType;
  private StreamSender        m_eventSender;
...
  public BusStopAdapter()
  {
    super();
  }
 
...
  @Service(filter = EventTypeRepository.SERVICE_FILTER)
  public void setEventTypeRepository(EventTypeRepository etr)
  {
    m_etr = etr;
  }
 
  public void setShow(boolean b)
  {
    m_show = b;
  }
 
  public void run()
  {
    m_stopped = false;
 
    // Need to store running thread so that it can be interrrupted in case of
    // suspend.
    m_runningThread = Thread.currentThread();
 
    if (m_etr == null)
    {
      throw new RuntimeException("EventTypeRepoitory is not set");
    }
 
    m_eventType = m_etr.getEventType(m_eventTypeName);
    if (m_eventType == null)
    {
      throw new RuntimeException("EventType(" + m_eventType + ") is not found.");
    }

    s_logger.info("fileSource " + m_filePath);

    if (m_initialDelay > 0)
    {
      try
      {
        s_logger.info("Sleeping for : " + m_initialDelay);
        Thread.sleep(m_initialDelay);
      } catch (InterruptedException e)
      {
        e.printStackTrace();
      }
    }

    synchronized (this)
    {
      while (!m_start)
      {
        try
        {
          this.wait();
        } catch (InterruptedException e)
        {
        }
      }
    }
    BufferedReader reader = null;

    System.out.println("Sending " + m_eventType + " from " + m_filePath);
    while ((m_repeat != 0) && (!m_stopped))
    {
      try
      {
        s_logger.info("Starting fileSource " + m_filePath);
        m_lineno = 0;
        reader = new BufferedReader(new FileReader(m_filePath));
      } catch (Exception e)
      {
        s_logger.warn(e.toString());
        m_stopped = true;
        break;
      }
      while (!isStopped())
      {
        try
        {
          Object ev = null;
          ev = readLine(reader);
          if (ev == null)
          {
            reader.close();
            break;
          }
          m_eventSender.sendInsertEvent(ev);
          if (m_show)
          {
            System.out.println(ev.toString());
          }
        } catch (Exception e)
        {
          s_logger.fatal("Failed to get tuple from " + m_filePath + ":"
              + m_lineno + "\n" + e.toString() + "\n");
          m_stopped = true;
          break;
        }
        if (m_sleep > 0)
        {
          try
          {
            synchronized (this)
            {
              // We need to save thread so that it can be interrupted in case of
              // suspend.
              wait(m_sleep);
            }
          } catch (InterruptedException e)
          {
            s_logger.warn(e);
            break;
          }
        }
      } // while
      if (m_repeat > 0)
        m_repeat--;
    } // while
    s_logger.info("FileAdaptor  " + hashCode() + " stopped. " + m_filePath);
  }

  public void setEventSender(StreamSender sender)
  {
    m_eventSender = sender;
  }

...
}

Follow these guidelines when programming the adapter Java class; code snippets of the guidelines are shown in bold in the preceding example:

  • Import the interfaces and classes of the Oracle CEP API:

    import com.bea.wlevs.ede.api.StreamSender;
    import com.bea.wlevs.ede.api.StreamSource;
    import com.bea.wlevs.ede.api.RunnableBean;
    

    Because the adapter is an event source it must implement the StreamSource interface. If you want the adapter to run in a thread, also implement RunnableBean. The StreamSender interface sends event types to the next component in your application network. For full details of these APIs, see Oracle Fusion Middleware Java API Reference for Oracle Complex Event Processing.

  • The adapter class must implement the StreamSource and RunnableBean interfaces because it is an event source and will run in its own thread:

    public class BusStopAdapter implements RunnableBean, StreamSource, StreamSink
    

    The StreamSource interface provides the StreamSender that you use to send events.

  • Because the adapter implements the RunnableBean interface, your adapter must then implement the run method:

    public void run() {...
    

    This is where you should put the code that reads the incoming data, such as from a market feed, and convert it into an Oracle CEP event type, and then send the event to the next component in the network. Refer to the documentation of your data feed provider for details on how to read the incoming data. See Section 24.2.2.2, "Accessing Third-Party JAR Files" for information about ensuring you can access the vendor APIs if they are packaged in a third-party JAR file.

    In the Spatial example, the adapter itself generates the incoming data using the readLine protected method. This is just for illustrative purposes and is not a real-world scenario.

    For more information, see Chapter 2, "Creating Oracle CEP Event Types".

  • Because your adapter implements StreamSource, you must implement the setEventSender method, which passes in the StreamSender that you use to send events:

    public void setEventSender(StreamSender sender) { ...
    
  • If, as is typically the case, your adapter implements SuspendableBean, you must implement the suspend method that stops the adapter when, for example, the application is undeployed:

    public synchronized void suspend() throws Exception { ... 
    

14.2.1.2 Implementing a Custom Adapter as an Event Sink

The following sample code shows a Spring bean from HelloWorld application that acts as an event sink; see the explanation after the example for the code shown in bold:

The following example shows the custom adapter class of the Spatial sample; see the explanation after the example for coding guidelines that correspond to the Java code in bold.

package com.oracle.cep.sample.spatial;
 
import java.io.BufferedReader;
import java.io.File;
import java.io.FileReader;
 
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
 
import com.bea.wlevs.ede.api.EventProperty;
import com.bea.wlevs.ede.api.EventRejectedException;
import com.bea.wlevs.ede.api.EventType;
import com.bea.wlevs.ede.api.EventTypeRepository;
import com.bea.wlevs.ede.api.RunnableBean;
import com.bea.wlevs.ede.api.StreamSender;
import com.bea.wlevs.ede.api.StreamSink;
import com.bea.wlevs.ede.api.StreamSource;
import com.bea.wlevs.util.Service;
import java.lang.RuntimeException;
 
import oracle.spatial.geometry.JGeometry;
import com.oracle.cep.cartridge.spatial.Geometry;
 
public class BusStopAdapter implements RunnableBean, StreamSource, StreamSink
{
  private final static String APP_NAME              = "spatial_sample";
...
  private String              m_eventTypeName;
  private EventType           m_eventType;
  private StreamSender        m_eventSender;
...
  public BusStopAdapter()
  {
    super();
  }
 
...
  @Service(filter = EventTypeRepository.SERVICE_FILTER)
  public void setEventTypeRepository(EventTypeRepository etr)
  {
    m_etr = etr;
  }
 
  public void setShow(boolean b)
  {
    m_show = b;
  }
 
  public void run()
  {
    m_stopped = false;
 
    // Need to store running thread so that it can be interrrupted in case of
    // suspend.
    m_runningThread = Thread.currentThread();
 
    if (m_etr == null)
    {
      throw new RuntimeException("EventTypeRepoitory is not set");
    }
 
    m_eventType = m_etr.getEventType(m_eventTypeName);
    if (m_eventType == null)
    {
      throw new RuntimeException("EventType(" + m_eventType + ") is not found.");
    }

    s_logger.info("fileSource " + m_filePath);

    if (m_initialDelay > 0)
    {
      try
      {
        s_logger.info("Sleeping for : " + m_initialDelay);
        Thread.sleep(m_initialDelay);
      } catch (InterruptedException e)
      {
        e.printStackTrace();
      }
    }

    synchronized (this)
    {
      while (!m_start)
      {
        try
        {
          this.wait();
        } catch (InterruptedException e)
        {
        }
      }
    }
    BufferedReader reader = null;

    System.out.println("Sending " + m_eventType + " from " + m_filePath);
    while ((m_repeat != 0) && (!m_stopped))
    {
      try
      {
        s_logger.info("Starting fileSource " + m_filePath);
        m_lineno = 0;
        reader = new BufferedReader(new FileReader(m_filePath));
      } catch (Exception e)
      {
        s_logger.warn(e.toString());
        m_stopped = true;
        break;
      }
      while (!isStopped())
      {
        try
        {
          Object ev = null;
          ev = readLine(reader);
          if (ev == null)
          {
            reader.close();
            break;
          }
          m_eventSender.sendInsertEvent(ev);
          if (m_show)
          {
            System.out.println(ev.toString());
          }
        } catch (Exception e)
        {
          s_logger.fatal("Failed to get tuple from " + m_filePath + ":"
              + m_lineno + "\n" + e.toString() + "\n");
          m_stopped = true;
          break;
        }
        if (m_sleep > 0)
        {
          try
          {
            synchronized (this)
            {
              // We need to save thread so that it can be interrupted in case of
              // suspend.
              wait(m_sleep);
            }
          } catch (InterruptedException e)
          {
            s_logger.warn(e);
            break;
          }
        }
      } // while
      if (m_repeat > 0)
        m_repeat--;
    } // while
    s_logger.info("FileAdaptor  " + hashCode() + " stopped. " + m_filePath);
  }

  @Override
  public void onInsertEvent(Object event) throws EventRejectedException  {
    if (!m_start)
    {
      m_start = true;
      synchronized (this)
      {
        notify();
      }
    }
    // Throw com.bea.wlevs.ede.api.EventRejectedException to have exceptions propagated
    // up to senders. Other errors will be logged and dropped.
  }
...
}

The programming guidelines shown in the preceding example are as follows:

  • Your custom adapter must implement the com.bea.wlevs.ede.api.StreamSink interface:

    public class BusStopAdapter implements RunnableBean, StreamSource, StreamSink
    
  • The StreamSink interface has a single method that you must implement, onInsertEvent(java.lang.Object), which is a callback method for receiving events. The parameter of the method is an Object that represents the actual event that the bean received from the component that sent it the event:

    public void onInsertEvent(Object event)
    

    Your implementation should throw com.bea.wlevs.ede.api.EventRejectedException to have exceptions propagated up to senders. Other errors will be logged and dropped.

For complete API reference information about the Oracle CEP APIs described in this section, see the Oracle Fusion Middleware Java API Reference for Oracle Complex Event Processing.

14.2.2 Implementing a Custom Adapter Factory

Your adapter factory class must implement the com.bea.wlevs.ede.api.AdapterFactory interface, which has a single method, create, in which you code the creation of your specific adapter class. Event beans implement Factory.

The following is a possible adapter factory class for the HelloWorld example:

package com.bea.adapter.wlevs.example.helloworld;
import com.bea.wlevs.ede.api.Adapter;
import com.bea.wlevs.ede.api.AdapterFactory;
public class HelloWorldAdapterFactory implements Factory {
    public HelloWorldAdapterFactory() {
    }
    public synchronized Adapter create() throws IllegalArgumentException {
        return new HelloWorldAdapter();
    }
}

For full details of these APIs, see the Oracle Fusion Middleware Java API Reference for Oracle Complex Event Processing.

14.3 Passing Login Credentials from an Adapter to a Data Feed Provider

If your adapter accesses an external data feed, the adapter might need to pass login credentials (username and password) to the data feed for user authentication.

The simplest, and least secure, way to do this is to hard-code the non-encrypted login credentials in your adapter Java code. However, this method does not allow you to encrypt the password or later change the login credentials without recompiling the adapter Java code.

The following procedures describe a different method that takes these two issues into account. In the procedure, it is assumed that the username to access the data feed is juliet and the password is superSecret.

You must decide whether you want the login credentials to be configured statically in the EPN assembly file, or dynamically by extending the configuration of the adapter. Configuring the credentials statically in the EPN assembly file is easier, but if the credentials later change you must restart the application for the update to the EPN assembly file to take place. Extending the adapter configuration allows you to change the credentials dynamically without restarting the application, but extending the configuration involves additional steps, such as creating an XSD file and compiling it into a JAXB object.

This section describes:

For more information, see Chapter 19, "Extending Component Configuration".

14.3.1 How to Pass Static Login Credentials to the Data Feed Provider

This procedure describes how to pass login credentials that you configure statically in the EPN assembly file.

To pass static credentials to the data feed provider:

  1. Open a command window and set your environment as described in "Setting Your Development Environment" in the Oracle Fusion Middleware Getting Started Guide for Oracle Complex Event Processing.

  2. Change to the directory that contains the EPN assembly file for your application.

  3. Using your favorite XML editor, edit the EPN assembly file by updating the wlevs:adapter element that declares your adapter.

    In particular, add two instance properties that correspond to the username and password of the login credentials. For now, specify the cleartext password value; you will encrypt it in a later step. Also add a temporary password element whose value is the cleartext password. For example:

    <wlevs:adapter id="myAdapter" provider="myProvider">
      <wlevs:instance-property name="user" value="juliet"/>
      <wlevs:instance-property name="password" value="superSecret"/>
      <password>superSecret</password>
    </wlevs:adapter>
    
  4. Save the EPN assembly file.

  5. Use the encryptMSAConfig command to encrypt the value of the password element in the EPN assembly file:

    prompt> ORACLE_CEP_HOME/ocep_11.1/bin/encryptMSAConfig . epn_assembly_file aesinternal.dat_file
    

    where ORACLE_CEP_HOME refers to the main directory into which you installed Oracle CEP, such as d:\oracle_cep. The second argument refers to the directory that contains the EPN assembly file; because this procedure directs you to change to the directory, the example shows ".". The epn_assembly_file parameter refers to the name of your EPN assembly file. Finally, the aesinternal.dat_file parameter refers to the location of the .aesinternal.dat file associated with your domain; by default this file is located in the DOMAIN_DIR/servername directory, where DOMAIN_DIR refers to the domain directory such as /oracle_cep/user_projects/domains/mydomain and servername refers to the server instance.

    For more information, see "The encryptMSAConfig Command-Line Utility" in the Oracle Fusion Middleware Administrator's Guide for Oracle Complex Event Processing.

    After you run the command, the value of the password element of the EPN assembly file will be encrypted.

  6. Edit the EPN assembly file:

    Copy the encrypted value of the password element to the value attribute of the password instance property.

    Remove the password element from the XML file.

    For example:

    <wlevs:adapter id="myAdapter" provider="myProvider">
        <wlevs:instance-property name="user" value="juliet"/>
        <wlevs:instance-property name="password"
            value="{Salted-3DES}B7L6nehu7dgPtJJTnTJWRA=="/>
    </wlevs:adapter>
    
  7. Update your adapter Java code to access the login credentials properties you have just configured and decrypt the password.

    See Section 14.3.1, "How to Pass Static Login Credentials to the Data Feed Provider."

  8. Edit the MANIFEST.MF file of the application and add the com.bea.core.encryption package to the Import-Package header. See Section 24.2.2.1, "Creating the MANIFEST.MF File."

  9. Re-assemble and deploy your application as usual. See Chapter 24, "Assembling and Deploying Oracle CEP Applications."

14.3.2 How to Pass Dynamic Login Credentials to the Data Feed Provider

This procedure describes how to pass login credentials that you configure dynamically by extending the configuration of the adapter.

To pass dynamic login credentials to the data feed provider:

  1. Extend the configuration of your adapter by adding two new elements: user and password, both of type string.

    For example, if you were extending the adapter in the HelloWorld example, the XSD file might look like the following:

    <xs:complexType name="HelloWorldAdapterConfig">
       <xs:complexContent>
         <xs:extension base="wlevs:AdapterConfig">
           <xs:sequence>
             <xs:element name="message" type="xs:string"/>
             <xs:element name="user" type="xs:string"/>
             <xs:element name="password" type="xs:string"/>
           </xs:sequence>
         </xs:extension>
       </xs:complexContent>
    </xs:complexType>
    

    See Chapter 19, "Extending Component Configuration" for detailed instructions.

  2. Open a command window and set your environment as described in "Setting Your Development Environment" in the Oracle Fusion Middleware Getting Started Guide for Oracle Complex Event Processing.

  3. Change to the directory that contains the component configuration XML file for your adapter.

  4. Using your favorite XML editor, update this component configuration XML file by adding the required login credentials using the <user> and <password> elements. For now, specify the cleartext password value; you will encrypt it in a later step. For example:

    <?xml version="1.0" encoding="UTF-8"?>
    <myExample:config
      xmlns:myExample="http://www.bea.com/xml/ns/wlevs/example/myExample">
      <adapter>
        <name>myAdapter</name>
        <user>juliet</user>
        <password>superSecret</password>
      </adapter>
    </myExample:config>
    
  5. Save the adapter configuration file.

  6. Use the encryptMSAConfig command to encrypt the value the password element in the adapter configuration file:

    prompt> ORACLE_CEP_HOME/ocep_11.1/bin/encryptMSAConfig . adapter_config_file aesinternal.dat_file
    

    where ORACLE_CEP_HOME refers to the main directory into which you installed Oracle CEP, such as d:\oracle_cep. The second argument refers to the directory that contains the adapter configuration file; because this procedure directs you to change to the directory, the example shows ".". The adapter_config_file parameter refers to the name of your adapter configuration file. Finally, the aesinternal.dat_file parameter refers to the location of the .aesinternal.dat file associated with your domain; by default this file is located in the DOMAIN_DIR/servername directory, where DOMAIN_DIR refers to the domain directory such as /oracle_cep/user_projects/domains/mydomain and servername refers to the server instance.

    For more information, see "The encryptMSAConfig Command-Line Utility" in the Oracle Fusion Middleware Administrator's Guide for Oracle Complex Event Processing.

    After you run the command, the value of the password element will be encrypted.

  7. Update your adapter Java code to access the login credentials properties you have just configured and decrypt the password.

    See Section 14.3.1, "How to Pass Static Login Credentials to the Data Feed Provider."

  8. Edit the MANIFEST.MF file of the application and add the com.bea.core.encryption package to the Import-Package header. See Section 24.2.2.1, "Creating the MANIFEST.MF File."

  9. Re-assemble and deploy your application as usual. See Chapter 24, "Assembling and Deploying Oracle CEP Applications."

14.3.3 How to Access Login Credentials From an Adapter at Runtime

This section describes how update your custom adapter Java code to dynamically get the user and password values from the extended adapter configuration, and then use the com.bea.core.encryption.EncryptionService API to decrypt the encrypted password.

The code snippets below build on the HelloWorld adapter Java code, shown in Section 14.2.1.1, "Implementing a Custom Adapter as an Event Source."

To access login credential properties from an adapter at runtime:

  1. Import the additional APIs that you will need to decrypt the encrypted password:

    import com.bea.core.encryption.EncryptionService;
    import com.bea.core.encryption.EncryptionServiceException;
    import com.bea.wlevs.util.Service;
    
  2. Use the @Service annotation to get a reference to the EncryptionService:

    private EncryptionService encryptionService;
    ...
    @Service
    public void setEncryptionService(EncryptionService encryptionService) {
        this.encryptionService = encryptionService;
    }
    
  3. In the @Prepare callback method, get the values of the user and password properties of the extended adapter configuration as usual (only code for the password value is shown):

    private String password;
    ...
    public String getPassword() {
        return password;
    }
    public void setPassword(String password) {
        this.password = password;
    ...
    @Prepare
    public void checkConfiguration(HelloWorldAdapterConfig adapterConfig) {
        if (adapterConfig.getMessage() == null
                || adapterConfig.getMessage().length() == 0) {
            throw new RuntimeException("invalid message: " + message);
        }
        this.password= adapterConfig.getPassword();
        ...
    }
    

    See Section 19.3, "Programming Access to the Configuration of a Custom Adapter or Event Bean" for information about accessing the extended adapter configuration.

  4. Use the EncryptionService.decryptStringAsCharArray method in the @Prepare callback method to decrypt the encrypted password:

    @Prepare
    public void checkConfiguration(HelloWorldAdapterConfig adapterConfig) {
        if (adapterConfig.getMessage() == null
                || adapterConfig.getMessage().length() == 0) {
            throw new RuntimeException("invalid message: " + message);
        }
        this.password= adapterConfig.getPassword();
        try {
            char[] decrypted = encryptionService.decryptStringAsCharArray(password);
            System.out.println("DECRYPTED PASSWORD is "+ new String(decrypted));
        } catch (EncryptionServiceException e) {
            throw new RuntimeException(e);
        }
    }
    

    The signature of the decryptStringAsCharArray method is as follows:

    char[] decryptStringAsCharArray(String encryptedString)
                                    throws EncryptionServiceException
    
  5. Pass these credentials to the data feed provider using the vendor API.

14.4 Configuring the Custom Adapter EPN Assembly File

The adapter and adapter factory (if used) must be registered in the EPN assembly file, as discussed in the following sections:

For a complete description of the configuration file, including registration of other components of your application, see Section 4.3, "Creating EPN Assembly Files."

14.4.1 Registering the Custom Adapter Factory

You register factories in the EPN assembly file using the wlevs:factory element:

<wlevs:factory provider-name="myprovider" class="my.Implementation"/>

If you need to specify service properties, then you must use the osgi:service element to register the factory as an OSGI service in the EPN assembly file. The scope of the OSGI service registry is the entire Oracle CEP. This means that if more than one application deployed to a given server is going to use the same adapter factory, be sure to register the adapter factory only once as an OSGI service.

Add an entry to register the service as an implementation of the com.bea.wlevs.ede.api.AdapterFactory interface. Provide a property, with the key attribute equal to type, and the name by which this adapter provider will be referenced. Finally, add a nested standard Spring bean element to register your specific adapter class in the Spring application context

For example, the following segment of the EPN assembly file registers the HelloWorldAdapterFactory as the provider for type hellomsgs:

<osgi:service interface="com.bea.wlevs.ede.api.AdapterFactory">
    <osgi:service-properties>
        <entry key="type" value="hellomsgs"</entry>
    </osgi:service-properties>
    <bean  class="com.bea.adapter.wlevs.example.helloworld.HelloWorldAdapterFactory" />
</osgi:service>

For more information on how to reference a factory by its type, see Section 14.4.2, "Declaring the Custom Adapter Components in your Application".

14.4.2 Declaring the Custom Adapter Components in your Application

In the EPN assembly file, you use the wlevs:adapter element to declare an adapter as a component in the event processor network. For example:

<wlevs:adapter id="recplayEventSink"
                  class="com.bea.wlevs.example.recplayRecplayEventSink">
    <wlevs:listener ref="playbackHttpPublisher"/>
</wlevs:adapter>

If you registered an optional factory as an OSGI service, then use the provider attribute to point to the name you specified as the type in your osgi:service entry; for example:

<wlevs:adapter id="helloworldAdapter" provider="hellomsgs"/>

This means that an adapter will be instantiated by the factory registered for the type hellomsgs.

You can also use a wlevs:instance-property child element of wlevs:adapter to set any static properties in the adapter bean. Static properties are those that you will not dynamically change after the adapter is deployed.

For example, if your adapter class has a setPort method, you can pass it the port number as shown:

<wlevs:adapter id="myAdapter" provider="myProvider">
    <wlevs:instance-property name="port" value="9001" />
</wlevs:adapter>

14.5 Configuring the Custom Adapter Component Configuration File

Each adapter in your application has a default configuration, and, optionally, an extended component configuration.

If your application has more than one adapter, you can create separate component configuration XML files for each adapter, or create a single component configuration XML file that contains the configuration for all adapters, or even all components of your application (adapters, processors, and streams). Choose the method that best suits your development environment.

The following procedure describes the main steps to create the adapter configuration file. For simplicity, it is assumed in the procedure that you are going to configure all components of an application in a single XML file

For more information, see:

14.5.1 How to Configure a Custom Adapter Manually

The following procedure describes how to configure a custom adapter manually.

To configure the custom adapter component configuration file:

  1. Create an XML file using your favorite XML editor.

    You can name this XML file anything you want, provided it ends with the .xml extension.

    The root element of the configuration file is config, with namespace definitions shown in the next step.

  2. For each adapter in your application, add an adapter child element of config.

    Uniquely identify each adapter with the name child element. This name must be the same as the value of the id attribute in the wlevs:adapter element of the EPN assembly file that defines the event processing network of your application. This is how Oracle CEP knows to which particular adapter component in the EPN assembly file this adapter configuration applies. See Section 4.3, "Creating EPN Assembly Files" for details.

    For example, if your application has two adapters, the configuration file might initially look like this:

    <?xml version="1.0" encoding="UTF-8"?>
    <helloworld:config
      xmlns:helloworld="http://www.bea.com/xml/ns/wlevs/example/helloworld">
      <processor>
       ...
      </processor>
      <adapter>
        <name>firstAdapter</name>
        ...
      </adapter>
      <adapter>
        <name>secondAdapter</name>
        ...
      </adapter>
    </helloworld:config>
    

    In the example, the configuration file includes two adapters called firstAdapter and secondAdapter. This means that the EPN assembly file must include at least two adapter registrations with the same identifiers:

    <wlevs:adapter id="firstAdapter" ...>
      ...
    </wlevs:adapter>
    <wlevs:adapter id="secondAdapter" ...>
      ...
    </wlevs:adapter>
    

    Caution:

    Identifiers and names in XML files are case sensitive, so be sure you specify the same case when referencing the component's identifier in the EPN assembly file.

14.5.1.1 Example of a Custom Adapter Configuration File

The following sample XML file shows how to configure two adapters, firstAdapter and secondAdapter.

<?xml version="1.0" encoding="UTF-8"?>
<sample:config
  xmlns:sample="http://www.bea.com/xml/ns/wlevs/example/sample">
  <adapter>
    <name>firstAdapter</name>
  </adapter>
  <adapter>
    <name>secondAdapter</name>
  </adapter>
</sample:config>