109 IO Connector Service Specification

109.1 Introduction

Communication is at the heart of OSGi Framework functionality. Therefore, a flexible and extendable communication API is needed: one that can handle all the complications that arise out of the Reference Architecture. These obstacles could include different communication protocols based on different networks, firewalls, intermittent connectivity, and others.

Therefore, this IO Connector Service specification adopts the [1] Java 2 Micro Edition (J2ME) javax.microedition.io packages as a basic communications infrastructure. In J2ME, this API is also called the Connector framework. A key aspect of this framework is that the connection is configured by a single string, the URI.

In J2ME, the Connector framework can be extended by the vendor of the Virtual Machine, but cannot be extended at run-time by other code. Therefore, this specification defines a service that adopts the flexible model of the Connector framework, but allows bundles to extend the Connector Services into different communication domains.

109.1.1 Essentials

  • Abstract - Provide an intermediate layer that abstracts the actual protocol and devices from the bundle using it.

  • Extendable - Allow third-party bundles to extend the system with new protocols and devices.

  • Layered - Allow a protocol to be layered on top of lower layer protocols or devices.

  • Configurable - Allow the selection of an actual protocol/device by means of configuration data.

  • Compatibility - Be compatible with existing standards.

109.1.2 Entities

  • Connector Service - The service that performs the same function, creating connections from different providers, as the static methods in the Connector framework of javax.microediton.io.

  • Connection Factory - A service that extends the Connector service with more schemes.

  • Scheme - A protocol or device that is supported in the Connector framework.

Figure 109.1 Class Diagram, org.osgi.service.io (jmi is javax.microedition.io)

Class Diagram, org.osgi.service.io (jmi is javax.microedition.io)

109.2 The Connector Framework

The [1] Java 2 Micro Edition specification introduces a package for communicating with back-end systems. The requirements for this package are very similar to the following OSGi requirements:

  • Small footprint

  • Allows many different implementations simultaneously

  • Simple to use

  • Simple configuration

The key design goal of the Connector framework is to allow an application to use a communication mechanism/protocol without understanding implementation details.

An application passes a Uniform Resource Identifier (URI) to the java.microedition.io.Connector class, and receives an object implementing one or more Connection interfaces. The java.microedition.io.Connector class uses the scheme in the URI to locate the appropriate Connection Factory service. The remainder of the URI may contain parameters that are used by the Connection Factory service to establish the connection; for example, they may contain the baud rate for a serial connection. Some examples:

  • sms://+46705950899;expiry=24h;reply=yes;type=9

  • datagram://:53

  • socket://www.acme.com:5302

  • comm://COM1;baudrate=9600;databits=9

  • file:c:/autoexec.bat

The javax.microedition.io API itself does not prescribe any schemes. It is up to the implementer of this package to include a number of extensions that provide the schemes. The javax.microedition.io.Connector class dispatches a request to a class which provides an implementation of a Connection interface. J2ME does not specify how this dispatching takes place, but implementations usually offer a proprietary mechanism to connect user defined classes that can provide new schemes.

The Connector framework defines a taxonomy of communication mechanisms with a number of interfaces. For example, a javax.microedition.io.InputConnection interface indicates that the connection supports the input stream semantics, such as an I/O port. A javax.microedition.io.DatagramConnection interface indicates that communication should take place with messages.

When a javax.microedition.io.Connector.open method is called, it returns a javax.microedition.io.Connection object. The interfaces implemented by this object define the type of the communication session. The following interfaces may be implemented:

  • HttpConnection - A javax.microedition.io.ContentConnection with specific HTTP support.

  • DatagramConnection - A connection that can be used to send and receive datagrams.

  • OutputConnection - A connection that can be used for streaming output.

  • InputConnection - A connection that can be used for streaming input.

  • StreamConnection - A connection that is both input and output.

  • StreamConnectionNotifier - Can be used to wait for incoming stream connection requests.

  • ContentConnection - A javax.microedition.io.StreamConnection that provides information about the type, encoding, and length of the information.

