Oracle® Communications ASAP Cartridge Development Guide
Release 7.2
E22486-01
  Go To Table Of Contents
Contents

Previous
Previous
 
Next
Next
 

12 Creating Java Action Processors

This chapter describes how to create Java and State Table implementations for network element (NE) connections and atomic action scripts that implement MML commands for Oracle Communications ASAP.

Generating Java Stubs for the Connection Handlers and Action Processors

Each Action Processor entity has to be mapped to a specific Java method, which contains the business logic for a specific atomic action. When developing a new cartridge Oracle recommends using the Java code auto-generation feature, available in the Action Processor editor.

Select Java Action Processor (with Code Generation) ->New.

While you can use a classic Java implementation or a State Table implementation, the recommended approach is to use the auto generated option for code generation. This method autogenerates code that otherwise would have to be written by developers. A consistent naming convention is enforced for Java packages and class names by accepting the defaults.

The Java with code generation implementation for an action processor creates a Java processor class with default name like ActionEntityProcessor.Java. The business logic triggered by the execution of the atomic action (get order parameters, build the command, send request to NE, handle response, and so one) is contained in this class execute () method.


Note:

Define atomic action parameters before auto generating Java code, because Design Studio creates a proxy layer for accessing these parameters. These helper classes will be in a generated folder and should not be modified, or checked in under source control. If parameters are not yet defined or the action processor is not yet associated with the atomic action, then the generated sample code will be incomplete.

After creating the Java class stubs the project/cartridge should rebuild without any errors.


Developing a Java Action Processor

The following sections provide information about the Java action processor:

For every action processor you need to define a processor as the implementation that performs the work.

While you can use a classic Java implementation or a State Table implementation, the recommended approach is to implement using Java with code generation. This method provides code that would normally have to be written by developers.

Understanding Java with Code Generation

The Java with code generation implementation for an action processor creates a Java processor that composes messages to be sent to a device, evaluates the response for errors, extracts output information from the response, and populates the information into output parameters.


In the Java processor with code generation, the central class is the Processor, which is editable by the developer. The Processor is generated only once and includes sample code based on the associated parameters at creation time. You should delay the creation of the processor until the action processor is associated with an atomic action that has fully defined parameters. If parameters are not yet defined or the action processor is not yet associated with the atomic action, then the generated sample code will be incomplete and, because it is generated only once, would require additional coding.


Note:

Synchronized classes or interfaces are rebuilt every time you save changes of atomic action parameters (for example, classes and interfaces are synchronized with the model and reflect the model). Therefore, you should never make code changes to any synchronized class or interface. Oracle Communications Design Studio overwrites these changes when you run the next build (with changes in the model). Developers should write code only for the processor class.

There are 2 methods in the Processor:

  • execute

  • init

The main method is execute. When called, it is provided with the following:

  • A number of classes to perform operations.

  • An input class that contains all input parameters.

  • An output class to populate the output parameters.

  • Access to a logger.

  • An implementation of the exit type to match responses against user-defined exit types and to set the exit type for the processor.

  • Access to the Connection Handler to send requests and get responses from a connected device.

About Processor Classes and Interfaces

The following classes and interfaces are used by the Processor:

InputBean

The InputBean is generated and synchronized, tied to the parameters of the atomic action (has set and get methods for all parameters of the atomic action), and provides setters and getters for manipulating parameters.

If the parameter is a scaler (simple type), it is received as a string and can be used immediately

CompoundBean

If the parameter is a compound parameter with named members, the InputBean returns another bean that represents the compound. The returned bean has convenience methods to get the members within the compound. A compound bean for every defined type of compound parameter is created. You also get a set of instances of these beans based on the work order (you get a list of these). If the compound parameter does not have named members, it provides a vector of the members.


Note:

Specify the compound members whenever possible. Indicating the members will simplify the coding required and eliminate possible code to mode synchronization issues.

Multi-instance Compound parameters start at index one (e.g. CMPD[1]).

