Showing posts with label Bundles. Show all posts
Showing posts with label Bundles. Show all posts

March 30, 2021
Estimated Post Reading Time ~

Trace AEM Bundle Issues

There comes a point where you need to triage why a bundle isn't behaving as you would expect. The simplest way I've found is to setup a logger. A logger has many advantages over tailing logs/error.log...

  • You can target a specific bundle. No need to grep.
  • You can leave the generic logger on something less frequent like 'Information'.
  • This is likely what you'll be sending if you end up talking to Adobe support.

On to setting up a logger for a specific bundle...

  1. Open Console: http://localhost:4502/system/console/configMgr
  2. Find the bundle PID you want to trace. In our case, we want to trace com.adobe.granite.auth.saml
  3. Add a new Logger entry at "Apache Sling Logging Logger"
    • Set the Log Level: Trace
    • Set the Log File Location: logs/saml-error.log
    • Specify your Bundle PID: com.adobe.granite.auth.saml
  4. Go tail it via terminal: tail -f logs/saml-error.log

Bundle Trace 1 Bundle Trace 3



By aem4beginner

January 4, 2021
Estimated Post Reading Time ~

ACS Commons Installation

Following is the guide to install the ACS Commons package on the AEM instance.

Step-01: Go to the following link to ACS Commons Package


Step-02: Directly download the latest version from the following link


[code lang=’bash’]
$ https://github.com/Adobe-Consulting-Services/acs-aem-commons/releases/download/acs-aem-commons-3.17.0/acs-aem-commons-content-3.17.0.zip
[/code]

Step-03: Open CRXDE and select the Package Manager


Step-04: On Package Manager, select UPLOAD PACKAGE


Step-05: Browse and Upload the downloaded ACS commons package


Step-06: Install the uploaded Package




Step-07: Verifying Package installation


By aem4beginner

January 2, 2021
Estimated Post Reading Time ~

Speed up the AEM Build Time

How to Speed up the AEM Build Time
Recently I found the tool to speed up the build time of your Maven-based projects.
Maven Daemon is let's say maven wrapper tool which provides faster build time.

Some facts about Maven Daemon:

  • build executes in a long-living background process
  • native executable
  • use multiple CPU cores to build modules in parallel
More information about Maven Daemon you can find in the GitHub repository.

Maven Daemon Installation
Use sdk or brew to install Maven Daemon
$ sdk install mvnd
$ brew install mvndaemon/homebrew-mvnd/mvnd

You can verify the installation with
~ mvnd --version 
mvnd native client 0.2.0-darwin-amd64 (0cd0b3f04692b7970fda06c206c1fbaac68fe9ce) 
Terminal: org.jline.terminal.impl.PosixSysTerminal with pty org.jline.terminal.impl.jansi.osx.OsXNativePty 
Apache Maven 3.6.3 (cecedd343002696d0abb50b32b541b8a6ba2883f) 
Maven home: /usr/local/Cellar/mvnd/HEAD-1c610c3/libexec/mvn 
Java version: 15.0.1, vendor: N/A, 
runtime: /usr/local/Cellar/openjdk/15.0.1/libexec/openjdk.jdk/Contents/Home Default locale: en_GB, platform encoding: UTF-8 
OS name: "mac os x", version: "10.14.6", arch: "x86_64", family: "mac"

Maven vs Maven Daemon build time comparison

For testing purposes, I will compare build times for the AEM project. The project was built 2x times before measurement.

This measurement is not perfect, since a lot of factors can affect final build time (+- few seconds), but is fair enough to see a difference.

For testing purposes, I have used AEM Project Archetype version 24.
mvn clean install vs mvnd clean install
mvn: 26.586 s
mvnd: 12.654 s

mvn clean install 
[INFO] Reactor Summary for mysite 1.0.0-SNAPSHOT: 
[INFO] [INFO] mysite ............................................. SUCCESS [ 0.242 s] 
[INFO] My Site - Core ..................................... SUCCESS [ 6.994 s] 
[INFO] My Site - UI Frontend .............................. SUCCESS [ 11.099 s] 
[INFO] My Site - Repository Structure Package ............. SUCCESS [ 0.795 s] [INFO] My Site - UI apps .................................. SUCCESS [ 3.890 s] 
[INFO] My Site - UI content ............................... SUCCESS [ 1.672 s] 
[INFO] My Site - UI config ................................ SUCCESS [ 0.105 s] 
[INFO] My Site - All ...................................... SUCCESS [ 0.138 s] 
[INFO] My Site - Dispatcher ............................... SUCCESS [ 0.080 s] 
[INFO] My Site - UI Tests ................................. SUCCESS [ 0.274 s] 
[INFO] ------------------------------------------------------------------------ 
[INFO] BUILD SUCCESS 
[INFO] ------------------------------------------------------------------------ 
[INFO] Total time: 26.586 s 
[INFO] Finished at: 2020-12-30T11:59:11+01:00 
[INFO] ------------------------------------------------------------------------

mvnd clean install 
[INFO] Reactor Summary for mysite 1.0.0-SNAPSHOT: 
[INFO] [INFO] mysite ............................................. SUCCESS [ 0.016 s] 
[INFO] My Site - Core ..................................... SUCCESS [ 4.300 s]
 [INFO] My Site - UI Frontend .............................. SUCCESS [ 10.442 s] 
[INFO] My Site - Repository Structure Package ............. SUCCESS [ 0.178 s] [INFO] My Site - UI apps .................................. SUCCESS [ 1.126 s] 
[INFO] My Site - UI content ............................... SUCCESS [ 0.911 s] 
[INFO] My Site - UI config ................................ SUCCESS [ 0.156 s] 
[INFO] My Site - All ...................................... SUCCESS [ 0.107 s] 
[INFO] My Site - Dispatcher ............................... SUCCESS [ 0.078 s] 
[INFO] My Site - UI Tests ................................. SUCCESS [ 0.063 s] 
[INFO] ------------------------------------------------------------------------ 
[INFO] BUILD SUCCESS 
[INFO] ------------------------------------------------------------------------ 
[INFO] Total time: 12.654 s (Wall Clock) 
[INFO] Finished at: 2020-12-30T11:59:58+01:00 
[INFO] ------------------------------------------------------------------------

mvn clean install -PautoInstallPackage vs mvnd clean install -PautoInstallPackage
mvn: 29.582 s
mvnd: 12.995 s


mvn clean install -PautoInstallPackage 
[INFO] Reactor Summary for mysite 1.0.0-SNAPSHOT: 
[INFO] [INFO] mysite ............................................. SUCCESS [ 0.223 s] 
[INFO] My Site - Core ..................................... SUCCESS [ 7.354 s] 
[INFO] My Site - UI Frontend .............................. SUCCESS [ 11.338 s] 
[INFO] My Site - Repository Structure Package ............. SUCCESS [ 0.826 s] [INFO] My Site - UI apps .................................. SUCCESS [ 4.343 s] 
[INFO] My Site - UI content ............................... SUCCESS [ 2.885 s] 
[INFO] My Site - UI config ................................ SUCCESS [ 0.454 s] 
[INFO] My Site - All ...................................... SUCCESS [ 0.346 s] 
[INFO] My Site - Dispatcher ............................... SUCCESS [ 0.061 s] 
[INFO] My Site - UI Tests ................................. SUCCESS [ 0.374 s] 
[INFO] ------------------------------------------------------------------------ 
[INFO] BUILD SUCCESS 
[INFO] ------------------------------------------------------------------------ 
[INFO] Total time: 29.582 s [INFO] Finished at: 2020-12-30T12:06:29+01:00 [INFO] ------------------------------------------------------------------------

mvnd clean install -PautoInstallPackage 
[INFO] Reactor Summary for mysite 1.0.0-SNAPSHOT: 
[INFO] 
[INFO] mysite ............................................. SUCCESS [ 0.005 s] 
[INFO] My Site - Core ..................................... SUCCESS [ 4.004 s] 
[INFO] My Site - UI Frontend .............................. SUCCESS [ 10.288 s]
 [INFO] My Site - Repository Structure Package ............. SUCCESS [ 0.177 s] [INFO] My Site - UI apps .................................. SUCCESS [ 1.433 s] 
