Skip navigation
All Places > Alfresco Content Services (ECM) > Blog > 2018 > December
2018

Introduction

Sometimes you need to use a 3rd party Java library when you develop Alfresco extensions. Meaning a library that is not available as part of the standard Alfresco installation. So you cannot just specify a provided dependency in the Maven POM and expect the library to be available in webapps/[alfresco|share]/WEB-INF/lib during runtime, you need to supply the 3rd party JAR file as part of the installation. This can be achieved by using what’s called an AMP file for the distribution of the extension. An AMP file can contain other JAR files and they are then installed automatically into the webapps/[alfresco|share]/WEB-INF/lib directory when you install the extension.

 

In this article we will use a 3rd party library called Jsoup that can be used to parse and create HTML. It’s not by default part of an Alfresco installation, so we need to supply this library via an AMP. To make sure the 3rd party library can be called and works we will create a Repository Web Script with a Java controller that uses the Jsoup library.

 

Alfresco SDK 3.0 can be used to build extensions for Alfresco version 4.2, 5.1, and 5.2. We are going to work with the default settings, which assumes version 5.2.

Source Code

Source code for this article can be found here: https://github.com/gravitonian/repo-ext-3rd-party-lib

Generating an Alfresco SDK 3.0 project

We need an Alfresco SDK 3.0 project to work with so let’s generate a Repository extension project. This is a project that can be used to develop extensions that should be applied to the alfresco.war file, such as a Repository Web Script.

 

Here is how to generate this SDK project:

 

$ mvn archetype:generate -Dfilter=org.alfresco:

[INFO] Scanning for projects...

[INFO]

[INFO] ------------------------------------------------------------------------

[INFO] Building Maven Stub Project (No POM) 1

[INFO] ------------------------------------------------------------------------

[INFO]

[INFO] <<< maven-archetype-plugin:3.0.1:generate (default-cli) < generate-sources @ standalone-pom<<<

[INFO]

[INFO]

[INFO] --- maven-archetype-plugin:3.0.1:generate (default-cli) @ standalone-pom---

[INFO] Generating project in Interactive mode

[INFO] No archetype defined. Using maven-archetype-quickstart (org.apache.maven.archetypes:maven-archetype-quickstart:1.0)

Choose archetype:

1: remote -> org.alfresco.maven.archetype:activiti-jar-archetype (Sample project with full support for lifecycle and rapid development of Activiti JARs)

2: remote -> org.alfresco.maven.archetype:alfresco-allinone-archetype (Sample multi-module project for All-in-One development on the Alfresco plaftorm. Includes modules for Platform/Repository JAR and Share JAR)

3: remote -> org.alfresco.maven.archetype:alfresco-amp-archetype (Sample project with full support for lifecycle and rapid development of Repository AMPs (Alfresco Module Packages))

4: remote -> org.alfresco.maven.archetype:alfresco-platform-jar-archetype (Sample project with full support for lifecycle and rapid development of Platform/Repository JARs and AMPs (Alfresco Module Packages))

5: remote -> org.alfresco.maven.archetype:alfresco-share-jar-archetype (Share project with full support for lifecycle and rapid development of JARs and AMPs (Alfresco Module

       Packages))

6: remote -> org.alfresco.maven.archetype:share-amp-archetype (Share project with full support for lifecycle and rapid development of AMPs (Alfresco Module

       Packages))

Choose a number or apply filter (format: [groupId:]artifactId, case sensitive contains): : 4

Choose org.alfresco.maven.archetype:alfresco-platform-jar-archetype version:

1: 3.0.0

2: 3.0.1

Choose a number: 2:

Define value for property 'groupId': org.alfresco.training

Define value for property 'artifactId':repo-ext-3rd-party-lib

[INFO] Using property: version = 1.0-SNAPSHOT

Define value for property 'package' org.alfresco.training: :

Confirm properties configuration:

groupId: org.alfresco.training

artifactId: aio-3rd-party-lib

version: 1.0-SNAPSHOT

package: org.alfresco.training

Y: :

 

From the Maven archetype list choose alfresco-platform-jar-archetype, then select SDK version 3.0.1, and finally specify the group and artifact IDs for the project.

 

This generates an SDK project with the following files:

 

$ cd repo-ext-3rd-party-lib/

repo-ext-3rd-party-lib mbergljung$ tree

.

├── README.md

├── debug.bat

├── debug.sh