Bracket type (Index Parameter Identification Tokens) and delimiter (Indexed Parameter Delimiter) settings are configured on the Cartridge editor Cartridge Locations tab in the Code Generation area. Design Studio applies these settings to all generated code within the cartridge. The following examples assume the defaults (square brackets with a period delimiter).

The following example shows a scalar parameter.

Service Action Parameter Name: SCALAR
Atomic Action Parameter Name: SCALAR
Order Format: 
     SCALAR
Usage: 
     String myscalar = parms.getMyScalar();

The following example shows a compound parameter with no members specified.

Service Action Parameter Name: CMPD
Atomic Action Parameter Name: CMPD
Order Format: 
Entries will have the compound name as a prefix. There may be multiple entries with that prefix. For example, a compound named "CMPD" may have the following entries on an order.
     CMPD
     CMPD.X
     CMPD.Y
     CMPD.Z
Usage:
     String mycmpd = parms.getMyCmpd
       String x = parms.getMyCmpd ("X");
       String y = parms.getMyCmpd ("Y");
       String z = parms.getMyCmpd ("Z");

The following example shows a compound parameter with members.

Service Action Parameter Name: CMPDMBR
Atomic Action Parameter Name: CMPDMBR
Order Format:
     CMPDMBR.A
     CMPDMBR.B
     CMPDMBR.C
Usage:
     MyCmdMbrBean mycmpdmbr = parms.getMyCmpdMbr();
       mycmpdmbr.getA();
       mycmpdmbr.getB();
       mycmpdmbr.getC();

The following example shows a multi-instance compound parameter with no members specified.

Service Action Parameter Name: CMPDMULTI
Atomic Action Parameter Name: CMPDMULTI
Order Format:
Entries will have the compound name as a prefix. There may be multiple entries with that prefix. For example, a compound named "CMPDMULTI" may have the following entries on an order.
     CMPDMULTI[1]
     CMPDMULTI[1].X
     CMPDMULTI[1].Y
     CMPDMULTI[1].Z
     CMPDMULTI[2].X
     CMPDMULTI[2].Y
     CMPDMULTI[2].Z
Usage:
     String mycmpdmulti = parms.getMyCmpdMulti ();
       String x1 = parms.getMyCmpdMulti (1, "X");
       String y1 = parms.getMyCmpdMulti (1, "Y");
       String z1 = parms.getMyCmpdMulti (1, "Z");
       String x2 = parms.getMyCmpdMulti (2, "X");
       String y2 parms.getMyCmpdMulti (2, "Y");
       String z2 = parms.getMyCmpdMulti (2,"Z");

The following example shows a multi-instance compound parameter with members.

Service Action Parameter Name: CMPDMULTIMBR
Atomic Action Parameter Name: CMPDMULTIMBR
Order Format:
     CMPDMULTIMBR[1].A
     CMPDMULTIMBR[1].B
     CMPDMULTIMBR[1].C
     CMPDMULTIMBR[2].A
     CMPDMULTIMBR[2].B
     CMPDMULTIMBR[2].C
Usage:
     MyCmpdMultiMbrBean[] mycmpdmultimbr = parms.getMyCmpdMultiMbr();
     for (int i = 0; i <mycmpdmultimbr.length; i++) 
     {
       MyCmpdMultiMbrBean bean = mycmpdmultimbr[i];
       bean.getA();
       bean.getB();
       bean.getC();
     }

The following example shows an indexed compound parameter with no members.

Service Action Parameter Name: CMPDIDX[++]
Atomic Action Parameter Name: CMPDIDX
Order Format:
Entries will have the compound name as a prefix. There may be multiple entries with that prefix. For example, a compound named "CMPDIDX" may have the following entries on an order.
     CMPDIDX[0]
     CMPDIDX[0].X
     CMPDIDX[0].Y
     CMPDIDX[0].Z
     CMPDIDX[1].X
     CMPDIDX[1].Y
     CMPDIDX[1].Z
