May 10, 2020
Estimated Post Reading Time ~

OSGi in AEM

  • OSGI is a modular programming approach. The application can be divided into modules or bundles. The bundle will be JAR file + Metadata.
  • OSGI uses Apache Felix Implementation.
  • All Bundles are deployed on Felix container.
  • Every bundle has its own life cycle. i.e., it’s independent. It can be redeployed without affecting another bundle.
  • Each Bundle has its own classloader. Which allows developers to start and stop each bundle separately.
  • OSGI supports multiple versions of the bundle.
  • AEM works with the inbuilt bundles for separate functionalities
  • Bundles are stored under cr-quickstart/launchpad/felix.
  • All the OSGI configurations are stored under (/apps/sling/config or /apps/system/config) by default. The configuration will be saved as a paragraph property jcr:data in binary(non-readable format) on the respective node.
  • You can manage the configuration settings for such bundles by either:
Adobe CQ Web console
The Web Console is the standard interface for OSGi configuration. It provides a UI for editing the various properties, where possible values can be selected from predefined lists.

As such it is the easiest method to use.

Any configurations made with the Web Console are applied immediately and applicable to the current instance, irrespective of the current run mode, or any subsequent changes to the run mode.

content-nodes (sling:osgiConfig) in the repository
This requires manual configuration using CRXDE Lite.
Due to the naming conventions of the sling:OsgiConfig nodes, you can tie the configuration to a specific run mode. You can even save configurations for more than one run mode in the same repository.
Any appropriate configurations are applied immediately (dependent on the run mode).

Basic SCR Annotation used for developing a component or service in osgi are:-
@Component – defines the class as a component.
@Service – defines the service interface that is provided by the component.
@Reference – injects a service into the component.
@Property – defines a property that can be used in the class.

Differences between package and bundle
Package: A Package is a zip file that contains the content in the form of a file-system serialization (called “vault” serialization) that displays the content from the repository as an easy-to-use-and-edit representation of files and folders. Packages can include content and project-related data.
Bundle: Bundle is a tightly coupled, dynamically loadable collection of classes, jars, and configuration files that explicitly declare their external dependencies (if any).

Difference between OSGi bundle and Normal Jar file
OSGi bundles are jar files with metadata inside. Much of this metadata is in the jar’s manifest, found at META-INF/MANIFEST.MF. This metadata, when read by an OSGi runtime container, is what gives the bundle its power.

With OSGi, just because a class is public doesn’t mean you can get to it. All bundles include an export list of package names, and if a package isn’t in the export list, it doesn’t exist to the outside world. This allows developers to build an extensive internal class hierarchy and minimize the surface area of the bundle’s API without abusing the notion of package-private visibility. A common pattern, for instance, is to put interfaces in one package and implementations in another, and only export the interface package.

All OSGi bundles are given a version number, so it’s possible for an application to simultaneously access different versions of the same bundle (eg: junit 3.8.1 and junit 4.0.). Since each bundle has it’s own class-loader, both bundles classes can coexist in the same JVM.

OSGi bundles declare which other bundles they depend upon. This allows them to ensure that any dependencies are met before the bundle is resolved. Only resolved bundles can be activated. Because bundles have versions, versioning can be included in the dependency specification, so one bundle can depend on version junit version 3.8.1 and another bundle depend on junit version 4.0.
In OSGi bundle, there will be an Activator.java class in OSGi which is an optional listener class to be notified of bundle start and stop events.

Life cycle of OSGI[Open Systems Gateway initiative] bundle
OSGi is a framework which allows modular development of applications using java. A large application can be constructed using small reusable components(called bundles in terms of OSGi) each of which can be independently started, stopped, and also can be configured dynamically while running without requiring a restart.
Following are the states of OSGI life cycle:
Installed – The bundle has been successfully installed.
Resolved – All Java classes that the bundle needs are available. This state indicates that the bundle is either ready to be started or has stopped.
Starting – The bundle is being started, the BundleActivator.start method will be called, and this method has not yet returned. When the bundle has an activation policy, the bundle will remain in the STARTING state until the bundle is activated according to its activation policy.
Active – The bundle has been successfully activated and is running; its Bundle Activator start method has been called and returned.
Stopping – The bundle is being stopped. The BundleActivator.stop method has been called but the stop method has not yet returned.
Uninstalled – The bundle has been uninstalled. It cannot move into another state.

Service
An OSGi service is a java object instance, registered into an OSGi framework with a set of properties. Any java object can be registered as a service, but typically it implements a well-known interface.
The client of a service is always an OSGi bundle, i.e. a piece of java code possible to start via the BundleActivator interface.
Each bundle may register zero or more services. Each bundle may also use zero or more services. There exists no limit on the number of services, more than the ones given by memory limits or java security permissions.