[INFO] My Site - UI content ............................... SUCCESS [ 1.010 s] 
[INFO] My Site - UI config ................................ SUCCESS [ 0.292 s] 
[INFO] My Site - All ...................................... SUCCESS [ 0.227 s] 
[INFO] My Site - Dispatcher ............................... SUCCESS [ 0.079 s] 
[INFO] My Site - UI Tests ................................. SUCCESS [ 0.053 s] 
[INFO] ------------------------------------------------------------------------ 
[INFO] BUILD SUCCESS 
[INFO] ------------------------------------------------------------------------ 
[INFO] Total time: 12.995 s (Wall Clock) 
[INFO] Finished at: 2020-12-30T12:08:30+01:00 
[INFO] ------------------------------------------------------------------------

Note:
Your AEM project build will fail with Maven Daemon if you use bnd-maven-plugin version < 5.1.01

[ERROR] Failed to execute goal biz.aQute.bnd:bnd-maven-plugin:5.0.0:bnd-process (bnd-process) on project lot-polish-airlines.core: bnd error: null: ConcurrentModificationException -> [Help 1]

Sum up
As we can see by the results Maven Daemon build time is approximately 2x faster then with normal maven. Installation was pretty much straightforward and so far didn't notice any downsides, so why not use it and save some time.


By aem4beginner

FSClassLoader Now In AEM



Customers and developers upgrading to AEM 6.0 SP3 will find that there’s a new bundle in use, FSClassLoader. As I described this bundle offers superior performance as compared to the repository-based classloader, however, it does remove the option for developers to access the generated Java code for their JSP’s under /var/classes.

Luckily, when Adobe built AEM 6.0 SP3, they used FSClassLoader version 1.0.2 which includes an OSGi console allowing developers to view the compiled Java files. To view this, open up the OSGi console at http://localhost:4502/system/console and select the console under Sling >> File System Class Loader


From the console, you can view or download the compiled .class file, generated .java file, or the .deps file which lists the JSP scripts and TagLibs the files depends on.


Hopefully, this helps anyone upgrading to AEM 6.0 SP3 and wondering why their generated Java files aren’t appearing under /var/classes


By aem4beginner

December 28, 2020
Estimated Post Reading Time ~

AEM inheritedpageproperties with Sightly, JSP, OSGI Bundle

Inheritedpageproperties helps you retrieve a parent property from parent pages. Inherited page properties utilises com.day.cq.commons.inherit.HierarchyNodeInheritanceValueMap, where the search is made on the page hierarchy, upwards; searching children of the page nodes (components) are not included. Inherited page properties can be retrieved in multiple ways, where this article will only focus on 3 ways.

In this article, we will go through the 3 different ways in how we can retrieve inherited page properties.

1. inheritedPageProperties with Sightly
Sightly offers a plethora of AEM Global objects, and one of them notably is the “inheritedPageProperties”. Utilizing the inheritedPageProperties global object, we can use dot or square bracket notation to access the inherited page property value.

${inheritedPageProperties.myCustomProperty}
${inheritedPageProperties['myCustomProperty']}
${inheritedPageProperties.jcr:title}
${inheritedPageProperties['jcr:title']}


2. inheritedPageProperties with JSP
Utilising the JSP include, /libs/foundation/global.jsp (purpose of retreiving the currentPage AEM global object), we can make use of the HierarchyNodeInheritanceValueMap.class, and currentPage resource to initialise the InheritanceValueMap.class object. Next, calling the method getInherited(String name, Class<T> type), we are able to get the inherited page property.

<%@include file="/libs/foundation/global.jsp"%>
<%@ page import="com.day.cq.commons.inherit.InheritanceValueMap" %>
<%@ page import="com.day.cq.commons.inherit.HierarchyNodeInheritanceValueMap" %>

<%
InheritanceValueMap ivm = new HierarchyNodeInheritanceValueMap(currentPage.getContentResource());
String inheritedValueMyCustomProperty = ivm.getInherited("myCustomerProperty", String.class);
String inheritedValueJcrTitle = ivm.getInherited("jcr:title", String.class);
%>
inheritedValueMyCustomProperty = <%= inheritedValueMyCustomProperty %>
inheritedValueJcrTitle = <%= inheritedValueJcrTitle %>


3. inheritedPageProperties with OSGI Bundle, Java Backend
Similar to the JSP implementation above, we can make use of the HierarchyNodeInheritanceValueMap.class, and the currentPage resource to initialize the InheritanceValueMap.class object. Next, calling the method get inherited(String name, Class<T> type), we are able to get the inherited page property.

import com.day.cq.commons.inherit.InheritanceValueMap;
import com.day.cq.commons.inherit.HierarchyNodeInheritanceValueMap;

@ScriptVariable
private Page currentPage;
...
InheritanceValueMap ivm = new HierarchyNodeInheritanceValueMap(currentPage.getContentResource());
String inheritedValueMyCustomProperty = ivm.getInherited("myCustomerProperty", String.class);
String inheritedValueJcrTitle = ivm.getInherited("jcr:title", String.class);





By aem4beginner

May 27, 2020
Estimated Post Reading Time ~

How to Add and Read Bundle / Service Configurations(String, Dropdown, Array/Multifield )

Adding Properties to the Bundle/ OSGI CQ Service
String / TextField
@Property(value = "GET")
static final String STRING_VAL = "string.textfield";

String Array / Multifield
@Property ( unbounded=PropertyUnbounded.ARRAY, value={"*"},label="Template paths",description="eg: /apps/devtools/templates/page-home" )
private static final String MUTIFIELD_EX = "multifield.test";

Boolean Field
@Property(boolValue={false}, label="Boolean values", description="Booealn test")
private static final String BOOLEN_TEST = "boolean_test";
Dropdown
@Property( options={
@PropertyOption(name="blue", value="color-blue"),
@PropertyOption(name="green", value="color-green"),
@PropertyOption(name="red", value="color-red"),
@PropertyOption(name="yellow", value="color-yellow"),
private static final String SELECTION_TEST = "dropdown.test";

Reading Properties of Bundle/ OSGI CQ Service

1) You to get the ConfigurationAdmin reference
@Reference
ConfigurationAdmin configAdmin;

2) Get Bundle Configuration
Configuration config = configAdmin.getConfiguration(this.getClass().getCanonicalName());

3) Get properties of conguration
Dictionary<?, ?> configProperties = config.getProperties();

4) Red Properties
Reading String/TextField
String texfiledValue = (String) configProperties.get( STRING_VAL );
Reading the Dropdown
String dropdownTest = (String) configProperties.get( SELECTION_TEST );
Reading Boolean
Boolean booealnTest = ( Boolean ) configProperties.get( BOOLEN_TEST );
Reading Array/Multifield
String[] multifieldVlaues = (String[]) configProperties.get( MUTIFIELD_EX );

for( String value : multifieldVlaues ){
out.println( value );
}


By aem4beginner

How to Install/Add Bundles, Content Packages or Configurations at Runtime CRX in AEM

Install Bundles, Content Packages, or Configurations at Runtime If you want to install additional packages into the CRX, Create an install folder under the crx-quickstart.
Put your bundles, content packages, or configurations in the install folder. It will pick up while instance start and install into the CRX repository. Packages will install into CRX in the alphabetic order.

References:
AEM Documentation
Adobe Community

You can define additional bundles based on run modes for this you need to create an install.<run mode> folder.

for more information click here


By aem4beginner

May 20, 2020
Estimated Post Reading Time ~

Develop OSGi Bundle Using Adobe CRXDE Lite


It is often confusing as to how to set up an OSGi development environment for CQ5. In this post, I'll set what is to be coded aside, but focus on how to quickly and easily use CRXDE Lite (the web interface of CQ5) for
  1. setting up an OSGi project skeleton for development,
  2. adding libraries to OSGi project's internal build path,
  3. building OSGi projejct,
  4. deploying the compiled OSGi bundle in to CQ5 container.
What OSGi Bundle Can Bring to CQ
CQ5 runs in an Apache Felix OSGi container. To add configurable modular code to CQ, the code must also be an OSGi bundle jar. Out of the box, Adoble CQ5 is deployed with several OSGi components that you can configure them. To extend CQ's functionalities, you can develop your own OSGi bundle and deploy it into Felix, the OSGi container.

For example, if you want to write a custom library in Java that your JSP can import and use from any JSP file, you can develop an OSGi bundle. Or, if you want to some code to be triggered and executed whenever you 'activate/publish' a page node, you can develop an custom Workflow OSGi bundle with code of jobs to be executed whenever such an 'activate/publish' event is fired.

Create OSGi Bundle with CRXDE Lite
Step #1: Create an OSGi bundle project skeleton

