【OSGi】Service

44330 ワード

コンセプト
  • サービス
  • サービスとは、他人のために完成した仕事です.目的:自分ですべてのことをしようとするのではなく、他の人にあなたのために仕事をさせることです.
    方法呼び出しとの違い:サービスとは、プロバイダとその使用者との間の契約であり、使用者はサービスの具体的な実現に関心を持たず、誰が提供したのかさえ関心を持たず、約束の契約を守ればよい.
    サービス向けの設計方式は、ソフトウェア開発をプラグアンドプレイで行うことを奨励します.これは、開発、テスト、導入、メンテナンスの過程でより柔軟性があることを意味します.
  • インタフェース+依存注入
  • Javaでは一般的にインタフェースに基づいてプログラミングされていますが、特定のインタフェース実装クラスを知っていない限り、インタフェースインスタンスを作成することはできません.
    従来のJavaは,この問題を依存注入(Dependency Injection,DI)によって解決できる.
    欠点:
  • 依存注入は静的であり、注入は一度しか発生しないが、一般的にはアプリケーション起動時に注入され、アプリケーションが閉じるまで変更できない.

  • sensitive dependence on start-up ordering.

  • また、メタデータ(属性)を指定することはできません.

  • OSGiはこの問題を動的サービスで解決することができる.複数のサービスインプリメンテーションをサポートし、メタデータに基づいて必要なサービスインプリメンテーションをフィルタリングできます.
    公開サービス
     
  • 登録サービス
  • 登録サービスはOSGiと対話する方式であるため、BundleContextで完了しなければならない.
     
    public class WelcomeMailboxActivator implements BundleActivator {
        public void start(BundleContext context) throws Exception {
            context.registerService(Mailbox. class.getName(), new FixedMailbox(), null) ; //1
       }
        public void stop (BundleContext context) throws Exception {
       }
     }

    BundleContext.registerService()

    :interface name、service object、service properties。 String[], 。

    bundle , services :

    osgi > services
    . . .
    { org . osgi . book . reader . api . Mailbox }={ service . id =24}
    Registered by bundle : welcome_mailbox_0 . 0 . 0 [ 2 ]
    No bundles using service .
    . . .

     

    start() , stop() ?

    , bundle ,OSGi 。 :

    serviceRegistration.unregister();
     

    serviceRegistration BundleContext.registerService() 。

     

    • public void start ( BundleContext context ) throws Exception {
         this.context = context;
        printMessageCount( );

       
      private void printMessageCount() throws MailboxException {
        ServiceReference ref = context.getServiceReference (Mailbox. class.getName());   // 1
        if (ref != null) {
           Mailbox mbox = (Mailbox) context.getService(ref); // 2
           if (mbox != null) {
             try {
                int count = mbox.getAllMessages().length; // 3
               System.out.println( "There are " + count + " messages");
             } finally {
               context.ungetService(ref); // 4
             }
           }
       }

      1、BundleContext.getServiceReference()

      getServiceReference() ,

      2、BundleContext.getService()

      null, getService() 。

      , null, , null。

      3、

      mbox.getAllMessages().length。 Java 。

      4、BundleContext.ungetService()

      ungetService() , 。 bundle , 0, bundle , 。

      ungetService() finally ! , 。

      —— ! serviceRegistration.unregister()

       

      【 】

      , , metadata, 。

      registerService() java.util.Dictionary ( java.util.Properties), , ; , 。

      public void start( BundleContext context) throws Exception {
        Properties props = new Properties();
        props.put(Mailbox.NAME_PROPERTY, "welcome");
        context.registerService(Mailbox. class.getName(), new FixedMailbox(), props);
      }

      bundle , services :

      osgi > services
      . . .
      { org . osgi . book . reader . api . Mailbox }={ mailboxName=welcome , service . id =27}
      Registered by bundle : welcome_mailbox_0 . 0 . 0 [ 2 ]
      No bundles using service .
      . . .

      service.id , 。

      {org . osgi . book . reader . api . Mailbox } :objectClass

      org.osgi.framework.Constants。

       

      【 】

      ServiceReference[] refs = bundleContext.getServiceReferences(Mailbox. class.getName(),
             "& (mailboxName=welcome) (objectClass=...)");

      LDAP

      ServiceReference.getProperty() ; getPropertyKeys()

      ,ServiceReference.getService() null, 。 , 。 ?OSGi :

      1. service.ranking 。 , 0
      2. service ID 。 。

      1. BundleContext.getServiceReference() ServiceReference
      2. BundleContext.getService()

      ? , , 。—— ServiceReference 。

      ,ServiceReference , bundle 。 , OSGi bundle 。 bundle service , ServiceReference bundle, getService ungetService。

      start() , , ?

      ——NO! , 。

      ——NO! .getService(), , 。 。

       

      Whenever a service is either registered or unregistered, the framework publishes a ServiceEvent to all registered ServiceListeners.

      【 】 DataSource , DbMailbox; DataSource DbMailbox。 ?

      • Service

      【 】 ServiceListener:

      public void start(BundleContext context) throws Exception {
         this.context = context;
        String filter = "(" +Constants.OBJECTCLASS   + "=" + DataSource. class.getName() + ")";
        context. addServiceListener( new DbListener (), filter );
      }

      class DbListener implements ServiceListener {
       
        DataSource db;

         public void serviceChanged(ServiceEvent event) {
             switch () {
                 case ServiceEvent.REGISTERED :
                      this.db = (DataSource) context.getService( event.getServiceReference());
                      ...  db  DbMailbox.....
                     break;
                 case ServiceEvent.UNREGISTERED :
                      this.db = null;
                     break;
               ....
            }
        }
      }

      【 】 Service; Service 。

      • Service + Service

      【 】 ; Service, :

      public void start(BundleContext context) throws Exception {
          this.context = context;
          this.listener = new DbListener();
          synchronized(listener) {
                // 1.
               String filter = "(" +Constants.OBJECTCLASS   + "=" + DataSource. class.getName() + ")";
               context. addServiceListener( new DbListener (), filter );

                 //2. service
                ServiceReference[] refs = context. getServiceReferences(null, filter);
                 if (refs != null) {
                      for (ServiceReference ref : refs) {
                           this.listener.serviceChanged( new ServiceEvent(ServiceEvent.REGISTERED, ref)); //
                     }
                }
                
         }
      }

      Service, Service:

      class DbListener implements ServiceListener {
       
        SortedSet <ServiceReference > refs = new TreeSet <ServiceReference >();

         public void serviceChanged(ServiceEvent event) {
             switch () {
                 case ServiceEvent.REGISTERED :
                     refs.add(event.getServiceReference());
                      ...  getService()  DbMailbox.....
                      break;
                 case ServiceEvent.UNREGISTERED :
                     refs.remove(event.getServiceReference());
                      break;
               ....
            }
        }
      }
       
       
      public synchronized DataSource getService() {
           if (refs.size() > 0) {
               return (DataSource) context.getService( refs.last());
          }
           return null;
      }

      【 1】 service, ?

      ——NO! 、 , service , service !

      , service 2 。 !

       

      【 2】OSGi , ,

       

      • ServiceTracker

      , 。OSGi ServiceTracker , 。Rather than simply “listening”, which is passive, we wish to actively “track” the ser-vices we depend on.

      public class MessageCountActivator2 implements BundleActivator {
         private ServiceTracker mboxTracker ;
         public void start(BundleContext context) throws Exception {
            mboxTracker = new ServiceTracker(context, Mailbox.class.getName(), null); //1
            mboxTracker .open(); // 2
            printMessageCount ( ) ;
        }
         public void stop(BundleContext context) throws Exception {
            mboxTracker .close(); // 3
        }
       
         private void printMessageCount ( ) throws MailboxException {
            Mailbox mbox = (Mailbox) mboxTracker.getService(); // 4 service?——
             if (mbox != null) {
                 int count = mbox.getAllMessages().length ; // 5
                System.out.println( "There are " + count + " messages");
           }
        }
      }

      ServiceTracker.getService(), ServiceTracker.waitForService (5000) ; , 5 。

      The first difference, which we can see at marker 1 of the start method, is that instead of saving the bundle context directly into a field, we instead construct a new ServiceTracker field, passing it the bundle context and the name of the service that we are using it to track. Next at marker 2, we “open” the tracker, and at marker 3 in the stop() method we “close” it.

      —— ServiceTracker

      The next difference is at marker 4, where we call getService on the tracker. Refreshingly, this immediately gives us the actual service object (if available) rather than a ServiceReference. So we simply go ahead and call the service at marker 5, bearing in mind that we still need to check if the service was found.  Also, we don’t need to clean up after ourselves with a finally block: we simply let the variable go out of scope, as the tracker will take care of releasing the service.

      ——getService , ServiceReference; , ungetService, ServiceTracker 。

      • ServiceTrackerCustomizer

      DbMailbox , :

      public class DbMailboxActivator implements BundleActivator {
           private BundleContext context;
           private ServiceTracker tracker;
           public void start(BundleContext context) throws Exception {
               this.context = context ;
              tracker = new ServiceTracker(context, DataSource. class.getName(), new DSCustomizer()); // 1
             // 2
             // When we call open() on a service tracker, it hooks up a ServiceListener
             // and then scans the pre-existing services, eliminates duplicates etc.
              tracker.open(); 
          }
           public void stop(BundleContext context) throws Exception {
               tracker.close(); // 3
          }

           private class DSCustomizer implements ServiceTrackerCustomizer {
          
        // when we return null from addingService, which the tracker takes to mean that we don’t care about this particular service reference.
        // That is, if we return null from addingService, the tracker will “forget” that particular service reference and will not call either modifiedService or removedService later if it is modified or removed.
        // Thus returning null can be used as a kind of filter, but in the next section we will see a more convenient way to apply filters declaratively
               public Object addingService(ServiceReference ref) {
                DataSource ds = (DataSource)context.getService(ref); // 4
                DbMailbox mbox = new DbMailbox(ds);
                ServiceRegistration registration = context.registerService(Mailbox. class.getName(), mbox, null); // 5
                return registration; // 6
             }
             public void modifiedService(ServiceReference ref, Object service ) {
             }
             public void removedService(ServiceReference ref, Object service ) {
                ServiceRegistration registration = (ServiceRegistration) service; // 7 service, addingService()
                registration.unregister(); // 8
                context.ungetService(ref); // 9
             }
          }
      }

      1、 ServiceTracker:we pass in an instance of the ServiceTrackerCustomizer interface, which tells the tracker what to do when services are added, removed  or modified.

      2、ServiceTracker.open(): ServiceListener, , 。

      3、ServiceTracker.close():

      4&5、addingService(): DataSource service 、 service ,

      6、addingService() : modifiedService() removedService()。

      null, ,tracker , , modifiedService() removedService()。

      null “ ”, Filter

      7&8&9、 DataSource service reference , , DataSource service。

       
       

      , service addingService(), service addingService()。 service、 service。

      unlike a listener, the adding and removed methods of ServiceTracker are called not only when the state of a service changes but also when the tracker is opened, to notify us of pre-existing services.

      The addingService() method is called multiple times when the tracker is opened, once for each service currently registered, and it is also called whenever a new service is registered at any time later for as long as the tracker is open.

      Furthermore the removedService() is called any time a service that we have been previously been notified of goes away, and it is also called for each service when the tracker closes.

      Therefore we can deal with services in a uniform fashion without needing to distinguish between pre-existing services and ones that are registered while our listener is active. This greatly simplifies the code we need to write.

      • Filter

      Filter filter = FrameworkUtil.createFilter (
           " (&( objectClass =" + Mailbox. class.getName() + ")" +
           "( mailboxName = welcome )( lang = en ))" ) ;
      tracker = new ServiceTracker(context, filter, null ;

      getServiceReference Properties :

      context.getServiceReference(Mailbox. class.getName(),
             " (&( mailboxName = welcome )( lang = en )) " )

       

      FrameworkUtil.createFilter() InvalidSyntaxException, 。

      , String.format(); , :

      context.createFilter ( String.format( " (&(%s =%s )(%s =%s )(%s=%s))" ,
          Constants.OBJECTCLASS, Mailbox. class.getName(),
          Mailbox.NAME_PROPERTY, "welcome",
          "lang", "en*")) ;

      【 】

      • service bundle 。 logger , bundle 。
      • Service:ServiceFactory allows us to delay the creation of service objects until they are actually needed.

      【 】

      , ServiceFactory。The factory does not itself implement the service interface, but it knows how to create an object that does.

      , Service ServiceFactory。

      【 】

      ServiceFactory :


      public interface ServiceFactory {
           public Object getService ( Bundle bundle, ServiceRegistration registration ) ;
           public void ungetService ( Bundle bundle, ServiceRegistration registration, Object service ) ;
      }

      getService 1-bundle bundle, 2-registration ServiceRegistration。

      —— ServiceFactory ; ServiceRegistration 。

      ungetService bundle , 。 3-service getService 。

      【 】

      import org.osgi.framework.Bundle;
      import org.osgi.framework.ServiceFactory;
      import org.osgi.framework.ServiceRegistration;
      class LogImpl implements Log {
           private String sourceBundleName ;
           public LogImpl(Bundle bundle) {
               this.sourceBundleName = bundle.getSymbolicName();
          }
           public void log(String message) {
              System.out.println(sourceBundleName + ": " + message );
          }
      }

      public class LogServiceFactory implements ServiceFactory {
           public Object getService(Bundle bundle, ServiceRegistration registration ) {
               return new LogImpl(bundle) ;
          }
           public void ungetService(Bundle bundl, ServiceRegistration registration, Object service) {
               // No spec i a l clean −up required
          }
      }
       
      import org.osgi.framework.BundleActivator;
      import org.osgi.framework.BundleContext;
      public class LogServiceFactoryActivator implements BundleActivator {
           public void start(BundleContext context) throws Exception {
              context.registerService( Log. class.getName(),
                                new LogServiceFactory(), null) ;
          }
           public void stop(BundleContext context) throws Exception {
          }
      }