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.
-
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.
-
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.
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 ) { ... }
}
}
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.
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:
-
createConnection(String,int,boolean) - Creates a new connection object from the given URI.
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() {}
}
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.
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.
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.
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
-
ConnectionFactory
- A Connection Factory service is called by the implementation of the Connector Service to createjavax.microedition.io.Connection
objects which implement the scheme named byIO_SCHEME
. -
ConnectorService
- The Connector Service should be called to create and openjavax.microedition.io.Connection
objects.
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.
Service property containing the scheme(s) for which this Connection
Factory can create Connection
objects. This property is of type
String[]
.
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.
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
.
Read/Write access mode.
javax.microedition.io.Connector.READ_WRITE
Write access mode.
javax.microedition.io.Connector.WRITE
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)
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)
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)
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)
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)
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)
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)
[1]Java 2 Micro Editionhttp://www.oracle.com/technetwork/java/javame/index.html
[2]J2ME Foundation Profilehttp://www.jcp.org/en/jsr/detailid=46