4 Cartridge Creation Example

This chapter describes the creation of Cartridges with the Oracle Communications Offline Mediation Controller CDK.

Creating Airline Flight Node Chain

Follow these guidelines:

  1. All nodes should be derived from EINode, ProcessorNode, or OINode.

    • Processor nodes should utilize the NPLProcessorNode or be extensions of it.

    • We have EINodeTmpl.java as a template for CC nodes.

    • We have OINodeTmpl.java as a template for DC nodes.

  2. All “inter-node" communication should be handled by the DCStreamHandler.

    The DCStreamHandler at this time is the NARFileManager, which is responsible for writing NAR files to disk.

  3. All nodes should have NPL rules file, which maps ALL fields available in the case of a CC node, and only the fields necessary for enhancement in the case of a Processor node. Obviously, a DC node will only include the fields that meet that specific output requirement.

  4. All nodes should have the necessary NodeConfigGUI class, rules/NPL file, and should be defined in the appropriate properties file.

    • OMC_Home/customization/nodeTemplateDef.xml

    • OMC_Home/customization/nodeGroupDef.xml

    Where OMC_Home is the directory in which you installed Offline Mediation Controller

  5. All nodes should have implementations of DataProviders and DataReceivers with getData() and processData() methods for which the issues of synchronization have been taken into consideration.

  6. All nodes should have a main() method to be used for testing purpose only.

    Allows the node to run from the command line before the NodeConfigGUI component is complete.

Existing Node Types

The following list displays the nodes existing in Offline Mediation Controller CDK when you install the product. You can use these existing nodes as a base and customize the NPL file to achieve the desired functionality.

Collection Cartridg (CC) Nodes:
  • ASCII CC node

  • IPDR File CC node

  • Network Accounting Record CC node

Enhancement Processor (EP) Nodes
  • Record Processing EP node

  • Record Enhancement (Local File) EP node

  • Service Resource EP node

  • LDAP Enhancer EP node

  • Record Enhancement (LDAP) EP node

Aggregation Processors (AP) Nodes
  • Aggregation Processor

  • Programmable Aggregation Processor

Distribution Cartridges (DC) Nodes
  • ASCII DC node

  • IPDR DC node

  • XML DC node

  • Network Accounting Record DC node

  • JDBC DC node

  1. Identify your data source or destination (CC node vs. DC node)

    • Know the format

    • Know how it is transferred

  2. Identify your transport

    • Does one already exist?

    • Do you need to write your own?

    • Will your transport know about your DCFieldContainer? -OR-

    • Will you need to write a factory?

  3. Write a factory (optional) - the mass production of record objects.

    • A DCRecordFactory is generally used to take raw data and produce EIRecord objects.

    • A factory would typically be used to take in an OIRecord and produce raw data for an OITransport.

    • The definition of this object is only necessary when dealing with an object (generally a transport) that needs this to generate record objects for it.

  4. Write a DCFieldContainer

    • In an EIRecord this means getting raw data into the object, and implementing the interface methods for getting the data out as individual fields/attributes. Please refer to EIRecordTmpl.java.

    • In an OIRecord this means implementing methods to get the data in as fields and a mechanism to get raw data out. Please refer to OIRecordTmpl.java.

  5. Implement the Node - where you really put it all together

    • Write the constructor if warm restart capability is not implemented.

      • Get all the cnfiguration information of this node.

      • Construct your transport with knowledge of your factory or record

      • Construct an NPLFieldProcessor with: knowledge of it's output type (NAR or your Record object) and knowledge of your rules file (which is obtained from config)

      • Set receivers and providers appropriately.

      • Decide what is running in a thread.

      • Start the appropriate components.

    • If implement warm restart capability, construct the node without any operations, override boolean warmRestartImplemented() to return true, and implement these two methods

      • startup(): instantiate transport and field processor and start all the threads.

      • reconfigure(): reconfigure the node without stopping itself.

    • Implement remaining abstract methods.

      • getMinorType()

      • getConfigGUIClass()

    • Implement an “orderly" shutdown method.

      • Make sure components are shutdown in the proper order.

      • Make sure all threads are REALLY stopped.

    • Implement a main() method for testing purpose.

    • Write your NPL file.

      • In a CC node and a DC node this should be primarily mapping to/from NAR attribute.

    • Implement your NodeConfigGUI class.

    • Modify/create the appropriate property files.

