Note
Tutorial: create, build, publish, deploy

This tutorial walks new users step by step through:

  • creating a new SIP feature, with associated configuration profile and mapper, from a pre-prepared example

  • updating properties as needed in the Sentinel VoLTE SDK

  • viewing and understanding the content of key files

  • building, publishing, and deploying the feature

  • altering, re-building, re-publishing, and re-deploying the feature.

This section assumes that the instructions in installing the SDK have been followed.

Creating a new module

The sdkadm tool includes a command named create-module. For help on using this command, type the following command in the sdkadm tool:

help create-module

create-module uses "module-pack" artifacts as a template for the creation of a new module. Any module-pack can be used to create a new module.

Note A module-pack contains one or more modules. The create-module command may create more than one module in the SDK (all in a single directory).

The module pack used in this tutorial contains:

  • a group module

  • a SIP POJO feature module

  • a mapper module

  • a profile module.

To view the available module-packs, type the following command inside the sdkadm tool:

list-modules +module-pack
Note Where you see a version number of 2.7.0.0 use the version number of the product you have downloaded.

Now create a new module from the module pack published in opencloud#sentinel-sip-example#sentinel-sip/2.7.0;2.7.0.0. This requires two steps:

1

Run the command:

create-module my-sip-example opencloud#sentinel-sip-example#sentinel-sip/2.7.0;2.7.0.0

This command:

  • downloads the module pack from the repository

  • creates a new directory called my-sip-example inside your Sentinel VoLTE SDK, which contains all the newly created modules

  • scans the content of the module pack and prompts you to enter new values where necessary

  • re-writes the new modules according to your answers.

When prompted, answer as shown in the example output below. Numbered annotations mark the prompts, and their answers are listed by number immediately after the example output.

> create-module my-sip-example opencloud#sentinel-sip-example#sentinel-sip/2.7.0;2.7.0.0
downloading https://repo.opencloud.com/artifactory/opencloud-internal-snapshots/opencloud/sentinel-sip/2.7.0/sentinel-sip-example/2.7.0.0/sentinel-sip-example-module-pack-2.7.0.0.zip ...
.... (40kB)
.. (0kB)
	[SUCCESSFUL ] opencloud#sentinel-sip-example#sentinel-sip/2.7.0;2.7.0.0!sentinel-sip-example-module-pack.zip(module-pack) (160ms)
Extracting '/home/testuser/sentinel-volte-sdk/build/target/ivy-caches/online-resolvers.cache/opencloud/sentinel-sip-example/sentinel-sip/2.7.0/module-packs/sentinel-sip-example-module-pack-2.7.0.0.zip' to '/home/testuser/sentinel-volte-sdk/my-sip-example'.


Command line invocation did not contain enough rename arguments to rename all modules.
To specify rename arguments on the command line, include <oldvalue>:<newvalue> pairs as additional arguments.
Missing values will now be prompted for interactively.

Please enter a name for the top level module, usually this will match the name of the directory for the new module
Rename top level module 'sentinel-sip-example' to [my-sip-example]: 1

Please enter names for the following sub-module(s) in the module-pack
Rename module 'sentinel-sip-example-profile' to [sentinel-sip-example-profile]: my-sip-example-profile 2
Rename module 'example-feature-event-handler-sbbpart' to [example-feature-event-handler-sbbpart]: my-sip-example-event-handler-sbbpart 3
Rename module 'sentinel-sip-example-mapper' to [sentinel-sip-example-mapper]: my-sip-example-mapper 4
Rename module 'sentinel-sip-example-feature' to [sentinel-sip-example-feature]: my-sip-example-feature 5
The longest common package prefix is 'com.opencloud.sentinel.example.feature'.
Rename package prefix 'com.opencloud.sentinel.example.feature' to [com.opencloud.sentinel.example.feature]: 6

Command line invocation did not contain enough rename arguments to rename all features.
To specify rename arguments on the command line, include <oldvalue>:<newvalue> pairs as additional arguments.
Missing values will now be prompted for interactively.

Rename feature 'SipPojoFeature' to [SipPojoFeature]: MySipPojoFeature 7

Command line invocation did not contain enough rename arguments to rename all mappers.
To specify rename arguments on the command line, include <oldvalue>:<newvalue> pairs as additional arguments.
Missing values will now be prompted for interactively.

Rename mapper 'StringToString' to [StringToString]: 8

New package prefix is the same as old prefix. Java package declarations will not be re-namespaced.

Renaming ivy modules and updating dependencies.

Renaming symbolic property references in source files.
Checking "deps.properties" for missing values.

Done. New module(s) should now be available at: /home/testuser/sentinel-volte-sdk/my-sip-example
1 Press Enter to accept the default
2 Type my-sip-example-profile and press Enter
3 Type my-sip-example-event-handler-sbbpart and press Enter
4 Type my-sip-example-mapper and press Enter
5 Type my-sip-example-feature and press Enter
6 Press Enter to accept the default
7 Type MySipPojoFeature and press Enter
8 Press Enter to accept the default
Note It is possible to use the command in a non-interactive mode by providing all substitution values.
Run help create-module for instructions.

2

Update the deps.properties file in the root of the Sentinel VoLTE SDK install.

As the output says, there are two properties that need updating:

The following properties are missing from "deps.properties" and will need to be updated manually:
 sentinel-sip-support.ivy.revision
 sentinel-sip-support.ivy.branch

Before updating, the deps.properties file contains many properties, including this fragment:

cat deps.properties

... edited for brevity

fsmtool.ivy.revision=1.1.0.9
sentinel-sip-support.ivy.revision=FIXME_IN_DEPS_PROPERTIES
sentinel-registrar.ivy.branch=sentinel-registrar/2.7.0

... edited for brevity

sentinel-registrar-sdk-setup.ivy.branch=sentinel-registrar/2.7.0
sentinel-sip-support.ivy.branch=FIXME_IN_DEPS_PROPERTIES
  • Set the sentinel-sip-support.ivy.branch=FIXME_IN_DEPS_PROPERTIES line to:

sentinel-sip-support.ivy.branch=sentinel-sip/2.7.0
  • Set the sentinel-sip-support.ivy.revision=FIXME_IN_DEPS_PROPERTIES line to the release you are using e.g. if using 2.7.0.0 then replace with 2.7.0.0:

sentinel-sip-support.ivy.revision=2.7.0.0

3

Add the new module to source control (optional).

git add my-sip-example
git commit -m "Added initial version of my-sip-example." my-sip-example

Directory structure

Here’s what your my-sip-example directory should look like:

$ cd my-sip-example/
$ ls
build.xml                             my-sip-example-event-handler-sbbpart feature                               ivy.xml                               mapper                                module.properties                     profile

It contains these files and directories:

File or directory What it’s for

build.xml

contains build targets so that the module can be built, published, deployed, and so on

ivy.xml

provides Ivy with enough information to correctly publish the module

module.properties

contains variables that are substituted during build and publish

example-feature-event-handler-sbbpart

contains a sbbpart module

feature

contains a feature module

mapper

contains a mapper module

profile

contains a profile module

The module.properties file is fairly typical for a group module that publishes a module-pack. Note the three lines indicating where the module pack is created from.

The build.xml and ivy.xml files are also typical for a group module. It’s worth noting that group modules often may publish no artifacts, or only documentation artifacts. In this case the group module publishes no artifact.

Here’s what the build.xml file looks like:

<?xml version="1.0"?>

<project name="sentinel-sip-example" default="publish-local" basedir=".">

    <!-- Common build infrastructure. -->
    <property file=".sdk.root"/>
    <property file="${sdk.root}/.build.local"/>
    <property file="${sdk.root}/.build"/>
    <import file="${build}/targets.xml"/>

    <target name="do-build">
      <default-module-build/>
      <default-module-create-artifacts/>
      <default-package-module-pack/>
    </target>

</project>

Here’s what the ivy.xml file looks like:

<ivy-module version="2.0" xmlns:e="http://ant.apache.org/ivy/extra">
    <info organisation="${sdk.ivy.org}"
          module="sentinel-sip-example" e:user="${user.name}"
          e:indextags="sip, group, example"/>
    <configurations>
       <conf name="antlib"           description="Ant tasks used to build this module" />

        <conf name="slee-component"   description="SLEE Components published by this module" />
        <conf name="api"              description="Artifacts needed to compile components using this module" />
        <conf name="deploy"           description="Deployment artifacts" />
        <conf name="doc"              description="Documentation source artifacts" />
        <conf name="config"           description="SLEE component configuration files" />
        <conf name="module-pack"      description="Module source artifact" />
        <conf name="slee-binding"     description="SLEE component binding metadata" />
        <conf name="provisioning"     description="Feature provisioning definitions" />

        <conf name="self"             description="" visibility="private"/>
        <conf name="test"             description="" visibility="private"/>

    </configurations>
    <publications>
        <artifact name="${ivy.module}-module-pack"    type="module-pack"    ext="zip"     conf="module-pack"/>
    </publications>
    <dependencies>
        <dependency org="opencloud"       name="sentinel-support"                       rev="${sentinel-support.ivy.revision}"  branch="${sentinel-support.ivy.branch}"  conf="antlib; self -> api" />

        <!-- Add additional features here to have them pulled in by 'ant deploy' -->
        <dependency org="${sdk.ivy.org}"  name="sentinel-sip-example-feature"           rev="latest.${ivy.status}"              branch="${branch.name}"                  conf="slee-component; config; provisioning; slee-binding" />
        <dependency org="${sdk.ivy.org}"  name="example-pojo-feature-with-multiple-fsms"           rev="latest.${ivy.status}"              branch="${branch.name}"                  conf="slee-component; config; slee-binding" />
         <dependency org="${sdk.ivy.org}"  name="example-feature-event-handler-sbbpart"  rev="latest.${ivy.status}"              branch="${branch.name}"                  conf="slee-component; config; slee-binding" />
    </dependencies>
</ivy-module>
Important This is the original ivy.xml file — it will have different module names than those in your environment.

feature

The feature directory is an Ivy module containing a Sentinel POJO feature.

Here’s what it contains:

File or directory What it’s for

build.xml

contains build targets so that the module can be built, published, deployed, and so on

ivy.xml

provides Ivy with enough information to correctly build and publish the module

module.properties

contains variables that are substituted during build and publish

config

contains a sample configuration for the feature, such as JSLEE profile tables and profiles for the configurer to create

doc

contains documentation source code, in Asciidoc markup format

src

contains the module’s source code

build.xml

This build.xml file is typical of any feature (nothing noteworthy to mention):

<?xml version="1.0"?>

<project name="sentinel-sip-example-feature" default="publish-local" basedir="." xmlns:ivy="antlib:org.apache.ivy.ant">

    <!-- Common build infrastructure. -->
    <property file=".sdk.root"/>
    <property file="${sdk.root}/.build.local"/>
    <property file="${sdk.root}/.build"/>
    <import file="${build}/targets.xml"/>

    <target name="do-build">
      <init-extensions/>
      <sentinel-annotation-processing/>

      <default-module-build/>
      <default-module-create-artifacts/>
      <default-package-module-pack/>
    </target>

</project>
ivy.xml

This ivy.xml file is also typical; however it is very important and so warrants discussion. It includes module identification-related information, publications, and dependencies.

Here’s more about the info, publications, and dependencies sections in ivy.xml:

<info>

The 'identification' information is contained in the info element. This contains the name of the module, its publishing organisation, and some other attributes.

Here is the info element for the example module:

    <info organisation="${sdk.ivy.org}"
          module="my-sip-example-feature"
          e:sourceurl="${svn.info.url}" e:sourcerev="${svn.info.wcversion}" e:user="${user.name}"
          e:indextags="sip, feature, sbb-part"/>

This module’s name is my-sip-example-feature; and its publishing organisation is a variable, called sdk.ivy.org. This variable is substituted at publication time, based on the sdk.ivy.org value in the sdk.properties file at the root of the SDK.

<publications>

Next is the publications section, which looks like this:

    <publications>
        <artifact name="${ivy.module}"                type="sbbpart"        ext="jar"     conf="slee-component,api"/>
        <artifact name="${ivy.module}-javadoc"        type="javadoc"        ext="zip"     conf="doc"/>
        <artifact name="${ivy.module}-config"         type="config"         ext="zip"     conf="config"/>
        <artifact name="${ivy.module}-bindings"       type="binding"        ext="zip"     conf="slee-binding"/>
    </publications>

This feature is a POJO feature. All POJO features publish a single jar file to the slee-component and api Ivy configurations. This jar is a JSLEE component jar.

JSLEE component jar files can contain many different types of components. POJO features always publish an SBB Part component.

Note The name of the artifact is a variable, which is substituted with the name of the Ivy module.

<dependencies>

Finally the dependencies section for the feature:

    <dependencies>
        <dependency org="opencloud"  name="sentinel-sip-support"    rev="${sentinel-sip-support.ivy.revision}" branch="${sentinel-sip-support.ivy.branch}" conf="antlib; self->api" />

        <dependency org="${sdk.ivy.org}"  name="my-sip-example-profile"   rev="latest.${ivy.status}" conf="self,provisioning -> api; slee-component; config; slee-binding"/>
        <dependency org="${sdk.ivy.org}"  name="my-sip-example-mapper"    rev="latest.${ivy.status}" conf="self -> api; slee-component; config; slee-binding"/>
    </dependencies>

The dependencies for the feature include:

Dependency What it does What it’s for

sentinel-sip-support

provides the feature with necessary APIs to compile against, and suitable SLEE dependencies

all SIP features, either directly or transitively

my-sip-example-profile

provides profile configuration for the feature (so the feature needs a dependency on the profile)

specific to this feature

my-sip-example-mapper

invokes a mapper (so the feature needs a dependency on the mapper)

specific to this feature

The my-sip-example-profile and my-sip-example-mapper dependencies include various Ivy configurations, such as slee-component, config and slee-binding. These are required so that deployer, binder, and configurer included in the Sentinel VoLTE SDK can do their job when reading from a repository.
For details, please see deployer docs, binder docs, and configuring modules in Rhino sections.

The feature includes various Java source files under the src directory. The following is a source listing of the ExamplePojoFeature.java source file.

/**
 * Copyright (c) 2014 Open Cloud Limited, a company incorporated in England and Wales (Registration Number 6000941) with its principal place of business at Edinburgh House, St John's Innovation Park, Cowley Road, Cambridge CB4 0DS.
 *
 * All rights reserved.
 *
 * Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met:
 *
 * 1  Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer.
 *
 * 2  Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution.
 *
 * 3  The name of the author may not be used to endorse or promote products derived from this software without specific prior written permission.
 *
 * 4  The source code may not be used to create, develop, use or distribute software for use on any platform other than the Open Cloud Rhino and Open Cloud Rhino Sentinel platforms or any successor products.
 *
 * 5  Full license terms may be found https://developer.opencloud.com/devportal/display/OCDEV/Feature+Source+License
 *
 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF SATISFACTORY QUALITY AND FITNESS FOR A PARTICULAR PURPOSE ARE EXCLUDED TO THE FULLEST EXTENT PERMITTED BY LAW.
 *
 * TO THE FULLEST EXTENT PERMISSIBLE BY LAW, THE AUTHOR SHALL NOT BE LIABLE FOR ANY LOSS OF REVENUE, LOSS OF PROFIT, LOSS OF FUTURE BUSINESS, LOSS OF DATA OR ANY INDIRECT, SPECIAL, CONSEQUENTIAL, PUNITIVE OR OTHER LOSS OR DAMAGES ARISING OUT OF OR IN CONNECTION WITH THE SOFTWARE, WHETHER ARISING IN CONTRACT, TORT (INCLUDING NEGLIGENCE) MISREPRESENTATION OR OTHERWISE AND REGARDLESS OF WHETHER OPEN CLOUD HAS BEEN ADVISED OF THE POSSIBILITY OF ANY SUCH LOSS OR DAMAGE. THE AUTHORS MAXIMUM AGGREGATE LIABILITY WHETHER IN CONTRACT, TORT (INCLUDING NEGLIGENCE) OR OTHERWISE, SHALL NOT EXCEED EUR100.
 *
 * NOTHING IN THIS LICENSE SHALL LIMIT THE LIABILITY OF THE AUTHOR FOR DEATH OR PERSONAL INJURY RESULTING FROM NEGLIGENCE, FRAUD OR FRAUDULENT MISREPRESENTATION.
 *
 * Visit Open Cloud Developer's Portal for how-to guides, examples, documentation, forums and more: http://developer.opencloud.com
 */
package com.opencloud.sentinel.example.feature;

import com.opencloud.sce.fsmtool.Facilities;
import com.opencloud.sentinel.annotations.ConfigurationReader;
import com.opencloud.sentinel.annotations.FeatureProvisioning;
import com.opencloud.sentinel.annotations.ProvisioningConfig;
import com.opencloud.sentinel.annotations.ProvisioningField;
import com.opencloud.sentinel.annotations.ProvisioningProfile;
import com.opencloud.sentinel.annotations.ProvisioningProfileId;
import com.opencloud.sentinel.annotations.SentinelFeature;
import com.opencloud.sentinel.common.NullSentinelSessionState;
import com.opencloud.sentinel.feature.ExecutionPhase;
import com.opencloud.sentinel.feature.impl.BaseFeature;
import com.opencloud.sentinel.feature.spi.FeatureEndpoint;
import com.opencloud.sentinel.feature.spi.init.InjectFeatureConfigurationReader;
import com.opencloud.sentinel.feature.spi.init.InjectFeatureStats;
import com.opencloud.slee.annotation.BinderTargets;
import com.opencloud.slee.annotation.SBBPartReference;
import com.opencloud.slee.annotation.SBBPartReferences;

import javax.slee.ActivityContextInterface;
import javax.slee.annotation.ComponentId;
import javax.slee.annotation.ProfileReference;
import javax.slee.annotation.ProfileReferences;
import javax.slee.facilities.Tracer;

/**
 *
 * An example feature.
 */
@SentinelFeature(
    featureName = ExamplePojoFeature.NAME,
    componentName = "@component.name@",
    featureVendor = "@component.vendor@",
    featureVersion = "@component.version@",
    featureGroup = SentinelFeature.CORE_FEATURE_GROUP,
    configurationReader = @ConfigurationReader(
        readerInterface = ExampleConfigReader.class,
        readerClass = ExampleConfigProfileReader.class
    ),
    usageStatistics = ExampleUsageStats.class,
    executionPhases = ExecutionPhase.SipSessionPhase,
    provisioning = @FeatureProvisioning(
        displayName = "SIP POJO Feature",
        configs = {
            @ProvisioningConfig(
                type = "SipPojoFeatureConfig",
                displayName = "Config",
                fields = {
                    @ProvisioningField(
                        name = "aValue",
                        displayName = "A value",
                        type = "int",
                        description = "An example value to set."
                    )
                },
                profile = @ProvisioningProfile(
                    tableName = "ExampleConfigProfileTable",
                    specification = @ProvisioningProfileId(name = "@sentinel-sip-example-profile.name@", vendor = "@sentinel-sip-example-profile.vendor@", version = "@sentinel-sip-example-profile.version@")
                )
            )
        }
    )
)
@SBBPartReferences(
    sbbPartRefs = {
        @SBBPartReference(id = @ComponentId(name = "@sentinel-sip-spi.SentinelSipFeatureSPI SBB Part.name@", vendor = "@sentinel-sip-spi.SentinelSipFeatureSPI SBB Part.vendor@", version = "@sentinel-sip-spi.SentinelSipFeatureSPI SBB Part.version@")),
        @SBBPartReference(id = @ComponentId(name = "@sentinel-sip-example-mapper.name@", vendor = "@sentinel-sip-example-mapper.vendor@", version = "@sentinel-sip-example-mapper.version@"))
    }
)
@ProfileReferences(
    profileRefs = {
        @ProfileReference(profile = @ComponentId(name="@sentinel-sip-example-profile.name@", vendor="@sentinel-sip-example-profile.vendor@", version="@sentinel-sip-example-profile.version@"))
    }
)

@BinderTargets(services = "sip")
@SuppressWarnings("unused")
public class ExamplePojoFeature extends BaseFeature<NullSentinelSessionState, FeatureEndpoint> implements InjectFeatureConfigurationReader<ExampleConfigReader>, InjectFeatureStats<ExampleUsageStats> {

    public ExamplePojoFeature(FeatureEndpoint caller, Facilities facilities, NullSentinelSessionState sessionState) {
        super(caller, facilities, sessionState);
    }

    public static final String NAME = "SipPojoFeature";
    @SuppressWarnings("FieldCanBeLocal")
    private ExampleConfigReader configReader;
    private ExampleUsageStats featureStats;

    /**
     * All features must have a unique name.
     *
     * @return the name of this feature
     */
    @Override
    public String getFeatureName() { return NAME; }

    /**
     * Kick off the feature.
     *
     * @param trigger  a triggering context. The feature implementation must be able to cast this to a useful type for it to run
     * @param activity the slee activity object this feature is related to (may be null)
     * @param aci      the activity context interface of the slee activity this feature is related to
     */
    @Override
    public void startFeature(Object trigger, Object activity, ActivityContextInterface aci) {

        Tracer tracer = getTracer();
        if (tracer.isInfoEnabled()) {
             tracer.info("Starting " + NAME);
        }

        getCaller().featureHasFinished();

        featureStats.incrementFeatureStarted(1);
    }

    public void injectFeatureConfigurationReader(ExampleConfigReader configurationReader) {
        this.configReader = configurationReader;
    }

    /**
     * Implement {@link InjectFeatureStats#injectFeatureStats}
     */
    @Override
    public void injectFeatureStats(ExampleUsageStats featureStats) {
        this.featureStats = featureStats;
    }

}
Important This is the original source file — it may have different package names and feature names than those in your environment.

sbbpart

The sbbpart directory is an Ivy module containing a Sentinel SbbPart component, in this case defining a simple extension event handler.

Here’s what it contains:

File or directory What it’s for

build.xml

contains build targets so that the module can be built, published, deployed, and so on

ivy.xml

provides Ivy with enough information to correctly build and publish the module

module.properties

contains variables that are substituted during build and publish

src

contains the module’s source code

build.xml

The build.xml file is a typical build file (there is nothing specific to describe):

<?xml version="1.0"?>

<project name="example-feature-event-handler-sbbpart" default="publish-local" basedir=".">

    <!-- Common build infrastructure. -->
    <property file=".sdk.root"/>
    <property file="${sdk.root}/.build.local"/>
    <property file="${sdk.root}/.build"/>
    <import file="${build}/targets.xml"/>

    <target name="do-build">
        <default-module-build/>
        <default-module-create-artifacts/>
    </target>

</project>
ivy.xml

The ivy.xml file is typical for an sbbpart that is 'part of' a feature:

<ivy-module version="2.0" xmlns:e="http://ant.apache.org/ivy/extra">
    <info organisation="${sdk.ivy.org}"
          module="example-feature-event-handler-sbbpart" e:user="${user.name}"
          e:indextags="sip, sbb-part">
        <description>Example sbb part that demonstrates how to create an event handler that fires an extension event.</description>
    </info>
    <configurations>
        <conf name="antlib"           description="Ant tasks used to build this module" />

        <conf name="slee-component"   description="SLEE Components published by this module" />
        <conf name="api"              description="Artifacts needed to compile components using this module" />
        <conf name="deploy"           description="Deployment artifacts" />
        <conf name="doc"              description="Documentation source artifacts" />
        <conf name="config"           description="SLEE component configuration files" />
        <conf name="module-pack"      description="Module source artifact" />
        <conf name="slee-binding"     description="SLEE component binding metadata" />

        <conf name="self"             description="" visibility="private"/>
        <conf name="test"             description="" visibility="private"/>
    </configurations>
    <publications>
        <artifact name="${ivy.module}"               type="sbbpart"         ext="jar"          conf="slee-component, api"/>
        <artifact name="${ivy.module}-javadoc"       type="javadoc"     ext="zip"          conf="doc"/>
        <artifact name="${ivy.module}-bindings"       type="binding"      ext="zip"          conf="slee-binding"/>
    </publications>
    <dependencies>
        <!-- Common Sentinel build extension and dependencies. -->
        <dependency org="opencloud"    name="sentinel-sip-support"     rev="${sentinel-sip-support.ivy.revision}"      branch="${sentinel-sip-support.ivy.branch}"     conf="antlib; self -> api" />

        <dependency org="opencloud"         name="sentinel-http-ra-deploy"  rev="${sentinel-http-ra-deploy.ivy.revision}"   branch="${sentinel-http-ra-deploy.ivy.branch}"  conf="self -> slee-component" />
        <dependency org="opencloud"         name="http-ratype"              rev="${http-ratype.ivy.revision}"               branch="${http-ratype.ivy.branch}"              conf="api; self -> api" />
        <dependency org="javax.inject"      name="inject-api"               rev="${inject-api.ivy.revision}"                                                                conf="self -> api" />

    </dependencies>
</ivy-module>
Important This is the original source file --- it may have different module names than those in your environment.

SBB parts are always published as an SBB part component into the slee-component Ivy configuration. A single SBB part component may contain multiple event handler methods.

The sbb part example above is included to show the right file locations, annotations, publications, and dependencies for a typical SIP feature event handler.

Java source

The sbb part includes a single source file under the example-feature-event-handler-sbbpart/src directory.

The sbb part class itself, in the ExampleFeatureEventHandlerSbbPart.java source file:

/**
 * Copyright (c) 2014 Open Cloud Limited, a company incorporated in England and Wales (Registration Number 6000941) with its principal place of business at Edinburgh House, St John's Innovation Park, Cowley Road, Cambridge CB4 0DS.
 *
 * All rights reserved.
 *
 * Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met:
 *
 * 1  Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer.
 *
 * 2  Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution.
 *
 * 3  The name of the author may not be used to endorse or promote products derived from this software without specific prior written permission.
 *
 * 4  The source code may not be used to create, develop, use or distribute software for use on any platform other than the Open Cloud Rhino and Open Cloud Rhino Sentinel platforms or any successor products.
 *
 * 5  Full license terms may be found https://developer.opencloud.com/devportal/display/OCDEV/Feature+Source+License
 *
 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF SATISFACTORY QUALITY AND FITNESS FOR A PARTICULAR PURPOSE ARE EXCLUDED TO THE FULLEST EXTENT PERMITTED BY LAW.
 *
 * TO THE FULLEST EXTENT PERMISSIBLE BY LAW, THE AUTHOR SHALL NOT BE LIABLE FOR ANY LOSS OF REVENUE, LOSS OF PROFIT, LOSS OF FUTURE BUSINESS, LOSS OF DATA OR ANY INDIRECT, SPECIAL, CONSEQUENTIAL, PUNITIVE OR OTHER LOSS OR DAMAGES ARISING OUT OF OR IN CONNECTION WITH THE SOFTWARE, WHETHER ARISING IN CONTRACT, TORT (INCLUDING NEGLIGENCE) MISREPRESENTATION OR OTHERWISE AND REGARDLESS OF WHETHER OPEN CLOUD HAS BEEN ADVISED OF THE POSSIBILITY OF ANY SUCH LOSS OR DAMAGE. THE AUTHORS MAXIMUM AGGREGATE LIABILITY WHETHER IN CONTRACT, TORT (INCLUDING NEGLIGENCE) OR OTHERWISE, SHALL NOT EXCEED EUR100.
 *
 * NOTHING IN THIS LICENSE SHALL LIMIT THE LIABILITY OF THE AUTHOR FOR DEATH OR PERSONAL INJURY RESULTING FROM NEGLIGENCE, FRAUD OR FRAUDULENT MISREPRESENTATION.
 *
 * Visit Open Cloud Developer's Portal for how-to guides, examples, documentation, forums and more: http://developer.opencloud.com
 */
package com.opencloud.sentinel.example.feature.eventhandler;

import com.opencloud.rhino.facilities.Tracer;
import com.opencloud.rhino.slee.lifecycle.PostCreate;
import com.opencloud.rhino.slee.sbbpart.SbbPartContext;
import com.opencloud.sentinel.common.SentinelFireEventException;
import com.opencloud.sentinel.endpoint.SentinelEndpoint;
import com.opencloud.slee.annotation.du.SBBPartDeployableUnit;
import com.opencloud.slee.annotation.SBBPart;
import com.opencloud.slee.annotation.SBBPartClass;
import com.opencloud.slee.annotation.SBBPartClasses;
import com.opencloud.slee.annotation.SBBPartReference;
import com.opencloud.slee.resources.http.HttpResponse;

import javax.inject.Inject;
import javax.inject.Named;
import javax.slee.ActivityContextInterface;
import javax.slee.CreateException;
import javax.slee.EventContext;
import javax.slee.InitialEventSelector;
import javax.slee.annotation.ComponentId;
import javax.slee.annotation.EventMethod;
import javax.slee.annotation.RATypeBinding;
import javax.slee.annotation.RATypeBindings;
import javax.slee.annotation.SecurityPermissions;

@SBBPart(
    id = @ComponentId(name = "@component.name@", vendor = "@component.vendor@", version = "@component.version@"),
    sbbPartRefs = {
        @SBBPartReference(id = @ComponentId(name = "@sentinel-sip-spi.SentinelSipFeatureSPI SBB Part.name@", vendor = "@sentinel-sip-spi.SentinelSipFeatureSPI SBB Part.vendor@", version = "@sentinel-sip-spi.SentinelSipFeatureSPI SBB Part.version@")),
    },
    sbbPartClasses = @SBBPartClasses(
        sbbPartClass = @SBBPartClass(
            className="com.opencloud.sentinel.example.feature.eventhandler.ExampleFeatureEventHandlerSbbPart"
        )
    )
)
@RATypeBindings(
    raTypeBindings = {
        @RATypeBinding(
            activityContextInterfaceFactoryName = "slee/resources/http/activitycontextinterfacefactory",
            resourceAdaptorObjectName = "slee/resources/http/provider",
            resourceAdaptorEntityLink = "sentinel-http",
            raType = @ComponentId(name = "@sentinel-http-ra-deploy.ResourceAdaptorTypeID.HTTP.name@", vendor = "@sentinel-http-ra-deploy.ResourceAdaptorTypeID.HTTP.vendor@", version = "@sentinel-http-ra-deploy.ResourceAdaptorTypeID.HTTP.version@")
        )
    }
)
@SBBPartDeployableUnit(
  securityPermissions = @SecurityPermissions(securityPermissionSpec = "grant { permission java.security.AllPermission; };")
)
@SuppressWarnings("unused")
public class ExampleFeatureEventHandlerSbbPart {

    @PostCreate
    public void onCreate() throws CreateException {
        if(rootTracer.isFinerEnabled())
            rootTracer.finer("SBB part created");
    }

    public InitialEventSelector ies(InitialEventSelector ies) {
        return ies;
    }

    @EventMethod(
        initialEvent = false,
        eventType = @ComponentId(name = "@sentinel-http-ra-deploy.EventTypeID.com.opencloud.slee.resources.http.HttpResponse.name@", vendor = "@sentinel-http-ra-deploy.EventTypeID.com.opencloud.slee.resources.http.HttpResponse.vendor@", version = "@sentinel-http-ra-deploy.EventTypeID.com.opencloud.slee.resources.http.HttpResponse.version@")
    )
    public void onHttpResponse(HttpResponse event, ActivityContextInterface aci, EventContext eventContext) {

        if (rootTracer.isFinerEnabled())
            rootTracer.finer("ExampleFeatureEventHandlerSbbPart received: " + event);

        // see if there is a custom header included that tells me which feature should receive the response
        String featureToInvoke = event.getHeader("FeatureToInvoke");
        if (null == featureToInvoke || "".equals(featureToInvoke))
            featureToInvoke = "TestReceiveHttpResponse";

        // processEvent does not return until the event has been processed by Sentinel.
        try {
            SentinelEndpoint sentinelEndpoint = (SentinelEndpoint)sbbPartContext.getSbbLocalObject();
            // ask sentinel to process the http response by calling the 'featureToInvoke' feature
            sentinelEndpoint.processEvent(featureToInvoke, event, false, aci, eventContext);
        }
        catch (NullPointerException | IllegalArgumentException | SentinelFireEventException e) {
            rootTracer.fine("Caught exception in processEvent for HttpResponse", e);
        }
    }

    @Inject
    private Tracer rootTracer;

    @Inject @Named("timer")
    private Tracer timerTracer;

    @Inject
    private SbbPartContext sbbPartContext;
}
Important This is the original source file — it may have a different package name than that in your environment.

mapper

The mapper directory is an Ivy module containing a Sentinel Mapper component.

Here’s what it contains:

File or directory What it’s for

build.xml

contains build targets so that the module can be built, published, deployed, and so on

ivy.xml

provides Ivy with enough information to correctly build and publish the module

module.properties

contains variables that are substituted during build and publish

src

contains the module’s source code

build.xml

The build.xml file is a typical build file (there is nothing specific to describe):

<?xml version="1.0"?>

<project name="sentinel-sip-example-mapper" default="publish-local" basedir="." xmlns:ivy="antlib:org.apache.ivy.ant">

    <!-- Common build infrastructure. -->
    <property file=".sdk.root"/>
    <property file="${sdk.root}/.build.local"/>
    <property file="${sdk.root}/.build"/>
    <import file="${build}/targets.xml"/>

    <target name="do-build">
      <default-module-build/>
      <default-module-create-artifacts/>
      <default-package-module-pack/>
    </target>

</project>
ivy.xml

The ivy.xml file is typical for a mapper that is 'part of' a feature:

<ivy-module version="2.0" xmlns:e="http://ant.apache.org/ivy/extra">
    <info organisation="${sdk.ivy.org}"
          module="sentinel-sip-example-mapper" e:user="${user.name}"
          e:indextags="sip, sbb-part, mapper"/>
    <configurations>
       <conf name="antlib"           description="Ant tasks used to build this module" />

        <conf name="slee-component"   description="SLEE Components published by this module" />
        <conf name="api"              description="Artifacts needed to compile components using this module" />
        <conf name="deploy"           description="Deployment artifacts" />
        <conf name="doc"              description="Documentation source artifacts" />
        <conf name="config"           description="SLEE component configuration files" />
        <conf name="module-pack"      description="Module source artifact" />
        <conf name="slee-binding"     description="SLEE component binding metadata" />
        <conf name="provisioning"     description="Feature provisioning definitions" />

        <conf name="self"             description="" visibility="private"/>
        <conf name="test"             description="" visibility="private"/>

    </configurations>
    <publications>
        <artifact name="${ivy.module}"                type="sbbpart"        ext="jar"    conf="slee-component,api"/>
        <artifact name="${ivy.module}-javadoc"        type="javadoc"        ext="zip"    conf="doc"/>
        <artifact name="${ivy.module}-bindings"       type="binding"        ext="zip"    conf="slee-binding"/>
    </publications>
    <dependencies>
        <dependency org="opencloud"  name="sentinel-sip-support"  rev="${sentinel-sip-support.ivy.revision}"  branch="${sentinel-sip-support.ivy.branch}"  conf="antlib; self -> api" />
    </dependencies>
</ivy-module>
Important This is the original source file --- it may have different module names than those in your environment.

Mappers are always published as an SBB part component into the slee-component Ivy configuration. A single SBB part component may contain multiple Sentinel mappers. Each mapper tends to be small, and many of them tend to be related to one feature or purpose. Therefore a module tends to hold one or more mappers and publish them into a single SBB part.

The mapper example above is included to show the right file locations, annotations, publications, and dependencies for a typical SIP feature mapper.

Java source

The mapper includes two source files, under the mapper/src directory.

First, the package-info.java source file, declaring the mapper as an SBB part component:

/**
 * Copyright (c) 2014 Open Cloud Limited, a company incorporated in England and Wales (Registration Number 6000941) with its principal place of business at Edinburgh House, St John's Innovation Park, Cowley Road, Cambridge CB4 0DS.
 *
 * All rights reserved.
 *
 * Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met:
 *
 * 1  Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer.
 *
 * 2  Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution.
 *
 * 3  The name of the author may not be used to endorse or promote products derived from this software without specific prior written permission.
 *
 * 4  The source code may not be used to create, develop, use or distribute software for use on any platform other than the Open Cloud Rhino and Open Cloud Rhino Sentinel platforms or any successor products.
 *
 * 5  Full license terms may be found https://developer.opencloud.com/devportal/display/OCDEV/Feature+Source+License
 *
 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF SATISFACTORY QUALITY AND FITNESS FOR A PARTICULAR PURPOSE ARE EXCLUDED TO THE FULLEST EXTENT PERMITTED BY LAW.
 *
 * TO THE FULLEST EXTENT PERMISSIBLE BY LAW, THE AUTHOR SHALL NOT BE LIABLE FOR ANY LOSS OF REVENUE, LOSS OF PROFIT, LOSS OF FUTURE BUSINESS, LOSS OF DATA OR ANY INDIRECT, SPECIAL, CONSEQUENTIAL, PUNITIVE OR OTHER LOSS OR DAMAGES ARISING OUT OF OR IN CONNECTION WITH THE SOFTWARE, WHETHER ARISING IN CONTRACT, TORT (INCLUDING NEGLIGENCE) MISREPRESENTATION OR OTHERWISE AND REGARDLESS OF WHETHER OPEN CLOUD HAS BEEN ADVISED OF THE POSSIBILITY OF ANY SUCH LOSS OR DAMAGE. THE AUTHORS MAXIMUM AGGREGATE LIABILITY WHETHER IN CONTRACT, TORT (INCLUDING NEGLIGENCE) OR OTHERWISE, SHALL NOT EXCEED EUR100.
 *
 * NOTHING IN THIS LICENSE SHALL LIMIT THE LIABILITY OF THE AUTHOR FOR DEATH OR PERSONAL INJURY RESULTING FROM NEGLIGENCE, FRAUD OR FRAUDULENT MISREPRESENTATION.
 *
 * Visit Open Cloud Developer's Portal for how-to guides, examples, documentation, forums and more: http://developer.opencloud.com
 */

/**
 <p>Example POJO Feature Mappers</p>
 */
@SBBPart(
        id = @ComponentId(name = "@component.name@", vendor = "@component.vendor@", version = "@component.version@")
)
@SBBPartDeployableUnit(
  securityPermissions = @SecurityPermissions(securityPermissionSpec = "grant { permission java.security.AllPermission; };")
)
package com.opencloud.sentinel.example.feature;

import javax.slee.annotation.ComponentId;
import javax.slee.annotation.SecurityPermissions;

import com.opencloud.slee.annotation.du.SBBPartDeployableUnit;
import com.opencloud.slee.annotation.SBBPart;

Next, the mapper class itself, in the StringToStringMapper.java source file:

/**
 * Copyright (c) 2014 Open Cloud Limited, a company incorporated in England and Wales (Registration Number 6000941) with its principal place of business at Edinburgh House, St John's Innovation Park, Cowley Road, Cambridge CB4 0DS.
 *
 * All rights reserved.
 *
 * Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met:
 *
 * 1  Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer.
 *
 * 2  Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution.
 *
 * 3  The name of the author may not be used to endorse or promote products derived from this software without specific prior written permission.
 *
 * 4  The source code may not be used to create, develop, use or distribute software for use on any platform other than the Open Cloud Rhino and Open Cloud Rhino Sentinel platforms or any successor products.
 *
 * 5  Full license terms may be found https://developer.opencloud.com/devportal/display/OCDEV/Feature+Source+License
 *
 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF SATISFACTORY QUALITY AND FITNESS FOR A PARTICULAR PURPOSE ARE EXCLUDED TO THE FULLEST EXTENT PERMITTED BY LAW.
 *
 * TO THE FULLEST EXTENT PERMISSIBLE BY LAW, THE AUTHOR SHALL NOT BE LIABLE FOR ANY LOSS OF REVENUE, LOSS OF PROFIT, LOSS OF FUTURE BUSINESS, LOSS OF DATA OR ANY INDIRECT, SPECIAL, CONSEQUENTIAL, PUNITIVE OR OTHER LOSS OR DAMAGES ARISING OUT OF OR IN CONNECTION WITH THE SOFTWARE, WHETHER ARISING IN CONTRACT, TORT (INCLUDING NEGLIGENCE) MISREPRESENTATION OR OTHERWISE AND REGARDLESS OF WHETHER OPEN CLOUD HAS BEEN ADVISED OF THE POSSIBILITY OF ANY SUCH LOSS OR DAMAGE. THE AUTHORS MAXIMUM AGGREGATE LIABILITY WHETHER IN CONTRACT, TORT (INCLUDING NEGLIGENCE) OR OTHERWISE, SHALL NOT EXCEED EUR100.
 *
 * NOTHING IN THIS LICENSE SHALL LIMIT THE LIABILITY OF THE AUTHOR FOR DEATH OR PERSONAL INJURY RESULTING FROM NEGLIGENCE, FRAUD OR FRAUDULENT MISREPRESENTATION.
 *
 * Visit Open Cloud Developer's Portal for how-to guides, examples, documentation, forums and more: http://developer.opencloud.com
 */
package com.opencloud.sentinel.example.feature;

import com.opencloud.sentinel.annotations.Mapping;
import com.opencloud.sentinel.annotations.SentinelMapper;
import com.opencloud.sentinel.common.NullSentinelSessionState;
import com.opencloud.sentinel.mapper.Mapper;
import com.opencloud.sentinel.mapper.MapperException;
import com.opencloud.sentinel.mapper.MapperFacilities;

/**
* An example mapper.
*/
@SentinelMapper(
    mappings = {
        @Mapping(name = "StringToString", fromClass = String.class, toClass = String.class)
    }
)
@SuppressWarnings("unused")
public class StringToStringMapper implements Mapper<NullSentinelSessionState> {

    @Override
    public Object map(final Object arg, final NullSentinelSessionState sessionState, final MapperFacilities facilities) throws MapperException {

        return arg;
    }

}
Important These are the original source files — they may have different package names than those in your environment.

profile

The profile directory is an Ivy module containing a SLEE profile.

Here’s what it contains:

File or directory What it’s for

build.xml

contains build targets so that the module can be built, published, deployed, and so on

ivy.xml

provides Ivy with enough information to correctly build and publish the module

module.properties

contains variables that are substituted during build and publish

src

contains the module’s source code

Note The build.xml file is a typical build file; there is nothing specific to describe.
ivy.xml

Here’s what the profile directory’s ivy.xml file looks like:

<ivy-module version="2.0" xmlns:e="http://ant.apache.org/ivy/extra">
    <info organisation="${sdk.ivy.org}"
          module="sentinel-sip-example-profile" e:user="${user.name}"
          e:indextags="sip, profile"/>
    <configurations>
        <conf name="antlib"           description="Ant tasks used to build this module" />

        <conf name="slee-component"   description="SLEE Components published by this module" />
        <conf name="api"              description="Artifacts needed to compile components using this module" />
        <conf name="deploy"           description="Deployment artifacts" />
        <conf name="doc"              description="Documentation source artifacts" />
        <conf name="config"           description="SLEE component configuration files" />
        <conf name="module-pack"      description="Module source artifact" />
        <conf name="slee-binding"     description="SLEE component binding metadata" />

        <conf name="self"             description="" visibility="private"/>
        <conf name="test"             description="" visibility="private"/>

    </configurations>
    <publications>
        <artifact name="${ivy.module}"             type="profile"     ext="jar"          conf="slee-component,api"/>
        <artifact name="${ivy.module}-javadoc"     type="javadoc"     ext="zip"          conf="doc"/>
        <artifact name="${ivy.module}-config"      type="config"      ext="zip"          conf="config"/>
        <artifact name="${ivy.module}-bindings"    type="binding"     ext="zip"          conf="slee-binding"/>
    </publications>
    <dependencies>
        <dependency org="opencloud"  name="sentinel-sip-support"  rev="${sentinel-sip-support.ivy.revision}"  branch="${sentinel-sip-support.ivy.branch}"  conf="antlib; self -> api" />
    </dependencies>
</ivy-module>
Important This is the original source file — it may have different module names than those in your environment.

The module publishes a SLEE component jar to the Ivy configurations named slee-component and api. This SLEE component jar is a JSLEE profile specification jar. Only one JSLEE component can be published into the slee-component Ivy configuration.

The profile module, for a SIP feature, only needs to depend on sentinel-sip-support.

Java source

The profile module includes several source files located under the profile/src directory. The most relevant file is ExampleConfigProfileCMP.java:

/**
 * Copyright (c) 2014 Open Cloud Limited, a company incorporated in England and Wales (Registration Number 6000941) with its principal place of business at Edinburgh House, St John's Innovation Park, Cowley Road, Cambridge CB4 0DS.
 *
 * All rights reserved.
 *
 * Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met:
 *
 * 1  Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer.
 *
 * 2  Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution.
 *
 * 3  The name of the author may not be used to endorse or promote products derived from this software without specific prior written permission.
 *
 * 4  The source code may not be used to create, develop, use or distribute software for use on any platform other than the Open Cloud Rhino and Open Cloud Rhino Sentinel platforms or any successor products.
 *
 * 5  Full license terms may be found https://developer.opencloud.com/devportal/display/OCDEV/Feature+Source+License
 *
 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF SATISFACTORY QUALITY AND FITNESS FOR A PARTICULAR PURPOSE ARE EXCLUDED TO THE FULLEST EXTENT PERMITTED BY LAW.
 *
 * TO THE FULLEST EXTENT PERMISSIBLE BY LAW, THE AUTHOR SHALL NOT BE LIABLE FOR ANY LOSS OF REVENUE, LOSS OF PROFIT, LOSS OF FUTURE BUSINESS, LOSS OF DATA OR ANY INDIRECT, SPECIAL, CONSEQUENTIAL, PUNITIVE OR OTHER LOSS OR DAMAGES ARISING OUT OF OR IN CONNECTION WITH THE SOFTWARE, WHETHER ARISING IN CONTRACT, TORT (INCLUDING NEGLIGENCE) MISREPRESENTATION OR OTHERWISE AND REGARDLESS OF WHETHER OPEN CLOUD HAS BEEN ADVISED OF THE POSSIBILITY OF ANY SUCH LOSS OR DAMAGE. THE AUTHORS MAXIMUM AGGREGATE LIABILITY WHETHER IN CONTRACT, TORT (INCLUDING NEGLIGENCE) OR OTHERWISE, SHALL NOT EXCEED EUR100.
 *
 * NOTHING IN THIS LICENSE SHALL LIMIT THE LIABILITY OF THE AUTHOR FOR DEATH OR PERSONAL INJURY RESULTING FROM NEGLIGENCE, FRAUD OR FRAUDULENT MISREPRESENTATION.
 *
 * Visit Open Cloud Developer's Portal for how-to guides, examples, documentation, forums and more: http://developer.opencloud.com
 */
package com.opencloud.sentinel.example.feature;

import javax.slee.annotation.ComponentId;
import javax.slee.annotation.LibraryReference;
import javax.slee.annotation.Profile;
import javax.slee.annotation.ProfileAbstractClass;
import javax.slee.annotation.ProfileClasses;
import javax.slee.annotation.ProfileLocalInterface;

@Profile(
    vendorExtensionID = "@component.name@",
    description = "Example Configuration Profile",
    id = @ComponentId(name = "@component.name@", vendor = "@component.vendor@", version = "@component.version@"),
    libraryRefs = {
        @LibraryReference(library = @ComponentId(name = "@sentinel-profile-util-library.name@", vendor = "@sentinel-profile-util-library.vendor@", version = "@sentinel-profile-util-library.version@"))
    },
    profileClasses = @ProfileClasses(
        profileLocal = @ProfileLocalInterface(interfaceName = "com.opencloud.sentinel.example.feature.ExampleConfigProfileLocal"),
        profileAbstractClass = @ProfileAbstractClass(className = "com.opencloud.sentinel.example.feature.ExampleConfigProfileAbstractClass")
    ),
    singleProfile = false
)
@SuppressWarnings("unused")
public interface ExampleConfigProfileCMP {

    void setAValue(int value);

    int getAValue();

}
Important This is the original source file — it may have different package names than those in your environment.

Scoping Feature Configuration

Using the session selection key to select feature config data

Note The Sentinel selection key is a simple yet flexible means for scoping feature config data to platform, network, session type, plan, or subscriber granularity. The config data can be stored in SLEE profiles or external databases. Furthermore, the selection key can be modified in order to affect the configuration of subsequent features in the session, including feature script selections (which are also based on the session’s current selection key).

Below are procedures for accessing the Sentinel selection key; using the SentinelSelectionKeyIterator; and using the selection key to scope SLEE profiles, SLEE tables, and config in external datasources.

Accessing the Sentinel selection key

The selection key is stored in and retrieved from session state:

SentinelSelectionKey key = getSessionState().getSentinelSelectionKey();

The individual fields of the selection key can be accessed directly via getters and setters:

String platformOperator = key.getPlatformOperator();
key.setNetworkOperator("ExampleNet");

All of the fields in the selection key are just Strings, and may contain any valid String value including null. You use the SentinelSelectionKeyIterator when retrieving feature config data.

Using the SentinelSelectionKeyIterator

The SentinelSelectionKeyIterator provides a basic scope fall-back mechanism that can be used to fall-back to the config data for the most specific match of the current session’s selection key. It does this by returning subkeys of increasingly broader scope from the key provided to it. For example, the following code

SentinelSelectionKey key = getSessionState().getSentinelSelectionKey();
String platform = key.getPlatformOperator();
key.setPlatformOperator("OpenCloud");
key.setNetworkOperator("OpenCloud");
key.setSessionType("call");
key.setPlanId("plan1");
key.setSubscriptionId("64123456789");

SentinelSelectionKeyIterator iter = new SentinelSelectionKeyIterator(key);
while (iter.hasNext()) {
    System.out.println(iter.next());
}

…​prints the following:

OpenCloud:OpenCloud:call:plan1:64123456789
OpenCloud:OpenCloud:call:plan1:
OpenCloud:OpenCloud:call::
OpenCloud:OpenCloud:::
OpenCloud::::

If one of the fields is null or "", then the subsequent fields will be ignored. In the above example, if the session type field was empty, then only the last two subkeys would be returned. For example, the following code

SentinelSelectionKey key = getSessionState().getSentinelSelectionKey();
String platform = key.getPlatformOperator();
key.setPlatformOperator("OpenCloud");
key.setNetworkOperator("OpenCloud");
key.setSessionType("");
key.setPlanId("plan1");
key.setSubscriptionId("64123456789");

SentinelSelectionKeyIterator iter = new SentinelSelectionKeyIterator(key);
while (iter.hasNext()) {
    System.out.println(iter.next());
}

…​prints the following:

OpenCloud:OpenCloud:::
OpenCloud::::

The SentinelSelectionKeyIterator helps to enforce certain assumptions about the state and usage of the selection key. These are:

  1. The fields are always populated from left to right.

  2. The scope of config data is narrowed progressively by each field from left to right.

  3. Once config data is found at a particular scope, config data at broader scopes should be ignored.

Using the selection key to scope SLEE profiles

The most common use for the selection key is to scope profiles. This is commonly achieved by naming the profile after the selection scope to which it applies. The profile name may additionally have a standard prefix or suffix which can be used to further scope the profile.

For example, a feature config table may contain following config profiles:

OpenCloud:OpenCloud:call::
OpenCloud:OpenCloud:::
OpenCloud::::

Then for sessions of type call on the OpenCloud network, the config profile OpenCloud:OpenCloud:call:: would be selected; while for all other session types, the second is chosen.

For the selection key OpenCloud::call::, the config profile OpenCloud:::: would be selected.

For example:

try {
    promotionsDbQueryConfigProfileTable =
        facilities.getProfileFacility().getProfileTable(PROMOTIONS_DBQUERY_CONFIG_PROFILE_TABLE_NAME);
}
catch (UnrecognizedProfileTableNameException uptne) {
    throw new PromotionsDbQueryConfigLoadException("No promotions dbquery config table found:", uptne);
}

// Find the profile whose name is the closest match to the selection key
SentinelSelectionKeyIterator iter = new SentinelSelectionKeyIterator(key);
ProfileLocalObject profile = null;
while (iter.hasNext() && profile == null) {
    profile = promotionsDbQueryConfigProfileTable.find(iter.next());
}

if (null == profile)
    throw new PromotionsDbQueryConfigLoadException("No promotions dbquery config profile found at any scope for session key: " + key);

Using the selection key to scope SLEE tables

A similar idiom exists for scoping tables as for profiles. However, in the case of scoped tables, a table name prefix or suffix should always be used to avoid saturating the table namespace.

TableExistsVerifier tableExistenceTester = new TableExistsVerifier();

while (iter.hasNext() &&
    ! tableExistenceTester.profileTableExists(
        tableName = (iter.next() + SentinelSelectionKey.SEPARATOR + SUBSCRIBER_DATA_FIELDDEF_PROFILE_TABLE_NAME)));

try {
    subscriberDataProfileTable = facilities.getProfileFacility().getProfileTable(tableName);
}
catch (UnrecognizedProfileTableNameException e) {
    throw new SubscriberDataLoadException("No subscriber data field definition table exists at any scope for the selection key " + key, e);
}

Using the selection key to scope config in external datasources

You can use the selection key to scope config in external databases, by coding the scope fallback logic in an SQL statement, or by making multiple queries from Java (as in the preceding SLEE examples). It really depends on the interface to the datasource. In any case, the earlier guidelines around selection key semantics should be observed as far as possible.

Propagating properties with the public.properties file

In some cases you may want to propagate certain properties to depending modules, for example component versions. This is possible with a *.public.properties file published as an additional artifact in the api Ivy configuration. This file should be named after the Ivy module name with an appended .public.properties, so for example my-sip-example.public.properties.

Once you have created such a file modify the module’s build.xml to process the properties file in any way that is necessary, and then copy it to the target/artifacts directory.

Finally modify the module’s ivy.xml to publish the file in the api configuration:

    <publications>
        <!-- ... other artifact publications ... --->
        <artifact name="${ivy.module}.public"     type="properties" ext="properties"    conf="api"/>
    </publications>

This will make the properties available during the build process of any module that depends on the api configuration of your module.

Building a module

All modules include a build.xml file. This means that they can be built and published using Ant.

There are two ant target to build and publish a module:

  • publish-local — Compiles and publishes just the current module. Does not include any other modules.

  • publish-local-branch — Compiles and publishes all modules, from the current directory and all subdirectories. The module compilation and publication order is automatically determined, such that the modules are compiled and published in the correct order.

If there is ever a question about which to use, publish-local-branch should take precedence over publish-local. (The publish-local target can be considered an 'optimisation', where only one module is compiled and published.)

The publish-local-branch target can be run from within any module that includes the availability of the target under the ant -p output. This means that all modules within a module group can be built (and not other, unnecessary modules). If this target is used from the 'root' of the Sentinel VoLTE SDK, then all modules are compiled and published.

There are two 'clean' targets, that delete on-disk files generated by a build. These are:

  • clean — Cleans the current module. This is often used in conjunction with publish-local.

  • clean-branch — Cleans all modules, from the current directory and all subdirectories. This is often used in conjunction with publish-local-branch.

Tip As my-sip-example is a module that contains other modules, it makes sense to use publish-local-branch to build it and the contained modules.

To compile and publish the my-sip-example module group, use following command:

1

cd into the my-sip-example directory

2

Run ant publish-local-branch

Checking deployment prerequisites

Before you deploy a feature, make sure that the Sentinel services you want are deployed. The installation of Sentinel SIP service is necessary for this example feature. And if the module is bound to a running service, the service must be deactivated.

Check the Sentinel service

To view the currently deployed services, use the following command within the rhino-console tool:
listservices

[Rhino@localhost (#1)] listservices
ServiceID[name=sentinel.registrar,vendor=OpenCloud,version=2.7.0.0-copy#1]
ServiceID[name=sentinel.registrar,vendor=OpenCloud,version=2.7.0.0]
ServiceID[name=sentinel.registrar,vendor=OpenCloud,version=2.7.0]
ServiceID[name=sentinel.registrar,vendor=OpenCloud,version=current]
ServiceID[name=volte.sentinel.sip,vendor=OpenCloud,version=2.7.0.0-copy#1]
ServiceID[name=volte.sentinel.sip,vendor=OpenCloud,version=2.7.0.0]
ServiceID[name=volte.sentinel.sip,vendor=OpenCloud,version=2.7.0]
ServiceID[name=volte.sentinel.sip,vendor=OpenCloud,version=current]
ServiceID[name=volte.sentinel.ss7,vendor=OpenCloud,version=2.7.0.0-copy#1]
ServiceID[name=volte.sentinel.ss7,vendor=OpenCloud,version=2.7.0.0]
ServiceID[name=volte.sentinel.ss7,vendor=OpenCloud,version=2.7.0]
ServiceID[name=volte.sentinel.ss7,vendor=OpenCloud,version=current]

Various types of features are installed into different Sentinel services:

Type of feature Name of service deploy module

Diameter

sentinel-diameter-modules-deploy

Registrar

sentinel-registrar-modules-deploy

SIP

sentinel-sip-modules-deploy

SS7 Camel

sentinel-ss7-modules-deploy

SS7 CS1+

sentinel-ss7-cs1plus-modules-deploy

For Sentinel VoLTE there is one service deploy module: volte-sentinel-full-deploy

Deactivate the running service

In order to deactivate the running service, use the rhino-console program and use command deactivateservice in console.

For Example, to deactivate the service name=sentinel.sip,vendor=OpenCloud,version=2.7.0-copy#1, type the following command in the console:

deactivateservice name=sentinel.sip,vendor=OpenCloud,version=2.7.0-copy#1

For Example, to deactivate the service `name=volte.sentinel.sip,vendor=OpenCloud,version=2.7.0-copy#1`, type the following command in the console:

`deactivateservice name=volte.sentinel.sip,vendor=OpenCloud,version=2.7.0-copy#1`

[role="small",subs="attributes"]
----
[Rhino@localhost (#0)] listservicesbystate Active
Services in Active state on node 101:
 ServiceID[name=sentinel.registrar,vendor=OpenCloud,version=2.7.0]
 ServiceID[name=sentinel.registrar,vendor=OpenCloud,version=2.7.0.0-copy#1]
 ServiceID[name=sentinel.registrar,vendor=OpenCloud,version=current]
 ServiceID[name=volte.sentinel.sip,vendor=OpenCloud,version=2.7.0]
 ServiceID[name=volte.sentinel.sip,vendor=OpenCloud,version=2.7.0.0-copy#1]
 ServiceID[name=volte.sentinel.sip,vendor=OpenCloud,version=current]
 ServiceID[name=volte.sentinel.ss7,vendor=OpenCloud,version=2.7.0]
 ServiceID[name=volte.sentinel.ss7,vendor=OpenCloud,version=2.7.0.0-copy#1]
 ServiceID[name=volte.sentinel.ss7,vendor=OpenCloud,version=current]
[Rhino@localhost (#1)] deactivateservice name=volte.sentinel.sip,vendor=OpenCloud,version=2.7.0.0-copy#1
Deactivating service ServiceID[name=volte.sentinel.sip,vendor=OpenCloud,version=2.7.0.0-copy#1] on node(s) [101]
Service transitioned to the Stopping state on node 101
----

After configuring a feature, the service must be activated again, please see activate a service.

Deploying a feature

Once a module has been published, it can be deployed. To deploy in the Sentinel VoLTE SDK, you use the deployer tool.

The deployer reads the current module and looks for its published artifacts. It then uses published artifacts and their dependencies to deploy a module.

Warning This means that a module must be published before it can be deployed !

To deploy my-sip-example:

1

cd into the my-sip-example directory

2

Run ant deploy-with-deps

This command will deploy the current module, after having first deployed any dependent modules. It does so all the way up the dependency heirarchy. If a module has already been deployed into Rhino, and it has the most recent version, then the deployer will skip it.

Tip For more about the deployer, please see Deploying modules in Rhino

Deployer output

Here’s what the deployer’s output should look like:

$ ant -Ddeployer.latest-revision-checks.enabled=false deploy-with-deps
Buildfile: /home/testuser/sentinel-volte-sdk/my-sip-example/build.xml

... edited for brevity ...

init:

init-module:
     [echo] Resolving ivy configurations "*" for my-sip-example

deploy-with-deps:
     [echo] Deploying module.
[oc:deploy] :: loading settings :: file = /home/testuser/sentinel-volte-sdk/build/ivy/ivysettings.xml
[oc:deploy] Created deployer with options: OutdatedIvyModuleDetection: Disabled, IvyStatusesToCheck: [integration]
[oc:deploy] Invoking the deployer to process root module UNSET#my-sip-example#trunk;1.0.0.0-DEV2-testuser and its dependencies ...
[oc:deploy] Installing module UNSET#my-sip-example-event-handler-sbbpart#trunk;1.0.0.0-DEV2-testuser
[oc:deploy] Installing module UNSET#my-sip-example-mapper#trunk;1.0.0.0-DEV2-testuser
[oc:deploy] Installing module UNSET#my-sip-example-profile#trunk;1.0.0.0-DEV3-testuser
[oc:deploy] Installing module UNSET#my-sip-example-feature#trunk;1.0.0.0-DEV2-testuser
[oc:deploy] Deployment Result:
[oc:deploy] ---------------------------------------------------------------------
[oc:deploy] |  Deploy result:
[oc:deploy] ---------------------------------------------------------------------
[oc:deploy] |  Modules with no Component:
[oc:deploy] |  UNSET#my-sip-example#trunk;1.0.0.0-DEV2-testuser
[oc:deploy] ---------------------------------------------------------------------
[oc:deploy] |  Deployed Modules:
[oc:deploy] |  UNSET#my-sip-example-feature#trunk;1.0.0.0-DEV2-testuser
[oc:deploy] |  |__ SbbPartID[name=my-sip-example-feature,vendor=UNSET,version=1.0]
[oc:deploy] |  UNSET#my-sip-example-mapper#trunk;1.0.0.0-DEV2-testuser
[oc:deploy] |  |__ SbbPartID[name=my-sip-example-mapper,vendor=UNSET,version=1.0]
[oc:deploy] |  UNSET#my-sip-example-event-handler-sbbpart#trunk;1.0.0.0-DEV2-testuser
[oc:deploy] |  |__ SbbPartID[name=my-sip-example-event-handler-sbbpart,vendor=UNSET,version=1.0]
[oc:deploy] |  UNSET#my-sip-example-profile#trunk;1.0.0.0-DEV3-testuser
[oc:deploy] |  |__ ProfileSpecificationID[name=my-sip-example-profile,vendor=UNSET,version=1.0]
[oc:deploy] ---------------------------------------------------------------------
[oc:deploy] All modules deployed successfully.
   [delete] Deleting directory /home/testuser/sentinel-volte-sdk/my-sip-example/target/deployer-work

BUILD SUCCESSFUL
Total time: 9 seconds

The output shows:

  1. The deployer analyses the dependencies of the my-sip-example module.

  2. The group module depends on the feature module.

  3. The deployer analyses the dependencies of the feature module.
    It has deployment dependencies on the mapper and profile modules.
    These are dependencies on the slee-component Ivy configuration in the feature’s ivy.xml file.

  4. The deployer analyses the dependencies of the mapper and profile modules.
    These modules have no deployment dependencies, so the deployer installs them into Rhino.
    Once the mapper and profile modules have been installed, the feature can be installed, because its dependencies have been deployed.

  5. The deployer analyses the group module.
    This module has published no slee-components, so deployment has finished.

The end of the deployment output shows a summary of what was deployed.

Undeploying and redeploying modules

If code in a module has changed, it makes sense to re-compile and re-publish the module. In order to test changes within Rhino, the module must be deployed. Since a version is already deployed, you’ll want to undeploy it.

The undeploy target is available to remove SLEE components from Rhino. This command works by:

  1. calculating which components the module deployed

  2. uninstalling those SLEE components from Rhino

Note
undeploy and deploy-with-deps

The way the undeploy command works is a bit more complex than deploy-with-deps:

  • The deploy-with-deps command deploys dependent modules, by following Ivy dependences through the slee-component Ivy Configuration.

  • The undeploy command merely undeploys the current module.

For example, the group module my-sip-example has no slee-component publications; so the undeploy target does nothing when executed. However, the profile, mapper, and feature modules it contains do publish SLEE components. And the feature depends on the profile.

Therefore, if you uninstall the profile, you’ll be prompted to confirm that you want to uninstall both the the profile component and the feature component (since it depends on the profile).

But if you uninstall the feature itself, since there are no dependencies on it, only the feature component will be uninstalled.

The undeploy-all target is also available to remove SLEE components from Rhino. This command works by finding all modules in subdirectories of the current working directory, and then asking each module to undeploy.

Warning If a component has been bound, we recommend unbinding it before undeploying it.

For more about deployment and undeployment, see Deploying modules in Rhino

Version checks and deployment

When a module is published, its dependencies are published along with it.

With the my-sip-example group, the first time you run publish-local-branch you get this:

Module Published revision Dependency A name and revision Dependency B name and revision

group

1.0.0-DEV0

feature revision 1.0.0-DEV0

N/A

profile

1.0.0-DEV0

N/A

N/A

mapper

1.0.0-DEV0

N/A

N/A

feature

1.0.0-DEV0

profile revision 1.0.0-DEV0

mapper revision 1.0.0-DEV0

When the deployer reads the published group module or feature module it will retrieve revision 1.0.0-DEV0, and follow the dependencies to published revision 1.0.0-DEV0 of the appropriate module.

Then, if you rebuilt all modules using the publish-local-branch target, you’d get this:

Module Published revision Dependency A name and revision Dependency B name and revision

group

1.0.0-DEV1

feature revision 1.0.0-DEV1

N/A

profile

1.0.0-DEV1

N/A

N/A

mapper

1.0.0-DEV1

N/A

N/A

feature

1.0.0-DEV1

profile revision 1.0.0-DEV1

mapper revision 1.0.0-DEV1

Next, if you’d changed some logic in your profile module, then entered publish-local in the profile module, the revisions would be:

Module Published revision Dependency A name and revision Dependency B name and revision

group

1.0.0-DEV1

feature revision 1.0.0-DEV1

N/A

profile

1.0.0-DEV2

N/A

N/A

mapper

1.0.0-DEV1

N/A

N/A

feature

1.0.0-DEV1

profile revision 1.0.0-DEV1

mapper revision 1.0.0-DEV1

When the deployer reads the feature now, it will see that it depends on profile revision 1.0.0-DEV1, not profile revision 1.0.0-DEV2. So it would have to deploy profile revision 1.0.0-DEV1. This would likely to cause confusion, as the changes to the profile would have not taken effect!

This is almost certainly not the desired result (after publishing some changes to the profile).

To avoid this situation, by default the deployer checks that the dependent revision of a module is also the most recently published revision of that module. If those two revisions are not equal, it will not deploy anything into Rhino.

Here’s what the error message looks like:

$ ant deploy-with-deps
Buildfile: /home/testuser/sentinel-volte-sdk/my-sip-example/build.xml

init-build-extensions:

pre-init-ivy-common:

init-ivy-common:
     [echo] Ivy Resolvers: /home/testuser/sentinel-volte-sdk/build/ivy/resolvers-remote.xml
     [echo] Configuring Ivy with settings: /home/testuser/sentinel-volte-sdk/build/ivy/ivysettings.xml
  [ivy:var] :: Apache Ivy 2.3.0 - 20130110142753 :: http://ant.apache.org/ivy/ ::
  [ivy:var] :: loading settings :: file = /home/testuser/sentinel-volte-sdk/build/ivy/ivysettings.xml

ivy-authentication-check:
[ivy:resolve] :: loading settings :: file = /home/testuser/sentinel-volte-sdk/build/ivy/ivysettings.xml
     [echo] Build infrastructure lib/ directory is up to date.

update-index-properties:
[oc:index-properties] Properties file "/home/testuser/sentinel-volte-sdk/release.properties" already exists.
[oc:index-properties] Index configuration has not changed since previous build.
[oc:index-properties] Index configuration uses dynamic revisions. Current version of indexes will be queried.
[oc:index-properties] Querying current version of: opencloud#volte-sentinel-index#volte/2.7.0;latest.integration
[oc:index-properties] Current version is: opencloud#volte-sentinel-index#volte/2.7.0;2.7.0.0
[oc:index-properties] Currently available index versions are the same as previous build. Properties file "/home/testuser/sentinel-volte-sdk/release.properties" will not be regenerated.

init:

init-module:
     [echo] Resolving ivy configurations "*" for my-sip-example

deploy-with-deps:
     [echo] Deploying module.
[oc:deploy] :: loading settings :: file = /home/testuser/sentinel-volte-sdk/build/ivy/ivysettings.xml
[oc:deploy] Created deployer with options: OutdatedIvyModuleDetection: Enabled, IvyStatusesToCheck: [integration]
[oc:deploy] Invoking the deployer to process root module UNSET#my-sip-example#trunk;1.0.0.0-DEV3-testuser and its dependencies ...
[oc:deploy] Deployment Result:
[oc:deploy] ---------------------------------------------------------------------
[oc:deploy] |  Deploy result:
[oc:deploy] ---------------------------------------------------------------------
[oc:deploy] |  Failed Modules:
[oc:deploy] |  UNSET#my-sip-example-profile#trunk;1.0.0.0-DEV4-testuser
[oc:deploy] |  |__ Module has a newer revision available in 'latest.integration': '1.0.0.0-DEV5-testuser'.
[oc:deploy] |      Note: this failure was encountered while checking that versions are up to date.
[oc:deploy] |      To disable this version checking behaviour when running the 'deploy' or 'deploy-with-deps' targets,
[oc:deploy] |      set the system property 'deployer.latest-revision-checks.enabled' to 'false'.
[oc:deploy] |        E.g. when using Ant:
[oc:deploy] |            ant -Ddeployer.latest-revision-checks.enabled=false deploy-with-deps
[oc:deploy] |        or within the sdkadm client:
[oc:deploy] |            deploy-module ... -properties deployer.latest-revision-checks.enabled=false
[oc:deploy] ---------------------------------------------------------------------

BUILD FAILED
/home/testuser/sentinel-volte-sdk/build/module-targets.xml:88: The following error occurred while executing this line:
/home/testuser/sentinel-volte-sdk/build/toolchain-macrodefs.xml:22:  task failed to deploy all modules.

Total time: 8 seconds

To override this behaviour, add the following to the deploy or deploy-with-deps target:

-Ddeployer.latest-revision-checks.enabled=false

For example:

ant -Ddeployer.latest-revision-checks.enabled=false deploy-with-deps

Binding a module

Once the module has been deployed, its SLEE components are present inside the SLEE. However they are not referenced by the appropriate Sentinel service(s).

To have them referenced, they must be bound into the appropriate service(s).

To do this, you use a tool called the binder:

1

To invoke the binder, enter the group module (in the example, the my-sip-example module) and type:

ant bind-with-deps

This command will read the slee-binding Ivy configuration, and walk up the Ivy dependencies binding components as necessary. It produces a report when finished.

For the my-sip-example module, the output looks like this:

$ ant bind-with-deps
Buildfile: /home/testuser/sentinel-volte-sdk/my-sip-example/build.xml

... edited for brevity ...

bind-with-deps:
     [echo] Binding module.
  [oc:bind] Connecting to Rhino ...
  [oc:bind] Connected to Rhino.
  [oc:bind] Initialising Ivy.
  [oc:bind] :: loading settings :: file = /home/testuser/sentinel-volte-sdk/build/ivy/ivysettings.xml
  [oc:bind] Creating binder.
  [oc:bind] Created binder with options: ServiceStrategy: FAIL_IF_ACTIVE
  [oc:bind] Finished resolving dependencies.
  [oc:bind] Invoking the binder to process root module UNSET#my-sip-example#trunk;1.0.0.0-DEV3-testuser and its dependencies ...

... edited for brevity ...

  [oc:bind] Finished processing root modules.
  [oc:bind] ---
  [oc:bind] |  Bind result:
  [oc:bind] ---
  [oc:bind] |  Successfully processed modules:
  [oc:bind] |  UNSET#my-sip-example-mapper#trunk;1.0.0.0-DEV3-testuser
  [oc:bind] |  |__ ModuleBindResult{resultParts=[no bindings in module]}
  [oc:bind] |  UNSET#my-sip-example-feature#trunk;1.0.0.0-DEV3-testuser
  [oc:bind] |  |__ ModuleBindResult{resultParts=[bindings installed, bindings applied for service ServiceID[name=volte.sentinel.sip,vendor=OpenCloud,version=2.7.0.0-copy#1]]}
  [oc:bind] |  UNSET#my-sip-example-profile#trunk;1.0.0.0-DEV4-testuser
  [oc:bind] |  |__ ModuleBindResult{resultParts=[bindings installed, bindings applied for service ServiceID[name=volte.sentinel.sip,vendor=OpenCloud,version=2.7.0.0-copy#1]]}
  [oc:bind] |  UNSET#my-sip-example-event-handler-sbbpart#trunk;1.0.0.0-DEV3-testuser
  [oc:bind] |  |__ ModuleBindResult{resultParts=[bindings installed, bindings applied for service ServiceID[name=volte.sentinel.sip,vendor=OpenCloud,version=2.7.0.0-copy#1]]}
  [oc:bind] |  UNSET#my-sip-example#trunk;1.0.0.0-DEV3-testuser
  [oc:bind] |  |__ ModuleBindResult{resultParts=[no bindings in module]}
  [oc:bind] ---
  [oc:bind] ---
  [oc:bind] All modules bound successfully.

BUILD SUCCESSFUL
Total time: 24 seconds

When applying bindings, the binder has created a copy of the service and its root SBB, and added a reference from the root SBB to the new feature’s SBB part.

2

In order to see the new service, use the rhino-console program and type listservices:

[Rhino@localhost (#1)] listservices
ServiceID[name=sentinel.registrar,vendor=OpenCloud,version=2.7.0.0-copy#1]
ServiceID[name=sentinel.registrar,vendor=OpenCloud,version=2.7.0.0]
ServiceID[name=sentinel.registrar,vendor=OpenCloud,version=2.7.0]
ServiceID[name=sentinel.registrar,vendor=OpenCloud,version=current]
ServiceID[name=volte.sentinel.sip,vendor=OpenCloud,version=2.7.0.0-copy#1]
ServiceID[name=volte.sentinel.sip,vendor=OpenCloud,version=2.7.0.0]
ServiceID[name=volte.sentinel.sip,vendor=OpenCloud,version=2.7.0]
ServiceID[name=volte.sentinel.sip,vendor=OpenCloud,version=current]
ServiceID[name=volte.sentinel.ss7,vendor=OpenCloud,version=2.7.0.0-copy#1]
ServiceID[name=volte.sentinel.ss7,vendor=OpenCloud,version=2.7.0.0]
ServiceID[name=volte.sentinel.ss7,vendor=OpenCloud,version=2.7.0]
ServiceID[name=volte.sentinel.ss7,vendor=OpenCloud,version=current]
Note There are services with -copy#1 present. These service copies were created by the binder.

3

Compare a copy with an original using the getdescriptor command:

[Rhino@localhost (#5)] getdescriptor sbb name=volte.sentinel.sip,vendor=OpenCloud,version=2.7.0
For component SbbID[name=volte.sentinel.sip,vendor=OpenCloud,version=2.7.0]:
 Deployable unit: DeployableUnitID[url=file:modules/opencloud/volte-sentinel-sip-service-build-2.7.0.0.jar]
 Component source: volte-sentinel-sip-sbb.jar
 Defined using SLEE version: 1.1
 Checksum: 0x730f623eb9bce32da00df2bd23243dd5ca310354
 Install level: DEPLOYED
 Manifest attributes:
  Ant-Version: Apache Ant 1.9.4
  Created-By: 1.7.0_71-b14 (Oracle Corporation)
  Manifest-Version: 1.0
 Copies made from this component:
  SbbID[name=volte.sentinel.sip,vendor=OpenCloud,version=2.7.0-copy#1]
 Library refs:
  LibraryID[name=FSMTool Library,vendor=OpenCloud,version=1.1.0]
  LibraryID[name=Google Protocol Buffers support runtime,vendor=OpenCloud,version=2.3.0]
  LibraryID[name=Sentinel promotion script library,vendor=OpenCloud,version=2.7.0]
... edited for brevity ...
  LibraryID[name=mmtel-standard-schema,vendor=OpenCloud,version=1.0]
 Event type refs:
  EventTypeID[name=com.opencloud.slee.resources.http.HttpRequest.GET,vendor=OpenCloud,version=2.2]
  EventTypeID[name=com.opencloud.slee.resources.http.HttpRequest.POST,vendor=OpenCloud,version=2.2]
  EventTypeID[name=javax.slee.ActivityEndEvent,vendor=javax.slee,version=1.0]
  EventTypeID[name=javax.slee.facilities.TimerEvent,vendor=javax.slee,version=1.0]
  EventTypeID[name=org.jainslee.resources.sip.IncomingSipRequest.ACK,vendor=jainslee.org,version=1.4]
  EventTypeID[name=org.jainslee.resources.sip.IncomingSipRequest.BYE,vendor=jainslee.org,version=1.4]
  EventTypeID[name=org.jainslee.resources.sip.IncomingSipRequest.CANCEL,vendor=jainslee.org,version=1.4]
  EventTypeID[name=org.jainslee.resources.sip.IncomingSipRequest.INFO,vendor=jainslee.org,version=1.4]
  EventTypeID[name=org.jainslee.resources.sip.IncomingSipRequest.INVITE,vendor=jainslee.org,version=1.4]
  EventTypeID[name=org.jainslee.resources.sip.IncomingSipRequest.MESSAGE,vendor=jainslee.org,version=1.4]
... edited for brevity ...
 Profile spec refs:
  ProfileSpecificationID[name=AddressListEntryProfile,vendor=OpenCloud,version=2.7.0]
  ProfileSpecificationID[name=DiameterMediationConfigurationProfile,vendor=OpenCloud,version=2.7.0]
  ProfileSpecificationID[name=DiameterMediationOcsConfigurationProfile,vendor=OpenCloud,version=2.7.0]
  ProfileSpecificationID[name=DiameterSentinelServiceIDConfigProfile,vendor=OpenCloud,version=2.7.0]
  ProfileSpecificationID[name=ExecutionPoint,vendor=OpenCloud,version=2.7.0]
 SBB refs:
  SbbID[name=volte.sentinel.ro.ocs,vendor=OpenCloud,version=2.7.0]
 SBB part refs:
  SbbPartID[name=SentinelDiameterMediationMappers,vendor=OpenCloud,version=2.7.0]
  SbbPartID[name=SentinelRegistrarHssData SBB Part,vendor=OpenCloud,version=2.7.0]
  SbbPartID[name=SentinelSipFeatureSPI SBB Part,vendor=OpenCloud,version=2.7.0]
  SbbPartID[name=sentinel-feature-runner,vendor=OpenCloud,version=2.7.0]
 Resource adaptor type refs:
  ResourceAdaptorTypeID[name=CDR Generation,vendor=OpenCloud,version=2.2]
  ResourceAdaptorTypeID[name=Correlation RA Type,vendor=OpenCloud,version=2.7.0]
  ResourceAdaptorTypeID[name=Database Query,vendor=OpenCloud,version=1.4]
  ResourceAdaptorTypeID[name=Diameter Ro,vendor=jainslee.org,version=2.6]
  ResourceAdaptorTypeID[name=EasySIP,vendor=jainslee.org,version=1.4]
  ResourceAdaptorTypeID[name=HTTP,vendor=OpenCloud,version=2.2]
  ResourceAdaptorTypeID[name=Hector RA Type,vendor=OpenCloud,version=2.7.0]
  ResourceAdaptorTypeID[name=UniqueID RA Type,vendor=OpenCloud,version=2.7.0]
  ResourceAdaptorTypeID[name=sentinel.management.ra.type,vendor=OpenCloud,version=2.7.0]
  ResourceAdaptorTypeID[name=sh-cache-ratype,vendor=OpenCloud,version=1.0.1]
 Resource adaptor entity links:
  sentinel-cassandra
  sentinel-cdrra
  sentinel-correlation-etcari
  sentinel-correlation-reorigination
  sentinel-dbquery
  sentinel-http
  sentinel-internal-diameterro
  sentinel-management
  sentinel-sip
  sentinel-uid
  sh-cache-ra
 Address profile spec: none

 This component is a dependent of:
  BindingDescriptorID[name=my-sip-example-event-handler-sbbpart-volte.sentinel.sip-bindings,vendor=UNSET,version=1.0]
  BindingDescriptorID[name=mmtel-cdiv-volte.sentinel.sip-bindings,vendor=opencloud,version=2.7.0]
  BindingDescriptorID[name=mmtel-conf-mapper-library-dialogic-volte.sentinel.sip-bindings,vendor=opencloud,version=2.7.0]
  BindingDescriptorID[name=mmtel-conf-mapper-library-radisys-volte.sentinel.sip-bindings,vendor=opencloud,version=2.7.0]
  BindingDescriptorID[name=mmtel-conf-subscription-volte.sentinel.sip-bindings,vendor=opencloud,version=2.7.0]

... edited for brevity ...

  BindingDescriptorID[name=volte-sip-header-manipulation-feature-volte.sentinel.sip-bindings,vendor=opencloud,version=2.7.0]
  BindingDescriptorID[name=volte-to-ccr-mappers-volte.sentinel.sip-bindings,vendor=opencloud,version=2.7.0]
  ServiceID[name=volte.sentinel.sip,vendor=OpenCloud,version=2.7.0.0]

... edited for brevity ...
Note The service with suffix -copy#1 has been copied from the original. The copied service has a different root SBB than the original.

4

Use the getdescriptor command to view the descriptors of the two root SBBs. The new SBB has an additional SBB part reference — to the new feature. The new feature has an SBB part with name=my-sip-example-feature:

[Rhino@localhost (#7)] getdescriptor sbb name=volte.sentinel.sip,vendor=OpenCloud,version=2.7.0-copy#1
For component SbbID[name=volte.sentinel.sip,vendor=OpenCloud,version=2.7.0-copy#1]:
 Copied from: SbbID[name=volte.sentinel.sip,vendor=OpenCloud,version=2.7.0]
 Copy date: Fri Apr 01 17:26:06 NZDT 2016
 Original component: SbbID[name=volte.sentinel.sip,vendor=OpenCloud,version=2.7.0]
 Install level: VERIFIED
 Library refs:
  LibraryID[name=FSMTool Library,vendor=OpenCloud,version=1.1.0]
  LibraryID[name=Google Protocol Buffers support runtime,vendor=OpenCloud,version=2.3.0]
  LibraryID[name=Sentinel promotion script library,vendor=OpenCloud,version=2.7.0]
  LibraryID[name=SentinelAddressList,vendor=OpenCloud,version=2.7.0]
  LibraryID[name=SentinelFeaturesCommon,vendor=OpenCloud,version=2.7.0]
  LibraryID[name=SentinelRegistrarHssData,vendor=OpenCloud,version=2.7.0]
  LibraryID[name=SentinelSdpLibrary,vendor=OpenCloud,version=1.0.0]
  LibraryID[name=SentinelSs7FeatureSPI,vendor=OpenCloud,version=2.7.0]
  LibraryID[name=SentinelXpath,vendor=OpenCloud,version=2.7.0]
  LibraryID[name=easysip-jxpath,vendor=OpenCloud,version=2.7.0]
  LibraryID[name=jxpath-util,vendor=OpenCloud,version=1.1]
  LibraryID[name=mmtel-standard-schema,vendor=OpenCloud,version=1.0]
 Event type refs:
  EventTypeID[name=com.opencloud.slee.resources.http.HttpRequest.GET,vendor=OpenCloud,version=2.2]
  EventTypeID[name=com.opencloud.slee.resources.http.HttpRequest.POST,vendor=OpenCloud,version=2.2]
  EventTypeID[name=javax.slee.ActivityEndEvent,vendor=javax.slee,version=1.0]
  EventTypeID[name=javax.slee.facilities.TimerEvent,vendor=javax.slee,version=1.0]
  EventTypeID[name=org.jainslee.resources.sip.IncomingSipRequest.ACK,vendor=jainslee.org,version=1.4]
  EventTypeID[name=org.jainslee.resources.sip.IncomingSipRequest.BYE,vendor=jainslee.org,version=1.4]
  EventTypeID[name=org.jainslee.resources.sip.IncomingSipRequest.CANCEL,vendor=jainslee.org,version=1.4]
  EventTypeID[name=org.jainslee.resources.sip.IncomingSipRequest.INFO,vendor=jainslee.org,version=1.4]
  EventTypeID[name=org.jainslee.resources.sip.IncomingSipRequest.INVITE,vendor=jainslee.org,version=1.4]
  EventTypeID[name=org.jainslee.resources.sip.IncomingSipRequest.MESSAGE,vendor=jainslee.org,version=1.4]
  EventTypeID[name=org.jainslee.resources.sip.IncomingSipRequest.NOTIFY,vendor=jainslee.org,version=1.4]
  EventTypeID[name=org.jainslee.resources.sip.IncomingSipRequest.OPTIONS,vendor=jainslee.org,version=1.4]
  EventTypeID[name=org.jainslee.resources.sip.IncomingSipRequest.PRACK,vendor=jainslee.org,version=1.4]
  EventTypeID[name=org.jainslee.resources.sip.IncomingSipRequest.PUBLISH,vendor=jainslee.org,version=1.4]
  EventTypeID[name=org.jainslee.resources.sip.IncomingSipRequest.REFER,vendor=jainslee.org,version=1.4]
  EventTypeID[name=org.jainslee.resources.sip.IncomingSipRequest.SUBSCRIBE,vendor=jainslee.org,version=1.4]
  EventTypeID[name=org.jainslee.resources.sip.IncomingSipRequest.UPDATE,vendor=jainslee.org,version=1.4]
  EventTypeID[name=org.jainslee.resources.sip.IncomingSipResponse.Error,vendor=jainslee.org,version=1.4]
  EventTypeID[name=org.jainslee.resources.sip.IncomingSipResponse.Provisional,vendor=jainslee.org,version=1.4]
  EventTypeID[name=org.jainslee.resources.sip.IncomingSipResponse.Redirect,vendor=jainslee.org,version=1.4]
  EventTypeID[name=org.jainslee.resources.sip.IncomingSipResponse.Success,vendor=jainslee.org,version=1.4]
  EventTypeID[name=org.jainslee.resources.sip.NoAckReceived,vendor=jainslee.org,version=1.4]
  EventTypeID[name=org.jainslee.resources.sip.NoPrackReceived,vendor=jainslee.org,version=1.4]
 Profile spec refs:
  ProfileSpecificationID[name=AddressListEntryProfile,vendor=OpenCloud,version=2.7.0]
  ProfileSpecificationID[name=DiameterMediationConfigurationProfile,vendor=OpenCloud,version=2.7.0]
  ProfileSpecificationID[name=DiameterMediationOcsConfigurationProfile,vendor=OpenCloud,version=2.7.0]
  ProfileSpecificationID[name=DiameterSentinelServiceIDConfigProfile,vendor=OpenCloud,version=2.7.0]
  ProfileSpecificationID[name=ExecutionPoint,vendor=OpenCloud,version=2.7.0]
  ProfileSpecificationID[name=FeatureExecutionScript,vendor=OpenCloud,version=2.7.0]
  ProfileSpecificationID[name=PromotionsTable,vendor=OpenCloud,version=2.7.0]
  ProfileSpecificationID[name=SentinelConfigurationProfile,vendor=OpenCloud,version=2.7.0]
  ProfileSpecificationID[name=SipSentinelConfigurationProfile,vendor=OpenCloud,version=2.7.0]
  ProfileSpecificationID[name=SipThirdPartyCallConfigurationProfile,vendor=OpenCloud,version=2.7.0]
  ProfileSpecificationID[name=TccTimerConfigurationProfile,vendor=OpenCloud,version=2.7.0]
  ProfileSpecificationID[name=registrar.config,vendor=OpenCloud,version=2.7.0]
 SBB refs:
  SbbID[name=mmtel-conf-sbb,vendor=OpenCloud,version=2.7.0-copy#1]
  SbbID[name=scc-send-request-to-anchor-sbb,vendor=OpenCloud,version=2.7.0-copy#1]
  SbbID[name=scc-tads-data-lookup-sbb,vendor=OpenCloud,version=2.7.0-copy#1]
  SbbID[name=sentinel-core-subscriber-data-lookup-feature,vendor=OpenCloud,version=2.7.0-copy#2]
  SbbID[name=volte-hss-subscriber-data-lookup,vendor=OpenCloud,version=2.7.0-copy#1]
  SbbID[name=volte-hss-subscriber-data-lookup-2,vendor=OpenCloud,version=2.7.0-copy#1]
  SbbID[name=volte-imsid-lookup,vendor=OpenCloud,version=2.7.0-copy#1]
  SbbID[name=volte.sentinel.ro.ocs,vendor=OpenCloud,version=2.7.0]
 SBB part refs:
  SbbPartID[name=SentinelDiameterMediationMappers,vendor=OpenCloud,version=2.7.0]
  SbbPartID[name=SentinelRegistrarHssData SBB Part,vendor=OpenCloud,version=2.7.0]
  SbbPartID[name=SentinelSipFeatureSPI SBB Part,vendor=OpenCloud,version=2.7.0]
  SbbPartID[name=my-sip-example-event-handler-sbbpart,vendor=UNSET,version=1.0-copy#1]

... edited for brevity ...

 Resource adaptor type refs:
  ResourceAdaptorTypeID[name=CDR Generation,vendor=OpenCloud,version=2.2]
  ResourceAdaptorTypeID[name=Correlation RA Type,vendor=OpenCloud,version=2.7.0]
  ResourceAdaptorTypeID[name=Database Query,vendor=OpenCloud,version=1.4]
  ResourceAdaptorTypeID[name=Diameter Ro,vendor=jainslee.org,version=2.6]
  ResourceAdaptorTypeID[name=EasySIP,vendor=jainslee.org,version=1.4]
  ResourceAdaptorTypeID[name=HTTP,vendor=OpenCloud,version=2.2]
  ResourceAdaptorTypeID[name=Hector RA Type,vendor=OpenCloud,version=2.7.0]
  ResourceAdaptorTypeID[name=UniqueID RA Type,vendor=OpenCloud,version=2.7.0]
  ResourceAdaptorTypeID[name=sentinel.management.ra.type,vendor=OpenCloud,version=2.7.0]
  ResourceAdaptorTypeID[name=sh-cache-ratype,vendor=OpenCloud,version=1.0.1]
 Resource adaptor entity links:
  sentinel-cassandra
  sentinel-cdrra
  sentinel-correlation-etcari
  sentinel-correlation-reorigination
  sentinel-dbquery
  sentinel-http
  sentinel-internal-diameterro
  sentinel-management
  sentinel-sip
  sentinel-uid
  sh-cache-ra
 Address profile spec: none

 This component is a dependent of:
  ServiceID[name=volte.sentinel.sip,vendor=OpenCloud,version=2.7.0.0-copy#1]
Note

When the binder traverses a module, it:

  1. reads the published bindings metadata from the module

  2. produces Rhino bindings files in the target/binder-work directory inside the module that the binder was run from (not necessarily the same as the current module it is processing)

  3. installs the Rhino bindings files into Rhino

  4. applies the bindings to the appropriate Sentinel service.

Both the bindings metadata files and the Rhino bindings files are in JSON format and so can be viewed in a text editor. The bindings metadata files are published in a zip file in the module’s target/artifacts directory. The file is named after the module, with the suffix -bindings.zip.

The content of the bindings metadata zip file is created in the module’s target/generated/bindings directory. These files can be viewed in a text editor.

In order to unbind a module in Rhino, the unbind and unbind-all targets exist.

For more about the binder, please see Binding modules in Rhino .

Configuring a feature

Once a module has been bound it can be configured. Configuration can include:

  • profile tables and profiles

  • RA entity link names

  • RA entity configuration properties

  • RA entity activation state

  • service activation state

  • trace levels for SLEE components.

Configuration is applied through the configure-with-deps target. This target reads the config Ivy configuration, and walks up the Ivy dependencies configuring components as necessary. If the configuration in the SLEE matches the desired configuration, the configurer does not apply any changes for that module.

Configuration is specified in a YAML format. An example is included in the my-sip-example/feature/config directory.

For more about configuration, please see Configuring modules in Rhino

Activate a service

If a service was deactivated in checking deployment prerequisites, the service must be activated again.

In order to activate the running service, use the rhino-console program and use activateservice in console.

For Example, to activate the service name=volte.sentinel.sip,vendor=OpenCloud,version=2.7.0-copy#1, type the following command in console:

activateservice name=volte.sentinel.sip,vendor=OpenCloud,version=2.7.0-copy#1

[Rhino@localhost (#3)] activateservice name=volte.sentinel.sip,vendor=OpenCloud,version=2.7.0.0-copy#1
Activating service ServiceID[name=volte.sentinel.sip,vendor=OpenCloud,version=2.7.0.0-copy#1] on node(s) [101]
Service transitioned to the Active state on node 101

Testing the feature

For unit testing, include the sentinel-unit-test-support dep in ivy.xml and write unit tests in the tests/directory of the module

Once deployed, bound, and configured, the feature can be integration tested.

After installing your module you may want to make changes and install again. See General Development Cycles for more information.

Adding the feature to the deployment module

In order to be able to easily deploy the feature as part of the deployment module, you can add a dependency to the ivy.xml in the deployment module so that the deployment module depends upon the feature module. If the new feature is a dependency of a group module, then the group module should instead be added as the dependency to the deployment module’s ivy.xml file.

For the example feature, this means that you would have to add this line to the dependencies section of the deployment module’s ivy.xml:

<dependency org="${sdk.ivy.org}"  name="my-sip-example-feature"    rev="latest.${ivy.status}" conf="slee-component; deploy; config; slee-binding" />`
Previous page Next page