Usage:
     String mycmpdidx = parms.getMyCmpdIdx();
       String x = parms.getMyCmpdIdx ("X");
       String y = parms.getMyCmpdIdx ("Y");
       String z = parms.getMyCmpdIdx ("Z"); 

Note:

The implementation will be called multiple times, providing one instance of the compound during each call.

The following example shows a compound parameter with members.

Service Action Parameter Name: CMPDIDXMBR[++]
Atomic Action Parameter Name: CMPDIDXMBR
Order Format:
     CMPDIDXMBR[0].A
     CMPDIDXMBR[0].B
     CMPDIDXMBR[0].C
     CMPDIDXMBR[1].A
     CMPDIDXMBR[1].B
     CMPDIDXMBR[1].C
Usage:
     MyCmpdIdxMbrBean mycmpdidxmbr = parms.getMyCmpdIdxMbr();
       mycmpdidxmbr.getA();
       mycmpdidxmbr.getB();
       mycmpdidxmbr.getC();

Notes:

  • The implementation will be called multiple times providing one instance of the compound during each call.

  • For multi-instance compounds, member parameters cannot be set as required because the system cannot determine whether a member is present or if there are additional entries.


Output

The Output class enables you to populate output parameters. There are convenience methods for populating parameters to varying scope within a work order. Examples of parameters are as follows:

  • Action parameters are available to the service action.

  • Input parameters.

  • Global parameters are available to everything.

  • Rollback parameters enable you to populate for the rollback action if it is defined within the atomic action.


Note:

The output parameters are not explicitly defined in the model, so there are no convenience methods. To set a parameter you need to know its string name and include it.

ILogger

ILogger is an interface for debug logs. When the processor is running on the Oracle Communications ASAP system, it logs to the Diagnosis log. If you are running the processor in JUnit, you can use other implementations of logger to log to the console instead.

IExitType

IExitType enables you to set the exit type explicitly or by matching a response string against the user-defined exit types.

IConnectionHandler

IConnectionHandler is an instance of the Connection Handler that is associated with the vendor, technology, and software load of the action processor. For the Telnet Connection Handler, the basic methods on the interface can be used to send requests (because it is string-based). For technologies (for example, SOAP or XML) that provide multiple convenience methods, the Processor may want to test the type of Connection Handler and pass it to a more specific Connection Handler to obtain access to the convenience methods. If you want to expose more explicit methods when writing a Connection Handler, you can define an interface that extends the IConnectionHandler and ensure that those methods are available through that interface. The Processor should always use an interface when interacting with the ConnectionHandler, to achieve the implementation in more than one way and allow for unit testing. For more information about unit testing, see "Understanding Unit Testing".

Processor

Processor needs to implement the processor interface, which is generated in the code generation and kept synchronized with the model.

Proxy

Proxy is situated between the NEP and Processor class and manages the interaction between them. Proxy sets up all classes used by the Processor and initiates and calls the Processor. Most importantly, the proxy simplifies the work required by the Processor by:

  • Creating all instances of the InputBean and initializes CompoundBeans so they are available and populated through the processor.

  • Performing much of the standard logging, including the entry and exit of the processor and the contents of the parameters passed in for debugging.

  • Extending the JProcessor. This isolates the portion of the Java processor code that needs to relate directly to the version of the activation, and allows the processor, its interface, and all its related classes and interfaces to run outside of the ASAP system and, therefore, to be unit tested


    Note:

    When creating a Java processor from the action processor editor, the resulting class name is "Proxy" because the proxy gets initiated by the NEP (Proxy is registered to be called in the activation). When you open that implementation it opens to the Processor class, where you write your code for editing.

Example: Typical Processor Call Sequence

