Versions Compared

Key

  • This line was added.
  • This line was removed.
  • Formatting was changed.
Comment: Migrated to Confluence 5.3

...

Example

...

8

...

-

...

Spell

...

Checker

...

Service

...

using

...

Service

...

Binder

...

[Note:

...

The

...

Service

...

Binder

...

was

...

the

...

original

...

project

...

to

...

attempt

...

to

...

automate

...

service

...

dependency

...

management

...

for

...

the

...

OSGi

...

platform

...

and

...

was

...

the

...

inspiration

...

for

...

Declarative

...

Services

...

introduced

...

in

...

OSGi

...

R4.

...

The

...

Service

...

Binder

...

is

...

no longer under

...

active

...

development,

...

but

...

this

...

example

...

is

...

kept

...

in

...

the

...

tutorial

...

for

...

historical

...

purposes.

...

New

...

projects

...

should

...

consider

...

using

...

one

...

of

...

the

...

other

...

dependency

...

injection

...

technologies

...

(e.g.,

...

Declarative

...

Services,

...

Dependency

...

Manager,

...

or

...

iPOJO).]

...

The

...

purpose

...

of

...

this

...

example

...

is

...

to

...

re-implement

...

the

...

spell

...

checker

...

service

...

in

...

Example

...

6,

...

but

...

to

...

do

...

so

...

using

...

the

...

Service

...

Binder;

...

to

...

complete

...

this,

...

we

...

must

...

download

...

the

...

Service

...

Binder

...

bundle.

...

The

...

Service

...

Binder

...

bundle

...

is

...

needed

...

to

...

compile

...

the

...

example

...

and

...

at

...

run

...

time

...

to

...

execute

...

the

...

example.

...

The

...

spell

...

checker

...

service

...

of

...

Example

...

6

...

was

...

complex

...

because

...

it

...

needed

...

to

...

aggregate

...

all

...

available

...

dictionary

...

services

...

and

...

monitor

...

their

...

dynamic

...

availability.

...

In

...

addition,

...

the

...

spell

...

checker

...

service's

...

own

...

availability

...

was

...

dependent

...

upon

...

the

...

availability

...

of

...

dictionary

...

services;

...

in

...

other

...

words,

...

the

...

spell

...

checker

...

service

...

had

...

a

...

dynamic,

...

one-to-many

...

dependency

...

on

...

dictionary

...

services.

...

As

...

it

...

turns

...

out,

...

service

...

dependencies

...

are

...

not

...

managed

...

at

...

all

...

by

...

the

...

OSGi

...

framework

...

and

...

end

...

up

...

being

...

the

...

responsibility

...

of

...

the

...

application

...

developer.

...

The

...

Service

...

Binder

...

tries

...

to

...

eliminate

...

complex

...

and

...

error-prone

...

service

...

dependency

...

handling

...

by

...

automating

...

it.

...

To

...

do

...

this,

...

the

...

Service

...

Binder

...

replaces

...

the

...

BundleActivator

...

code

...

with

...

a

...

generic

...

bundle

...

activator

...

that

...

parses

...

an

...

XML

...

file

...

that

...

describes

...

the

...

instances

...

we

...

want

...

to

...

create

...

and

...

their

...

service

...

dependencies.

...

Instead

...

of

...

writing

...

a

...

lot

...

of

...

complex

...

code,

...

we

...

simply

...

write

...

a

...

declarative

...

XML

...

file.

...

For

...

an

...

example,

...

consider

...

the

...

following

...

code

...

for

...

the

...

new

...

service's

...

bundle

...

activator

...

in

...

a

...

file

...

called

...

Activator.java

...

:

{
Code Block
}
/*
 * Apache Felix OSGi tutorial.
**/

package tutorial.example8;

import org.apache.felix.servicebinder.GenericActivator;