├── pom.xml

├── run.bat

├── run.sh

└── src

   ├── main

   │ ├── assembly

   │ │   ├── amp.xml

   │ │   ├── file-mapping.properties

   │ │   └── web

   │ │       └── README.md

   │ ├── java

   │ │   └── org

   │ │       └── alfresco

   │ │           └── training

   │ │               └── platformsample

   │ │                   ├── Demo.java

   │ │                   ├── DemoComponent.java

   │   │                └── HelloWorldWebScript.java

   │ └── resources

   │    ├── META-INF

   │    │ └── resources

   │    │ └── test.html

   │    └── alfresco

   │        ├── extension

   │        │ └── templates

   │        │ └── webscripts

   │        │ └── alfresco

   │        │    └── tutorials

   │        │        ├── helloworld.get.desc.xml

   │        │        ├── helloworld.get.html.ftl

   │        │        └── helloworld.get.js

   │        └── module

   │            └── repo-ext-3rd-party-lib

   │                ├── alfresco-global.properties

   │                ├── context

   │                │ ├── bootstrap-context.xml

   │                │ ├── service-context.xml

   │                │ └── webscript-context.xml

   │                ├── messages

   │                │ └── content-model.properties

   │                ├── model

   │                │ ├── content-model.xml

   │                │ └── workflow-model.xml

   │                ├── module-context.xml

   │                ├── module.properties

   │                └── workflow

   │                    └── sample-process.bpmn20.xml

   └── test

       ├── java

       │ └── org

       │ └── alfresco

       │    └── training

       ├── license

       │ └── README.md

       ├── properties

       │ └── local

       │ ├── alfresco-global-enterprise.properties

       │ ├── alfresco-global-h2.properties

       │ ├── alfresco-global-mysql.properties

       │ └── alfresco-global-postgresql.properties

       └── resources

           ├── alfresco

           │ └── extension

           │ ├── dev-log4j.properties

           │ └── disable-webscript-caching-context.xml

           ├── platform-hotswap-agent.properties

           └── tomcat

               └── context-solr.xml

 

Note that the Repository extension project comes with a Hello World Web Script that has a Java Controller. So we don’t need to create a new Web Script for our exercise, we can just extend the Hello World Web Script.

Add the 3rd Party Library Dependency

Before we can start using a 3rd party library we need to add a dependency to it in the Maven POM. Open up the repo-ext-3rd-party-lib/pom.xml project file and add a dependency to the JSoup library as follows:

 

 

<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/maven-v4_0_0.xsd">

<modelVersion>4.0.0</modelVersion>
<groupId>org.alfresco.training</groupId>
<artifactId>repo-ext-3rd-party-lib</artifactId>
<version>1.0-SNAPSHOT</version>
<name>repo-ext-3rd-party-lib Platform Jar Module - SDK 3</name>
<description>Platform JAR Module (to be included in the alfresco.war) - SDK 3</description>
<packaging>jar</packaging>

...

<dependencies>
<dependency>
<!-- jsoup HTML parser library @ https://jsoup.org/ -->
<groupId>org.jsoup</groupId>
<artifactId>jsoup</artifactId>
<version>1.11.3</version>
</dependency>
...

If your IDE auto imports new Maven dependencies, then we should now be ready to use this library in our Web Script Java Controller.

Using the 3rd Party Lib in the Hello World Web Script Java Controller

Now, let’s use the Jsoup library in the Web Script’s Java Controller. Open up the repo-ext-3rd-party-lib/src/main/java/org/alfresco/training/platformsample/HelloWorldWebScript.java file and make changes so it looks like this:

 

package org.alfresco.training.platformsample;

import org.jsoup.Connection;
import org.jsoup.Jsoup;
import org.springframework.extensions.webscripts.Cache;
import org.springframework.extensions.webscripts.DeclarativeWebScript;
import org.springframework.extensions.webscripts.Status;
import org.springframework.extensions.webscripts.WebScriptRequest;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;

import java.io.IOException;
import java.util.HashMap;
import java.util.Map;

public class HelloWorldWebScript extends DeclarativeWebScript {
private static Log logger = LogFactory.getLog(HelloWorldWebScript.class);

protected Map<String, Object> executeImpl(
WebScriptRequest req, Status status, Cache cache) {
Map<String, Object> model = new HashMap<String, Object>();

Connection.Response html = null;
try {
html = Jsoup.connect("http://www.example.com/").execute();
} catch (IOException e) {
e.printStackTrace();
}

model.put("fromJava", "HelloFromJava(" + html.body() + ")");

logger.debug("Your 'Hello World' Web Script was called!");

return model;
}
}

 