Service Factory
An OSGi service factory is a special class ServiceFactory, which can create individual instances of service objects for different bundles. Sometimes a service needs to be differently configured depending on which bundle uses the service. For example, the log service needs to be able to print the logging bundle’s id, otherwise the log would be hard to read.

Get session in servlet
We can get session from SlingHttpServletRequest.
Session session = slingHttpServletRequest.getResourceResolver().adaptTo(Session.class)
From ResourceResolverFactory,
Session session = resolver.adaptTo(Session.class);
SlingSafeMethodsServlet – Helper base class for read-only Servlets used in Sling. This base class is actually just a better implementation of the Servlet API HttpServlet class which accounts for extensibility. So extensions of this class have great control over what methods to overwrite. It supports GET, HEAD, OPTIONS etc methods.
SlingAllMethodsServlet – Helper base class for data modifying Servlets used in Sling. This class extends the SlingSafeMethodsServlet by support for the POST, PUT and DELETE methods.

OSGI
This architecture allows you to extend Sling with application specific modules. Sling, and therefore CQ5, uses the Apache Felix implementation of OSGI (Open Services Gateway initiative) .They are both collections of OSGi bundles running within an OSGi framework.

This enables you to perform the following actions on any of the packages within your installation:
  • install
  • start
  • stop
  • update
  • uninstall
  • see the current status
  • access more detailed information (e.g. symbolic name, version, location, etc) about the specific bundles
Each OSGi Component is contained in one of the various bundles.

You can manage the configuration settings for such bundles by either:
using the Adobe CQ Web console
using configuration files
configuring content-nodes (sling:OsgiConfig) in the repository

OSGi Configuration with the Web Console
The Web console in AEM provides a standardize interface for configuring the bundles. The Configuration tab is used for configuring the OSGi bundles, and is therefore the underlying mechanism for configuring AEM system parameters.
Any changes made are immediately applied to the relevant OSGi configuration, no restart is required.

Access the Configuration tab of the Web Console by either:
Opening the web console from the link on the Tool -> Operations menu. After logging into the console you can use the drop-down menu of:
OSGi >
The direct URL; for example:
http://localhost:4502/system/console/configMgr

OSGi Configuration with configuration files
Configuration changes made using the Web Console are persisted in the repository as configuration files (.config) under:
/apps

These can be included in content packages and re-used on other instances.
example: apps/system/config/org.apache.felix.webconsole.internal.servlet.OsgiManager.config
You can open this file to view your changes, but to avoid typing errors it is recommended to make actual changes with the console.

OSGi Configuration in the Repository
In addition to using the web console, you can also define configuration details in the repository. This allows you to easily configure your differing run modes.
These configurations are made by creating sling:OsgiConfig nodes in the repository for the system to reference. These nodes mirror the OSGi configurations, and form a user interface to them. To update the configuration data you update the node properties.

If you modify the configuration data in the repository the changes are immediately applied to the relevant OSGi configuration as if the changes had been made using the Web console, with the appropriate validation and consistency checks. This also applies to the action of copying a configuration from /libs/ to /apps/.

As the same configuration parameter can be located in several places, the system:
searches for all nodes of type sling:OsgiConfig
filters according to service name
filters according to run mode

Creating the Configuration in the Repository
To actually add the new configuration to the repository:
Use CRXDE Lite to navigate to:
/apps/<yourProject>

If not already existing, create the config folder (sling:Folder):
config – applicable to all run modes
config.<run-mode> – specific to a particular run mode

Under this folder create a node:

Type: sling:OsgiConfig
Name: the persistent identity (PID);
for example for AEM WCM Version Manager use com.day.cq.wcm.core.impl.VersionManagerImpl

Note:
When making a Factory Configuration append -<identifier> to the name.
As in: org.apache.sling.commons.log.LogManager.factory.config-<identifier>
Where <identifier> is replaced by free text that you (must) enter to identify the instance (you cannot omit this information); for example:
org.apache.sling.commons.log.LogManager.factory.config-MINE

For each parameter that you want to configure, create a property on this node:
  • Name: the parameter name as shown in the Web console; the name is shown in brackets at the end of the field description. For example, for Create Version on Activation use versionmanager.createVersionOnActivation
  • Type: as appropriate.
  • Value: as required.
You only need to create properties for the parameters that you want to configure, others will still take the default values as set by AEM.

Save all changes.
Changes are applied as soon as the node is updated by restarting the service (as with changes made in the Web console).

Configuration Details
Resolution Order at Startup
The following order of precedence is used:
  1. Repository nodes under /apps/*/config….either with type sling:OsgiConfig or property files.
  2. Repository nodes with type sling:OsgiConfig under /libs/*/config…. (out-of-the-box definitions).
  3. Any .config files from <cq-installation-dir>/crx-quickstart/launchpad/config/…. on the local file system.
