Skip to content
Thibaud Flury edited this page Aug 20, 2013 · 3 revisions
Tutorial Level Goals Prerequisites
Beginners
  • Properties
  • Property injection
  • Substitution

This tutorial introduces the properties. You will also create a small application composed by several ApAM Components.

Table of Contents

Step 1. The SpellDico Specification Component

This component provide a very simple service defined with this interface (SpellDico.java) :

package fr.imag.adele.apam.tutorials.spell.dico.spec;

public interface SpellDico {

	/**
	 * @param word
	 * @return true if word is defined in the dictionary
	 */
	public boolean check(String word);
}
More interesting, using the ApAM descriptor we can define a property for this component (metadata.xml) :
<apam xmlns="fr.imag.adele.apam" xmlns:ipojo="org.apache.felix.ipojo"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" 
 xsi:schemaLocation="fr.imag.adele.apam http://repository-apam.forge.cloudbees.com/release/schema/ApamCore.xsd" >    

	<specification name="SpellDico" 
	   interfaces="fr.imag.adele.apam.tutorials.spell.dico.spec.SpellDico">
 	   <definition name="Language" type="French, English, German, Italian" />
	</specification>
</apam>
This definition describe a property whose name is "Language" and whose value can be French or English or German or Italian.
In this case we have an enumeration of predefined string values, but we can also define type="int" or type="string" or even an array using type="{int}" type="{string}"...

Step 2. SpellDicoFr, an Implementation Component

As an example we have a very simple implementation of the service (SpellDicoFr.java) : (Feel free to implement more complex dictionaries, or other languages)

package fr.imag.adele.apam.tutorials.spell.dico.impl;

import java.util.HashSet;
import java.util.Set;
import fr.imag.adele.apam.tutorials.spell.dico.spec.SpellDico;

public class SpellDicoFr implements SpellDico{
	
	private Set<String> FrenchDictionary;
	
	public SpellDicoFr() {
		FrenchDictionary = new HashSet<String>();
		// Adding a few words for testing purpose
		FrenchDictionary.add("le");
		FrenchDictionary.add("petit");
		FrenchDictionary.add("chat");
		FrenchDictionary.add("est");
		FrenchDictionary.add("mort");
	}
	
	/**
	 * @param word is supposed to be a word in french
	 * @return true if word is defined in the dictionary
	 */
	public boolean check(String word) {
		return FrenchDictionary.contains(word);
	}	
}

In the descriptor for this component, we will define the property corresponding to the specification (metadata.xml) :

<apam xmlns="fr.imag.adele.apam" xmlns:ipojo="org.apache.felix.ipojo"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" 
 xsi:schemaLocation="fr.imag.adele.apam http://repository-apam.forge.cloudbees.com/release/schema/ApamCore.xsd" >    
	
	<implementation name="SpellDicoFr" 
	      specification="SpellDico"      
	      classname="fr.imag.adele.apam.tutorials.spell.dico.impl.SpellDicoFr">
	   <property name="Language" value="French" />
	</implementation>
</apam>
Please notice that we do not need callback function for this one. But the property value MUST be valid according to the type.

Step 3. SpellChecker

Within the same OSGi bundle, we can also package several ApAM Components, in this case the SpellChecker Specification and the SpellChecker Implementation.

The java interface is defined as follow (SpellChecker.java) :

package fr.imag.adele.apam.tutorials.spell.checker;

public interface SpellChecker {
	
	/**
	 * @param passage is a sentence (sequence of words)
	 * @return An array of String, each String is a word that haven't been recognized
	 */
	public String[] check(String passage);
}
And its implementation (SimpleSpellChecker.java) :
package fr.imag.adele.apam.tutorials.spell.checker;

import java.util.HashSet;
import java.util.Set;
import java.util.StringTokenizer;
import fr.imag.adele.apam.tutorials.spell.dico.spec.SpellDico;

public class SimpleSpellChecker implements SpellChecker {
	
	private SpellDico dictionnaryProvider ;

	/* (non-Javadoc)
	 * @see fr.imag.adele.apam.tutorials.spell.checker.SpellChecker#check(java.lang.String)
	 */
	public String[] check(String passage) {
		if ((passage == null) || (passage.length() == 0))
			return null;
		Set<String> errorList = new HashSet<String>(); 
	     
		StringTokenizer st = new StringTokenizer(passage, " ,.!?;:"); 
	    while (st.hasMoreTokens()) {
	    	String word = st.nextToken();
	    	if (!dictionnaryProvider.check(word))
	    		errorList.add(word);
	    }
	    
	    return errorList.toArray(new String[0]);
	}
}