Test it with the SDK 3.0 Runner

We can now test this out and see if it works by using the SDK 3.0 Runner, which is built into the Alfresco Maven Plugin. We can kick off Tomcat with the Repository extension applied to the alfresco.war as follows:

 

repo-ext-3rd-party-lib mbergljung$ mvn clean install alfresco:run

 

Now we can access the Web Script on the http://localhost:8080/alfresco/s/sample/helloworld URL, we should see the following response:

 

 

So that worked nicely.

Create a distribution AMP for the extension

If you look in the repo-ext-3rd-party-lib/target directory you will see the repo-ext-3rd-party-lib-1.0-SNAPSHOT.jar file, which contains the extension code (i.e. the Hello World Web Script files). But it does not contain the Jsoup library, so it will not work to just drop this file into an Alfresco 5.2 installation. We need to provide an AMP with this extension JAR and the Jsoup JAR.

 

Enable AMP file generation by uncommenting the maven-assembly-plugin in the repo-ext-3rd-party-lib/pom.xml project file:

 

<?xml version="1.0" encoding="UTF-8"?>

<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/maven-v4_0_0.xsd">

<modelVersion>4.0.0</modelVersion>
<groupId>org.alfresco.training</groupId>
<artifactId>repo-ext-3rd-party-lib</artifactId>
<version>1.0-SNAPSHOT</version>
<name>repo-ext-3rd-party-lib Platform Jar Module - SDK 3</name>
<description>Platform JAR Module (to be included in the alfresco.war) - SDK 3</description>
<packaging>jar</packaging>
...
<build>
<plugins>
...
<!--
Build an AMP if 3rd party libs are needed by the extensions
JARs are the default artifact produced in your modules, if you want to build an amp for each module
you have to enable this plugin and inspect the src/main/assembly.xml file if you want to customize
the layout of your AMP. The end result is that Maven will produce both a JAR file and an AMP with your
module.
-->

<plugin>
<artifactId>maven-assembly-plugin</artifactId>
<version>2.6</version>
<executions>
<execution>
<id>build-amp-file</id>
<phase>package</phase>
<goals>
<goal>single</goal>
</goals>
<configuration>
<appendAssemblyId>false</appendAssemblyId>
<descriptor>src/main/assembly/amp.xml</descriptor>
</configuration>
</execution>
</executions>
<dependencies>
<dependency>
<groupId>org.alfresco.maven.plugin</groupId>
<artifactId>alfresco-maven-plugin</artifactId>
<version>${alfresco.sdk.version}</version>
</dependency>
</dependencies>
</plugin>
...

 

 

Now execute the build again to create also an AMP:

 

repo-ext-3rd-party-lib mbergljung$mvn clean package

[INFO] Scanning for projects...

[INFO]

[INFO] ------------------------------------------------------------------------

[INFO] Building repo-ext-3rd-party-lib Platform Jar Module - SDK 3 1.0-SNAPSHOT

[INFO] ------------------------------------------------------------------------

[INFO]

[INFO] --- maven-clean-plugin:2.5:clean (default-clean) @ repo-ext-3rd-party-lib---

[INFO] Deleting /Users/mbergljung/IDEAProjects/sdk-test/repo-ext-3rd-party-lib/target

[INFO]

[INFO] --- maven-resources-plugin:3.0.1:resources (default-resources) @ repo-ext-3rd-party-lib---

[INFO] Using 'UTF-8' encoding to copy filtered resources.

[INFO] Copying 14 resources

[INFO]

[INFO] --- jrebel-maven-plugin:1.1.6:generate (generate-rebel-xml) @ repo-ext-3rd-party-lib---

[INFO] Processing org.alfresco.training:repo-ext-3rd-party-lib with packaging jar

[INFO]

[INFO] --- maven-compiler-plugin:3.1:compile (default-compile) @ repo-ext-3rd-party-lib---

[INFO] Changes detected - recompiling the module!

[INFO] Compiling 3 source files to /Users/mbergljung/IDEAProjects/sdk-test/repo-ext-3rd-party-lib/target/classes

[INFO]

[INFO] --- maven-resources-plugin:3.0.1:testResources (default-testResources) @ repo-ext-3rd-party-lib---