This means that a generic configuration in /libs can be masked by a project specific configuration in /apps.

Resolution Order at Runtime
Configuration changes made while the system is running trigger a reload with the modified configuration.
Then the following order of precedence applies:
  1. Modifying a configuration in the Web console will take immediate effect as it takes precedence at runtime.
  2. Modifying a configuration in /apps will take immediate effect.
  3. Modifying a configuration in /libs will take immediate effect, unless it is masked by a configuration in /apps.
Resolution of multiple Run Modes
For run mode specific configurations, multiple run modes can be combined. For example, you can create configuration folders in the following style:
/apps/*/config.<runmode1>.<runmode2>/
Configurations in such folders will be applied if all run modes match a run mode defined at startup.

For example, if an instance was started with the run modes author,dev,emea, configuration nodes in /apps/*/config.emea, /apps/*/config.author.dev/ and /apps/*/config.author.emea.dev/ will be applied, while configuration nodes in /apps/*/config.author.asean/ and /config/author.dev.emea.noldap/ will not be applied.

If multiple configurations for the same PID are applicable, the configuration with the highest number of matching run modes is applied.
For example, if an instance was started with the run modes author,dev,emea, and both /apps/*/config.author/ and /apps/*/config.emea.author/ define a configuration for com.day.cq.wcm.core.impl.VersionManagerImpl, the configuration in/apps/*/config.emea.author/ will be applied.

This rule’s granularity is at a PID level.
You cannot define some properties for the same PID in/apps/*/config.author/ and more specific ones in /apps/*/config.emea.author/ for the same PID.
The configuration with the highest number of matching run modes will be effective for the entier PID.

Standard Configurations
The following list shows a small selection of the configurations available (in a standard installation) in the repository:
  • Author – AEM WCM Filter: libs/wcm/core/config.author/com.day.cq.wcm.core.WCMRequestFilter
  • Publish – AEM WCM Filter: libs/wcm/core/config.publish/com.day.cq.wcm.core.WCMRequestFilter
  • Publish – AEM WCM Page Statistics: libs/wcm/core/config.publish/com.day.cq.wcm.core.stats.PageViewStatistics
Note:
As these configurations reside in /libs they must not be edited directly, but copied to your application area (/apps) before customization.

To list all configuration nodes in your instance, use the Query functionality in CRXDE Lite to submit the following SQL query:
select * from sling:OsgiConfig

Configuration Persistence
If you change a configuration through the Web console, it is (usually) written into the repository at: /apps/{somewhere}
  • By default {somewhere} is system/config so the configuration is written to /apps/system/config
  • However, if you are editing a configuration which initially came from elsewhere in the repository: for example: /libs/foo/config/someconfigThen the updated configuration is written under the original location; for example: /apps/foo/config/someconfig
Settings that are changed by admin are saved in *.config files under:
/crx-quickstart/launchpad/config
  • This is the private data area of the OSGi configuration admin and holds all configuration details specified by admin, regardless how they entered the system.
  • This is an implementation detail and you must never edit this directory directly.
  • However, it is useful to know the location of these configuration files so that copies can be taken for backup and/or multiple installation:
    • Apache Felix OSGi Management Console.  "../crx/org/apache/felix/webconsole/internal/servlet/OsgiManager.config"
    • CRX Sling Client Repository "../com/day/crx/sling/client/impl/CRXSlingClientRepository/<pid-nr>.config"
Caution:
You must never edit the folders or files under:
/crx-quickstart/launchpad/config

What is a Service
The classical view of a service is nothing but work done for another part of AEM. So is it similar to a method call? The answer is no. How does a service differ from a method call?
A service implies a contract between the provider of the service and its consumers. Consumers typically are not worried about the exact implementation behind a service (or even who provides it) as long as it follows the agreed contract, suggesting that services are to some extent substitutable. Using a service also involves a form of discovery or negotiation, implying that each service has a set of identifying features.

What is a Component
An AEM back-end component refers to managing the life cycle of a class in an OSGi environment. All OSGi services should be a component so that AEM handles the life cycle of a service. For example, the AEM handles when the component is activated, stopped, and so on.

How to write an AEM Service
You can write an AEM service by developing a Java interface and implementation class. The implementation class uses the @Component and @Service annotations.

How declarative services works in AEM
AEM comes with a component framework called declarative services. OSGi bundles contain configuration files located at: OSGI-INF/servicecomponents.xml. A configuration file looks like the following illustration.


This is a configuration file that an OSGi bundle understands. This file is populated by using SCR annotations (for example, @Service) in the implementation class.

What is Dependency Injection
By using Dependency Injection within AEM, you can inject an AEM Service into another service. You perform this task by using a @Reference annotation. For example, consider an AEM DataSourcePool. You can inject that into another AEM service so that the service can perform SQL operations on a database.