We can now describe the components within the same ApAM descriptor (metadata.xml) :

<apam xmlns="fr.imag.adele.apam" xmlns:ipojo="org.apache.felix.ipojo"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" 
 xsi:schemaLocation="fr.imag.adele.apam http://repository-apam.forge.cloudbees.com/release/schema/ApamCore.xsd" >    

	<specification name="SpellChecker" 
	   interfaces="fr.imag.adele.apam.tutorials.spell.checker.SpellChecker">
	    <dependency specification="SpellDico" name="dico"/>	   
	</specification>
	
	<implementation name="SimpleSpellChecker" 
	      specification="SpellChecker"      
	      classname="fr.imag.adele.apam.tutorials.spell.checker.SimpleSpellChecker">
	   <dependency name="dico" specification="SpellDico" field="dictionnaryProvider" />
	</implementation>
</apam>
You may notice that the dependency defined in the specification AND injected in the implementation.

Step 4. SpellChecker

The java implementation is pretty simple (SpellGUIFrame.java) :

package fr.imag.adele.apam.tutorials.spell.gui;

import java.awt.Font;
import java.awt.event.ActionListener;

import fr.imag.adele.apam.tutorials.spell.checker.SpellChecker;

public class SpellGUIFrame implements ActionListener{
	
    private javax.swing.JFrame         frame;
    private javax.swing.JTextArea     textAreaEnter;
    private javax.swing.JLabel     textAreaReturn;    
    private javax.swing.JButton        checkBtn;
    private String name ="APAM Spell Checker Tutorial";
    
    private SpellChecker spellCheckerServiceProvider;
    private String currentLanguage;

    public void start() {
    	System.out.println("SpellGUIFrame Service Started");
        frame = new javax.swing.JFrame(name);
        initComponents();
        frame.setVisible(true);
    }

    public void stop() {
    	System.out.println("SpellGUIFrame Service Stopped");

        if (frame != null) {
            frame.dispose();
            frame = null;
        }
    }

    private void initComponents() {
        frame.setSize(600, 200);
        textAreaEnter = new javax.swing.JTextArea("Enter your passage here...",5,100);
        textAreaEnter.setFont(new Font("Serif", Font.ITALIC, 16));
        textAreaReturn = new javax.swing.JLabel(" | No results for the moment !");
        
        checkBtn = new javax.swing.JButton("Check Text !");
        
        checkBtn.addActionListener(this);
        frame.setLayout(new java.awt.BorderLayout());
        frame.add(textAreaEnter, java.awt.BorderLayout.NORTH);
        frame.add(checkBtn, java.awt.BorderLayout.CENTER);
        frame.add(textAreaReturn, java.awt.BorderLayout.SOUTH);
    }
    
    public void actionPerformed(java.awt.event.ActionEvent e) {
        String passage = textAreaEnter.getText();
        String[] wrongs = spellCheckerServiceProvider.check(passage);
        String results= "Current Language : "+currentLanguage+" | Wrong words : ";
        for(int i=0;i<wrongs.length;i++)
        	results+=" - "+wrongs[i];
        textAreaReturn.setText(results);
    }
}
More interesting comes with the ApAM descriptor (metadata.xml) :
<apam xmlns="fr.imag.adele.apam" xmlns:ipojo="org.apache.felix.ipojo"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" 
 xsi:schemaLocation="fr.imag.adele.apam http://repository-apam.forge.cloudbees.com/release/schema/ApamCore.xsd" >    
	
	<implementation name="SpellGUIFrame"
	      classname="fr.imag.adele.apam.tutorials.spell.gui.SpellGUIFrame">
	   <callback onInit="start" onRemove="stop"/>
	   <dependency name="spellChecker" specification="SpellChecker" field="spellCheckerServiceProvider" />
 	   <definition name="Language" field="currentLanguage" type="French, English, German, Italian" value="$this.spellChecker.dico$Language"/>
	</implementation>
	
	<apam-instance implementation="SpellGUIFrame" name="SpellGUIFrameInstance"/>

</apam>
We have one dependency injected and the two callback that should now be familiar. But the property definition is interesting. You can see that it can be dynamically injected to a java attribute as a dependency (more interesting, the synchronization works both ways, if value is changed in java it is also changed in ApAM).
Another operation we use is substitution, $thisindicate the source (the current instance), in which we retrieve the spellChecker dependecy (the field that is dynamically injected), in the spellChecker we retrieve the dico dependency (another field dynamically injected) and finally the value of the attribute (the Language property).


Last but not least, we can see that we declare directly an ApAM component instance in the descriptor (instead of calling it from the console).

Clone this wiki locally