Bundles using this approach must indicate to the Operator what kind of interfaces they expect to receive. The operator must then configure the bundle with a URI that contains the scheme and appropriate options that match the bundle's expectations. Well-written bundles are flexible enough to communicate with any of the types of javax.microedition.io.Connection interfaces they have specified. For example, a bundle should support javax.microedition.io. StreamConnection as well as javax.microedition.io. DatagramConnection objects in the appropriate direction ( input or output).

The following code example shows a bundle that sends an alarm message with the help of the javax.microedition.io.Connector framework:

public class Alarm {
    String uri;
    public Alarm(String uri) { this.uri = uri; }
    private void send(byte[] msg) {
        while ( true ) try {
            Connection  connection = Connector.open( uri );
            DataOutputStream    dout = null;
        if ( connection instanceof OutputConnection ) {
                dout = ((OutputConnection)
                    connection).openDataOutputStream();
          dout.write( msg );
        }
        else if (connection instanceof DatagramConnection){
                DatagramConnection dgc = 
                    (DatagramConnection) connection;
          Datagram datagram = dgc.newDatagram( 
                    msg, msg.length );
          dgc.send( datagram );
        } else {
            error( "No configuration for alarm" );
            return;
        }
        connection.close();
      } catch( Exception e ) { ... }
   }
}

109.3 Connector Service

The javax.microedition.io.Connector framework matches the requirements for OSGi applications very well. The actual creation of connections, however, is handled through static methods in the javax.microedition.io.Connector class. This approach does not mesh well with the OSGi service registry and dynamic life-cycle management.

This specification therefore introduces the Connector Service. The methods of the ConnectorService interface have the same signatures as the static methods of the javax.microedition.io.Connector class.

Each javax.microedition.io.Connection object returned by a Connector Service must implement interfaces from the javax.microedition.io package. Implementations must strictly follow the semantics that are associated with these interfaces.

The Connector Service must provide all the schemes provided by the exporter of the javax.microedition.io package. The Connection Factory services must have priority over schemes implemented in the Java run-time environment. For example, if a Connection Factory provides the http scheme and a built-in implementation exists, then the Connector Service must use the Connection Factory service with the http scheme.

Bundles that want to use the Connector Service should first obtain a ConnectorService service object. This object contains open methods that should be called to get a new javax.microedition.io.Connection object.

109.4 Providing New Schemes

The Connector Service must be able to be extended with the Connection Factory service. Bundles that can provide new schemes must register a ConnectionFactory service object.

The Connector Service must listen for registrations of new ConnectionFactory service objects and make the supplied schemes available to bundles that create connections.

Implementing a Connection Factory service requires implementing the following method:

The Connection Factory service must be registered with the IO_SCHEME property to indicate the provided scheme to the Connector Service. The value of this property must be a String[].

If multiple Connection Factory services register with the same scheme, the Connector Service should select the Connection Factory service with the highest value for the service.ranking service registration property, or if more than one Connection Factory service has the highest value, the Connection Factory service with the lowest service.id is selected.

The following example shows how a Connection Factory service may be implemented. The example will return a javax.microedition.io.InputConnection object that returns the value of the URI after removing the scheme identifier.

public class ConnectionFactoryImpl 
    implements BundleActivator, ConnectionFactory {
        public void start( BundleContext context ) {
            Hashtable properties = new Hashtable();
            properties.put( IO_SCHEME, new String[]{"data"} );
            context.registerService(
                ConnectorService.class.getName(), 
                this, properties );
        }
        public void stop( BundleContext context ) {}

        public Connection createConnection( 
            String uri, int mode, boolean timeouts  ) {
            return new DataConnection(uri); 
        }
}