The proxy:

  1. The proxy creates the input, the output, and the exit type classes.

  2. The proxy populates the exit type classes and initializes them.

  3. The proxy creates the processor that will be called and initializes it.

  4. If the logger needs to be used by the processor, the proxy provides this during the init method call.

  5. The proxy invokes the processor by calling the execute method with the input, output, connection, and exit type.

  6. The processor obtains parameters from the InputBean to compose a message or command to be sent to a device.

  7. The processor calls the send request to send that message to the device.

  8. The processor sets the exit type based on the response.

  9. The processor sets output parameters based on the response.

    The processor may parse the response to obtain additional values for populating the output parameters.

  10. The proxy cleans up the processor.

  11. The proxy looks at the exit type that was set and populates it for return to the NEP, and cleans up the exit type.

  12. The proxy extracts all output parameters for return to the NEP and to populate the work order.

    The proxy then cleans up this class and (16) the remaining classes.


Note:

The developer is only responsible for the items related to the processor (steps 6 through 9); the proxy handles all other items.

Understanding the Java Processor Class

You need to write the logic in the execute method of the processor class (there is a processor class for each atomic action) to achieve the desired action in a switch. Use the Java editor in the Package Explorer view of the Java perspective to write all code.

When implementing the action processor, Design Studio provides you with support such as autogeneration of code and sample data. In Design Studio, this is currently set up specifically for the Telnet protocol (Soap, Corba and other protocols require more coding; for example, you must write your own logic for send methods, requests, to extend the connection class, and so on.).

Code for the processor is autogenerated by the proxy (getter and setter methods for each parameter) which provides you with an API to manipulate the data. For example, for an incoming object, methods such as getBilling are autogenerated (the type of methods depend on the parameters specified in the service model and how they are mapped). You can use these autogenerated methods in the processor class to get the value for the parameters.

See "Understanding Java with Code Generation" for more information about autogenerating processor code.

To obtain the required method to get a value for a parameter, type the name of the parameter followed by a dot. This displays all available methods for the parameter.


Notes:

  • Do not modify the autogenerated code. All changes are overwritten during any subsequent builds.

  • Code generation does not overwrite existing Java code. If you change the target implementation, the old code remains. Clean up old code when creating a new Java implementation for an action processor with an existing Java implementation.


Writing Java Processor Execute Method Logic

The basic development steps to write the logic for the execute method of a Java Processor class are as follows:

To write Java Processor execute method logic:

  1. Extract parameters from InputBean (retrieve information).

  2. Use these parameters to build a command.

  3. Send a message or command to the switch using the send request in Telnet.

  4. Handle the response by setting the user-defined exit type.

    See "Configuring Base Exit and User Exit Types" for more information about setting the user-defined exit type.

  5. Using the OutputBean, you have the option to return some parameters upstream to log, infoparm, and so on.

Occasionally, for Telnet, you may need to build some helper classes, perform data derivation, and create parsers.

Java Processor Class Example

The following is a coding example for an atomic action.

From the Java editor of the Package Explorer view:

  1. Create an atomic action and an action processor.

    See "Creating and Configuring Atomic Actions and Action Processors" for more information.

  2. Select an ADD action and LINE entity for each.

  3. In the Atomic Action editor, map the action processor to the atomic action.

    See "Mapping Network Element Commands to Actions, Entities, and Parameters" for more information.

  4. In the Parameters tab, right-click in the Parameters area and select Simple Data Element or Select Structured Data Element. See the Design Studio Help for more information.

  5. In the Parameter Details area, define values to the ASAP run-time type parameters.

  6. In the Mappings tab, click the mapped action processor to open the Action Processor editor.

  7. Select Java Action Processor (with Code Generation).

  8. Click New.

    The Studio Activation Java Implementation Wizard appears.

  9. Click Finish.

    A new atomic action class appears in the Java editor with basic code, such as the entry point, get functions to get the parameters defined in the atomic action, and, in the end portion, sendRequests and how the response is handled.


  10. Build the MML (the message itself) using the Eclipse message format.

    Use methods and classes. If no parameters are available in the atomic action, use a string to build the MML.

  11. Send the message to the switch using the send request.

  12. Set the user-defined exit type.

Understanding Java Libraries in Design Studio

There are several types of Java libraries available in Design Studio:

Activation libraries

Activation libraries are utilized by many cartridges and include the following:

  • studio_2_6_0.jar

  • asaplibcommon.jar

  • JInterp.jar

Activation libraries are automatically added to the project when you create an action processor. They are added to the project classpath to enable the Java development toolkit access.


Notes:

  • The studio_2_6_0.jar file is not installed by the ASAP installation. The studio_2_6_0.jar must be added to the ASAP installation prior to deployment of a Design Studio-created cartridge. Configure the studio_2_6_0.jar, asaplibcommon.jar, and JInterp.jar files on the server. See the discussion of installing a cartridge using Design Studio in ASAP Installation Guide.

  • When you are packaging a cartridge, exclude the studio_2_6_0.jar, asaplibcommon.jar, and JInterp.jar files. These JAR files are installed on the Activation server and are shared by all cartridges If you include these JAR files, Design Studio generates an error.


Other Libraries

Add other libraries to the lib folder under the project. Update the Java project properties to set the Java buildpath to make use of those libraries. See Eclipse help for adding folder or packages to the Java buildpath.

In the Cartridge editor Packaging tab, select Libraries to display any jar files contained in the lib folder.

Understanding Unit Testing

Unit testing in Design Studio does not need to be implemented to complete a cartridge, although it is highly recommended for these reasons:

  • Unit testing contributes to building quality code.

  • Unit testing provides repeatable tests for regression.

You can test the processor outside of the ASAP system because the interfaces and generative classes of the Java processor are all independent of the ASAP system and its classes (the generated InputBeans and output are not tied to ASAP). To run the processor, a TestCase is generated once (with a sample test based on information at the time of creation), after which the developer owns it and can extend it.

The unit test framework initiates all tests in test subfolder. Unit testing is implemented as a JUnit test. JUnit tests can optionally be run with the JDT Debugger.


The TestCase simulates the proxy for each individual test, and:

  • Creates an implementation of the interfaces, either the real implementation or a stubbed test implementation.

  • Generates input and output beans.

  • Invokes the processor.

The TestCase is a JUnitTestCase. Each TestCase can contain many tests, and each test is defined by a no-parameter method beginning with "test".

The generated TestCase has a framework that provides a test. The test runs based on input files, which find the data and test criteria for a particular test. This framework enables developers to create simple files to define new tests. This works for any standard type of test where you pass in data and check the request to ensure it was sent as expected, and that the returned exit type is the one you expected. Also, this allows for a simple, standard response to be used inside the test.

Sample test classes are provided for simulating IExit and ILogger. A base output class provides the methods required for output classes.

Running Unit Test Cases

Run the TestCase class as a JUnit test, or as a Java application. Running as a JUnit test provides a richer user experience by providing results in the JUnit view. Running as a Java application allows the TestCase to be run as part of an automated test framework. Java application test case results appear in the Eclipse IDE in the Console view.

To run unit test cases:

  1. Right click the TestCase class and select Run As.

  2. Select JUnit Test or Java Application.

    Design Studio displays the results in the JUnit view or Console view, depending on your selection in step 2. Logging information is sent to the Console View.

Running Unit Tests with the JDT Debugger

To run unit test cases with the JDT debugger:

  1. Set breakpoints in your Processor class as desired.

  2. Right click the TestCase class and select Run As.

  3. Select JUnit Test or Java Application.

    The unit test is executed and the debugger will break as appropriate, allowing for full debugger functionality, including variable inspection and code stepping.

Understanding Unit Test Property Files

You use a set of property files to set up a unit test (both are property file and follow the Java property file format):

  • testdata file (for example, TestExample.testdata)

  • testinfo file (for example, TestExample.testinfo).


    Note:

    The testinfo file is optional. Design Studio uses defaults if it is not present.

Testdata file

The testdata format for naming the input parameters is similar to that within a work order. However, you must populate the test data with atomic action labels (and not service action labels). Run the unit test as if the parameters have been previously defaulted.