/**
 * This example re-implements the spell checker service of
 * Example 6 using the Service Binder. The Service Binder
 * greatly simplifies creating OSGi applications by
 * essentially eliminating the need to write OSGi-related
 * code; instead of writing OSGi code for your bundle, you
 * create a simple XML file to describe your bundle's service
 * dependencies. This class extends the generic bundle activator;
 * it does not provide any additional functionality. All
 * functionality for service-related tasks, such as look-up and
 * binding, is handled by the generic activator base class using
 * data from the metadata.xml file. All application
 * functionality is defined in the SpellCheckerImpl.java
 * file.
**/

public class Activator extends GenericActivator
{
}
{code}

All

...

custom

...

functionality

...

has

...

been

...

removed

...

from

...

the

...

bundle

...

activator,

...

it

...

is

...

only

...

necessary

...

to

...

subclass

...

the

...

generic

...

activator

...

exported

...

by

...

the

...

Service

...

Binder.

...

The

...

generic

...

activator

...

performs

...

its

...

task

...

by

...

parsing

...

an

...

XML

...

meta-data

...

file

...

that

...

describes

...

what

...

instances

...

should

...

be

...

created

...

and

...

what

...

their

...

service

...

dependencies

...

are;

...

for

...

our

...

example,

...

we

...

create

...

a

...

file

...

called

...

metadata.xml

...

that

...

contains

...

the

...

instance

...

and

...

service

...

dependency

...

meta-data:

{
No Format
}
<?xml version="1.0" encoding="UTF-8"?>
<bundle>
  <!--
    -- This meta-data file instructs the Service Binder to
    -- create one instance of "SpellCheckerImpl". It also
    -- tells the generic activator that this instance implements the
    -- "SpellChecker" service interface and that it has an
    -- aggregate dependency on "DictionaryService" services. Since
    -- the service dependency on dictionary services has a lower
    -- cardinality of one, the generic activator will create the instance
    -- and offer its spell checker service only when there is at least
    -- one dictionary service available. The service dependency is
    -- "dynamic", which means that dictionary service availability
    -- will be monitored dynamically at runtime and it also tells the
    -- generic activator which methods to call when adding and removing
    -- dictionary services.
    -->
  <instance class="tutorial.example8.SpellCheckerImpl">
    <service interface="tutorial.example6.service.SpellChecker"/>
    <requires
      service="tutorial.example2.service.DictionaryService"
      filter="(Language=*)"
      cardinality="1..n"
      policy="dynamic"
      bind-method="addDictionary"
      unbind-method="removeDictionary"
    />
  </instance>
</bundle>
{noformat}

The

...

above

...

meta-data

...

tells

...

the

...

generic

...

activator

...

to

...

create

...

one

...

instance

...

of

...

tutorial.example8.SpellCheckerImpl

...

,

...

which

...

we

...

will

...

define

...

next.

...

The

...

meta-data

...

also

...

tells

...

the

...

generic

...

activator

...

that

...

the

...

instance

...

has

...

an

...

aggregate

...

service

...

dependency

...

(in

...

this

...

case,

...

one-to-many)

...

on

...

dictionary

...

services

...

and

...

that

...

the

...

services

...

should

...

be

...

tracked

...

dynamically.

...

It

...

also

...

specifies

...

the

...

bind

...

and

...

unbind

...

methods

...

that

...

should

...

be

...

called

...

on

...

the

...

instance

...

when

...

dictionary

...

services

...

appear

...

and

...

disappear.

...

It

...

is

...

important

...

to

...

understand

...

that

...

the

...

generic

...

activator

...

is

...

constantly

...

trying

...

to

...

maintain

...

the

...

instances

...

defined

...

in

...

the

...

meta-data

...

file.

...

At

...

any

...

given

...

point

...

in

...

time,

...

a

...

specific

...

instance

...

may

...

be

...

valid

...

(if

...

all

...

service

...

dependencies

...

are

...

satisfied)

...

or

...

invalid

...

(if

...

any

...

service

...

dependencies

...

are

...

unsatisfied),

...

but

...

at

...

all

...

times

...

the

...

generic

...

activator

...

is

...

trying

...

to

...

get

...

the

...

declared

...

instances

...

into

...

a

...

valid

...

state.

...

The

...

code

...

for

...

our

...

new

...

spell

...

checker

...

service

...

is

...

very

...

similar

...

to

...

the

...

implementation

...

in

...

Example

...

6,

...

but

...

it

...

is

...

no

...

longer

...

implemented

...

as

...

an

...

inner

...

class

...

of

...

the

...

activator.

...

We

...

define

...

the

...

new

...

spell

...

checker

...

service

...

in

...

a

...

file

...

called

...

SpellCheckerImpl.java

...

as

...

follows:

{
Code Block
}
/*
 * Apache Felix OSGi tutorial.
**/

package tutorial.example8;

import java.io.BufferedReader;
import java.io.InputStreamReader;
import java.io.IOException;
import java.util.ArrayList;
import java.util.StringTokenizer;

import tutorial.example2.service.DictionaryService;
import tutorial.example6.service.SpellChecker;

/**
 * This class re-implements the spell checker service of Example 6.
 * This service implementation behaves exactly like the one in
 * Example 6, specifically, it aggregates all available dictionary
 * services, monitors their dynamic availability, and only offers
 * the spell checker service if there are dictionary services
 * available. The service implementation is greatly simplified,
 * though, by using the Service Binder. Notice that there is no OSGi
 * references in the application code; instead, the metadata.xml
 * file describes the service dependencies, which is read by the
 * Service Binder to automatically manage the dependencies and
 * register the spell checker service as appropriate.
**/
public class SpellCheckerImpl implements SpellChecker
{
    // List of service objects.
    private ArrayList m_svcObjList = new ArrayList();

    /**
     * This method is used by the Service Binder to add
     * new dictionaries to the spell checker service.
     * @param dictionary the dictionary to add to the spell
     *                   checker service.
    **/
    public void addDictionary(DictionaryService dictionary)
    {
        // Lock list and add service object.
        synchronized (m_svcObjList)
        {
            m_svcObjList.add(dictionary);
        }
    }

    /**
     * This method is used by the Service Binder to remove
     * dictionaries from the spell checker service.
     * @param dictionary the dictionary to remove from the spell
     *                   checker service.
    **/
    public void removeDictionary(DictionaryService dictionary)
    {
        // Lock list and remove service object.
        synchronized (m_svcObjList)
        {
            m_svcObjList.remove(dictionary);
        }
    }

    /**
     * Checks a given passage for spelling errors. A passage is any
     * number of words separated by a space and any of the following
     * punctuation marks: comma (,), period (.), exclamation mark (!),
     * question mark (?), semi-colon (;), and colon(:).
     * @param passage the passage to spell check.
     * @return An array of misspelled words or null if no
     *         words are misspelled.
    **/
    public String[] check(String passage)
    {
        // No misspelled words for an empty string.
        if ((passage == null) || (passage.length() == 0))
        {
            return null;
        }

        ArrayList errorList = new ArrayList();

        // Tokenize the passage using spaces and punctionation.
        StringTokenizer st = new StringTokenizer(passage, " ,.!?;:");

        // Lock the service list.
        synchronized (m_svcObjList)
        {
            // Loop through each word in the passage.
            while (st.hasMoreTokens())
            {
                String word = st.nextToken();

                boolean correct = false;

                // Check each available dictionary for the current word.
                for (int i = 0; (!correct) && (i < m_svcObjList.size()); i++)
                {
                    DictionaryService dictionary =
                        (DictionaryService) m_svcObjList.get(i);

                    if (dictionary.checkWord(word))
                    {
                        correct = true;
                    }
                }

                // If the word is not correct, then add it
                // to the incorrect word list.
                if (!correct)
                {
                    errorList.add(word);
                }
            }
        }

        // Return null if no words are incorrect.
        if (errorList.size() == 0)
        {
            return null;
        }

        // Return the array of incorrect words.
        return (String[]) errorList.toArray(new String[errorList.size()]);
    }
}

Notice

...

how

...

much

...

simpler

...

this

...

service

...

implementation

...

is

...

when

...

compared

...

to

...

the

...

same

...

service

...

implemented

...

in

...

Example

...

6.

...

There

...

are

...

no

...

references

...

to

...

OSGi

...

interfaces

...

in

...

our

...

application

...

code

...

and

...

all

...

tricky

...

and

...

complex

...

code

...

dealing

...

with

...

monitoring

...

of

...

services

...

is

...

handled

...

for

...

us.

...

We

...

must

...

still

...

create

...

a

...

manifest.mf

...

file

...

that

...

contains

...

the

...

meta-data

...

for

...

the

...

bundle;

...

the

...

manifest

...

file

...

is

...

as

...

follows:

{
No Format
}
Bundle-Activator: tutorial.example8.Activator
Import-Package: tutorial.example2.service, tutorial.example6.service,
 org.apache.felix.servicebinder
Bundle-Name: Service Binder Spell checker service
Bundle-Description: A bundle that implements a simple spell checker service
Bundle-Vendor: Apache Felix
Bundle-Version: 1.0.0
Metadata-Location: tutorial/example8/metadata.xml
{noformat}

We

...

specify

...

which

...

class

...

is

...

used

...

to

...

activate

...

the

...

bundle

...

via

...

the

...

Bundle-Activator

...

attribute

...

and

...

also

...

specify

...

that

...

the

...

bundle

...

imports

...

the

...

spell

...

checker,

...

dictionary,

...

and

...

Service

...

Binder packages. (Note: Make sure your manifest file ends in a trailing carriage return or else the last line will be ignored.)

To compile the source code, we must include the felix.jar file (found in Felix' lib directory), the servicebinder.jar file, the example2.jar file, and the example6.jar file in the class path. We compile the source file using a command like:

No Format
 packages.

To compile the source code, we must include the {{felix.jar}} file (found in Felix' {{lib}} directory), the servicebinder.jar file, the example2.jar file, and the example6.jar file in the class path. We compile the source file using a command like:

{noformat}
javac -d c:\classes *.java
{noformat}

This command compiles all source files and outputs the generated classes into a subdirectory of the {{

This command compiles all source files and outputs the generated classes into a subdirectory of the c:\classes

...

directory;

...

this

...

subdirectory

...

is

...

tutorial\example8

...

,

...

named

...

after

...

the

...

package

...

we

...

specified

...

in

...

the

...

source

...

file.

...

For

...

the

...

above

...

command

...

to

...

work,

...

the

...

c:\classes

...

directory

...

must

...

exist.

...

Before

...

we

...

can

...

create

...

our

...

bundle

...

JAR

...

file,

...

we

...

must

...

copy

...

the

...

bundle's

...

service

...

dependency

...

meta-data

...

file,

...

called

...

metadata.xml

...

above,

...

into

...

the

...

example

...

class'

...

package.

...

Assuming

...

that

...

we

...

used

...

the

...

above

...

command

...

to

...

compile

...

the

...

bundle,

...

then

...

we

...

should

...

copy

...

the

...

metadata.xml

...

file

...

into

...

c:\classes\tutorial\example8

...

.

...

Now

...

we

...

can

...

create

...

the

...

JAR

...

file

...

for

...

our

...

bundle

...

using

...

the

...

following

...

command:

{
No Format
}
jar cfm example8.jar manifest.mf -C c:\classes tutorial\example8
{noformat}

This

...

command

...

creates

...

a

...

JAR

...

file

...

using

...

the

...

manifest

...

file

...

we

...

created

...

and

...

includes

...

all

...

of

...

the

...

classes

...

and

...

resources

...

in

...

the

...

tutorial\example8

...

directory

...

inside

...

of

...

the

...

c:\classes

...

directory.

...

Once

...

the

...

JAR

...

file

...

is

...

created,

...

we

...

are

...

ready

...

to

...

install

...

and

...

start

...

the

...

bundle.

...

To

...

run

...

Felix,

...

we

...

follow

...

the

...

instructions

...

described

...

in

...

usage.html.

...

When

...

we

...

start

...

Felix,

...

it

...

asks

...

for

...

a

...

profile

...

name,

...

we

...

will

...

put

...

all

...

of

...

our

...

bundles

...

in

...

a

...

profile

...

named

...

tutorial

...

.

...

After

...

running

...

Felix,

...

we

...

should

...

stop

...

all

...

tutorial

...

bundles

...

except

...

for

...

the

...

service

...

bundles.

...

Use the lb command to make sure that only the bundles from Example 2 and Example 2b are active; use the start and stop commands as appropriate to start and stop the various tutorial bundles, respectively. (Note: Felix uses some bundles to provide its command shell, so do not stop these bundles.) We must also install the servicebinder.jar bundle that we downloaded at the beginning of this example. Assuming that we saved the bundle in our tutorial directory, we install the bundle using the following command:

No Format
 the {{ps}} command to make sure that only the bundles from Example 2 and Example 2b are active; use the {{start}} and {{stop}} commands as appropriate to start and stop the various tutorial bundles, respectively. (Note: Felix uses some bundles to provide its command shell, so do not stop these bundles.) We must also install the {{servicebinder.jar}} bundle that we downloaded at the beginning of this example. Assuming that we saved the bundle in our tutorial directory, we install the bundle using the following command:

{noformat}
install file:/c:/tutorial/servicebinder.jar
{noformat}

We

...

do

...

not

...

need

...

to

...

start

...

the

...

Service

...

Binder

...

bundle,

...

because

...

it

...

is

...

only

...

a

...

library.

...

Now

...

we

...

can

...

install

...

and

...

start

...

our

...

spell

...

checker

...

service

...

bundle.

...

Assuming

...

that

...

we

...

created

...

our

...

bundle

...

in

...

the

...

directory

...

c:\tutorial

...

,

...

we

...

can

...

install

...

and

...

start

...

it

...

in

...

Felix'

...

shell

...

using

...

the

...

following

...

command:

{
No Format
}
start file:/c:/tutorial/example8.jar
{noformat}

The

...

above

...

command

...

installs

...

and

...

starts

...

the

...

bundle

...

in

...

a

...

single

...

step;

...

it

...

is

...

also

...

possible

...

to

...

install

...

and

...

start

...

the

...

bundle

...

in

...

two

...

steps

...

by

...

using

...

the

...

Felix

...

install

...

and

...

start

...

shell

...

commands.

...

To

...

stop

...

the

...

bundle,

...

use

...

the

...

Felix

...

stop

...

shell

...

command.

...

Use

...

the

...

Felix

...

shell lb command to get the bundle identifier number for the spell checker service bundle to stop and restart it at will using the stop and start commands, respectively. Using the services command, we can see which services are currently available in the OSGi framework, including our dictionary and spell checker services. We can experiment with our spell checker service's dynamic availability by stopping the dictionary service bundles; when both dictionary services are stopped, the services command will reveal that our bundle is no longer offering its spell checker service. Likewise, when the dictionary services comeback, so will our spell checker service. This bundle will work with the spell checker client bundle that we created in Example 7, so feel free to experiment. To exit Felix, use the shutdown command.

[Note: The spell checker client bundle in Example 7 could also be re-implemented using the Service Binder approach outlined in this example. The spell checker client has a one-to-one, dynamic service dependency on the spell checker service. Further, an entire application of instances could be described in a single metadata.xml in a single bundle or across a collection of bundles and the Service Binder will automatically manage the service dependencies among them.]