Create AirlineEINode (CC Node)

Now we will go through step by step as described in the previous section to create an AirLineEINode for the Airline Flight node chain.

  1. Identify the data source or destination (CC node vs. DC node).

    We need to write a CC node for the Airline Flight node chain. This CC node will collect the Airline passenger data via UDP. We have the Airline Flight Data Simulator, FlightInfoSender, which will be running on a machine somewhere and sending the datagram packet through UDP.

    FlightInfoSender Data Format: There is one passenger record per datagram packet. A single flight record is a byte array of 7 integer attributes. These attributes are (in their respective order):

    • Passenger ID

    • Flight Number

    • Departing Airport ID

    • Arriving Airport ID

    • Departure Time in Seconds

    • Arrival Time in Seconds

    • Number of Bags of Luggage for Passenger

  2. Identify the transport.

    Airline passenger data will be transferred to this CC node via UDP. In CDK, we already have a transport class for UDP, which is UdpEITransport. Therefore, we don't need to write our own transport class for this CC node. Here are the constructors of UdpEITransport:

    public UdpEITransport (EINode einode, DCRecordFactoryIfc factory, int prt)

    throws NodeStartException

    public UdpEITransport(EINode einode, DCRecordFactoryIfc factory, String host, int prt)

    throws NodeStartException

    public UdpEITransport(EINode einode, DCRecordFactoryIfc factory, int prt, int pktSize, int qSize) throws NodeStartException

    public UdpEITransport(EINode einode, DCRecordFactoryIfc factory, String host, int prt, int pktSize, int qSize) throws NodeStartException

    Obviously, UdpEITransport needs a DCRecordFactory in order to know about the EIRecord of the Airline passenger data.

  3. Write AirlineRecordFactory.

    AirlineRecordFactory is implementing DCRecordFactoryIfc. It will produce our AirlineEIRecord for Airline passenger data, which will be created in the next step. We have a template class for creating RecordFactory, please refer to RecordFactoryTmpl.java. This template is written particularly for producing EIRecord from UDP packet. For other type of raw data, you need to use the proper type of raw data instead of QueuedUdpPacket in getRecord() and getRecord() two methods.

  4. Write DCFieldContainer: AirlineEIRecord.

    Now we will create an EIRecord class, which will be responsible for collecting the data produced by the FlightInfoSender class and provide “get" methods for extracting the individual fields. Please refer to EIRecordTmpl.java.

    The AirlineEIRecord is derived from DCEIRecord. This DCFieldContainer should map all fields available in the input data. We know that from FlightInfoSender we have one passenger record per datagram packet. A single flight record is a byte array of 7 integer attributes. These attributes are (in their respective order):

    • Passenger ID

    • Flight Number

    • Departing Airport ID

    • Arriving Airport ID

    • Departure Time in Seconds

    • Arrival Time in Seconds

    • Number of Bags of Luggage for Passenger

    AirlineEIRecord should have the knowledge to extract each of the 7 integer attributes and map it into a DCField. Therefore, an AirlineEIRecord should contain totally 7 DCFields. Each DCField should have its ID, type, and value. For example, the raw data “Passenger ID" will map to an IntField, whose ID will be “Passenger_ID", type will be Integer; and value will be the integer value of the raw data. The IDs of these 7 DCFields will be listed as the InputRec in NPL of AirlineEINode.

    • AirlineEIRecord should at least implement the following methods defined in DCEIRecord:

    • DCField getField(String ID) - Giving the ID of a DCField, we should be able to retrieve the DCField itself.

    • byte[] getFieldValue(String ID) - Giving the ID of a DCField, we should be able to retrieve the value of this DCField as a byte array.

    • int getType(String ID) - Giving the ID of a DCField, we should be able to retrieve the type of this DCField.

    • String toString() - We should be able to get the string representation of this EIRecord.

    • byte[] toByteArray() - We should be able to get the binary representation of this EIRecord.

  5. Implement the Node.

    Now we will implement the AirlineEINode itself. We have a template, EINodeTmpl.java, which can be used to start creating the AirlineEINode.

    Note:

    AirlineEINode will implement a warm restart capability, which means that this node must implement startup() and reconfigure() these two methods.
    1. Construct AirlineEINode with warm restart implemented.

    2. Construct the node with no operation.

      public AirlineEINode( String[] args ) throws NodeStartException {
                  super(args);
      }
      
    3. Override method warmRestartImplemented() to return true.

    4. Implement startup() method.

      • Get all the config information of this node.

      • Construct the UdpEITransport as described in step 2, which will utilize the record factory created in Step 3 in "Create AirlineEINode (CC Node)".

        // Create record factory
         String nid = getNodeId();
         recordFactory = new AirlineRecordFactory(nid, this);
        
         // Create the Transport
         UdpEITransport eiTransport = new UdpEITransport(this,
                                                                recordFactory,
                                                                udpListenPort,
                                                                maxPacketSize,
                                                                queueSize);
        setTransport(eiTransport);
        
    5. Construct an NPLFieldProcessor.

      // Set the FieldProcessor
      Class NARClass = (new NAR()).getClass();
      try {
               setFieldProcessor(new NPLFieldProcessor(NARClass, this,
                                              scratchDir.getAbsolutePath(), NPLFile)
                                             );
      }
      catch (NodeProcessingException npex)
      {
               throw new NodeStartException(npex.getMessage());
      }
      
    6. Set up appropriate receivers and providers relationship.

      Note:

      UdpEITransport requires a “pull" data transfer model.
      getFieldProcessor().setDataProvider(getTransport());
      getFieldProcessor().setDataReceiver(getDCStreamHandler());
      
    7. Start the appropriate components.

      // Start the threads
      setTransportThread(getTransport());
      getTransportThread().start();
      setFieldProcessorThread(getFieldProcessor());
      getFieldProcessorThread().start();
      
  6. Implement reconfigure() method so that node can be reconfigured without stopping it. Here is the steps that should be performed during reconfiguration:

    1. Set the state of transport to begin reconfiguration.

    2. Shut down Field Processor and DCStreamHandler.

    3. Start reconfiguration:

      • Call super.reconfigure().

      • Get the new config information.

      • Reconfigure the transport.

      • Re-instantiate Field Processor.

      • Re-establish the receivers and providers relationship.

      • Start Field Processor.

    4. Finally set the state of transport to end reconfiguration and set the flag of this node to be not in reconfiguration state.

  7. Implement remaining abstract methods:

    1. GetMinorType(): return the minor type of this node, which will be “Airline" in this case.

    2. getConfigGUIClass(): return the package name of the config GUI class of this node. We will implement the config GUI class for this node later.

  8. Implement an “orderly" shutdown method.

    Shutdown method is very important for a node. When you are writing the shutdown() method:

    • Make sure components are shutdown in the proper order.

    • Make sure all threads are really stopped.

    Usually the shutdown order will be like this:

    1. Call super.shutdown().

    2. Shut down the transport.

    3. Shut down the Field Processor.

    4. Shut down the DCStreamHandler.

  9. Implement a main() method for testing purpose.

  10. Write the NPL file for this node. In a CC node this should be primarily mapping to NAR attribute. Following is the NPL file, airline.npl, for AirlineEINode:

    InputRec {
      Integer Passenger_ID;
      Integer Flight_Number;
      Integer Depart_Airport_ID;
      Integer Arrive_Airport_ID;
      TimeInSecs Depart_TIS;
      TimeInSecs Arrive_TIS;
      Integer Number_Bags;
    } in;
    
    OutputRec {
      Integer 0;
      Integer 1;
      Integer 2;
      Integer 3;
      TimeInSecs 4;
      TimeInSecs 5;
      Integer 6;
    } out;
    
    out.0 = in.Passenger_ID;
    out.1 = in.Flight_Number;
    out.2 = in.Depart_Airport_ID;
    out.3 = in.Arrive_Airport_ID;
    out.4 = in.Depart_TIS;
    out.5 = in.Arrive_TIS;
    out.6 = in.Number_Bags;
    
    write(out);
    
  11. Implement the NodeConfigGUI class.

    We now implement the config GUI class, AirlineEINodeCOnfigGUI, for AirlineEINode. We have a template config GUI class, EINodeConfigGUITmpl.java, for reference.

    When we write the config GUI class, we need to identify what kind of config information we need for the node and what kind of node (CC, DC, or Processor). For CC node, its config GUI class should be derived from EINodeConfigGUI; for DC node, it should be derived from OINodeConfigGUI; for Processor node, it should be derived from ProcessorNodeConfigGUI.

    Next, we need to identify the necessary config information for this node. AirlineEINode is collecting the airline passenger data via UDP. We need to know the UDP port number, as well as the size of the queue used in the transport. So we need to add two TextFields in the GUI to allow users to specify the UDP port number and queue size. Now follow the template, we should be able to implement AirlineEINodeConfigGUI class.