What is service ranking
There can be multiple implementations for a given interface which means there can be multiple implementations for a service. If there are multiple implementations and the consumer is interested about a particular implementation, there are ways to select it by using OSGi properties.

If nothing is specified, then the implementation with the highest ranking is selected. In some scenarios, there is a chance of having the same service ranking in that case OSGi considers service identifier. Because the service identifier is an increasing number assigned by the framework, lower identifiers are associated with older services. So if multiple services have equal ranks, the framework effectively chooses the oldest service, which guarantees some stability and provides an affinity to existing services.

The following code shows an implementation example. There is interface named HelloWorld which contains the sayHellomethod. The implementation class is named HelloWorldImpl1 and contains an implementation sayHello method with service rankings 1000 and 1001 respectively. Now when this service is referenced the service with the highest ranking is selected.

public interface HelloWorld {
String sayHello();
}

The following Java code represents the implementation class.
@Component
@Service
@Property(name="service.ranking", intValue=1000)
public class HelloWorldImpl1 implements HelloWorld {

@Override
public String sayHello() {
return "This message is from Hello service 1";
}
}


The following represents the other implementation class.
@Component
@Service
@Property(name="service.ranking", intValue=1001)
public class HelloWorldImpl2 implements HelloWorld {

@Override
public String sayHello() {
return "This message is from Hello service 2";
}
}


This raises a question what if new service implementation called HelloServiceImpl3 with the service ranking 1002 is deployed. In this case all the services which are bind to the HelloWorldImpl2 until they are reinitialized. The easiest way to bind to new service is restart the component which is using that service or restart the bundle.

What is Cardinality while referencing a service
There can be multiple implementations of a service. So while referencing cardinality plays two roles in the Declarative Services specification:
1. Optionality: Cardinality values starting with 0 are treated as optional, whereas values starting with 1 are treated as mandatory.
2. Aggregation: Cardinality values ending with 1 are treated as a dependency on a single service object of the specified type, whereas values ending in n are treated as a dependency on all available service objects of the specified type. This leads to four different possible values:
0..1 – Optional and unary
1..1 – Mandatory and unary (Default)
0..n – Optional and multiple
1..n – Mandatory and multiple
3. Optional Vs Mandatory: If the Optionality value is “0” then the service, which is referencing is active even if the referenced service isn’t available. If the value is “1” then the referencing service is active if and only if the referenced service is active.
4 Unary Vs Multiple: If the aggregation value is “1” then it is bounded to singular dependency. This service selection again depends on service ranking or service identifier. If the value is” n” then it is requesting for aggregate dependency this will take all the service implementations. This is a special case and should be handled differently with the code as shown in the below code snippet.

@Reference(cardinality= ReferenceCardinality.MANDATORY_MULTIPLE,
bind="bind",unbind="unbind",
referenceInterface=HelloWorld.class,
policy=ReferencePolicy.DYNAMIC)

List<HelloWorld> helloWorldImplList;

protected void bind(HelloWorld helloWorld){
if(helloWorldImplList == null){
helloWorldImplList = new ArrayList<HelloWorld>();

}
helloWorldImplList.add(helloWorld);
}
protected void unbind(HelloWorld helloWorld){
helloWorldImplList.remove(helloWorld);
}

In the above code bind and unbind methods, there are multiple calls. Each call is a helloWorld implementation that was found in the service registry that matched HelloWorld and all the implementation classes are added to a list. This list can be used to retrieve all the implementation classes.

What is reference policy while referencing a service?
AEM OSGi bundles are dynamic (which means that services can come and go on the fly). Therefore a service might be deregistered while it’s been referenced or might come back at any moment.To handle this possible situation, OSGi provides two types of reference policies:
  • Static (default)
  • Dynamic
Static Policy
When a static service is been referenced, a new instance is injected. This means
before using this referenced service, if it is being unregistered from the
service registry, SCR by default does not dynamically change the value of a
service reference. Instead, it discards the component instance and creates a
new instance (So on the fly it had replaced implementation class with the null
value). If the component is also published as a service then the service
registration is removed and replaced.
Consider the following code example.


Assume that HelloWorldImpl2 component is stopped. As soon as the component is stopped, it discarded the component instance and created a new one. Now what if the referenced service comes back?
Because it’s a static reference policy this component cannot bind newly created service reference. This component can be recreated to get it bind to the new service.

Dynamic Policy

Dynamic policy simply informs SCR that our component is capable of being updated with changing references. But code should handle synchronisation problems and should be careful while doing this.If a service reference is having dynamic policy then ideally we should have a bind and unbind methods. A bind method will be called and a reference is injected as a parameter. So inside the bind method reference has to be assigned to the local variable.