class DataConnection 
    implements javax.microedition.io.InputConnection {
    String uri;
    DataConnection( String uri ) {this.uri = uri;}
    public DataInputStream openDataInputStream() 
        throws IOException {
        return new DataInputStream( openInputStream() );
    }

    public InputStream openInputStream() throws IOException {
        byte [] buf = uri.getBytes();
        return new ByteArrayInputStream(buf,5,buf.length-5);
    }
    public void close() {}
}

109.4.1 Orphaned Connection Objects

When a Connection Factory service is unregistered, it must close all Connection objects that are still open. Closing these Connection objects should make these objects unusable, and they should subsequently throw an IOException when used.

Bundles should not unnecessarily hang onto objects they retrieved from services. Implementations of Connection Factory services should program defensively and ensure that resource allocation is minimized when a Connection object is closed.

109.5 Execution Environment

The javax.microedition.io package is available in J2ME configurations/profiles, but is not present in J2SE, J2EE, and the OSGi minimum execution requirements.

Implementations of the Connector Service that are targeted for all environments should carry their own implementation of the javax.microedition.io package and export it.

109.6 Security

The OSGi Connector Service is a key service available in the Framework. A malicious bundle which provides this service can spoof any communication. Therefore, it is paramount that the ServicePermission[ConnectorService, REGISTER] is given only to a trusted bundle. ServicePermission[ConnectorService,GET] may be handed to bundles that are allowed to communicate to the external world.

ServicePermission[ConnectionFactory, REGISTER] should also be restricted to trusted bundles because they can implement specific protocols or access devices. ServicePermission[ConnectionFactory,GET] should be limited to trusted bundles that implement the Connector Service.

Implementations of Connection Factory services must perform all I/O operations within a privileged region. For example, an implementation of the sms: scheme must have permission to access the mobile phone, and should not require the bundle that opened the connection to have this permission. Normally, the operations need to be implemented in a doPrivileged method or in a separate thread.

If a specific Connection Factory service needs more detailed permissions than provided by the OSGi or Java 2, it may create a new specific Permission sub-class for its purpose.

109.7 org.osgi.service.io

Version 1.0

IO Connector Package Version 1.0.

Bundles wishing to use this package must list the package in the Import-Package header of the bundle's manifest. This package has two types of users: the consumers that use the API in this package and the providers that implement the API in this package.

Example import for consumers using the API in this package:

Import-Package: org.osgi.service.io; version="[1.0,2.0)", javax.microedition.io

Example import for providers implementing the API in this package:

Import-Package: org.osgi.service.io; version="[1.0,1.1)", javax.microedition.io

109.7.1 Summary

  • ConnectionFactory - A Connection Factory service is called by the implementation of the Connector Service to create javax.microedition.io.Connection objects which implement the scheme named by IO_SCHEME.

  • ConnectorService - The Connector Service should be called to create and open javax.microedition.io.Connection objects.

109.7.2 public interface ConnectionFactory

A Connection Factory service is called by the implementation of the Connector Service to create javax.microedition.io.Connection objects which implement the scheme named by IO_SCHEME. When a ConnectorService.open method is called, the implementation of the Connector Service will examine the specified name for a scheme. The Connector Service will then look for a Connection Factory service which is registered with the service property IO_SCHEME which matches the scheme. The createConnection(String, int, boolean) method of the selected Connection Factory will then be called to create the actual Connection object.

109.7.2.1 public static final String IO_SCHEME = "io.scheme"

Service property containing the scheme(s) for which this Connection Factory can create Connection objects. This property is of type String[].

109.7.2.2 public Connection createConnection(String name, int mode, boolean timeouts) throws IOException

The full URI passed to the ConnectorService.open method

The mode parameter passed to the ConnectorService.open method

The timeouts parameter passed to the ConnectorService.open method

Create a new Connection object for the specified URI.

A new javax.microedition.io.Connection object.

IOException– If a javax.microedition.io.Connection object cannot be created.

109.7.3 public interface ConnectorService

