Article summary

Summary

Discusses OSGi concepts and provides information about the AEM Eclipse plug-in to create an AEM project.  

A special thank you to Kalyan Venkat a member of the AEM community for contributing content that is used in this article. 

A special thank you to Ranta Kumar Kotla, a top community member, for testing this Community Article.

In addition to reading this article, it is also recommended that you watch the following Ask the AEM Community Experts session on using the Eclipse Plug-in and Brackets

Digital Marketing Solution(s) Adobe Experience Manager (Adobe CQ)
Audience
Developer (beginner - intermediate)
Required Skills
JCR nodes, JavaScript, HTML
Tested On Adobe Experience Manager 6.x

Note:

The following software  should be installed:

• Java 7 or 8

• Adobe Experience Manager 6+

• Maven 3+ http://maven.apache.org

• Eclipse IDE for Java EE Developers https://eclipse.org/downloads/

• The AEM extension for Eclipse https://docs.adobe.com/docs/en/dev-tools/aem-eclipse.html

Introduction

Adobe Experience Manager (AEM) is developed using frameworks such as OSGi and Apache Sling. OSGi defines a dynamic component that is written in Java. These specifications enable a development model where dynamic applications comprise of reusable components. The OSGi specifications enable components to hide their implementations from other components while communicating through services, which are objects that are specifically shared between components. For more information, see OSGi Architecture.

 

OSGI-INrto
How OSGi is integrated within AEM

This article provides overview information about OSGi bundles and then covers how to create an AEM project by using the AEM Eclipse plug-in. 

Understanding OSGi concepts

As an AEM developer, it is important that you are familiar with these Sling annotations:

  • @Component 
  • @Service
  • @Reference
  • @Property

For more information about these annotations, see SCR Annotations.

It is also important that you understand the difference between components and services. 

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. Typically, you build an OSGi bundle by using Maven and an Adobe Archetype. For information, see Creating your first AEM Service using an Adobe Maven Archetype project.

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. 

xml
Servicecomponents XML file

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. For information about using Dependency Injection, see Injecting a DataSourcePool Service into an Adobe Experience Manager OSGi bundle.

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 sayHello method.  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. 

Code
Java code

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 ourcomponent is capable of being updated with changing references. But code shouldhandle synchronization problems and should be careful while doing this.If a service reference is having dynamic policy then ideallywe should have a bind and unbind methods. A bind method will be called and areference is injected as a parameter. So inside the bind method reference hasto 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.

Note:

If the side panel on the left side of the screen is not visible, click the Toggle Side Panel button (furthest to the left) in the top toolbar.

Using the AEM Eclipse Plug-in to set up an AEM Project

This section walks you through how to create an AEM project using the AEM plugin. 

Installing AEM Eclipse Plugin

Adobe has released an Eclipse plugin that lets you develop AEM projects. You can use the plugin to develop OSGi bundles, Components, Templates and Content. The plugin integrates with an AEM instance and all the changes can be deployed directly on an AEM server.

To install the AEM Plugin in Eclipse (Eclipse Luno), perform these steps: 

1. Goto Help, Install New Software.…
2. Click Add and enter http://eclipse.adobe.com/aem/dev-tools/ in Location and click OK.


 

setup1
Installing the AEM Eclipse plug-in

Step 3: Select both ‘AEM’ and ‘Sling’ and Click ‘Next’.

setup2
AEM Eclipse plug-in

Step 4: Click Finish and restart Eclipse.

Now, you are ready to create an AEM project. 

Creating a new project

You can create a new project by performing these steps: 

1. Open the Eclipse IDE.

2. Switch to the AEM perspective, to have the panels arranged in a convenient way: Menu Window –> Open Perspective –> Other… –> AEM –> OK.
 

3. Click on the new project icon.

4. Select AEM –> AEM Sample Multi-Module Project.

5. Select version 10 of the Maven Archetype, which is a blueprint used for the project that is going to be created. 

setup4
Archetype 10

6. Enter the project details:

  • Name: Summit Lab
  • Group Id: org.summit
  • Artefact Id: lab
setup5
AEM Project details

7. Configure the Server:

  •  Server name: AEM Development Instance
  •  Host name: localhost
  •  Port: 4502
  •  Username: admin
  •  Password: admin
  •  Debug Port: 10123
     
setup6
AEM Server settings

It will take a minute for creation of the project to complete and when it is done, it should look like:

setup7
An AEM project within Eclipse

Verify that the project got synchronized to the instance by checking the presence of the Summit Lab site:

  1. In the left navigation rail, go to Sites.
  2. Navigate to the “Summit Lab Site” page by clicking on its card (located at the bottom of the list).
  3. On the “English” page click the pencil icon of its card (displayed when hovering it with the mouse).

The page you see should resemble the following illustration. 
 

PageA
Output from the AEM Project

Note:

In case the AEM page does not appear, try performing a Clean and Publish operation in Eclipse.  For a full explanation of the default files created by a Maven Archetype 10, see Creating your first AEM 6.2 Project using Adobe Maven Archetype 10.

See also

Please refer to the AEM community page for other articles that discuss how to build AEM services/applications.

This work is licensed under a Creative Commons Attribution-Noncommercial-Share Alike 3.0 Unported License  Twitter™ and Facebook posts are not covered under the terms of Creative Commons.

Legal Notices   |   Online Privacy Policy