@Reference(bind = “bind”, unbind = “unbind”, policy =ReferencePolicy.DYNAMIC, cardinality=ReferenceCardinality.OPTIONAL_UNARY) HelloWorldhelloWorld;

LOG.info(“—————–binding———————“); 
this.helloWorld = helloWorld; }

Now even though a referenced service goes off as we haveassigned it to a local variable (helloWorld) it will be still exist until thecomponent gets destroyed.Now what if the referenced service comes back?Because it’s a dynamic reference policy, this componentbinds to the new service on the fly.

Layering
The OSGi has a layered model that is depicted in the following figure.
The following list contains a short definition of the terms:
  • Bundles – Bundles are the OSGi components made by the developers.
  • Services – The services layer connects bundles in a dynamic way by offering a publish-find-bind model for plain old Java objects.
  • Life-Cycle – The API to install, start, stop, update, and uninstall bundles.
  • Modules – The layer that defines how a bundle can import and export code.
  • Security – The layer that handles the security aspects.
  • Execution Environment – Defines what methods and classes are available in a specific platform.
These concepts are more extensively explained in the following sections.

Modules
The fundamental concept that enables such a system is modularity. Modularity simplistically said, is about assuming less. Modularity is about keeping things local and not sharing. It is hard to be wrong about things you have no knowledge of and make no assumptions about them. Therefore, modularity is at the core of the OSGi specifications and embodied in the bundleconcept. In Java terms, a bundle is a plain old JAR file. However, wherein standard Java everything in a JAR is completely visible to all other JARs, OSGi hides everything in that JAR unless explicitly exported. A bundle that wants to use another JAR must explicitly import the parts it needs. By default, there is no sharing.

Though the code hiding and explicit sharing provide many benefits (for example, allowing multiple versions of the same library being used in a single VM), the code-sharing was only there to support OSGi services model. The services model is about bundles that collaborate.

Services
The reason we needed the service model is that Java shows how hard it is to write a collaborative model with only class sharing. The standard solution in Java is to use factories that use dynamic class loading and statics. For example, if you want a DocumentBuilderFactory, you call the static factory method DocumentBuilderFactory.newInstance(). Behind that façade, the newInstance methods try every class loader trick in the book (and some that aren’t) to create an instance of an implementation subclass of the DocumentBuilderFactory class. Trying to influence what implementation is used is non-trivial (services model, properties, conventions in class name), and usually global for the VM. Also, it is a passive model. The implementation code can not do anything to advertise its availability, nor can the user list the possible implementations and pick the most suitable implementation. It is also not dynamic. Once an implementation hands out an instance, it can not withdraw that object. Worst of all, the factory mechanism is a convention used in hundreds of places in the VM where each factory has its own unique API and configuration mechanisms. There is no centralized overview of the implementations to which your code is bound.

The solution to all these issues is the OSGi service registry. A bundle can create an object and register it with the OSGi service registry under one or more interfaces. Other bundles can go to the registry and list all objects that are registered under specific interfaces or classes. For example, a bundle provides an implementation of the DocumentBuilder. When it gets started, it creates an instance of its DocumentBuilderFactoryImpl class and registers it with the registry under the DocumentBuilderFactory class. A bundle that needs a DocumentBuilderFactory can go to the registry and ask for all available services that extend the DocumentBuilderFactory class. Even better, a bundle can wait for a specific service to appear and then get a callback.

A bundle can, therefore, register a service, it can get a service, and it can listen for a service to appear or disappear. Any number of bundles can register the same service type, and any number of bundles can get the same service. This is depicted in the following figure.

What happens when multiple bundles register objects under the same interface or class? How can these be distinguished? The answer is properties. Each service registration has a set of standard and custom properties. An expressive filter language is available to select only the services in which you are interested. Properties can be used to find the proper service or can play other roles at the application level.

Services are dynamic. This means that a bundle can decide to withdraw its service from the registry while other bundles are still using this service. Bundles using such a service must then ensure that they no longer use the service object and drop any references. We know, this sounds like a significant complexity but it turns out that helper classes like the Service Tracker and frameworks like iPOJO, Spring, and Declarative Services can make the pain minimal while the advantages are quite large. The service dynamics were added so we could install and uninstall bundles on the fly while the other bundles could adapt. That is, a bundle could still provide functionality even if the http service went away. However, we found out over time that the real world is dynamic and many problems are a lot easier to model with dynamic services than static factories. 

For example, a Device service could represent a device on the local network. If the device goes away, the service representing it is unregistered. This way, the availability of the service models the availability of a real-world entity. This works out very well in, for example, the distributed OSGi model where a service can be withdrawn if the connection to the remote machine is gone. It also turns out that the dynamics solve the initialization problem. OSGi applications do not require a specific start ordering in their bundles.
The effect of the service registry has been that many specialized APIs can be much modeled with the service registry. Not only does this simplify the overall application, but it also means that standard tools can be used to debug and see how the system is wired up.