Shoot up your CQ instance, log on as admin, go to CRXDE Lite. In CRXDE Lite, find a folder named 'src' (/apps/[your project]/src) under which is where your OSGi project will/should reside. To create a OSGi project skeleton, simply right-click src, select Create, then Create Bundle:


In the pop-up, give information to the bundle you'd create.
  • Symbolic Name: will be used toward the final OSGi bundle jar's name.
  • Name: is the name for displaying purposes in the CQ's Web console interface.
  • Package: is the full Java package name of the bundle you'd create. CQ will create corresponding folder to hold the java code.

After you hit OK, the following file structure with folders will be generated, include a BND file and an Activator.java.




Adobe CQ is not very user friendly. A common mistake developers make is forget to save along the way. Until now, nothing I created so far is saved. I have to explicitly save them by clicking on 'Save All.' You must remember to save often and I'm not going to remind you any more from this point on.



What if you have libraries (e.g., jars) to add to the build path for the project to compile in? I do not know any official documentation from Adobe about this but my experiments indicate if I create a folder named libs at the same level as the src folder, jars put under this libs folder will be built toward the project. In addition, I learned that /etc/crxde/profiles/default/libs/ is probably also part of the buildpath that you can also drop libraries there.

To demonstrate, I created a folder named libs, under which I put a dom4j jar and it will be picked up by CRXDE Lite's default bundle build step. Also, for demonstration purposes, I created some more Java classes (PageActivationEventHandler.java and PostpageActivationWorkflow.java) as if I had developed them and put them under the proper folder just to show where your custom Java source should go.




Step #2: Modify bnd file
BND is a command-line tool used internally by CQ for building OSGi bundles from a given descriptor file (.bnd file) to structure your JARs/Bundles by generating not just the MANIFEST.MF but also bundle up the JAR itself.

It is the auto-generated com.test.service.bnd file that I modified to overwrite the default to export all package and import all package:


Export-Package: * # 1
Import-Package: *
Private-Package: com.test.service
# Include-Resource:
Bundle-Name: Test Bundle
Bundle-Description:
Bundle-SymbolicName: com.test.service
Bundle-Version: 1.0.0-SNAPSHOT
Bundle-Activator: com.test.service.Activator


[1] For some reason, in CRXDE Lite, this '*' is required for making a specific component 'configurable' via CQ's configuration console. Otherwise, even you annotate a component with metatype=true (so Metatype Service data is generated in the metatype.xml file for this component) which in terms instructs CQ5 to provide a configuration page in the Felix Web console, the configuration interface still won't show under Web Console.

Step #3: Build bundle
To build, high-light the .bnd file, select Tools, then Bunld Bundle:


The result is the final bundle jar file generated under a folder named install which is at the same level as the src folder. As a reminder, the generated bundle jar won't show on CRXDE Lite until you refresh the install folder:


Install OSGi Bundle Built by CRXDE Lite
Once a bundle (.jar) file is generated under install folder, this bundle Jar file under install folder will be automatically picked up and installed by CQ5, specifically, by the JCR Installer module implicitly. In other words, if you followed step #3 for the first time that generated the bundle file (.jar) for the first time, the .jar should be installed for you already.

To verify the bundle jar is installed, you can always go to CQ's Web Console (probably at http://localhost:4502/system/console/configMgr), and look under OSGi, Bundles to see if the bundle name specified in step #1 above shows up.


Re-install OSGi Bundle Build by CRXDE Lite
Chances are, you'll be using CRXDE Lite to change your OSGi bundle code, build, install it, change the code, re-build, and re-install it over and over as part of the development process. I concluded the following steps to be most reliable:

1. Delete the old OSGi bundle (.jar) file under install folder. Click 'Save' to persist the deletion. This deletion will remove the bundle from appearing in the OSGi console. In other words, delete the .jar will uninstall the bundle.
2. Modify your OSGi code with enhancement or bug fixes. Rebuild (refer to step #3 as mentioned before) it, which will re-generate bundle file (.jar) under install folder.
3. Go to OSGi Console, locate the Bundle, click on it to bring up a page that only shows that bundle, click on "Refresh Packages."

'Refresh packages' instructs Felix OSGi container to reload the package dependency related to the package.
The same OSGi bundle under your development is now re-deployed.


References
Developing with CRXDE Lite
Hello, OSGi, Part 1: Bundles for beginners


By aem4beginner

May 15, 2020
Estimated Post Reading Time ~

How to refresh OSGI R6 components on bundle activation

Recently, I had the need to wrap the default implementation for AEM’s mail service in a new service called CustomMailService where I wanted to transform certain emails and let other emails be handled by the default service.

My main interest was for the AccountManagementService to bind my implementation of the MailService, instead the default implementation, you can achieve this by adding the service.ranking property and giving it an integer higher than the default implementation:
import com.day.cq.mailer.MailService;
import com.day.cq.mailer.MailingException;
import com.day.cq.mailer.MessageGateway;
import org.apache.commons.mail.Email;
import org.apache.commons.mail.EmailException;
import org.osgi.framework.Constants;
import org.osgi.service.component.annotations.Component;
import org.osgi.service.component.annotations.Reference;
import org.osgi.service.component.annotations.ReferenceCardinality;
import org.osgi.service.component.annotations.ReferencePolicy;
@Component(
property = {
"label=Custom Mail Service",
"description=CustomMail Service",
Constants.SERVICE_RANKING + ":Integer=1000"},
service = MailService.class, immediate = true)
public class CustomMailService implements MessageGateway<Email>, MailService {
@Reference(target = "(service.pid=com.day.cq.mailer.DefaultMailService)",
cardinality = ReferenceCardinality.MANDATORY, policy = ReferencePolicy.DYNAMIC)
private volatile MailService defaultMailService;
@Override
public boolean handles(Class<? extends Email> aClass) {
return true;
}
@Override
public void send(Email email) throws MailingException {
// transform email based on some conditions
defaultMailService.send(email);
}
@Override
public void sendEmail(Email email) throws EmailException {
defaultMailService.send(email);
}
}

But I hit a problem
The problem is, the AccountManagementService refuses to bind my CustomMailService unless I refreshed AccountManagementService. The reason is that the AccountManagementService has a static reference to MailService which means that adding a new MailService in OSGI would not cause AccountManagementService to look for “better” service (higher ranking). See the OSGI spec for more details

I realize this is version 7 of the OSGI spec, but the same information is true for OSGI 6, you could download version 6 of the spec here
Now what?

Well, we could use a Bundle Activator and write some code to stop, then start the AccountManagementService. And do that we will!

First, we write a general util class to enable/disable components by providing the service PID, the bundle context and the ServiceComponentRuntime service.

import java.util.Optional;
import org.osgi.framework.Bundle;
import org.osgi.framework.BundleContext;
import org.osgi.service.component.runtime.ServiceComponentRuntime;
import org.osgi.service.component.runtime.dto.ComponentDescriptionDTO;
import org.osgi.util.promise.Deferred;
import org.osgi.util.promise.Promise;
public class OSGIComponentUtil {
public static ComponentDescriptionDTO getDTO(BundleContext bundleContext, ServiceComponentRuntime scr, String componentName){
for (Bundle bundle : bundleContext.getBundles()) {
ComponentDescriptionDTO dto = scr.getComponentDescriptionDTO(bundle, componentName);
if (dto != null) {
return dto;
}
}
return null;
}
public static Promise<Void> enable(ComponentDescriptionDTO dto, ServiceComponentRuntime scr){
return Optional.ofNullable(dto)
.map(scr::enableComponent)
.orElse(getFailedPromise());
}
public static Promise<Void> disable(ComponentDescriptionDTO dto, ServiceComponentRuntime scr) {
return Optional.ofNullable(dto)
.map(scr::disableComponent)
.orElse(getFailedPromise());
}
public static Promise<Void> getFailedPromise(){
Deferred deferred = new Deferred<Void>();
deferred.fail( new Exception());
return deferred.getPromise();
}
}

Now let’s write the bundle activator:
import com.adobe.cq.account.api.AccountManagementService;
import com.company.core.utils.OSGIComponentUtil;
import org.osgi.framework.BundleActivator;
import org.osgi.framework.BundleContext;
import org.osgi.framework.ServiceReference;
import org.osgi.service.component.runtime.ServiceComponentRuntime;
import org.osgi.service.component.runtime.dto.ComponentDescriptionDTO;
public class CustomBundleActivator implements BundleActivator {
@Override
public void start(BundleContext bundleContext) throws Exception {
refreshAccountManagementService(bundleContext);
}
@Override
public void stop(BundleContext bundleContext) throws Exception {
refreshAccountManagementService(bundleContext);
}
private void refreshAccountManagementService(BundleContext bundleContext){
ServiceComponentRuntime scr = getServiceComponentRuntime(bundleContext);
ComponentDescriptionDTO dto = getAccountManagementServiceDTO(bundleContext, scr);
OSGIComponentUtil.disable(dto, scr)
.then(p -> OSGIComponentUtil.enable(dto, scr));
}
private ServiceComponentRuntime getServiceComponentRuntime(BundleContext bundleContext){
ServiceReference reference = bundleContext.getServiceReference(ServiceComponentRuntime.class.getName());
return (ServiceComponentRuntime) bundleContext.getService(reference);
}
private ComponentDescriptionDTO getAccountManagementServiceDTO(BundleContext bundleContext, ServiceComponentRuntime scr){
return OSGIComponentUtil.getDTO(bundleContext, scr, AccountManagementService.class.getName());
}
}

and then providing the bundle activator class in the configuration for the maven-bundle-plugin:
<plugin>
<groupId>org.apache.felix</groupId>
<artifactId>maven-bundle-plugin</artifactId>
<configuration>
<instructions>
...
<Bundle-Activator>com.company.core.activator.CustomBundleActivator</Bundle-Activator>
</instructions>
</configuration>
</plugin>

and voila! the AccountManagementService is now refreshed every time this bundle is deployed! You could also write some code to check if the custom mail service really got a bond to the AccountManagementService.

This implementation was really helpful with the code above: ComponentDisablerDriverDS13.java


By aem4beginner

May 10, 2020
Estimated Post Reading Time ~

How to FIX: AEM bundles going to Installed State


System Bundles going to Installed State | AEM Bundles not StartingMany times while working with AEM we find various errors related to bundles.Bundles or JAR files forms the backbone of AEM. When these bundles goes o installed state they give rise to issues like 403 forbidden errors, 500 internal server errors or sometimes errorsrelated and not limited to ACS Commons or DAM.

Sometimes it is very dificult to find as to why AEM bundles are going to installed state.
The reason being that various operations can cause your bundles to go to installed state.

Adobe has given us a HOTFIX for this issue.
"AEM bundles going to installed sate" HOTFIX comes in the form of a small JAR file.
he AEM bundle hotfix comes in the form of org.eclipse.equinox.region jar file.

Ok enough TALKING... Gimme the SOLUTION Please..!!!!
Solution 1:
If you have tried other ways and just couldn't get it working and still see various AEM system
bundles in installed state then try to install this JAR into your Felix console /system/console/bundles.

JAR Download : https://drive.google.com/open?id=0B3gwHkSOERmZRlZNQzZUMEFoUzQ

This is a good fix which works most of the time. Also trying this solution will not hurt.You can
always delete the bundle if it didn't do the job.

NOTE: AEM will refresh all the bundles. So please wait 5 minutes after installing the Equinox HOTFIX.

Solution 2: For AEM version 6.1 only.

If the above method didn't resolve your problem then try to remove equinox related JAR file.
Look for a bundle with this name "Region Digraph(org.eclipse.equinox.region)"


Now remove this bundle. Also remove the bundle you installed in Solution 1 if necessary.
Long story short, there should not be any equinox jars installed.

Why this Happens? 
According to Adobe the equinox eclipse bundle has some dependency on eclipse and should not be in AEM6.1, it was meant for AEM version 6.2. But this bundle got introduced in this version.

Other Version of Jar file:
http://www.java2s.com/Code/Jar/o/Downloadorgeclipseequinoxregion110v201205221841jar.htm


By aem4beginner

May 9, 2020
Estimated Post Reading Time ~

Repository inconsistency issue in AEM

---------------------------------Unable to read Bundle ......-------------------------

If you are facing some problem related to this, then here is the solution.
----> This is because of abnormal closing of the instance or corrupted the indexes. Reindexing required for your instance. Some times because of failed to access the repository.
----> Building the indexes means it will fetch the data from the data tar file in the repository.

For this, we need to delete the index files from the cq root folder.

Here specifying the folder paths, but make sure take a backup of repository--<br/>
--The total process may take hours of time depends on the repository size. But be ready to face downtime.

\author\crx-quickstart\repository\repository---delete index folder
\author\crx-quickstart\repository\tarJournal---delete all index_*.tar
\author\crx-quickstart\repository\version------delete all index_*.tar
\author\crx-quickstart\repository\workspaces\crx.default---delete index folder and delete all index_*.tar

Now Start your instance through the server.bat file
You will notice that the Multi-indexing will start........Each and every information will be available in logs.
After that please run these steps for better performance.

1)Tar optimization
2)Tar Index-merge
3)Data-store garbage collection