Now AirlineEINode is finished. We need to work on EP nodes and DC nodes. When all the nodes are created, we will modify/create the appropriate property files. So we can create those nodes with Node Creation Wizard.

Create Node Chain

You have finished creating the AirlineEINode. You still need to create EP node and DC nodes to set up a node chain to process the airline passenger data.

The EP node will read information from a file to add two additional attributes to each NAR:

  • Departure Airport Name

  • Arrival Airport Name

These values will be read from a “airports.lookup" file which maps the (integer) Airport ID to the Airport Name. The EP node will be FileEnhancer node, which is included in CDK.

airports.lookup file contents:

1000=Logan International Airport

1001=O'Hare International Airport

1002=John F. Kennedy International Airport

1003=Orlando International Airport

1004=Baltimore/Washington International Airport

1005=Bangor International Airport

1006=Portland International Airport

1007=St. Louis Regional Airport

1008=Honolulu International Airport

1009=Austin-Bergstrom International Airport

1010=Dallas/Fort Worth International Airport

1011=LaGuardia International Airport

1012=Los Angeles International Airport

1013=San Francisco International Airport

1014=Manchester Airport

1015=Seattle-Tacoma International Airport

1016=Juneau International Airport

The DC node will simply output all the records to an ASCII file. The DC node will be FFOINode, which is also included in CDK.