[INFO] Using 'UTF-8' encoding to copy filtered resources.

[INFO] Copying 4 resources

[INFO]

[INFO] --- maven-compiler-plugin:3.1:testCompile (default-testCompile) @ repo-ext-3rd-party-lib---

[INFO] Nothing to compile - all classes are up to date

[INFO]

[INFO] --- maven-surefire-plugin:2.12.4:test (default-test) @ repo-ext-3rd-party-lib---

[INFO]

[INFO] --- maven-jar-plugin:2.4:jar (default-jar) @ repo-ext-3rd-party-lib---

[INFO] Building jar: /Users/mbergljung/IDEAProjects/sdk-test/repo-ext-3rd-party-lib/target/repo-ext-3rd-party-lib-1.0-SNAPSHOT.jar

[INFO]

[INFO] --- maven-assembly-plugin:2.6:single (build-amp-file) @ repo-ext-3rd-party-lib---

[INFO] Building amp: /Users/mbergljung/IDEAProjects/sdk-test/repo-ext-3rd-party-lib/target/repo-ext-3rd-party-lib-1.0-SNAPSHOT.amp

[INFO] ------------------------------------------------------------------------

[INFO] BUILD SUCCESS

[INFO] ------------------------------------------------------------------------

[INFO] Total time: 6.121 s

[INFO] Finished at: 2018-12-19T11:44:33Z

[INFO] Final Memory: 50M/529M

[INFO] ------------------------------------------------------------------------

 

We can see in the console logs that the target/repo-ext-3rd-party-lib-1.0-SNAPSHOT.amp

AMP file was created. Looking inside the AMP (it’s just a ZIP) we can see it contains the following files:

 

repo-ext-3rd-party-lib-1.0-SNAPSHOT mbergljung$ tree

.

├── file-mapping.properties

├── lib

│   ├── jsoup-1.11.3.jar

│   └── repo-ext-3rd-party-lib-1.0-SNAPSHOT.jar

├── module.properties

└── web

 

So we should be ready to distribute this AMP file and use it to install the extension into any Alfresco 5.2 server.

Deploy the AMP to an Alfresco Server

We now got a tested Repository Extension that uses a third party library. Time to deploy it to a real Alfresco server. But before we do that, what would happen if we just dropped the repo-ext-3rd-party-lib-1.0-SNAPSHOT.jar into the <ALFRESCO_INSTALL_DIR>/tomcat/webapps/alfresco/WEB-INF/lib directory and restarted. We would see an error like follows when calling the Web Script:

 

Caused by: java.lang.NoClassDefFoundError: org/jsoup/Jsoup

at org.alfresco.training.platformsample.HelloWorldWebScript.executeImpl(HelloWorldWebScript.java:47)

at org.springframework.extensions.webscripts.DeclarativeWebScript.execute(DeclarativeWebScript.java:64)

... 36 more

Caused by: java.lang.ClassNotFoundException: org.jsoup.Jsoup

at org.apache.catalina.loader.WebappClassLoader.loadClass(WebappClassLoader.java:1720)

at org.apache.catalina.loader.WebappClassLoader.loadClass(WebappClassLoader.java:1571)

... 38 more

 

This is because the extension JAR does not contain the 3rd party library that is needed, so we really need to install the AMP to get everything needed for the extension. I got a 5.2 installation locally and I can use the Alfresco Module Management tool to install the AMP as follows (note that I have stopped the server and I have copied the AMP to the tomcat/webapps directory):

 

acs5211 mbergljung$ ./alfresco.sh stop

Using CATALINA_BASE:   /Applications/acs5211/tomcat

Using CATALINA_HOME:   /Applications/acs5211/tomcat

Using CATALINA_TMPDIR: /Applications/acs5211/tomcat/temp

Using JRE_HOME:        /Applications/acs5211/java

Using CLASSPATH:       /Applications/acs5211/tomcat/bin/bootstrap.jar:/Applications/acs5211/tomcat/bin/tomcat-juli.jar

Using CATALINA_PID:    /Applications/acs5211/tomcat/temp/catalina.pid

Tomcat stopped.

/Applications/acs5211/tomcat/scripts/ctl.sh : tomcat stopped

waiting for server to shut down.... done

server stopped

/Applications/acs5211/postgresql/scripts/ctl.sh : postgresql stopped

 

