Versions Compared

Key

  • This line was added.
  • This line was removed.
  • Formatting was changed.

...

Before diving into all annotations, we must first introduce the different types of components DependencyManager is supporting. In Dependency Manager, you may use the following types of components, depending on what you need:

  • Service component: This kind of component is rather like an OSGi Service: it's an implementation class that may publish an OSGi Component: Components are the main building blocks for OSGi applications. They can publish themselves as a service, and/or refer to other dependencies, along with eventual service properties. A Service has a lifecycle: it is started once the component bundle is started and all required dependencies are injected, and it is then stopped if a required dependency is lost, or if the bundle is stopped. However, notice that in DependencyManager, a Service may not necessarily publish a Service into the OSGi registry: in this case, the component can still have a managed lifecycle, with dependencies.they can have dependencies. These dependencies will influence their life cycle as component will only be activated when all required dependencies are available.
  • Aspect Service: A service Aspect Service component: A Service that provides a non-functional aspect on top of an existing service. In aspect oriented programming, an aspect, or interceptor can sit between a client and another target service used by the client. An Aspect Service first tracks a target service and is created once the target service is detected. Then the Aspect Service is provided, but with a higher ranking, and the client is transparently updated with the aspect. Aspects can be chained and may apply to the same target service (and in this case, the ranking of the Aspect service is used to chain aspects in the proper order).
  • Adapter Service  : component: A Service that adapts another existing service into a new one. Like with aspects, sometimes you want to create adapters for certain services, which add certain behavior that results in the publication of (in this case) a different service. Adapters can dynamically be added and removed and allow you to keep your basic services implementations clean and simple, adding extra features on top of them in a modular way.

Now we have introduced the different types of components, here is the list of annotations, allowing to declare DependencyManager service components:

  • @Service@Component: for declaring a component Component that eventually publishes a singleton OSGi service as long as its dependencies are resolved.
  • @AspectService: provides a non-functional aspect on top of an existing service.
  • @AdapterService: creates an OSGi service that adapts another existing service into a new interface.
  • @BundleAdapterService: creates an OSGi service a service on top of a given bundle.
  • @ResourceAdapterService: creates an OSGi service on top of a specific Resource.
  • @FactoryConfigurationAdapterService: creates an OSGi service from ConfigAdmin, using a factoryPid, and a ManagedServiceFactory.

...

@Component

This annotation annotates an implementation class that optionally publishes an OSGi service, and optionally has some dependencies, with a managed lifecycle. The annotation has the following attributes:

  • provides: By default, the component is registered into the OSGi registry under all directly implemented interfaces. If no interfaces are implemented, then the component is not registered, but it still has a managed lifecycle, and may have some dependencies. If you need to explicitly define the list of interfaces (or classes) under which the component must be registered in the OSGi registry, then use the provides attribute. You can also set this property to an empty array of classes if you don't want at all your component to be exposed in the OSGi registry (even if it implements some interfaces).

...

  • factorySet: The component factory ID. By default, a Service component is automatically instantiated as a singleton when the bundle is started, and when all required dependencies are satisfied. But when a component must be created, configured, or disposed dynamically, and when multiple instances of the same component are needed, a factorySet should be used. When you use this attribute, a java.util.Set<Dictionary> object is registered into the OSGi regitry, with a specific dm.factory.name property matching the ID you specify in the attribute. This Set<Dictionary> will act as a Factory API, and another component may define a dependency on this Set and add some configuration dictionaries in it, in order to fire some component instantiation/activation. There is one component instantiated per added dictionary, which is passed to component instances via a configurable callback method (using the factoryConfigure attribute). All public properties will be propagated along with eventual published service. A public property is a property which does not start with a dot ("."). Properties starting with a dot are considered private to the component, and won't be propagated to published service. This model is actually similar to the Declarative Service "Component Factories" concept, except that you don't have a dependency on a specific API, but rather on a basic jdk class (java.util.Set<Dictionary>). Notice that, unlike in Declarative Service, the component factory is  provided once the component bundle is started, even if required dependencies are not satisfied. This is useful when the component want to dynamically configure its dependency filters. So, to summarize:
    • Each time a new Dictionary is added into the Set, then a new instance of the annotated service component will be instantiated, and this dictionary is passed to the component callback specified with the factoryConfigure attribute.
    • Each time an existing Dictionary is re-added into the Set, then the corresponding Service component instance is updated, and the updated dictionary is also passed to the callback specified in the factoryConfigure attribute.
    • Each time an existing Dictionary is removed from the Set, then the corresponding component instance will be stopped and destroyed.

...

Usage example:

Code Block
 /**
   * This Servicecomponent will be activated once the bundle is started and when all required dependencies
   * are available.
   */
 @Service
@Component class X implements Z {
     @ConfigurationDependency(pid="MyPid")
     void configure(Dictionary conf) {
          // Configure or reconfigure our service.
     }

     @Start
     void start() {
         // Our Service is starting and is about to be registered in the OSGi registry as a Z service.
     }

     public void doService() {
         // ...
     }
 }

Example using a factorySet, where the X component is instantiated/updated/disposed by another Y component:

Code Block
  @Service@Component(factorySet="MyServiceFactoryMyComponentFactory", factoryConfigure="configure")
  class X implements Z {
      void configure(Dictionary conf) {
          // Configure or reconfigure our servicecomponent. The conf is provided by the factory,
          // and all public properties (which don't start with a dot) are propagated with the
          // Service properties eventually specified in the properties's Serviceannotation attribute.
      }

      @ServiceDependency
      void bindOtherService(OtherService other) {
          // store this require dependency
      }

      @Start
      void start() {
          // Our Servicecomponent is starting and is about to be registered in the OSGi registry as a Z service.
      }

      public void doService() {
          // ... part of Z interface
      }
  }

  /**
    * This class will instantiate some X Servicecomponent instances
    */
  @Service@Component
  class Y {
      @ServiceDependency(filter="(dm.factory.name=MyServiceFactoryMyComponentFactory)")
      Set<Dictionary> _XFactory; // This Set acts as a Factory API for creating X Servicecomponent instances.

      @Start
      void start() {
          // Instantiate a X Servicecomponent instance
          Dictionary x1 = new Hashtable() {{ put("foo", "bar1"); }};
          _XFactory.add(x1);

          // Instantiate another X Servicecomponent instance
          Dictionary x2 = new Hashtable() {{ put("foo", "bar2"); }};
          _XFactory.add(x2);

          // Update the first X Servicecomponent instance
          x1.put("foo", "bar1_modified");
          _XFactory.add(x1);

          // Destroy Xall Servicescomponents (Notice that invoking _XFactory.clear() willalso destroydestroys allevery X Service instances)
          _XFactory.remove(x1);
          _XFactory.remove(x2);
      }
  }

...