Though the service registry accepts any object as a service, the best way to achieve reuse is to register these objects under (standard) interfaces to decouple the implementer from the client code. This is the reason the OSGi Alliance publishes the Compendium specifications. These specifications define a large number of standard services, from a Log Service to a Measurement and State specification. All these standardized services are described in great detail.

SCR Annotations
The maven-scr-plugin uses the SCR annotations from the corresponding subproject at Apache Felix. All annotations are in the org.apache.felix.scr.annotations package. If you want to use the annotations in your project, you have to use a maven-scr-plugin version >= 1.24.0 and make sure that you add a dependency to the annotations to your POM:

<dependency> 
 <groupId>org.apache.felix</groupId> <artifactId>org.apache.felix.scr.annotations</artifactId> <version>1.12.0</version> 
</dependency>

The following annotations are supported:
  • @Component
  • @Activate, @Deactivate, and @Modified
  • @Service
  • @Property
  • @Reference
The annotations itself do not support the new features from R6 or above. It is suggested to use the official OSGi annotations for Declarative Services instead.

@Component
The @Component annotation is the only required annotation. If this annotation is not declared for a Java class, the class is not declared as a component.
This annotation is used to declare the <component> element of the component declaration. The required <implementation> element is automatically generated with the fully qualified name of the class containing the @Component annotation.

Supported attributes:
ds

Default: true
SCR Descriptor: —
Metatype Descriptor: —
Whether the Declarative Services descriptor is generated or not. If this parameter is not set or set to true the Declarative Services descriptor is generated in the service descriptor file for this component. Otherwise, no Declarative Services descriptor is generated for this component.

specVersion
Default: 1.0
SCR Descriptor: —
Metatype Descriptor: —
Defines what Declarative Services specification the component is written against. Though the Maven SCR Plugin is very good at detecting whether components are written against the original or a newer specification, there are some cases, where the plugin may fail. For these cases, the specVersion attribute may be set to the correct version. Currently supported values for this attribute are 1.0 and 1.1. Since version 1.4.1 of the Maven SCR Plugin and version 1.0.1 of the SCR Annotations.

metatype
Default: false
SCR Descriptor: —
Metatype Descriptor: —
Whether Metatype Service data is generated or not. If this parameter is set to true Metatype Service data is generated in the metatype.xml file for this component. Otherwise, no Metatype Service data is generated for this component.

componentAbstract
Default: see description
SCR Descriptor: —
Metatype Descriptor: —
This marks an abstract service description that is not added to the descriptor but intended for reuse through inheritance. This attribute defaults to true for abstract classes and false for concrete classes.

inherit
Default: true
SCR Descriptor: —
Metatype Descriptor: —
Whether any service, property, and reference declarations from base classes should be inherited by this class.

createPid
Default: true
SCR Descriptor: service.pid
Metatype Descriptor: —
Generate the service.pid property if non is declared.

name
Default: Fully qualified name of the Java class
SCR Descriptor: component.name
Metatype Descriptor: OCD.id
Defines the Component name also used as the PID for the Configuration Admin Service

enabled
Default: true
SCR Descriptor: component.enabled
Metatype Descriptor: —
Whether the component is enabled when the bundle starts

factory
Default: —
SCR Descriptor: component.factory
Metatype Descriptor: —
Whether the component is a factory component

immediate
Default: —
SCR Descriptor: component.immediate
Metatype Descriptor: —
Whether the component is immediately activated

policy
Default: OPTIONAL
SCR Descriptor: component.policy
Metatype Descriptor: —
The configuration policy for this component: OPTIONAL, IGNORE, or REQUIRE. This attribute is supported since version 1.4.0 of the plugin and requires a Declarative Service implementation 1.1 or higher.

label
Default: %<name>.name
SCR Descriptor: —
Metatype Descriptor: OCD.name
This is generally used as a title for the object described by the meta-type. This name may be localized by prepending a % sign to the name.

description
Default: %<name>.name
SCR Descriptor: —
Metatype Descriptor: OCD.description
This is generally used as a description for the object described by the meta-type. This name may be localized by prepending a % sign to the name.

configurationFactory
Default: false
SCR Descriptor: —
Metatype Descriptor: Designate.factoryPid
Is this a configuration factory? (since 1.4.0)

Abstract Service Descriptions
If the @Component annotations contain the attribute componentAbstract with a value of true, the containing class is regarded as an abstract class. It is not added to the service descriptor and the tags are not validated. The information about this class is added to the bundle. Classes from other bundles (or the same) can extend this abstract class and do not need to specify the references of the abstract class if they set the inheritparameter on the scr.component tag to true.
This allows creating abstract classes which already provide some valuable functionality without having to deal with the details like reference definitions in each and every subclass.

