# Platform Test Environment

# Extending the Platform Test Environment

One of the most common uses for the Platform Testing Environment is to test extension communication services. Depending on how those extensions are implemented, you may need to create one or more new modules so that the PTE can interact successfully with your new communication service. You can implement new client modules, and even new clients containing multiple modules, if support for the application-facing interface that you want your communication service to use is not already available in the PTE. You can also implement new simulators, if the network node type that you want your communication service to interact with is not available. From the point of view of the PTE, a module is a module.

The only relevant distinction in the PTE is between modules for operations that simply execute and return and those for operations that start a process which runs until it is turned off. These are called, respectively, stateless and stateful modules. See Figure 2-12 for more information. Stateless modules must implement the `CustomStatelessModule` SPI and stateful modules must implement the `CustomStatefulModule` SPI. There are two additional, optional interfaces that can be implemented if you would like your module to display results (for example, a notification, a message from the network delivered to a client Web Service) or provide statistics in the GUI. The custom module SPI hierarchy is as follows:

Figure 3-1 The Custom SPI Hierarchy

Any module that is created must be packaged as a .jar file which must be located in the`$PTE_HOME$/lib/modules/` directory. The root of the .jar file must include a descriptor file called `module.xml`. All custom modules automatically load when the PTE starts up.

Note: | The modules created for use with the example communication service are located in `<bea_home>/wlng_pds400/example/pte_module`.

### The Stateful SPI

Figure 3-2 shows the execution sequence for a stateful module:

Figure 3-2 The Execution Sequence for a Stateful Module

The following listing is the SPI that must be implemented by stateful PTE modules.

Listing 3-1 CustomStatefulModule SPI

    package com.bea.wlcp.wlng.et.spi;

    /**

     * This interface must be implemented by a custom stateful module.

     * A stateful module has a start() and a stop() method and will be

     * represented in the UI by the Start/Stop button.

     * Note: a stateful module is not used in duration tests.

     *

     * @author Copyright (c) 2008 by BEA Systems, Inc. All Rights Reserved.

     */

    public interface CustomStatefullModule extends CustomModule {

    /**

       * Starts the module.

       * @param context The custom module context

       * @return true if the module successfully started

       * @throws Exception Any exception preventing the module to start

       */

      public boolean start(CustomModuleContext context) throws Exception;

    /**

       * Stops the module.

       * @param context The custom module context

       * @return true if the module successfully stopped

       * @throws Exception Any exception preventing the module to stop

       */

      public boolean stop(CustomModuleContext context) throws Exception;

    }

### The Stateless SPI

Figure 3-3 shows the execution sequence for a stateless module:

Figure 3-3 The Execution Sequence for a Stateless Module

The following listing is the SPI that must be implemented by stateless PTE modules.

Listing 3-2 CustomStatelessModule SPI

    package com.bea.wlcp.wlng.et.spi;

    /**

     * This interface must be implemented by custom stateless module.

     * A stateless module has only an execute() method and will be

     * represented in the UI by the Send button.

     *

     * @author Copyright (c) 2008 by BEA Systems, Inc. All Rights Reserved.

     */

    public interface CustomStatelessModule extends CustomModule {

    /**

       * Asks the module to execute its job and return the result.

       *

       * @param context The custom module context

       * @return The result of the execution

       * @throws Exception Any exception that occurred during the execution

       */

      public Object execute(CustomModuleContext context) throws Exception;

    }

### The Custom Base SPI

This following is the base SPI for custom PTE modules. It should not be implemented directly. See the first comment.