Apply the defaults that are normally set by the SARM (based on what is configured in the atomic action) as if they had been applied in the test data (the processor runs after those defaults have been set). The unit test data should be based on data that has already been defaulted and based on names relating to the atomic action label (and not the service action label).

When you fill in the test data for compounds or incoming repeating elements, use square brackets to indicate the index for a compound as in the following example.

# Example Action Processor input property file
NETID=ERIC-SDP_3-6-2-HOST 
MSISDN=0701234567 
FAF_LIST[1].FAF_N=0701237777 
FAF_LIST[1].TSC=O 
FAF_LIST[1].RCO=1 
FAF_LIST[1].K=400 
FAF_LIST[2].FAF_N=07052 
FAF_LIST[2].TSC=4 
FAF_LIST[2].K=100 
FAF_LIST[3].FAF_N=071 
FAF_LIST[3].K=500

Testinfo file

You can use this optional file to define the properties for which you are testing. You can also define what expected request the processor should create, the expected canned response returned to the processor, the expected exit type and whether it should be tested.


Note:

If you do not define a testinfo file, then by default the test case only tests whether the exit type is succeed (that is, to confirm that the test data has gone through).

# Example Action Processor test info property file
request.check=true 
request.value=Test Message
response.value=Test Response
# Exit Type values: 
# SUCCEED 
# FAIL
# RETRY 
# MAINTENANCE 
# SOFT_FAIL 
# DELAYED_FAIL 
# STOP
exittype.check=true 
exittype.value=SUCCEED

If you wish to have multiple request and response values in your test, you can specify multiple values in the testinfo file. Add a dot separated numeric suffix to the value (starting at 1).

If your request or response has multiple lines or special character, follow the standard Java property guidelines.

# Example Action Processor test info property file
request.check=true 
request.value.1=Test Message 1
request.value.2=Test Message 2
response.value.1=Test Response 1
response.value.2=Test Response 2
# Exit Type values: 
# SUCCEED 
# FAIL 
# RETRY
# MAINTENANCE 
# SOFT_FAIL 
# DELAYED_FAIL 
# STOP
exittype.check=true 
exittype.value=SUCCEED

Configuring a Unit Test

To configure a unit test:

  1. Select File, select New, then select File.

  2. Create a file name.testdata.

    For example, you might create a file called TestExample.testdata.


    Note:

    Place this file in a subfolder of the action processor implementation package named test.

  3. Enter the text for the file.

    The file format is a Java property file, so each entry specifies the parameter and its value.

  4. Repeat steps 1 and 2 as necessary to create a second file name.testinfo.

    For example, you might create a file called TestExample.testinfo.

About Java Method Naming Convention

While a common service model may be implemented for a specific customer in which service actions and atomic actions are often vendor (possibly technology) and software load agnostic, Java methods are always considered by ASAP to be vendor, technology and software load specific. The mapping between any atomic action and its corresponding implementation (Java method) is performed by ASAP core and is based on the configuration provided in tbl_nep_asdl_prog and the configuration of the NE:

technology + software load = implementation

For service action and atomic action commands the technology field is currently overridden with a combination of vendor and technology (hence the use of the dash to separate the vendor and technology tokens as opposed to an underscore).

Design Studio implements this mapping with the action processor element. For more information, see "Creating an Action Processor".

Java Package Naming Convention

The Java package naming convention consists of the constant prefix com.oracle.cartridge.oss in lowercase, with each of the tokens separated by a period (.) character. Each of the tokens must be separated by an underscore (_) character. The format of a Java package is as follows:

com.oracle.cartridge.oss.vendor_technology_softwareload_entity_action_

Where:

The following example illustrates the structure of a Java package used for the Alcatel-Lucent fiber to the user (FTTU) node running software load 7, providing the pay per view (PPV) service, with a buy action:

com.mslv.activation.cartridge.alu.fttu.7.ppv.buy

The convention used in most cartridges is based on the Metasolv name. For example com.mslv.cartridge.activation.cartridge.