@Activate, @Deactivate, and @Modified
The Declarative Service version 1.1 allows to specify the name for the activate, deactivate, and modified method (see the spec for more information). The @Activate, @Deactivate, and @Modified annotation can be used to mark a method to be used for the specified purpose. However, as the DS specifies a method search algorithm, there are rare cases where the marked method is not used (if there is another method with the same name, but a different signature this might happen).
These annotations have no attributes.

@Service
The @Service annotation defines whether and which service interfaces are provided by the component. This is a class annotation.

This annotation is used to declare <service> and <provide> elements of the component declaration. See section 112.4.6, Service Elements, in the OSGi Service Platform Service Compendium Specification for more information.

Supported attributes:
value

Default: All implemented interfaces
SCR Descriptor: provide.interface
The name of the service interface provided by the component. This can either be the fully qualified name or just the interface class name if the interface is either in the same package or is imported. If this property is not set provide elements will be generated for all interfaces generated by the class

serviceFactory
Default: false
SCR Descriptor: service.servicefactory
Whether the component is registered as a ServiceFactory or not

Omitting the Service the annotation will just define (and activate if required) the component but not register it as a service. Multiple Service annotations may be declared each with its own value. These annotations need to be wrapped into a Services annotation. The component is registered as a ServiceFactory if at least on Service annotations declare the serviceFactory attribute as true.

@Property
The @Property annotation defines properties which are made available to the component through the ComponentContext.getProperties() method. These tags are not strictly required but may be used by components to the defined initial configuration. Additionally, properties may be set here to identify the component if it is registered as a service, for example, the service.description and service.vendor properties.

This annotation can be applied to the component class level or on a field-defining a constant with the name of the property.
This annotation is used to declare <property> elements of the component declaration. See section 112.4.5, Properties and Property Elements, in the OSGi Service Platform Service Compendium Specification for more information.

Supported attributes:
name

Default: The name of constant
SCR Descriptor: property.name
Metatype Descriptor: AD.id
The name of the property. If this tag is defined on a field with an initialization expression, the value of that expression is used as the name if the field is of type String.

value
Default: —
SCR Descriptor: property.value
Metatype Descriptor: AD.default
The string value of the property. This can either be a single value or an array.

longValue
Default: —
SCR Descriptor: property.value
Metatype Descriptor: AD.default
The long value of the property. This can either be a single value or an array.

doubleValue
Default: —
SCR Descriptor: property.value
Metatype Descriptor: AD.default
The double value of the property. This can either be a single value or an array.

floatValue
Default: —
SCR Descriptor: property.value
Metatype Descriptor: AD.default
The float value of the property. This can either be a single value or an array.

intValue
Default: —
SCR Descriptor: property.value
Metatype Descriptor: AD.default
The int value of the property. This can either be a single value or an array.

byteValue
Default: —
SCR Descriptor: property.value
Metatype Descriptor: AD.default
The byte value of the property. This can either be a single value or an array.

charValue
Default: —
SCR Descriptor: property.value
Metatype Descriptor: AD.default
The char value of the property. This can either be a single value or an array.

boolValue
Default: —
SCR Descriptor: property.value
Metatype Descriptor: AD.default
The boolean value of the property. This can either be a single value or an array.

shortValue
Default: —
SCR Descriptor: property.value
Metatype Descriptor: AD.default
The short value of the property. This can either be a single value or an array.

label
Default: %<name>.name
SCR Descriptor: —
Metatype Descriptor: AD.name
The label to display in a form to configure this property. This name may be localized by prepending a % sign to the name.

description
Default: %<name>.description
SCR Descriptor: —
Metatype Descriptor: AD.description
A descriptive text to provide the client in a form to configure this property. This name may be localized by prepending a % sign to the name.

propertyPrivate
Default: Depending on the name
SCR Descriptor: —
Metatype Descriptor: See description Boolean flag defining whether a metatype descriptor entry should be generated for this property or not. By default a metatype descriptor entry, i.e. an AD element, is generated except for the properties service.pid, service.description, service.id, service.ranking, service.vendor, service.bundlelocation and service.factoryPid. If a property should not be available for display in a configuration user interface, this parameter should be set to true.

cardinality
Default: Depends on property value(s)
SCR Descriptor: —
Metatype Descriptor: AD.cardinality
Defines the cardinality of the property and its collection type. If the cardinality is negative, the property is expected to be stored in a java.util.Vector (primitive types such as boolean are boxed in the Wrapper class), if the cardinality is positive, the property is stored in an array (primitve types are unboxed, that is Boolean type values are stored in boolean\[\]()). The actual value defines the maximum number of elements in the vector or array, where Integer.MIN*INT describes an unbounded Vector and Integer.MAX*INT describes an unbounded array. If the cardinality is zero, the property is a scalar value. If the defined value of the property is set in the value attribute, the cardinality defaults to 0 (zero for scalar value). If the property is defined in one or more properties starting with values, the cardinality defaults to Integer.MAX_INT, that is an unbounded array.