In this case, we only need to write NPL rules files for both EP and DC nodes.

  1. Write NPL file for the EP node.

    • Imports the FileEnhMethodHandlerIfc

    • Uses a corresponding “tablename" value as one that will be entered in the client GUI. - Your choice, just be consistent. (i.e. the “tablename" value that the method handler used must be the same value as that entered in the GUI)

    • Uses the method Java.lookup(StringField tablename, StringField attribute) to look up the Departure Airport Name and Arrival Airport Name.

      Following is the NPL file, AirPortEnh.npl, for the EP node:

      import com.nt.udc.processor.FileEnhancer.FileEnhMethodHandlerIfc;
      
      String table_name = "airports";
      
      InputRec {
        Integer 0;     // Passenger_ID
        Integer 1;     // Flight_Number
        Integer 2;     // Depart_Airport_ID
        Integer 3;     // Arrive_Airport_ID
        TimeInSecs 4;  // Depart_TIS  (time in seconds)
        TimeInSecs 5;  // Arrive_TIS  (time in seconds)
        Integer 6;     // Number_bags
      } in;
      //  The output record only needs to have the two new attributes defined.
      OutputRec {
        String 7;      // Departing Airport Name
        String 8;      // Arriving Airport Name
      } out;
      
      //  Record to record assignment
      out = in;
      
      //  Use the "javahook" lookup method to fetch the airport names using their IDs
      out.7 = Java.lookup(table_name,int2str(in.2));
      out.8 = Java.lookup(table_name,int2str(in.3));
      
      write(out);
      
  2. Write NPL file, ffoi_airline.npl, for the DC node that simply maps all of the NAR attributes from the input record (total of 9) to the output record.