Design Studio enforces this naming convention when you use the autogenerated code feature.

Java Class Naming Convention

A Java class is a single entity that is contained within a Java package. The following list contains each of the types of cartridge Java classes and their corresponding naming conventions:

Connection class—Connection.java (for example HLRConnection.java)
Provisioning class—<*>Provisioning.java (for example HLRProvisioning.java)
Library class—<*>Lib.java

Class names should be nouns, in mixed case, with the first letter capitalized and with the first letter of each internal word capitalized. Try to keep your class names simple and descriptive. The wildcard token (*) used in the naming convention for provisioning and library classes is an optional string that can be used to either divide a provisioning or library class that is too large in size or identify a group of related features that are contained in the provisioning or library classes.

Java Helper and Utility Class Naming Convention

Java helper and utility class file names consists of a series of tokens that are separated by the underscore (_) character. Each token must begin with a lowercase letter. The ".jar" constant always appears at the end of the Java library file name to identify the file as a Java library file. The maximum allowable length for a Java library file name is dictated by the operating system.

The format of Java helper and utility classes is as follows:

vendor_technology_softwareload_entity.jar

Where:

The following example illustrates the structure of a Java library file that contains the byte code to support VDSL service activation on a Alcatel-Lucent FTTU NE running software load 7.2:

alu_fttu_72_vdsl.jar

Java Method Naming Convention

Methods should be verbs. Tokens contained in the Java methods names are concatenated or separated using a combination of the period (.) and underscore (_) characters. The Java method naming convention consists of two tokens that are concatenated. The format of a Java method is as follows:

actionservice

Where:

The first letter of the action must appear in lowercase and the first letter of all subsequent tokens must appear in uppercase. The following example illustrates the structure of a Java method used for the Alcatel-Lucent FTTU NE supporting a pay per view (PPV) service:

addPpv

Java Variables Naming Convention

Variable names should be short yet meaningful. The choice of a variable name should be a mnemonic, and designed to indicate the intent of its use. One-character variable names should be avoided except for temporary "throwaway" variables. Common names for temporary variables are i, j, k, m, and n for integers; c, d, and e for characters.

Java Constants Naming Convention

The names of variables declared class constants should be all uppercase with words separated by underscores (_).

Using Default Values

Avoid hard coding default values in the Java methods. If there is a need to set a default value for one or more parameter the atomic action default configuration should be used (see tbl_asdl_parm).

Even if a default value has been configured in the cartridge (tbl_asdl_parm) for a particular parameter there is no guarantee that a default will be assigned in the customer specific service model (for example common service model), therefore the Java code cannot assume that the parameter will have a value and should therefore verify that it is not NULL before attempting to use it.

Enabling Value and Range Checking

The Java code must verify that parameters have a non-null value and log an error to the diagnostic file if such a parameter is missing (even if it is expected that it will be configured as a "required" parameter within the SARM) that are needed by an NE to ensure successful execution of the provisioning command. This checking is often used in common service modeling scenarios where it is not possible to perform error checking at the atomic action level. For example, a parameter may be required by one vendor, technology and software load and not another.

Perform value and range checking of atomic action parameters where possible within the Java code when an NE does not respond with a meaningful error message indicating which parameter has an invalid range/value.

If an NE expects a variable to be padded in some way the cartridge should perform the padding.

Logging Diagnostic Messages

Ensure that the ASAP core code (as well as cartridge code) does not write to stdout and stderr unless absolutely necessary. Instead, diagnostic messages should be written to the ASAP diagnostic files when required. For more information, see the Java diag method in the Diagnosis class in the Java Online Reference.

When ASAP is started, stderr and stdout messages are explicitly redirected to a file called ASAP.Console. For more information about the start_control_sys script that is called by the start_asap_sys script, see ASAP Administrator's Guide). Writing to stdout and stderr can result in the ASAP.Console file dramatically increasing in size.

When logging optional parameters to the diagnostic files be sure to check if they have actually been defined first (including the MCLI parameter which is optional if ID_ROUTING is being used).