options
Default: —
SCR Descriptor: —
Metatype Descriptor: See below
See below for a description of the options attribute.
Generating <properties> elements referring to bundle entries is not currently supported.
Multiple property annotations on the class level can be embedded in the 
@Properties annotation. 
For example:

@Properties({ 
 @Property(name = "prop1", value = "value1"), 
 @Property(name = "prop2", value = "value2") 
}
)

Naming the Property
It is important to carefully define the name of properties. By using a constant of the form

@Property(value="default value") 
static final String CONSTANT_NAME = "property.name";

and defining the @Property annotation on this constant, the name of the property is taken from the constant value. Thus it may easily be ensured, that both the property in the descriptor files and the property used by the implementation are actually the same. In addition the value attribute can refer to another constant.

The options Attribute
Some properties may only be set to a set of possible values. To support user interfaces which provide a selection list of values or a list of checkboxes the option values and labels may be defined as parameters to the @Property annotation.
The value of the options attribute is a list of @PropertyOptions annotations:

@Property(name = "sample", 
 options = { 
 @PropertyOption(name = "option1", value = "&option.label.1"),   @PropertyOption(name = "option2", value = "&option.label.2") 
 } 
)

The @PropertyOption‘s name is used as the value while the parameter value is used as the label in the user interface. This label may be prepended with a % sign to localize the string.
The options are written to the metatype.xml file as Option elements inside the AD element defining the property. The name of the parameter will be used for the Option.value attribute while the value of the parameter defines the Option.label attribute.

Multivalue Properties
Generally the value of a property is scalar, that is a property has a single value such as true, 5 or "This is a String". Such scalar values are defined with the different value attributes of the Property annotation. In the case of a scalar property value, the cardinality parameter value is assumed to be 0 (zero) unless of course set otherwise.
There may be properties, which have a list of values, such as a list of possible URL mappings for an URL Mapper. Such multiple values are defined just by comma separate as the value of the annotation parameter.
If the cardinality of the property is not explicilty set with the cardinality property, it defaults to Integer.MAX_INT, i.e. unbound array, if multiple values are defined. Otherwise the cardinality parameter may be set for example to a negative value to store the values in a java.util.Vector instead.

@Reference
The @Reference annotation defines references to other services made available to the component by the Service Component Runtime.
This annotation may be declared on a Class level or any Java field to which it might apply. Depending on where the annotation is declared, the parameters may have different default values.
This annotation is used to declare <reference> elements of the component declaration. See section 112.4.7, Reference Element, in the OSGi Service Platform Service Compendium Specification for more information.

Supported parameters:
name

Default: Name of the field
SCR Descriptor: reference.name
The local name of the reference. If the Reference annotation is declared in the class comment, this parameter is required. If the annotation is declared on a field, the default value for the name parameter is the name of the field

interfaceReference
Default: Type of the field
SCR Descriptor: reference.interface
The name of the service interface. This name is used by the Service Component Runtime to access the service on behalf of the component. If the Reference annotation is declared on a class level, this parameter is required. If the annoation is declared on a field, the default value for the interfaceReference parameter is the type of the field

cardinality
Default: 1..1
SCR Descriptor: reference.cardinality
The cardinality of the service reference. This must be one of value from the enumeration ReferenceCardinality

policy
Default: static
SCR Descriptor: reference.policy
The dynamicity policy of the reference. If dynamic the service will be made available to the component as it comes and goes. If static the component will be deactivated and re-activated if the service comes and/or goes away. This must be one of static and dynamic

target
Default: —
SCR Descriptor: reference.target
A service target filter to select specific services to be made available. In order to be able to overwrite the value of this value by a configuration property, this parameter must be declared. If the parameter is not declared, the respective declaration attribute will not be generated

bind
Default: See description
SCR Descriptor: reference.bind
The name of the method to be called when the service is to be bound to the component. The default value is the name created by appending the reference name to the string bind. The method must be declared public or protected and take single argument which is declared with the service interface type

unbind
Default: See description
SCR Descriptor: reference.unbind
The name of the method to be called when the service is to be unbound from the component. The default value is the name created by appending the reference name to the string unbind. The method must be declared public or protected and take single argument which is declared with the service interface type

strategy
Default: event
SCR Descriptor: reference.strategy
The strategy used for this reference, one of event or lookup. If the reference is defined on a field with a strategy of event and there is no bind or unbind method, the plugin will create the necessary methods


By aem4beginner

No comments:

Post a Comment

If you have any doubts or questions, please let us know.