Now, it is time to modify/create the node template definitions.

  1. First we will add the new Airline nodes to the nodeTemplateDef.xml file in the customization directory (OMC_Home/customization/nodeTemplateDef.xml, where OMC_Home is the directory in which you installed Offline Mediation Controller.)

    <nodetemplate id="Airline#EI#AirlineEINode">
        <name>Airline CC</name>
        <property name="Solution">cartridgekit</property>
        <rule id="airline.npl">
    <name>Airline Passenger</name>
            <nplfile>airline.npl</nplfile>
        </rule>
        <nodeclass>com.nt.udc.ei.node.airline.AirlineEINode</nodeclass>
    </nodetemplate>
    
    <nodetemplate id="Airline#EP#AirlineEPNode">
        <name>Airport Name EP</name>
        <property id="Solution">cartridgekit</property>
        <rule id="AirportEnh.npl">
            <name>Airport Name</name>
            <nplfile>AirportEnh.npl</nplfile>
        </rule>
        <nodeclass>com.nt.udc.processor.FileEnhancer.FileEnhancerNode</nodeclass>
    </nodetemplate>
    
    <nodetemplate id="Airline#OI#AirlineOINode">
        <name>ASCII DC</name>
        <property name="Solution">cartridgekit</property>
        <rule id="ffoi_airline.npl">
            <name>Airline</name>
            <nplfile>ffoi_airline.npl</nplfile>
        </rule>
        <nodeclass>com.nt.udc.oi.node.flatfile.FFOINode</nodeclass>
    </nodetemplate>
    
  2. Next we will add the node templates to the GUI using the nodeGroupDef.xml file in the customization directory (OMC_Home/customization/nodeGroupDef.xml, where OMC_Home is the directory in which you installed Offline Mediation Controller.)

    <nodetemplategroup>
        <name>Airline Example</name>
        <nodetemplategroup>
            <name>Collection Cartridge (CC)</name>
            <nodetemplate id="Airline#EI#AirlineEINode"/>
        </nodetemplategroup>
        <nodetemplategroup>
            <name>Enhancement Processor (EP)</name>
            <nodetemplate id="Airline#EP#AirlineEPNode"/>
        </nodetemplategroup>
        <nodetemplategroup>
            <name>Distribution Cartridge (DC)</name>
            <nodetemplate id="Airline#OI#AirlineOINode"/>
        </nodetemplategroup>
    </nodetemplategroup>
    
  3. Finally add the NPL rule files

    1. Create directory OMC_Home/rules/Airline/EI/Airline and copy airline.npl to this directory.

    2. Create directory OMC_Home/rules/Airline/Processor/FileEnhancer and copy AirPortEnh.npl to this directory.

    3. Create directory OMC_Home/rules/Airline/OI/FlatFile and copy ffoi_airline.npl to this directory.

    Where OMC_Home is the directory in which you installed Offline Mediation Controller

At this point, we have finished creating/modifying the appropriate node template files. We are able to start the client GUI and use Node Creation Wizard to create our Airline Flight node chain.

Starting FlightInfoSender Simulator

Before we can start our Airline Flight node chain, we need to start the FlightInfoSender simulator, which will send the simulated airline passenger data via UDP.

This simulator is intended strictly for generating data for the CDK Course Workshop. It generates fictional “flight" data.

  • The FlightInfoSender program sends data over TCP port number 2112

  • This program can be run from the command-line as follows:

    Note:

    This command should be typed in all on one line.

$JAVA_HOME/bin/java -classpath OMC_Home/web/htdocs FlightInfoSender \

OMC_Home/web/htdocs/DestIps.dat 10

where:

OMC_Home is the directory in which you installed Offline Mediation Controller.

DestIps.dat: File that lists the IP addresses of the machines to send the flight data to (One (1) IP Address per line). The default version of this file lists only “localhost". If this does not work for you, or you want to send data to one or more different machines, simply replace localhost with the IP address(es) of the desired machine(s).

10:    Delay in milliseconds between records being sent.

  • The simulator runs in an endless loop generating distinct passenger records, up to a point -

    • Each record has a unique passenger ID, which is generated sequentially starting at 1.

    • Flight numbers start at 1, and are incremented every 100 passengers.

    • A departing and arriving airport are generated randomly at the time a new flight number is created. The Airport IDs are pulled from a short list of “valid" airport IDs. There is a lookup file that maps these airport IDs from integers to names. This lookup file can be used for the FileEnhancer, however, the IDs used by the flight sender are hard-coded, and would require a recompile of the source code to add or change values.

This is the end of the CDK workshop exercise. You can now start the Airline Flight node chain and start collecting the airline passenger data.