<br/>I tested and succeded with the cq 5.4 version..<br/>
I hope it useful. Please Don't try directly with the production server.


By aem4beginner

AEM Packages and Bundles - Installing and Uninstalling Behavior

Purpose
We’re trying to use multiple packages to provide “sub-applications” and give Adobe AEM 6.1 more of a “microservice” feel. However, one of the major points of µservices is that they should be as “self-contained” as possible to allow for deployment flexibility. How practical is that in Apache Sling/Adobe AEM?

When installing bundles using Sling’s JCR Installer Provider via the Package Manager, there are some interesting behaviors that can easily catch people unaware.

Setup
To demonstrate, I created four packages with a single bundle — org.jsoup — in each.

tester1: /apps/install/jsoup-1.7.1.jar
tester2: /apps/install/jsoup-1.7.1.jar
tester3: /apps/tester3/install/jsoup-1.7.1.jar
tester4: /apps/tester4/install/jsoup-1.8.2.jar

They each have a filter.xml file that specifically uninstalls exactly the bundle file that package installs.

Results
The details of each run follow, but the summary is:

Installing the same bundle to the same location works, but is very order dependent when it comes to uninstallation.

It works great if you uninstall in FILO order. (In other words, treat package installation like a stack.) The bundle is INSTALLED and ACTIVE with the first package. The second package takes a snapshot of the state of the path before writing, and since Felix notices that the bundle name and version haven’t changed, it effectively ignores the operation. Uninstalling the second bundle, restoring the state of the path. Felix again notices that nothing about the bundle name and version have changed, so it does nothing. Finally, uninstalling the first package causes the bundle to be STOPPED, UNINSTALLED, and triggers a REFRESH.

It gets much more surprising if you uninstall in FIFO order. Again, the bundle is INSTALLED and ACTIVE with the first package. The second package takes a snapshot of the state of the path before writing, and since Felix notices that the bundle name and version haven’t changed, it effectively ignores the operation. Uninstalling the first package removes the file from the path, so it causes the bundle to be STOPPED, UNINSTALLED, and triggers a REFRESH. Even more interestingly, uninstalling the second bundle causes the snapshot it had taken earlier to be restored: putting the file back into the path and causing the bundle to once again be INSTALLED and ACTIVE — even though both of the packages are now uninstalled! 

Installing the same bundle in different locations behaves “reasonably.”
Because both files have the same bundle name and the same version, Felix sees the second one and goes “Oh, I already have this INSTALLED, so don’t try to install it again. But do take note of the fact that another file provides this bundle/version combination.” Uninstalling in any order leaves the bundle INSTALLED until the last file providing the bundle is removed.

There is a bug that causes Felix to not refresh the file providing the bundle when reporting on the bundle (such as in the Bundle view in the Felix web console). For example, install tester1, install tester3, uninstall tester1 and the bundle information still thinks that the file from tester1 is the source of the bundle. Fortunately, behavior-wise it makes no difference since it still properly uninstalls when tester3 is removed.Felix can only handle a single instance of a bundle.

What this means is that it has to follow some heuristics on what bundle to have ACTIVE at any time. The gist is that it will use the highest version available.

Installing tester3 will causes org.jsoup-1.7.1 to be ACTIVE. Installing tester4 will cause Felix to UNINSTALL org.jsoup-1.7.1 and then ACTIVATE org.jsoup-1.8.2.

Uninstall tester3 and then installing it again does nothing, because Felix knows that 1.7.1 is lower than 1.8.2.

Note that a bundle version is independent from a package version. For example, if the bundle in tester3 provided exactly the same package export information but its bundle name was changed to foo.org.jsoup, then the package org.jsoup could be available from the Service Locator with both versions 1.7.1 and 1.8.2.

Details
I’ve done some editing of the logs to reduce noise.

Test Cases
Same Location - FILO

Installing two packages that install the same bundle in the same location, then uninstall them FILO order.