Listing 3-3 The Custom Base SPI

    package com.bea.wlcp.wlng.et.spi;

    import com.bea.wlcp.wlng.et.api.CustomModuleContext;

    /**

     * This interface defines the general API a custom module must implement.

     * Note: a custom module should NOT implement this interface directly but

     * one of the subinterface like CustomStatefulModule or CustomStatelessModule.

     *

     * @author Copyright (c) 2008 by BEA Systems, Inc. All Rights Reserved.

     */

    public interface CustomModule {

      /**

       * Prepares the module with the given context. This method is invoked before

       * the module is executed: it can be used by the module to prepare

       * any internal states needed.

       * Note: when a duration test is performed on the Platform Test Environment,

       * prepare() is invoked only once at the beginning of the duration test.

       *

       * @param context The context of the custom module

       * @throws Exception Any exception that occurred during the module preparation

       */

      public void prepare(CustomModuleContext context) throws Exception;

### The Custom Results Provider SPI

The following listing is the SPI that must be implemented by modules that wish to display some sort of results in the GUI.

Listing 3-4 The CustomResultsProvider SPI

    package com.bea.wlcp.wlng.et.spi;

    /**

     * A custom module can implement this interface if it wants to provide

     * a list of results in the UI. The PTE will automatically display a list

     * and handle the user interaction with it.

     *

     * @author Copyright (c) 2008 by BEA Systems, Inc. All Rights Reserved.

     */

    public interface CustomResultsProvider {

    /**

       * Clears the results.

       */

      public void clearResults();

    /**

       * Returns an array of string that will be used to create

       * the name of each column of the results table.

       * @return An array of string to create the column headers

       */

      public String[] getResultsHeaders();

    /**

       * Returns the results. Each result is composed of a map whose keys are

       * the same as the strings returned by getResultsHeaders().

       *

       * Note: It is up to the custom module to accumulate the results until

       * this method is invoked by the PTE.

       *

       * @return A list of results

       */

      public List<Map<String,String>> getResults();

    }

### The Custom Statistics Provider SPI

The following listing is the SPI that must be implemented by modules that wish to display statistics in the GUI.

Listing 3-5 The CustomStatisticsProvider SPI

    package com.bea.wlcp.wlng.et.spi;

    /**

     * A custom module can implement this interface if it wants to provide

     * some statistics in the UI. The PTE will automatically display a list

     * and handle the user interaction with it.

     * @author Copyright (c) 2008 by BEA Systems, Inc. All Rights Reserved.

     */

    public interface CustomStatisticsProvider {

    /**

       * Clears the statistics.

       */

      public void clearStatistics();

    /**

       * Returns a map of statistics. Each key represent a particular statistic

       * and the value the value of the statistic.

       * @return The map of statistics

       */

      public Map<String,String> getStatistics();

    }

### The Context API

The following listing is the API that allows modules to acquire context.

Listing 3-6 The Context API

    package com.bea.wlcp.wlng.et.api;

    /**

     * This interface defines the context available to a custom module.

     *

     * @author Copyright (c) 2008 by BEA Systems, Inc. All Rights Reserved.

     */

    public interface CustomModuleContext {

      /**

       * Returns the custom module data object as described in the module.xml

       * @return The custom module data object

       */

      public Object getData();

      /**

       * Returns the module of the specified type that this module depends on.

       * If there are many modules of the same type, the one chosen by the user

       * in the UI will be chosen.

       *

       * @param type The type of module

       * @return The module instance of the specified type

       */

      public CustomModule getDependency(String type);

      /**

       * Prepares the stub that the module will use to send a request. The PTE

       * will perform various changes to the stub depending on the UI settings,

       * like TCP Monitor or Override Endpoint.

       *

       * @param stub The stub to prepare

       * @param path The path to the parameter declared in module.xml that corresponds

       * to the stub url. Use null if it doesn't have any corresponding parameter.

       */

      public void prepareStub(Stub stub, String path);

      /**

       * Deploy (or undeploy) a service using a specific WSDD file.

       *

       * @param wsddFile The WSDD file that the axis server will execute

       * @throws Exception Any exception when executing the command

       */

      public void axisDeploy(String wsddFile) throws Exception;

### The Module.xml Descriptor File

Every module is packaged in a .jar file with a descriptor file, `module.xml`, in its root. What is in the file depends on the nature of the module.

The following is the listing for a client module and the simulator module supplied with the example communication service:

Listing 3-7 The example module.xml

    <module-factory xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"

                    xsi:noNamespaceSchemaLocation="http://www.bea.com/ns/wlng/40/et">

      <module name="example_application_initiated"

              type="client"

              class="com.bea.wlcp.wlng.et.example.SendDataModule"

              version="1.0"

              depends="session"

              uiPanel="client"

              uiTabs="Other,Example,Application-Initiated"

              >

        <data>

          <parameter name="Parameters"

                     class="com.bea.wlcp.wlng.et.example.SendDataData"

                     occurs="1">

            <parameter name="url"

                       class="java.lang.String"

                       occurs="1"

                       default="http://${at.host}:${at.port}/example/SendData"

                       monitor="true"/>

            <parameter name="data"

                       class="com.acompany.schema.example.data.send.local.SendData"

                       occurs="1">

              <parameter name="address"

                         class="java.net.URI"

                         occurs="1"

                         default="tel:1234"/>

              <parameter name="data"

                         class="java.lang.String"

                         occurs="1"

                         default="Hello, world"/>

            </parameter>

          </parameter>

        </data>

      </module>

      ...

      <module name="example_simulator"

              type="netex"

              class="com.bea.wlcp.wlng.et.example.SimulatorModule"

              version="1.0"

              uiPanel="simulator"

              uiTabs="Netex"

              >

        <data>

          <parameter name="Parameters"

                     class="com.bea.wlcp.wlng.et.example.SimulatorData"

                     occurs="1">

            <parameter name="port"

                       class="int"

                       occurs="1"

                       default="5001"/>

          </parameter>

        </data>

      </module>

    </module-factory>

Below is the entire .xsd file for `module.xml`:

Listing 3-8 The module.xsd File

    <?xml version="1.0"?>

    <xs:schema xmlns:xs="http://www.w3.org/2001/XMLSchema"

               elementFormDefault="qualified">

      <!-- Main element that describes one or more modules -->

      <xs:element name="module-factory">

        <xs:complexType>

          <xs:sequence>

            <xs:element ref="module" minOccurs="0" maxOccurs="unbounded"/>

          </xs:sequence>

        </xs:complexType>

      </xs:element>

      <!-- Defines a single module -->

      <xs:element name="module">

        <xs:complexType>

          <xs:sequence>

            <!-- Optional data of the module -->

            <xs:element ref="data" minOccurs="0" maxOccurs="1"/>

          </xs:sequence>

          <!-- Name of the module. It will be used also for the display -->

          <xs:attribute name="name" type="xs:string" use="required"/>

          <!-- Type of the module -->

          <xs:attribute name="type" type="xs:string" use="required"/>

          <!-- Class of the module (fully qualified) -->

          <xs:attribute name="class" type="xs:string" use="required"/>

          <!-- Version of the module -->

          <xs:attribute name="version" type="xs:string" use="required"/>

          <!-- Name of the module this module depends on.

           Predefined types are:

           - session : session module

           - axis : axis server module

           The PTE will make sure that before this module is started, the

           dependent module is running. -->

          <xs:attribute name="depends" type="xs:string" use="optional"/>

          <!-- UI panel where the module will be located (see ui-panels) -->

          <xs:attribute name="uiPanel" type="ui-panels" use="required"/>

          <!-- Location of the module in the panel tabs.

           The location is a list of UI tab names separated by comma. For example:

           "Other,Example,SendData"

           means that the module will be in a tab named "SendData"

           located in the tab "Example" located in tab "Other".

           The name of each tab is available in the UI.

           If a tab doesn't exist for a particular name, it will be created.-->

          <xs:attribute name="uiTabs" type="xs:string" use="required"/>

        </xs:complexType>

      </xs:element>

      <!-- Available UI panels -->

      <xs:simpleType name="ui-panels">

        <xs:restriction base="xs:string">

          <!-- Client panel -->

          <xs:enumeration value="client"/>

          <!-- Simulator panel -->

          <xs:enumeration value="simulator"/>

        </xs:restriction>

      </xs:simpleType>

      <!-- Data of the module -->

      <xs:element name="data">

        <xs:complexType>

          <xs:sequence>

            <xs:element ref="parameter" minOccurs="0" maxOccurs="unbounded"/>

          </xs:sequence>

        </xs:complexType>

      </xs:element>

      <!-- A single parameter -->

      <xs:element name="parameter">

        <xs:complexType>

          <xs:sequence>

            <!-- Can contain other parameters too -->

            <xs:element ref="parameter" minOccurs="0" maxOccurs="unbounded"/>

            <!-- Values restriction of the parameter (see restricted) -->

            <xs:element ref="restricted" minOccurs="0" maxOccurs="1"/>

            <!-- Internal use only -->

            <xs:element ref="instance" minOccurs="0" maxOccurs="unbounded"/>

          </xs:sequence>

          <!-- Name of the parameter. It will be used to access the member

           of the parameter (MBean-style) -->

          <xs:attribute name="name" type="xs:string" use="required"/>

          <!-- Fully qualified name of the parameter -->

          <xs:attribute name="class" type="xs:string" use="required"/>

          <!-- Occurrences of the parameter (see parameter-occurs) -->

          <xs:attribute name="occurs" type="parameter-occurs" use="required"/>

          <!-- Default value of the parameter -->

          <xs:attribute name="default" type="xs:string" use="optional"/>

          <!-- Set to true if this parameter represent an URL to a stub. If true,

          it can be monitored by TCP monitor and have other properties -->

          <xs:attribute name="stub" type="xs:boolean" use="optional"/>

          <!-- Set to true if this parameter must be instanciated at creation time.

           This is only useful if the parameter is optional. -->

          <xs:attribute name="instanciate" type="xs:boolean" use="optional"/>

          <!-- Internal use only -->

          <xs:attribute name="preview" type="xs:boolean" use="optional"/>

          <!-- Internal use only -->

          <xs:attribute name="help" type="xs:boolean" use="optional"/>

          <!-- Internal use only -->

          <xs:attribute name="multiline" type="xs:integer" use="optional"/>

          <!-- Internal use only -->

          <xs:attribute name="timebase" type="parameter-timebase" use="optional"/>

          <!-- Optional display string to use instead of the name in the UI -->

          <xs:attribute name="display" type="xs:string" use="optional"/>

        </xs:complexType>

      </xs:element>

      <!-- The value the parameter is restricted to -->

      <xs:element name="restricted">

        <xs:complexType>

          <xs:sequence>

            <xs:element ref="value" minOccurs="1" maxOccurs="unbounded"/>

          </xs:sequence>

        </xs:complexType>

      </xs:element>

      <!-- A value has a content only -->

      <xs:element name="value">

        <xs:complexType>

          <xs:attribute name="content" type="xs:string" use="required"/>

        </xs:complexType>

      </xs:element>

      <!-- The occurrences of a parameter -->

      <xs:simpleType name="parameter-occurs">

        <xs:restriction base="xs:string">

          <!-- required (one and only one) -->

          <xs:enumeration value="1"/>

          <!-- optional -->

          <xs:enumeration value="?"/>

          <!-- one or more -->

          <xs:enumeration value="+"/>

          <!-- zero or more -->

          <xs:enumeration value="*"/>

          <!-- tree of parameter-->

          <xs:enumeration value="t"/>

        </xs:restriction>

      </xs:simpleType>

      <!-- Internal use only -->

      <xs:element name="instance">

        <xs:complexType>

          <xs:attribute name="v1" type="xs:string" use="required"/>

          <xs:attribute name="v2" type="xs:string" use="optional"/>

          <xs:attribute name="v3" type="xs:string" use="optional"/>

        </xs:complexType>

      </xs:element>

      <!-- Internal use only -->

      <xs:simpleType name="parameter-timebase">

        <xs:restriction base="xs:string">

          <xs:enumeration value="ms"/>

          <xs:enumeration value="s"/>

          <xs:enumeration value="min"/>

          <xs:enumeration value="h"/>

        </xs:restriction>

      </xs:simpleType>

    </xs:schema>