Do not log passwords of any kind (NE login passwords, database connection passwords etc.) to the ASAP diagnostic files.

Remove all internal debugging related diagnostic messages from the cartridge code when unit testing by the cartridge developer is complete.

Three diagnostic logging levels can be used within the cartridges. The developer can use KERN that should provide diagnostic messages more technical and debugging related. Use LOW for diagnostic message that are more cartridge related to show important information during development phase and test phase. Use SANE for diagnostic messages that are more informational. For more information about diagnostic levels, see ASAP Administrator's Guide.

Log messages which are stored in SARM database table tbl_srq_log to provide cartridge related information about work orders. For the telnet base cartridge, ASAP has already implemented that functionality, but for the CORBA, SOAP and another protocols you need to implement log messages, providing information about which method was executed, and provide all atomic action parameters implemented in the method, log NE response, and error messages.

TCP/IP Message Parsing Options

When using the TCP/IP protocol you can take the following two approaches when parsing responses from the NE:

  • parsing the raw response

  • using the virtual screen in conjunction with ASAP core method calls.

Parsing the raw response means that more cartridge code is required, however it results in improved performance. In domains such as wireless where high volumes of work orders are expected, consider parsing the raw response from the NE.

The virtual screen mechanism extracts only the meaningful text strings from the responses and places them in the correct position on a two dimensional virtual screen where responses may be extracted using Cartesian coordinates. This approach results in less cartridge code however it decreases the performance of the cartridge. Use the virtual screen approach in low volume scenarios where ease of implementation is preferred.

Use of Journal Functionality

Some switches provide a journal id as a response when a command is processed. If a subsequent error occurs on a later provisioning activity (either to the same switch or a different one) and rollback is therefore initiated, the journal id can be used to undo commands that have previously been processed. This way, the cartridge does not have to keep track of exactly what commands were performed or query the switch in anticipation of rollback being performed (for example, to get the features on a line before a delete is performed so that they could be reapplied to the line at a later time). The journal IDs do however need to be remembered as each command is processed until the work order is completed.

Cartridges must support journaling capability where provided by the NE and should support use of this approach for rollback purposes.

Telnet Provisioning Class Flow

The following list describes the flow for Telnet provisioning classes.

  1. Initialize generic data

  2. Get the connection reference

  3. Get the NE ID

  4. Enable the response log

  5. Get the work order parameters and build the AsapParameter objects passing the parameter label and value

  6. Build the provisioning command with a specific action type and append parameter objects to the command

  7. Convert the command to a string

  8. send the command to the switch

  9. Obtain the NE response

  10. Exit with the appropriate user-defined -> base exit type.

Example 12-1 Telnet Sample Code

//***** initialize generic data: get connection reference, get ne id, enable response log
initialize();
//****** get work order parameters and build AsapParameter objects passing the param label and value
String imsi = getParam(IMSI);
String bserv = getParam(BSERV);
String msisdn = getParam(MSISDN);
String nbr = getParam(NBR);
AsapParameter imsiParm = new AsapParameter(IMSI, imsi);
AsapParameter bservParm = new AsapParameter(BSERV, bserv);
AsapParameter msisdnParm = new AsapParameter(MSISDN, imsi);
AsapParameter nbrParm = new AsapParameter(NBR, bserv);
//***** Build the provisioning command with a specific action type and append parameter objects to the command
ProvisioningCommand cmd = new ProvisioningCommand(SAConstants.CREATE_BASIC_SRV); //***create command for adding a basic service
cmd.append(imsiParm).append(bservParm).append(msisdnParm).append(nbrParm);
//***** command ready! convert it to string mml and send it to the switch
String strCmd = cmd.toString();
String reply = sendNeRequest(strCmd);
//*****handle response, set user exit type etc
handler.checkResponse(reply); //optional
UserExitType uet = handler.getUserExitType(reply);
setASDLExitType(uet.getUserExitType(), uet.getUserErrorText());