acs5211 mbergljung$ cd tomcat/webapps/

webapps mbergljung$ cp ~/IDEAProjects/sdk-test/repo-ext-3rd-party-lib/target/repo-ext-3rd-party-lib-1.0-SNAPSHOT.amp .

 

webapps mbergljung$rm -rf alfresco

 

webapps mbergljung$ ls -l

total 694472

drwxr-xr-x   9 mbergljung admin        288 4 Jul 13:58 ROOT

-rw-r--r--   1 mbergljung admin     274599 19 Sep 2017 ROOT.war

drwxr-xr-x   5 mbergljung admin        160 4 Jul 13:58 _vti_bin

-rw-rw-r--   1 mbergljung admin     763917 6 Apr 2017 _vti_bin.war

-rw-r--r--   1 mbergljung admin  168007175 26 Feb 2018 alfresco.war

drwxr-xr-x   7 mbergljung admin        224 26 Feb 2018 host-manager

drwxr-xr-x   8 mbergljung admin        256 26 Feb 2018 manager

-rw-r--r--@  1 mbergljung admin     383139 19 Dec 13:08 repo-ext-3rd-party-lib-1.0-SNAPSHOT.amp

drwxr-xr-x  18 mbergljung  admin 576  4 Jul 13:58 share

-rw-r--r--   1 mbergljung admin   73494142 26 Feb 2018 share.war

drwxr-xr-x  10 mbergljung  admin 320  4 Jul 13:58 solr4

-rw-r--r--   1 mbergljung admin  100394429 19 Sep 2017 solr4.war

 

webapps mbergljung$ java -jar ../../bin/alfresco-mmt.jar install repo-ext-3rd-party-lib-1.0-SNAPSHOT.amp alfresco.war

 

webapps mbergljung$ ls -l

total 1023360

drwxr-xr-x   9 mbergljung admin        288 4 Jul 13:58 ROOT

-rw-r--r--   1 mbergljung admin     274599 19 Sep 2017 ROOT.war

drwxr-xr-x   5 mbergljung admin        160 4 Jul 13:58 _vti_bin

-rw-rw-r--   1 mbergljung admin     763917 6 Apr 2017 _vti_bin.war

-rw-r--r--   1 mbergljung admin  168389519 19 Dec 13:10 alfresco.war

-rw-r--r--   1 mbergljung admin  168007175 26 Feb 2018 alfresco.war-1545225046395.bak

drwxr-xr-x   7 mbergljung admin        224 26 Feb 2018 host-manager

drwxr-xr-x   8 mbergljung admin        256 26 Feb 2018 manager

-rw-r--r--@  1 mbergljung admin     383139 19 Dec 13:08 repo-ext-3rd-party-lib-1.0-SNAPSHOT.amp

drwxr-xr-x  18 mbergljung  admin 576  4 Jul 13:58 share

-rw-r--r--   1 mbergljung admin   73494142 26 Feb 2018 share.war

drwxr-xr-x  10 mbergljung  admin 320  4 Jul 13:58 solr4

-rw-r--r--   1 mbergljung admin  100394429 19 Sep 2017 solr4.war

 

Note also that I removed the exploded /alfresco WAR directory, so we are sure the newly generated WAR will be deployed instead.

 

Now start it all up again:

 

webapps mbergljung$ cd ..

tomcat mbergljung$ cd ..

acs5211 mbergljung$ ./alfresco.sh start

waiting for server to start.... done

server started

/Applications/acs5211/postgresql/scripts/ctl.sh : postgresql  started at port 5432

Using CATALINA_BASE:   /Applications/acs5211/tomcat

Using CATALINA_HOME:   /Applications/acs5211/tomcat

Using CATALINA_TMPDIR: /Applications/acs5211/tomcat/temp

Using JRE_HOME:        /Applications/acs5211/java

Using CLASSPATH:       /Applications/acs5211/tomcat/bin/bootstrap.jar:/Applications/acs5211/tomcat/bin/tomcat-juli.jar

Using CATALINA_PID:    /Applications/acs5211/tomcat/temp/catalina.pid

Tomcat started.

/Applications/acs5211/tomcat/scripts/ctl.sh : tomcat started

acs5211 mbergljung$ tail -f tomcat/logs/catalina.out

...


You should now be able to hit the Web Script URL again with a successful response:  http://localhost:8080/alfresco/s/sample/helloworld

Filter Blog

By date: By tag: