A collection of telecom features, modular or monolithic, rarely stands alone. As illustrated in Figure 2, telecom features are normally an integral part of a larger service that may, for example, access a database or provide a web-based user interface. Services consisting of SIP and non-SIP components are called converged services.
In this section we describe a lightweight framework included wth ECharts for SIP Servlets that enables the development of modular, reusable telecom features suitable for integration into converged services. We show how the framework supports interaction between an ECharts for SIP Servlets feature and its external environment and how it facilitates the discovery task in different scenarios. Following an overview of the framework we discuss two features that use the framework. Both features are included with the ECharts for SIP Servlets Development Kit. Finally, we discuss a few technical details of the framework useful to developers.
To support development of a SIP feature and the non-SIP external components that it interacts with, an interface must be defined between them. The interface should expose only what is strictly necessary to the accessing component in order to minimize component inter-dependencies. To ensure that the interface is light-weight and that it accommodate the widest range of possible non-SIP environments, we have chosen to demarcate the SIP/non-SIP boundary close to the SIP feature logic. This means that the only constraint on the environment is that it be accessible via Java. Furthermore, if a heavier-weight interface technology is desired, for example SOAP, then it can be added on top of the lower level Java interface.
There are two common types of interaction between a feature and its non-SIP environment:
Both interaction types are embodied as method calls. For example, a method would be called by the feature to read provisioned data from a database or a method would be called by the environment to exert control over a feature’s behavior. Thus, for a given feature the two interaction types can be defined in terms of two interfaces: (1) method signatures comprising its SIP-To-Java interface and (2) method signatures comprising its Java-To-SIP interface. These two interfaces are illustrated in Figure 3. Both interfaces are defined by the feature itself since the decision of how a feature interacts with its environment affects the feature’s internal design.
The implementation of a feature’s Java-To-SIP interface methods is clearly the responsibility of the feature itself. This is because these methods will most likely access or manipulate the feature’s internal state. On the other hand, the implementation of a feature’s SIP-To-Java interface is clearly the responsibility of the external non-SIP components that interact with the feature. For example, when a feature calls a SIP-To-Java method to indicate its own status, the method will most likely update the state of some external component. Because the SIP-To-Java interface implementation is not the responsibility of the feature, the identity of the external component and the nature of the interaction with the external component needn’t be known by the feature although these will be known by the SIP-To-Java interface implementation.
Specifying interfaces between a SIP feature and non-SIP components constitutes only part of the solution. In general there can be many feature instances, each associated with their own calls. There may also be different external components associated with different calls. For this reason, an external component needs to be able to find the Java-To-SIP interface associated with a particular feature instance, and a feature instance needs to be able to find the appropriate non-SIP components via its SIP-To-Java interface. The nature of these discovery tasks differ depending on whether a feature instance is created in response to (1) the receipt of a SIP request, or (2) a request by a non-SIP component.
In the first case, graphically depicted in Figure 4, the feature instance is created by the receipt of a SIP request from a SIP user agent, independent of non-SIP components. Most traditional call services are created this way, for example Call Forwarding, Call Waiting, etc. The feature instance first gets an instance of its SIP-To-Java interface from the framework. Since the implementation of this interface is the responsibility of external components, the interface implementation instance has embedded within it the information required to contact the appropriate external components. The feature instance then uses its SIP-To-Java interface to publish identifying information required by an external component to access its Java-To-SIP interface. This way, an external component can use this information to obtain the feature instance’s Java-To-SIP instance from the framework.
The framework is responsible for creating, storing and retrieving interface instances; these actions are hidden from features and external components. Instead, these components request to get an interface instance using a unique feature instance identifier, denoted by sasId in Figure 4, as an argument. This identifier is actually the SipApplicationSession ID assigned to a SipServletApplicationSession instance by a container. There is exactly one SipApplicationSession instance associated with an EChartsSipServlet feature instance. The framework uses the sasId as a key to store and retrieve an interface instance associated with a SIP feature instance. When a component requests to get an interface instance, the framework returns the currently stored copy. If none exists then the framework first creates a new interface instance and stores it for subsequent retrieval.
In the second case, graphically depicted in Figure 5, an EChartsSipServlet feature instance is created by a non-SIP component via a call to doNonSip(), as would be the case with a Click-To-Dial service, for example. In this case, the feature instance needn’t publish its sasId for discovery by a non-SIP component since an sasId is returned by doNonSip(). With this identifier, the non-SIP component is able to obtain a Java-To-SIP interface instance from the framework.
As shown in Figure 6, since the non-SIP component initiates the creation of the feature instance, we also permit the non-SIP component to provide the framework with a SIP-To-Java interface instance where the instance is created by the external environment itself. In this case, the doNonSip() call accesses the framework to store the specified interface instance value in addition to creating an EChartsSipServlet feature instance. This is a convenience that allows a non-SIP component to directly initialize a SIP-To-Java interface instance. The dual scenario in the SIP-initiated case, where a SIP feature sets the value of the non-SIP environment’s Java-to-SIP interface instance is not applicable because the non-SIP environment is intended to be outside the purview of the feature in order to support feature reuse.
Figure 7 graphically depicts the Click2DialFlow1Machine that is included as part of the click2DialFlow1 feature distributed with the ECharts for SIP Servlets Development Kit. A comprehensive discussion of this feature can be found in . In summary, the click2DialFlow1 feature is a converged feature that is initiated by non-SIP means. Once initiated, the feature calls a specified first party address and then, after the first party is connected, calls a specified second party address. When the second party is connected, the two parties are connected to one another.
The click2DialFlow1 feature includes both a Java-To-SIP and a SIP-To-Java interface. Following our naming convention, the former is defined by the class JavaToClick2DialFlow1Machine and the latter by the interface Click2DialFlow1MachineToJava. A default implementation of the Click2DialFlow1MachineToJava interface is also included: Click2DialFlow1MachineToJavaImpl. The JavaToClick2DialFlow1Machine interface exposes a method, dropCalls(), for dropping its calls, and the Click2DialFlow1MachineToJava interface includes methods to indicate call status: connected() and disconnected().
Since the click2DialFlow1 feature is initiated by non-SIP means then either of the non-SIP initiated discovery scenarios shown in Figures 5 and 6 can apply. The ClickToDialFlow1Machine provides a number of static initiate() methods that support both scenarios. All the initiate() methods call EChartsSipServlet.doNonSip() to create a EChartsSipServlet instance and its associated ClickToDialFlow1Machine instance. The Click2DialFlow1Machine instance calls EChartsMachineToJava.getInstance() in its constructor to obtain its Click2DialFlow1MachineToJava interface instance. The initiate() method also calls JavaToEChartsMachine.getInstance() to obtain a JavaToClick2DialFlow1Machine interface instance and returns the instance for subsequent use by the non-SIP caller.
Given the similarity to the previous example, we only briefly mention an example of a converged, SIP initiated feature. Such a feature is monitorControl, distributed with the ECharts for SIP Servlets Development Kit. This feature specifies both SIP-To-Java and Java-To-SIP interfaces and therefore follows the discovery scenario shown in Figure 4. Following the naming convention, the former is defined by MonitorControlMachineToJava and the latter by JavaToMonitorControlMachine. As shown in Figure 8, the MonitorControlMachine monitors call state and provides control over call state similar to the ClickToDial feature. In particular, the feature notifies the non-SIP environment of current call state (e.g. ringing, connected, disconnected) via its SIP-To-Java interface, and drops any in-progress call in response to a Java-To-SIP method call by the non-SIP environment.
Since the monitorControl feature is SIP-initiated and since it possesses a Java-To-SIP interface, it is the responsibility of the feature to publish its existence via a customized instance of its SIP-To-Java interface. To support publishing the identity of a feature box instance, the E4SS convergence framework automatically calls a method publish() when the machine gets its own SIP-To-Java instance via a call to EChartsMachineToJava.getInstance(). The default implementation of publish() does nothing so it is up to the developer to override the method in the MonitorControlMachineToJava interface implementation.
This section provides more details for developers wishing to use the framework.
First of all, the developer-visible parts of the “framework” are a number of static methods defined over three classes in the org.echarts.servlet.sip package: EChartsMachineToJava, JavaToEChartsMachine and EChartsProxyToJava. The first two classes constitute versions of SIP-To-Java and Java-To-SIP specialized for use with ECharts for SIP Servlets machines as defined by the EChartsSipServlet class. The last class is a specialized version of SIP-To-Java for ECharts SIP proxies as defined by the EChartsSipProxy class. We do not currently support Java-To-SIP interfaces for ECharts SIP proxies. The ECharts machine classes include a public getInstance() method to obtain an interface instance. The ECharts proxy class includes a similar public newInstance() method. See the ECharts for SIP Servlets javadocs for details on method parameters.
A Java-To-SIP interface class for an ECharts machine must abide by the following naming convention: if the ECharts machine is named org.echarts.servlet.sip.features.monitorControl.MonitorControlMachine then the interface class must be named org.echarts.servlet.sip.features.monitorControl.JavaToMonitorControlMachine.
When developing a Java-To-SIP interface class for a machine, the class should extend the JavaToEChartsMachine class in the org.echarts.servlet.sip package. The advantage of this is that the interface subclass will inherit a putEvent() method for logging events to the machine’s monitor. It will also inherit an init() method that will be called when a new interface instance is created. This provides an opportunity to intialize the instance with machine-specific field values. See the JavaToEChartsMachine javadocs for more details.
As discussed above, a feature’s SIP-To-Java interface must be implemented by the developer in order to customize it for its environment. By default, the framework attempts to use an interface implementation whose class name is related to the associated feature machine/proxy class name. For example, if the feature’s machine is org.echarts.servlet.sip.features.monitorControl.MonitorControlMachine, then the framework will look for a SIP-To-Java interface class named org.echarts.servlet.sip.features.monitorControl.MonitorControlMachineToJava. To specify that the framework use an implementation class with the non-default name, its fully qualified class name must be provided as the value of an init-param element of the associated servlet’s sip.xml file. See the EChartsMachineToJava and EChartsProxyServletToJava javadocs for more details.
When implementing a new feature with a SIP-To-Java interface, there is no need to include a default implementation of the interface with the feature. If the framework finds no implementation using the rules described above then it will dynamically create a default implementation of the interface that using Java’s java.lang.reflect.Proxy class. Any interface methods that define return values will return null values when called.
When implementing a SIP-To-Java interface the developer can choose for the implementation to extend the EChartsMachineToJava (or the EChartsProxyServletToJava) class. The advantage of extending the EChartsMachineToJava class is that the implementation will inherit a putEvent() method for logging events to the machine’s monitor (or the servlet’s monitor, for an ECharts proxy servlet).
As mentioned above in Section 9.4, extending the EChartsMachineToJava class also has the advantage of calling a publish() method for you when an EChartsMachineToJava instance is created. This is useful if your E4SS feature also defines a JavaToEChartsMachine interface.
Finally, another useful utility class for E4SS proxies or machines is the EChartsSipSession class. This class defines a static method that provides the caller with the SIP message associated with the calling thread. This method means that it is not necessary to include the SIP message as a parameter in SIP-To-Java interface methods. Another static method in this class provides the caller with the SIP request that initiated an E4SS application session. This is useful when an application receives more than one initial request in its lifetime.