Steps: Install tester1, install tester2, uninstall tester2

Install-Package: /etc/packages/tester1-2.0.1-SNAPSHOT.zip Installing content Creating snapshot for package twc/webcms:tester1:2.0.1-SNAPSHOT A /apps/install/jsoup-1.7.1.jar Package imported.

*INFO* [qtp1419958956-170] org.apache.jackrabbit.vault.packaging.impl.JcrPackageImpl Creating snapshot for twc/webcms/.snapshot:tester1:2.0.1-SNAPSHOT. *WARN* [qtp1419958956-170] org.apache.jackrabbit.oak.jcr.session.ItemImpl Item#refresh invokes Session#refresh! *INFO* [qtp1419958956-170] org.apache.jackrabbit.vault.packaging.impl.JcrPackageImpl Creating snapshot for twc/webcms/.snapshot:tester1:2.0.1-SNAPSHOT completed. *INFO* [JcrInstaller.1] org.apache.sling.installer.provider.jcr.impl.WatchedFolder Watching folder /apps/install (priority 200) *INFO* [JcrInstaller.1] org.apache.sling.installer.provider.jcr.impl.JcrInstaller Registering resource with OSGi installer: [InstallableResource, priority=200, id=/apps/install/jsoup-1.7.1.jar] *INFO* [OsgiInstallerImpl] org.jsoup BundleEvent INSTALLED *INFO* [OsgiInstallerImpl] org.apache.sling.audit.osgi.installer Installed bundle org.jsoup [474] from resource TaskResource(url=jcrinstall:/apps/install/jsoup-1.7.1.jar, entity=bundle:org.jsoup, state=INSTALL, attributes=[org.apache.sling.installer.api.tasks.ResourceTransformer=:24:43:21:, Bundle-SymbolicName=org.jsoup, Bundle-Version=1.7.1], digest=1437503887562) *INFO* [OsgiInstallerImpl] org.jsoup BundleEvent RESOLVED *INFO* [OsgiInstallerImpl] org.jsoup BundleEvent STARTING *INFO* [OsgiInstallerImpl] org.jsoup BundleEvent STARTED *INFO* [OsgiInstallerImpl] org.apache.sling.audit.osgi.installer Started bundle org.jsoup [474]

Install Package: /etc/packages/tester2-2.0.1-SNAPSHOT.zip Installing content Creating snapshot for package twc/webcms:tester2:2.0.1-SNAPSHOT A /apps/install/jsoup-1.7.1.jar Importing content... - /apps/install/jsoup-1.7.1.jar saving approx 0 nodes... Package imported.

*INFO* [qtp1419958956-181] org.apache.jackrabbit.vault.packaging.impl.JcrPackageImpl Creating snapshot for twc/webcms/.snapshot:tester2:2.0.1-SNAPSHOT. *WARN* [qtp1419958956-181] org.apache.jackrabbit.oak.jcr.session.ItemImpl Item#refresh invokes Session#refresh! *INFO* [qtp1419958956-181] org.apache.jackrabbit.vault.packaging.impl.JcrPackageImpl Creating snapshot for twc/webcms/.snapshot:tester2:2.0.1-SNAPSHOT completed.

Uninstall Package: /etc/packages/tester2-2.0.1-SNAPSHOT.zip Uninstalling content Uninstalling package from snapshot twc/webcms/.snapshot:tester2:2.0.1-SNAPSHOT Importing content... - /apps/install/jsoup-1.7.1.jar saving approx 0 nodes... Package imported.

*INFO* [qtp1419958956-170] org.apache.jackrabbit.vault.packaging.impl.ZipVaultPackage Extracting twc/webcms/.snapshot:tester2:2.0.1-SNAPSHOT *INFO* [qtp1419958956-170] org.apache.jackrabbit.vault.packaging.impl.ZipVaultPackage Extracting twc/webcms/.snapshot:tester2:2.0.1-SNAPSHOT completed.

/apps/install/jsoup-1.7.1.jar is still around and ACTIVE

Same Location - FIFO
Steps: Install tester1, install tester2, uninstall tester1, uninstall tester2

After restoring state to before with install of tester1 then tester2…​

Uninstall Package: /etc/packages/tester1-2.0.1-SNAPSHOT.zip Uninstalling content Uninstalling package from snapshot twc/webcms/.snapshot:tester1:2.0.1-SNAPSHOT Importing content... D /apps/install/jsoup-1.7.1.jar Package imported.

*INFO* [qtp1419958956-197] org.apache.jackrabbit.vault.packaging.impl.ZipVaultPackage Extracting twc/webcms/.snapshot:tester1:2.0.1-SNAPSHOT *INFO* [qtp1419958956-197] org.apache.jackrabbit.vault.packaging.impl.ZipVaultPackage Extracting twc/webcms/.snapshot:tester1:2.0.1-SNAPSHOT completed. *INFO* [JcrInstaller.1] org.apache.sling.installer.provider.jcr.impl.JcrInstaller Removing resource from OSGi installer: [/apps/install/jsoup-1.7.1.jar] *INFO* [OsgiInstallerImpl] org.jsoup BundleEvent STOPPING *INFO* [OsgiInstallerImpl] org.jsoup BundleEvent STOPPED *INFO* [OsgiInstallerImpl] org.jsoup BundleEvent UNRESOLVED *INFO* [OsgiInstallerImpl] org.jsoup BundleEvent UNINSTALLED *INFO* [OsgiInstallerImpl] org.apache.sling.audit.osgi.installer Uninstalled bundle org.jsoup [474] from resource TaskResource(url=jcrinstall:/apps/install/jsoup-1.7.1.jar, entity=bundle:org.jsoup, state=UNINSTALL, attributes=[org.apache.sling.installer.api.tasks.ResourceTransformer=:24:43:21:, Bundle-SymbolicName=org.jsoup, Bundle-Version=1.7.1], digest=1437503887562) *INFO* [FelixDispatchQueue] org.apache.felix.framework FrameworkEvent PACKAGES REFRESHED *INFO* [OsgiInstallerImpl] org.apache.sling.audit.osgi.installer Full package refreshing *INFO* [FelixDispatchQueue] org.apache.felix.framework FrameworkEvent PACKAGES REFRESHED *INFO* [OsgiInstallerImpl] org.apache.sling.audit.osgi.installer Done full package refresh

/apps/install/jsoup-1.7.1.jar is gone around and UNINSTALLED

When you uninstall tester2 /apps/install/jsoup-1.7.1.jar is put back and ACTIVE

Different Locations - FILO

STEPS: Install tester1, install tester3, uninstall tester3, uninstall tester1
Install Package: /etc/packages/tester1-2.0.1-SNAPSHOT.zip Installing content Creating snapshot for package twc/webcms:tester1:2.0.1-SNAPSHOT A /apps/install/jsoup-1.7.1.jar Package imported.

*INFO* [qtp1419958956-173] org.apache.jackrabbit.vault.packaging.impl.JcrPackageImpl Creating snapshot for twc/webcms/.snapshot:tester1:2.0.1-SNAPSHOT. *WARN* [qtp1419958956-173] org.apache.jackrabbit.oak.jcr.session.ItemImpl Item#refresh invokes Session#refresh! *INFO* [qtp1419958956-173] org.apache.jackrabbit.vault.packaging.impl.JcrPackageImpl Creating snapshot for twc/webcms/.snapshot:tester1:2.0.1-SNAPSHOT completed. *INFO* [JcrInstaller.1] org.apache.sling.installer.provider.jcr.impl.JcrInstaller Registering resource with OSGi installer: [InstallableResource, priority=200, id=/apps/install/jsoup-1.7.1.jar] *INFO* [OsgiInstallerImpl] org.jsoup BundleEvent INSTALLED *INFO* [OsgiInstallerImpl] org.apache.sling.audit.osgi.installer Installed bundle org.jsoup [476] from resource TaskResource(url=jcrinstall:/apps/install/jsoup-1.7.1.jar, entity=bundle:org.jsoup, state=INSTALL, attributes=[org.apache.sling.installer.api.tasks.ResourceTransformer=:24:43:21:, Bundle-SymbolicName=org.jsoup, Bundle-Version=1.7.1], digest=1437504361359) *INFO* [OsgiInstallerImpl] org.jsoup BundleEvent RESOLVED *INFO* [OsgiInstallerImpl] org.jsoup BundleEvent STARTING *INFO* [OsgiInstallerImpl] org.jsoup BundleEvent STARTED *INFO* [OsgiInstallerImpl] org.apache.sling.audit.osgi.installer Started bundle org.jsoup [476]

Installing content Creating snapshot for package twc/webcms:tester3:2.0.1-SNAPSHOT A /apps/tester3/install/jsoup-1.7.1.jar Package imported.

*INFO* [qtp1419958956-220] org.apache.jackrabbit.vault.packaging.impl.JcrPackageImpl Creating snapshot for twc/webcms/.snapshot:tester3:2.0.1-SNAPSHOT. *WARN* [qtp1419958956-220] org.apache.jackrabbit.oak.jcr.session.ItemImpl Item#refresh invokes Session#refresh! *INFO* [qtp1419958956-220] org.apache.jackrabbit.vault.packaging.impl.JcrPackageImpl Creating snapshot for twc/webcms/.snapshot:tester3:2.0.1-SNAPSHOT completed. *INFO* [JcrInstaller.1] org.apache.sling.installer.provider.jcr.impl.WatchedFolder Watching folder /apps/tester3/install (priority 200) *INFO* [JcrInstaller.1] org.apache.sling.installer.provider.jcr.impl.JcrInstaller Registering resource with OSGi installer: [InstallableResource, priority=200, id=/apps/tester3/install/jsoup-1.7.1.jar]

Uninstall Package: /etc/packages/tester1-2.0.1-SNAPSHOT.zip Uninstalling content Uninstalling package from snapshot twc/webcms/.snapshot:tester1:2.0.1-SNAPSHOT D /apps/install/jsoup-1.7.1.jar Package imported.

*INFO* [qtp1419958956-173] org.apache.jackrabbit.vault.packaging.impl.ZipVaultPackage Extracting twc/webcms/.snapshot:tester1:2.0.1-SNAPSHOT *INFO* [qtp1419958956-173] org.apache.jackrabbit.vault.packaging.impl.ZipVaultPackage Extracting twc/webcms/.snapshot:tester1:2.0.1-SNAPSHOT completed. *INFO* [JcrInstaller.1] org.apache.sling.installer.provider.jcr.impl.JcrInstaller Removing resource from OSGi installer: [/apps/install/jsoup-1.7.1.jar]


The bundle is still ACTIVE and at /apps/install/jsoup-1.7.1.jar

Uninstall Package: /etc/packages/tester3-2.0.1-SNAPSHOT.zip Uninstalling content Uninstalling package from snapshot twc/webcms/.snapshot:tester3:2.0.1-SNAPSHOT D /apps/tester3/install/jsoup-1.7.1.jar Package imported.

*INFO* [qtp1419958956-244] org.apache.jackrabbit.vault.packaging.impl.ZipVaultPackage Extracting twc/webcms/.snapshot:tester3:2.0.1-SNAPSHOT *INFO* [qtp1419958956-244] org.apache.jackrabbit.vault.packaging.impl.ZipVaultPackage Extracting twc/webcms/.snapshot:tester3:2.0.1-SNAPSHOT completed. *INFO* [JcrInstaller.1] org.apache.sling.installer.provider.jcr.impl.JcrInstaller Removing resource from OSGi installer: [/apps/tester3/install/jsoup-1.7.1.jar] *INFO* [OsgiInstallerImpl] org.jsoup BundleEvent STOPPING *INFO* [OsgiInstallerImpl] org.jsoup BundleEvent STOPPED *INFO* [OsgiInstallerImpl] org.jsoup BundleEvent UNRESOLVED *INFO* [OsgiInstallerImpl] org.jsoup BundleEvent UNINSTALLED *INFO* [OsgiInstallerImpl] org.apache.sling.audit.osgi.installer Uninstalled bundle org.jsoup [476] from resource TaskResource(url=jcrinstall:/apps/install/jsoup-1.7.1.jar, entity=bundle:org.jsoup, state=UNINSTALL, attributes=[org.apache.sling.installer.api.tasks.ResourceTransformer=:24:43:21:, Bundle-SymbolicName=org.jsoup, Bundle-Version=1.7.1], digest=1437504361359) *INFO* [OsgiInstallerImpl] org.apache.sling.audit.osgi.installer Full package refreshing *INFO* [OsgiInstallerImpl] org.apache.sling.audit.osgi.installer Done full package refresh *INFO* [FelixDispatchQueue] org.apache.felix.framework FrameworkEvent PACKAGES REFRESHED *INFO* [FelixDispatchQueue] org.apache.felix.framework FrameworkEvent PACKAGES REFRESHED

org.jsoup in UNINSTALLED

Install A Bundle Then Install A Higher Version
Steps: Install tester3, install tester4
Install Package: /etc/packages/tester3-2.0.1-SNAPSHOT.zip Installing content Creating snapshot for package twc/webcms:tester3:2.0.1-SNAPSHOT A /apps/tester3/install/jsoup-1.7.1.jar Package imported.
*INFO* [qtp1419958956-627] org.apache.jackrabbit.vault.packaging.impl.JcrPackageImpl Creating snapshot for twc/webcms/.snapshot:tester3:2.0.1-SNAPSHOT. *WARN* [qtp1419958956-627] org.apache.jackrabbit.oak.jcr.session.ItemImpl Item#refresh invokes Session#refresh! *INFO* [qtp1419958956-627] org.apache.jackrabbit.vault.packaging.impl.JcrPackageImpl Creating snapshot for twc/webcms/.snapshot:tester3:2.0.1-SNAPSHOT completed. *INFO* [JcrInstaller.1] org.apache.sling.installer.provider.jcr.impl.JcrInstaller Registering resource with OSGi installer: [InstallableResource, priority=200, id=/apps/tester3/install/jsoup-1.7.1.jar] *INFO* [OsgiInstallerImpl] org.jsoup BundleEvent INSTALLED *INFO* [OsgiInstallerImpl] org.apache.sling.audit.osgi.installer Installed bundle org.jsoup [479] from resource TaskResource(url=jcrinstall:/apps/tester3/install/jsoup-1.7.1.jar, entity=bundle:org.jsoup, state=INSTALL, attributes=[org.apache.sling.installer.api.tasks.ResourceTransformer=:24:43:21:, Bundle-SymbolicName=org.jsoup, Bundle-Version=1.7.1], digest=1437510415744) *INFO* [OsgiInstallerImpl] org.jsoup BundleEvent RESOLVED *INFO* [OsgiInstallerImpl] org.jsoup BundleEvent STARTING *INFO* [OsgiInstallerImpl] org.jsoup BundleEvent STARTED *INFO* [OsgiInstallerImpl] org.apache.sling.audit.osgi.installer Started bundle org.jsoup [479]

Install Package: /etc/packages/tester4-2.0.1-SNAPSHOT.zip Installing content Creating snapshot for package twc/webcms:tester4:2.0.1-SNAPSHOT A /apps/tester4/install/jsoup-1.8.2.jar Package imported.

*INFO* [qtp1419958956-627] org.apache.jackrabbit.vault.packaging.impl.JcrPackageImpl Creating snapshot for twc/webcms/.snapshot:tester4:2.0.1-SNAPSHOT. *WARN* [qtp1419958956-627] org.apache.jackrabbit.oak.jcr.session.ItemImpl Item#refresh invokes Session#refresh! *INFO* [qtp1419958956-627] org.apache.jackrabbit.vault.packaging.impl.JcrPackageImpl Creating snapshot for twc/webcms/.snapshot:tester4:2.0.1-SNAPSHOT completed. *INFO* [JcrInstaller.1] org.apache.sling.installer.provider.jcr.impl.WatchedFolder Watching folder /apps/tester4/install (priority 200) *INFO* [JcrInstaller.1] org.apache.sling.installer.provider.jcr.impl.JcrInstaller Registering resource with OSGi installer: [InstallableResource, priority=200, id=/apps/tester4/install/jsoup-1.8.2.jar] *INFO* [OsgiInstallerImpl] org.jsoup BundleEvent STOPPING *INFO* [OsgiInstallerImpl] org.jsoup BundleEvent STOPPED *INFO* [OsgiInstallerImpl] org.jsoup BundleEvent UNRESOLVED *INFO* [OsgiInstallerImpl] org.jsoup BundleEvent UPDATED *INFO* [OsgiInstallerImpl] org.apache.sling.audit.osgi.installer Updated bundle org.jsoup [479] from resource TaskResource(url=jcrinstall:/apps/tester4/install/jsoup-1.8.2.jar, entity=bundle:org.jsoup, state=INSTALL, attributes=[org.apache.sling.installer.api.tasks.ResourceTransformer=:24:43:21:, Bundle-SymbolicName=org.jsoup, Bundle-Version=1.8.2], digest=1437510445186) *INFO* [FelixDispatchQueue] org.apache.felix.framework FrameworkEvent PACKAGES REFRESHED *INFO* [OsgiInstallerImpl] org.apache.sling.audit.osgi.installer Refreshing 1 bundles: [org.jsoup [479]] *INFO* [OsgiInstallerImpl] org.apache.sling.audit.osgi.installer Done refreshing 1 bundles *INFO* [FelixDispatchQueue] org.apache.felix.framework FrameworkEvent PACKAGES REFRESHED *INFO* [OsgiInstallerImpl] org.jsoup BundleEvent RESOLVED *INFO* [OsgiInstallerImpl] org.jsoup BundleEvent STARTING *INFO* [OsgiInstallerImpl] org.jsoup BundleEvent STARTED *INFO* [OsgiInstallerImpl] org.apache.sling.audit.osgi.installer Started bundle org.jsoup [479]

It uninstalled the 1.7.1 version and installed 1.8.2

Uninstall Unused Bundle File
Steps: With tester3 and tester4 installed, uninstall tester3
Uninstall Package: /etc/packages/tester3-2.0.1-SNAPSHOT.zip Uninstalling content Uninstalling package from snapshot twc/webcms/.snapshot:tester3:2.0.1-SNAPSHOT D /apps/tester3/install/jsoup-1.7.1.jar Package imported.

*INFO* [qtp1419958956-642] org.apache.jackrabbit.vault.packaging.impl.ZipVaultPackage Extracting twc/webcms/.snapshot:tester3:2.0.1-SNAPSHOT *INFO* [qtp1419958956-642] org.apache.jackrabbit.vault.packaging.impl.ZipVaultPackage Extracting twc/webcms/.snapshot:tester3:2.0.1-SNAPSHOT completed. *INFO* [JcrInstaller.1] org.apache.sling.installer.provider.jcr.impl.JcrInstaller Removing resource from OSGi installer: [/apps/tester3/install/jsoup-1.7.1.jar]


Install A Bundle Then Install A Lower Version
Steps: Install tester4 then install tester3
Install Package: /etc/packages/tester4-2.0.1-SNAPSHOT.zip Installing content Creating snapshot for package twc/webcms:tester4:2.0.1-SNAPSHOT A /apps/tester4/install/jsoup-1.8.2.jar Package imported.

*INFO* [qtp1419958956-658] org.apache.jackrabbit.vault.packaging.impl.JcrPackageImpl Creating snapshot for twc/webcms/.snapshot:tester4:2.0.1-SNAPSHOT. *WARN* [qtp1419958956-658] org.apache.jackrabbit.oak.jcr.session.ItemImpl Item#refresh invokes Session#refresh! *INFO* [qtp1419958956-658] org.apache.jackrabbit.vault.packaging.impl.JcrPackageImpl Creating snapshot for twc/webcms/.snapshot:tester4:2.0.1-SNAPSHOT completed. *INFO* [JcrInstaller.1] org.apache.sling.installer.provider.jcr.impl.JcrInstaller Registering resource with OSGi installer: [InstallableResource, priority=200, id=/apps/tester4/install/jsoup-1.8.2.jar] *INFO* [OsgiInstallerImpl] org.jsoup BundleEvent INSTALLED *INFO* [OsgiInstallerImpl] org.apache.sling.audit.osgi.installer Installed bundle org.jsoup [480] from resource TaskResource(url=jcrinstall:/apps/tester4/install/jsoup-1.8.2.jar, entity=bundle:org.jsoup, state=INSTALL, attributes=[org.apache.sling.installer.api.tasks.ResourceTransformer=:24:43:21:, Bundle-SymbolicName=org.jsoup, Bundle-Version=1.8.2], digest=1437510694392) *INFO* [OsgiInstallerImpl] org.jsoup BundleEvent RESOLVED *INFO* [OsgiInstallerImpl] org.jsoup BundleEvent STARTING *INFO* [OsgiInstallerImpl] org.jsoup BundleEvent STARTED *INFO* [OsgiInstallerImpl] org.apache.sling.audit.osgi.installer Started bundle org.jsoup [480]

Install Package: /etc/packages/tester3-2.0.1-SNAPSHOT.zip Installing content Creating snapshot for package twc/webcms:tester3:2.0.1-SNAPSHOT A /apps/tester3/install/jsoup-1.7.1.jar Package imported.

*INFO* [qtp1419958956-673] org.apache.jackrabbit.vault.packaging.impl.JcrPackageImpl Creating snapshot for twc/webcms/.snapshot:tester3:2.0.1-SNAPSHOT. *WARN* [qtp1419958956-673] org.apache.jackrabbit.oak.jcr.session.ItemImpl Item#refresh invokes Session#refresh! *INFO* [qtp1419958956-673] org.apache.jackrabbit.vault.packaging.impl.JcrPackageImpl Creating snapshot for twc/webcms/.snapshot:tester3:2.0.1-SNAPSHOT completed. *INFO* [JcrInstaller.1] org.apache.sling.installer.provider.jcr.impl.JcrInstaller Registering resource with OSGi installer: [InstallableResource, priority=200, id=/apps/tester3/install/jsoup-1.7.1.jar]


The bundle file /apps/tester3/install/jsoup-1.7.1.jar was registered with the OSGi installer, but the bundle was not actually installed because of a higher version of the bundle name already exists.



By aem4beginner

Resolving OSGi bundle dependencies

In my early days of building OSGi bundles for AEM, I got used to this message in the error.log:

*INFO* [OsgiInstallerImpl] org.apache.sling.installer.core.impl.tasks.BundleStartTask Could not start bundle com.acme.samples.aem.bundledependency.samples-bundle-dependency-bundle [457]. Reason: {}. Will retry.
org.osgi.framework.BundleException: Unresolved constraint in bundle com.acme.samples.aem.bundledependency.samples-bundle-dependency-bundle [457]: Unable to resolve 457.14: missing requirement [457.14] osgi.wiring.package; (&(osgi.wiring.package=org.apache.commons.beanutils)(version>=1.9.0)(!(version>=2.0.0)))
at org.apache.felix.framework.Felix.resolveBundleRevision(Felix.java:4095)

And to the following result, when checking the status of my bundle at http://localhost:4502/system/console/bundles/


Both of them meaning that AEM was unable to resolve my bundle dependencies at deployment time.

If you find yourself in my shoes, you can either

Use classes exported by another bundle
By default, AEM has a lot of OSGi bundles deployed and one of them may be exporting the classes that you’ve been looking for. You just need to find out which versions are being exported and add to your project the correct version as a dependency.

Let’s say that you have a Maven-based project and you want to use Apache Commons Lang. So:
  • Access http://localhost:4502/system/console/depfinder;
  • Type org.apache.commons.lang3;
  • Click on find;
  • Copy the value provided as Maven dependency;
  • Paste it into your parent POM;
  • Paste it into your child POM, removing the tags <version> and <scope>.
Note: Installing new libraries as bundles will be explored in future posts.

Or embed classes into your own bundle

Apache Felix Maven Bundle Plugin can help you with that!
Suppose that you have a Maven-based project and you want to use Apache Commons BeanUtils. So:

1. Add the dependency to your POM
  • Access https://mvnrepository.com/;
  • Type commons beanutils;
  • Click on Search;
  • Select any version that depends on commons-collections 3.2.1;
  • Copy the content of the Maven tab;
  • Paste into your parent POM, adding <scope>compile</scope>;
  • Paste it into your child POM, removing the tags <version> and <scope>;
2. Instruct the Bundle Plugin to embed the dependency
  • Open your child POM;
  • Locate maven-bundle-plugin <instructions> tag;
  • Insert the following into it:
<!-- embed all compile and runtime scope dependencies -->
<Embed-Dependency>*;scope=compile|runtime</Embed-Dependency>


By aem4beginner

May 4, 2020
Estimated Post Reading Time ~

OSGi Bundle States

Here’s a breakdown of the bundle states, and their associated values.

An OSGi bundle can be in one of six states:
Name
Value
stateRaw
Description
UNINSTALLED
0x01
1
Only visible after a bundle is uninstalled; the bundle is in an unusable state but references to the bundle object may still be available and used for introspection.
INSTALLED
0x02
2
Visible if the bundle’s code dependencies are not resolved. The Framework may attempt to resolve an INSTALLED bundle’s code dependencies and move the bundle to the RESOLVED state.
RESOLVED
0x04
4
The Framework has successfully resolved the bundle’s code dependencies, but the bundle is not active. Dependencies include: the bundle’s classpath; the bundle’s package dependencies; the bundle’s required bundle dependencies;
STARTING
0x08
8
The bundle’s start method is active. A bundle must be in this state when the bundle’s BundleActivator.start(BundleContext) is called. If the BundleActivator.start method completes without exception, then the bundle has successfully started and must move to the ACTIVE state.
STOPPING
0x10
16
The bundle’s stop method is active. A bundle must be in this state when the bundle’s BundleActivator.stop(BundleContext) method is called. When the BundleActivator.stop method completes the bundle is stopped and must move to the RESOLVED state.
ACTIVE
0x20
32
The bundle has been successfully started and activated.


By aem4beginner

May 3, 2020
Estimated Post Reading Time ~

How do I convert an existing jar file into an OSGi bundle?

Question
How do I convert an existing jar file into an OSGi bundle?

Answer, Resolution
Here's a very simple way of turning an existing jar file in an OSGi bundle, while keeping control on exported packages.

The example creates an OSGi bundle from the attached junit-4.4.jar.

Note: The method below only works in a scenario where the jar file has no dependencies on other external jar files.
Start by creating a jar's manifest file:
Manifest-Version: 1.0 
Created-By: myself 
Bundle-ManifestVersion: 2 
Bundle-Name: JUnit 4.4 bundle 
Bundle-Description: Package junit 4.4 in an OSGi bundle 
Bundle-Version: 4.4.0 Bundle-ClassPath: .,junit-4.4.jar 
Bundle-SymbolicName: org.junit.framework 
Export-Package: junit.framework,junit.extensions,org.junit.runner,org.junit,junit.textui
  • Bundle-ClassPath header is set to allow embedding the original jar as is. Make sure its value matches the filename of the jar that you are going to embed in the bundle.
  • Export-Package is a list of packages contained in the jar that you would like to make available to other bundles running in the OSGi Container.
Jar file
Get the jar file, in our case from http://mirrors.ibiblio.org/pub/mirrors/maven2/junit/junit/4.4/junit-4.4.jar

Create the bundle jar file by running the following command:
jar cvfm junit-4.4-bundle.jar manifest.txt junit-4.4.jar

Where manifest.txt is the name of the manifest file created above.

That's it - the resulting jar file (attached to this page as an example) is an OSGi bundle the exports the packages listed in Export-Package above, using the classes of the embedded junit-4.4.jar.


By aem4beginner

Building OSGi Bundles with Apache Maven

It seems that still today some developers think that creating an OSGi bundle is complicated – in contrast to simply creating a jar. Well, an OSGi bundle is a jar. The factor which distinguishes the two is that an OSGi bundle has additional manifest entries. Adding those using the right tooling is really simple.

The more difficult part is creating good modules: clearly separating public API from the implementation and correctly version the API based on the changes you made. But this is a general problem not related to OSGi at all and applies to any Java coding. There are some simple guidelines:
  1. Leverage packages – put the API in a different package than your implementation. It’s also good still to use a package name for your implementation which makes clear that this is the implementation, e.g. by using impl as one part of the package name.
  2. Start private and only make public if necessary. Once something is public, you never can make it private without breaking your clients. Starting private makes things easier.
  3. Use semantic versioning. Whenever you change your public API, make sure to correctly increase the package version depending on the type of change you made.
Again, these are general guidelines and have nothing to do with OSGi. But OSGi uses headers in the manifest of your jar to know which packages from inside the jar are public API and the version of those packages. This is the export package header. Packages not listed there are private and not accessible to other modules. The other important header is the import package header, specifying which other packages this module is using. This usually comes with a version range, like a bundle is using package foo.bar version 1.1 or higher up to but not including 2.0.

Therefore, the only required thing to make a bundle out of your jar is more or less calculating these export and import packages headers and adding them to the manifest. But don’t fear, the tooling does this automatically for you. Let’s build a bundle/jar.

Using Apache Maven to Create a OSGi Bundle
There is always the year old debate on which build tool is the best one, I will not get into this discussion. I simply use what I know best and what I’m forced to use anyway: Apache Maven.

By default, Maven is not adding the additional manifest information to the jar, but there are different plugins for Maven available. For this tutorial, I’ll use the newer bnd Maven Plugin from the bnd project.

Add the following two plugin configurations to your pom. It’s usually a good idea to put this into your parent pom:

<plugin>
    <groupId>biz.aQute.bnd</groupId>
    <artifactId>bnd-maven-plugin</artifactId>
    <version>3.2.0</version>
    <executions>
        <execution>
            <goals>
               <goal>bnd-process</goal>
            </goals>
        </execution>
    </executions>
    <configuration>
        <bnd><![CDATA[
            -exportcontents: ${packages;VERSIONED}
        ]]></bnd>
    </configuration>
</plugin>
<plugin>
    <groupId>org.apache.maven.plugins</groupId>
    <artifactId>maven-jar-plugin</artifactId>
    <configuration>
        <useDefaultManifestFile>true</useDefaultManifestFile>
    </configuration>
</plugin>

The first adds the bnd maven plugin which creates the manifest data and the second instructs the default jar plugin to use the manifest created by the bnd plugin. And that’s it. If you now build your jar project using Maven you’ll have additional manifest entries in there.

Standard OSGi Bundle Headers
The first entries are standard headers which make your jar a bundle and contain some metadata:
  • Bundle-ManifestVersion: This header is required and marks the jar as a bundle, the value is always 2 (newer OSGi specifications might add more features in which case the number would be increased).
  • Bundle-Name: A human readable name for your bundle. This defaults to your project name from the pom.
  • Bundle-SymbolicName: In combination with the bundle version (see below) the symbolic name provides a key to uniquely identify a bundle. This name should be based on the reverse domain name convention and defaults to the artifact id of your project. I’ll talk a little bit more about this soon.
  • Bundle-Version: The version of your bundle, this defaults to the version of your project.
There is no magic in the above entries and having them in your jar does not hurt at all. As mentioned above, the symbolic name should be based on the reverse domain name convention. Usually in the Maven world you follow this rule for your group id, like org.mycompany.myproject and then use a simple name for the artifact id like scheduler-api. However a good practice is to use a full qualified name for the artifact id (which usually means you prefix the artifact id with the group id), e.g. org.mycompany.myproject.scheduler-api. Why is this a good idea? It has nothing to do with OSGi and simply makes sure that the final name of the artifact is fully qualified. If you don’t add the group id to the artifact id, the jar filename would be scheduler-api-1.2.3.jar – which is not very descriptive and gives you no clue what this thing is (and it might clash with other projects using the same artifact id).

The bundle version as any version in software development should increase with continued development/releases. For OSGi this information together with the symbolic name provides a unique key for a bundle and allows OSGi to verify if this exact bundle (name and version) is already installed in the OSGi framework. On a technical level, the bundle version information is more a marketing version.

Public API
More important than versioning your bundle (which still is important), it’s more important to correctly version your public API which might be used by others. For this add the following dependency to your pom:

<dependency>
    <groupId>org.osgi</groupId>
    <artifactId>osgi.annotation</artifactId>
    <version>1.0.0</version>
    <scope>provided</scoped>
</dependency>

The above dependency adds some annotations to your project – using the scope “provided” is a good practice as this avoids dragging in transitive dependencies.

Your public API should be in a separate Java package than your implementation – again this is a general good style and not tied to OSGi at all. If you want to export a package to be used by others, add a package-info.java file within your package:

@org.osgi.annotation.versioning.Version("1.0")
package org.osoco.software.samples.guessinggame;

If it’s the first version of your package, simply use 1.0 as the version – from now on once you have released this API as version 1.0, follow semantic versioning. Build your project again and you will see a header similar to this: 

Export-Package    org.osoco.software.samples.guessinggame; version="1.0"

As you can see creating the export is really easy, just use the above annotation and done. And the imports are even easier. The plugin analyses your classes and calculates the imports for you. For example, for my sample project, it looks like this: 

Import-Package  

javax.servlet; version="[3.1,4)", 
javax.servlet.http;version="[3.1,4)", org.osoco.software.samples.guessinggame;version="[1.0,1.1)"

And that’s it, your jar is now a bundle and can be used in any OSGi installation as a first-class citizen. It’s really simple – and in 96% of your cases, the automatic calculation by the tooling is sufficient. There are only rare and special cases where you want to have them differently. In that case, you can configure the plugin accordingly.


By aem4beginner