The Connector Service should be called to create and open javax.microedition.io.Connection objects. When an open* method is called, the implementation of the Connector Service will examine the specified name for a scheme. The Connector Service will then look for a Connection Factory service which is registered with the service property IO_SCHEME which matches the scheme. The createConnection method of the selected Connection Factory will then be called to create the actual Connection object.

If more than one Connection Factory service is registered for a particular scheme, the service with the highest ranking (as specified in its service.ranking property) is called. If there is a tie in ranking, the service with the lowest service ID (as specified in its service.id property), that is the service that was registered first, is called. This is the same algorithm used by BundleContext.getServiceReference.

109.7.3.1 public static final int READ = 1

Read access mode.

javax.microedition.io.Connector.READ

109.7.3.2 public static final int READ_WRITE = 3

Read/Write access mode.

javax.microedition.io.Connector.READ_WRITE

109.7.3.3 public static final int WRITE = 2

Write access mode.

javax.microedition.io.Connector.WRITE

109.7.3.4 public Connection open(String name) throws IOException

The URI for the connection.

Create and open a Connection object for the specified name.

A new javax.microedition.io.Connection object.

IllegalArgumentException– If a parameter is invalid.

javax.microedition.io.ConnectionNotFoundException– If the connection cannot be found.

IOException– If some other kind of I/O error occurs.

javax.microedition.io.Connector.open(String name)

109.7.3.5 public Connection open(String name, int mode) throws IOException

The URI for the connection.

The access mode.

Create and open a Connection object for the specified name and access mode.

A new javax.microedition.io.Connection object.

IllegalArgumentException– If a parameter is invalid.

javax.microedition.io.ConnectionNotFoundException– If the connection cannot be found.

IOException– If some other kind of I/O error occurs.

javax.microedition.io.Connector.open(String name, int mode)

109.7.3.6 public Connection open(String name, int mode, boolean timeouts) throws IOException

The URI for the connection.

The access mode.

A flag to indicate that the caller wants timeout exceptions.

Create and open a Connection object for the specified name, access mode and timeouts.

A new javax.microedition.io.Connection object.

IllegalArgumentException– If a parameter is invalid.

javax.microedition.io.ConnectionNotFoundException– If the connection cannot be found.

IOException– If some other kind of I/O error occurs.

javax.microedition.io.Connector.open(String name, int mode, boolean timeouts)

109.7.3.7 public DataInputStream openDataInputStream(String name) throws IOException

The URI for the connection.

Create and open a DataInputStream object for the specified name.

A DataInputStream object.

IllegalArgumentException– If a parameter is invalid.

javax.microedition.io.ConnectionNotFoundException– If the connection cannot be found.

IOException– If some other kind of I/O error occurs.

javax.microedition.io.Connector.openDataInputStream(String name)

109.7.3.8 public DataOutputStream openDataOutputStream(String name) throws IOException

The URI for the connection.

Create and open a DataOutputStream object for the specified name.

A DataOutputStream object.

IllegalArgumentException– If a parameter is invalid.

javax.microedition.io.ConnectionNotFoundException– If the connection cannot be found.

IOException– If some other kind of I/O error occurs.

javax.microedition.io.Connector.openDataOutputStream(String name)

109.7.3.9 public InputStream openInputStream(String name) throws IOException

The URI for the connection.

Create and open an InputStream object for the specified name.

An InputStream object.

IllegalArgumentException– If a parameter is invalid.

javax.microedition.io.ConnectionNotFoundException– If the connection cannot be found.

IOException– If some other kind of I/O error occurs.

javax.microedition.io.Connector.openInputStream(String name)

109.7.3.10 public OutputStream openOutputStream(String name) throws IOException

The URI for the connection.

Create and open an OutputStream object for the specified name.

An OutputStream object.

IllegalArgumentException– If a parameter is invalid.

javax.microedition.io.ConnectionNotFoundException– If the connection cannot be found.

IOException– If some other kind of I/O error occurs.

javax.microedition.io.Connector.openOutputStream(String name)

109.8 References