APAM/APAM versus OSGi

From Wiki Adele Team
< APAM
Revision as of 07:47, 16 October 2012 by Jander (talk | contribs)

Jump to: navigation, search

Overview

OSGi and APAM are both platforms for service oriented java applications, but their similarities end up there. The way of implementing, using and naming are done differently, so you should pay attention to those details so you don't mess up the informations on your mind. If you need more informations about how OSGi works, you should check here and here. For APAM information and updates you can check here.

Contrast Example

In order to give you a good contrast between OSGi and APAM and pin point the changes, we will pickup an example availablehere and convert it to APAM, doing so we should be able to see the difference between those two frameworks more clearly with hands on it. This example is implemented by, and for, OSGi. It is called spellchecker, at this point we will work in the Example7.

For better understanding it is important to define the concept of what a 'service' mean to us. On real life Service is something that you need but do not know how to do it yourself (generally), for that you look for someone that can provide this service for you. In software, the concept is pretty much the same: a service is when you need something to be done, but you do not know how it is done neither who can do it, and sometimes neither who to ask it for.

When you ask for a service you do not care about the details, you just want things to be done [figure] no matter who or how its done, that is where APAM acts. So, keep that in mind : service is something we want but we do not know where to find or how it is done. Now, we can continue with the spellchecker example explanation.

How would it be in real life?

In order to implement the spell checker, it needs someone to tell him what is right and wrong, the spell checker only know the setence to be verified. In order to verify this information it uses a dictionary service, verifying if one word of the sentence exists in a dictionary. Thus, the dictionary provides a complete set of the valid words.

An user story of the spellchecker application: someone enters the sentence «APAM is awsome! «  in a client application, this application sends the informations to a service (the spellchecker) and the user of the client application should be aware of which word do not exist in a dictionary, at this point we do not care about which dictionary we are talking about, can be any – english, french, etc.

Spellchecker example highlevel dependency diagram

As we can see, the client application does not know anything about the spellchecker, he only knows an interface that has one signature that gives him the hability to spell check one sentence. The client application have no idea how instantiate it or even if its available. After sending the information to the service, the service should point us out which word is incorrect.

The code

Example 3

Enough of talking, lets take a look on the osgi client application code:

public class Activator implements BundleActivator
{
    public void start(BundleContext context) throws Exception
    {
        // Query for all service references matching any language.
        ServiceReference[] refs = context.getServiceReferences(
            DictionaryService.class.getName(), "(Language=*)");

        if (refs != null)
        {
            try
            {
                System.out.println("Enter a blank line to exit.");
                BufferedReader in = new BufferedReader(new InputStreamReader(System.in));
                String word = "";

                // Loop endlessly.
                while (true)
                {
                    // Ask the user to enter a word.
                    System.out.print("Enter word: ");
                    word = in.readLine();

                    // If the user entered a blank line, then
                    // exit the loop.
                    if (word.length() == 0)
                    {
                        break;
                    }

                    // First, get a dictionary service and then check
                    // if the word is correct.
                    DictionaryService dictionary =
                        (DictionaryService) context.getService(refs[0]);
                    if (dictionary.checkWord(word))
                    {
                        System.out.println("Correct.");
                    }
                    else
                    {
                        System.out.println("Incorrect.");
                    }

                    // Unget the dictionary service.
                    context.ungetService(refs[0]);
                }
            } catch (IOException ex) { }
        }
        else
        {
            System.out.println("Couldn't find any dictionary service...");
        }
    }

    /**
     * Implements BundleActivator.stop(). Does nothing since
     * the framework will automatically unget any used services.
     * @param context the framework context for the bundle.
    **/
    public void stop(BundleContext context)
    {
        // NOTE: The service is automatically released.
    }
}

After adapting this code to ApAM it would look like this:

public class Activator 
{
    private DictionaryService dictionary;
    public void start() throws Exception
    {

            try
            {
                System.out.println("Enter a blank line to exit.");
                BufferedReader in = new BufferedReader(new InputStreamReader(System.in));
                String word = "";

                // Loop endlessly.
                while (true)
                {
                    // Ask the user to enter a word.
                    System.out.print("Enter word: ");
                    word = in.readLine();

                    // If the user entered a blank line, then
                    // exit the loop.
                    if (word.length() == 0)
                    {
                        break;
                    }
                    // First, get a dictionary service and then check
                    // if the word is correct.
                    if (dictionary.checkWord(word))
                    {
                        System.out.println("Correct.");
                    }
                    else
                    {
                        System.out.println("Incorrect.");
                    }
                }
            } catch (IOException ex) { }       
    }
}

And this is the diff or those two implementations:


Vimdiff of the files

 1 +--  6 lignes : *
 7  * listen for the arrival or departure of dictionary services).
 8  * When starting this bundle, the thread calling the start()
 9  * method is used to read words from standard input. You can
10  * stop checking words by entering an empty line, but to start
11  * checking words again you must stop and then restart the bundle.
12 **/
13 public class Activator implements BundleActivator
14 {
   ------
   ------
   ------
15     /**
16      * Implements BundleActivator.start(). Queries for
17      * all available dictionary services. If none are found it
18      * simply prints a message and returns, otherwise it reads
19      * words from standard input and checks for their existence
20      * from the first dictionary that it finds.
21      * (NOTE: It is very bad practice to use the calling thread
22      * to perform a lengthy process like this; this is only done
23      * for the purpose of the tutorial.)
24      * @param context the framework context for the bundle.
25     **/
26     public void start(BundleContext context) throws Exception
27     {
28         // Query for all service references matching any language.
29         ServiceReference[] refs = context.getServiceReferences(
30             DictionaryService.class.getName(), "(Language=*)");
31
32         if (refs != null)
33         {
34             try
35             {
36                 System.out.println("Enter a blank line to exit.");
37                 BufferedReader in = new BufferedReader(new InputStreamReader(System.in));
38                 String word = "";
39
40 +-- 10 lignes : Loop endlessly.
50                     {
51                         break;
52                     }
53
54                     // First, get a dictionary service and then check
55                     // if the word is correct.
56                     DictionaryService dictionary =
57                         (DictionaryService) context.getService(refs[0]);
58                     if (dictionary.checkWord(word))
59                     {
60                         System.out.println("Correct.");
61                     }
62                     else
63                     {
64                         System.out.println("Incorrect.");
65                     }
66
67                     // Unget the dictionary service.
68                     context.ungetService(refs[0]);
69                 }
70             } catch (IOException ex) { }
71         }
72         else
73         {
74             System.out.println("Couldn't find any dictionary service...");
75         }
76     }
77
78     /**
79      * Implements BundleActivator.stop(). Does nothing since
80      * the framework will automatically unget any used services.
81      * @param context the framework context for the bundle.
82     **/
83     public void stop(BundleContext context)
84     {
85         // NOTE: The service is automatically released.
86     }
87 }

As we can see, apam simplified a little more the way of using services, by :

  1. Removing the implementation of BundleActivator interface, avoiding adding dummie implementation that we are not always aware of what to put inside
  2. Avoid acquiring manually the existing services
  3. Avoid handling manually our own state based on other service availability
  4. Avoid manual releasing of the service

So the only thing we need to do is to declare a class attribute (which is an interface – just the contract of a class without the know how to implement the task), the APAM handles the laborious task of finding someone who implements this contract and attachs an instance in your class attribute during runtime.

But this is not exactly where the magic happens, under the hood (on the service implementation) is where APAM becomes an eyecandy.

Let's put aside for a moment the client perspective, and work a little as a provider by implementing the Dictionary service for instance. In the website this refers to the Example 2. Below we can see the difference between the OSGi and APAM service implementation more clearly.

[show diff file of the code]

Here you can see we removed part of the old code, mainly :

  1. Avoiding implementing dummie methods
  2. Removing code for service initialization (bundle activator implementation)

The killer application is not the simplification of OSGi code, but we are going to see further more details of what can be done with APAM.

Example 6

Try for yourself

If you wanna try yourself, you can download the APAM-Runtime and install the generated bundle


Or if you wanna check the code and make the changes yourself, you can download the adapted example from [here]. The requirement to compile and run this example you should have :

  • java develoment toolkit (equal or superior to the version 1.5)
  • maven (version 3)