(06) Apache Felix 入門 - 06

1、完整的 Dictionary Client Bundle

本文中的客戶端,對於例3中的例子進行了優化,使得代碼擁有能夠處理服務動態變化的問題,而且當此 bundle 在多線程環境下操作也是安全的,具體例子如下:

/*
 * Apache Felix OSGi tutorial.
**/

package tutorial.example4;

import java.io.BufferedReader;
import java.io.InputStreamReader;
import java.io.IOException;

import org.osgi.framework.BundleActivator;
import org.osgi.framework.BundleContext;
import org.osgi.framework.InvalidSyntaxException;
import org.osgi.framework.ServiceReference;
import org.osgi.framework.ServiceListener;
import org.osgi.framework.ServiceEvent;

import tutorial.example2.service.DictionaryService;

/**
 * 這個 bundle 使用字典服務檢測輸入的單詞是否正確,因爲我們在代碼中解決了服務的動態可用性問題,
 * 所以代碼相對於 Example3 是比較複雜。當服務被註銷的時候,則相應服務的使用者會自動停止使用該
 * 服務,當無服務被註冊的時候,則相應的服務會被自動投入使用。
**/
public class Activator implements BundleActivator, ServiceListener
{
    // Bundle's context.
    private BundleContext m_context = null;
    // The service reference being used.
    private ServiceReference m_ref = null;
    // The service object being used.
    private DictionaryService m_dictionary = null;

    /**
     * Implements BundleActivator.start(). Adds itself
     * as a listener for service events, then queries for 
     * available dictionary services. If any dictionaries are
     * found it gets a reference to the first one available and
     * then starts its "word checking loop". If no dictionaries
     * are found, then it just goes directly into its "word checking
     * loop", but it will not be able to check any words until a
     * dictionary service arrives; any arriving dictionary service
     * will be automatically used by the client if a dictionary is
     * not already in use. Once it has dictionary, it reads words
     * from standard input and checks for their existence in the
     * dictionary that it is using.
     * (NOTE: It is very bad practice to use the calling thread
     * to perform a lengthy process like this; this is only done
     * for the purpose of the tutorial.)
     * @param context the framework context for the bundle.
    **/
    public void start(BundleContext context) throws Exception
    {
        m_context = context;

        // We synchronize while registering the service listener and
        // performing our initial dictionary service lookup since we
        // don't want to receive service events when looking up the
        // dictionary service, if one exists.
        synchronized (this)
        {
            // Listen for events pertaining to dictionary services.
            m_context.addServiceListener(this,
                "(&(objectClass=" + DictionaryService.class.getName() + ")" +
                "(Language=*))");

            // Query for any service references matching any language.
            ServiceReference[] refs = m_context.getServiceReferences(
                DictionaryService.class.getName(), "(Language=*)");

            // If we found any dictionary services, then just get
            // a reference to the first one so we can use it.
            if (refs != null)
            {
                m_ref = refs[0];
                m_dictionary = (DictionaryService) m_context.getService(m_ref);
            }
        }

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

            // 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;
                }
                // If there is no dictionary, then say so.
                else if (m_dictionary == null)
                {
                    System.out.println("No dictionary available.");
                }
                // Otherwise print whether the word is correct or not.
                else if (m_dictionary.checkWord(word))
                {
                    System.out.println("Correct.");
                }
                else
                {
                    System.out.println("Incorrect.");
                }
            }
        } catch (Exception ex) { }
    }

    /**
     * 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.
    }

    /**
     * Implements ServiceListener.serviceChanged(). Checks
     * to see if the service we are using is leaving or tries to get
     * a service if we need one.
     * @param event the fired service event.
    **/
    public synchronized void serviceChanged(ServiceEvent event)
    {
        String[] objectClass =
            (String[]) event.getServiceReference().getProperty("objectClass");

        // If a dictionary service was registered, see if we
        // need one. If so, get a reference to it.
        if (event.getType() == ServiceEvent.REGISTERED)
        {
            if (m_ref == null)
            {
                // Get a reference to the service object.
                m_ref = event.getServiceReference();
                m_dictionary = (DictionaryService) m_context.getService(m_ref);
            }
        }
        // If a dictionary service was unregistered, see if it
        // was the one we were using. If so, unget the service
        // and try to query to get another one.
        else if (event.getType() == ServiceEvent.UNREGISTERING)
        {
            if (event.getServiceReference() == m_ref)
            {
                // Unget service object and null references.
                m_context.ungetService(m_ref);
                m_ref = null;
                m_dictionary = null;

                // Query to see if we can get another service.
                ServiceReference[] refs = null;
                try
                {
                    refs = m_context.getServiceReferences(
                        DictionaryService.class.getName(), "(Language=*)");
                }
                catch (InvalidSyntaxException ex)
                {
                    // This will never happen.
                }
                if (refs != null)
                {
                    // Get a reference to the first service object.
                    m_ref = refs[0];
                    m_dictionary = (DictionaryService) m_context.getService(m_ref);
                }
            }
        }
    }
}

構建 manifest.mf: 

Bundle-Name: Dynamic dictionary client
Bundle-Description: A bundle that uses the dictionary service whenever it becomes available
Bundle-Vendor: Apache Felix
Bundle-Version: 1.0.0
Bundle-Activator: tutorial.example4.Activator
Import-Package: org.osgi.framework,
 tutorial.example2.service

編譯、打包:

D:\devInstall\apache\felix-framework-6.0.0\examples\demo04\src> javac -cp ..\..\demo02\target\example2.jar;..\..\..\bin\felix.jar -encoding UTF-8 -d ../target tutorial\example4\Activator.java
D:\devInstall\apache\felix-framework-6.0.0\examples\demo04\src> cd ../target
D:\devInstall\apache\felix-framework-6.0.0\examples\demo04\src> cp ../src/manifest.mf ./
D:\devInstall\apache\felix-framework-6.0.0\examples\demo04\src> 
D:\devInstall\apache\felix-framework-6.0.0\examples\demo04\target> jar cvfm example4.jar .\manifest.mf -C . .
已添加清單
正在添加: manifest.mf(輸入 = 285) (輸出 = 182)(壓縮了 36%)
正在添加: tutorial/(輸入 = 0) (輸出 = 0)(存儲了 0%)
正在添加: tutorial/example4/(輸入 = 0) (輸出 = 0)(存儲了 0%)
正在添加: tutorial/example4/Activator.class(輸入 = 3147) (輸出 = 1592)(壓縮了 49%)

安裝、運行:

g! install file:./examples/demo04/target/example4.jar                                                           14:10:40
Bundle ID: 14
g! start 14                                                                                                     14:10:42
Enter a blank line to exit.
Enter word: ~                                                                                                           g! lb                                                                                                           14:10:47
START LEVEL 1
   ID|State      |Level|Name
    0|Active     |    0|System Bundle (6.0.0)|6.0.0
    1|Active     |    1|jansi (1.17.1)|1.17.1
    2|Active     |    1|JLine Bundle (3.7.0)|3.7.0
    3|Active     |    1|Apache Felix Bundle Repository (2.0.10)|2.0.10
    4|Active     |    1|Apache Felix Gogo Command (1.0.2)|1.0.2
    5|Active     |    1|Apache Felix Gogo JLine Shell (1.1.0)|1.1.0
    6|Active     |    1|Apache Felix Gogo Runtime (1.1.0)|1.1.0
    7|Active     |    1|Service listener example (1.0.0)|1.0.0
    8|Active     |    1|English dictionary (1.0.0)|1.0.0
   10|Active     |    1|French dictionary (1.0.0)|1.0.0
   11|Resolved   |    1|Dictionary client (1.0.0)|1.0.0
   14|Active     |    1|Dictionary client (1.0.0)|1.0.0
g!     

上面的處理對於在單線程的應用程序而言,許多操作是多餘的,但是對於多線程應用程序,如 GUI 應用,上面的處理是特別有用的。

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章