Hi folks, it's been a while since i write an article and i apologise for that. The work load has been crazy but because i didn't forget about you all I'm currently on a plane writing this post. Its very rewarding to visit customers and realize that the people (specially the technical folks) has read my blog posts have positive feedback about them. This is a big driver and motivator to keep me writing, so thanks for reading it and don't be shy to comment. Comments are good and help me to improve the materials i share. This very topic is a great example for a discussion topic, so i'm expecting a lot of comments and even some disagreements, again don't be shy.
Before we jump into the blog topic, you should know that this blog post represents my personal view and opinion and does not necessarily represents the view of my employer and colleagues.
1 About Maven
Maven is a build management tool with many time-saving features, being the most important one the ability to understand the dependencies your project relies on (and the dependencies of those dependencies and so on).
2 About the Alfresco SDK
This guide is based of SDK 2.2.0 and Alfresco 5.1. The main goal of the Alfresco SDK is to make extremely easy for developers to get started with Alfresco extensions development. It consists of a project template (an "archetype" in Maven language) that allows the creation of Alfresco extensions and test their deployment against specific versions of the platform. It creates an initial structure(template) allowing to write code that runs within the context of Alfresco and Share web-applications.
The archetypes provided by alfresco (all-in-one, alfresco-amp, share-amp) represent a good base start for any project, but they need to be adapted to reflect the reality of each project, that’s why we refer to them as project templates.
3 Understanding Alfresco Module framework
The design concept of an Alfresco module was to provide a modular approach to extend the base platform, but it does not enforce us to deploy our changes directly inside the base platform. In fact, this should be analysed according the nature of the extension.
3.1 An Alfresco module its not the same as an Alfresco module package (AMP)
An AMP it’s no more than a way to package the contents of an Alfresco module. The design concept of an Alfresco module was to provide a modular approach to extend the base platform, but it does not enforce us to deploy our changes directly inside the base platform. In fact, this should be analysed according the nature of the extension.
Let’s analyse the how Alfresco extension module system works behind the scenes. The Alfresco repository class loaders, execute a scan for new modules definitions and spring configurations during the start of the platform. New modules are then initialized when the Alfresco repository loads the root Spring configuration for each module. Per the alfresco module definition, a module's root Spring configuration must be placed in the package alfresco.module.<moduleId> and should be called module-context.xml.
When the module service is initialized, all the module-context.xml configurations found are loaded, thus initializing the installed modules ready for use. The module-context.xml is a standard Spring configuration file where typically new beans are defined, custom content models are introduced and data is loaded or patched.
In case of a big module that implements different extensions the configuration may be split up into smaller Spring configurations which are included by module-context.xml.
Note: The property executeOnceOnly (default: true) tells the system how many times to execute your module. If you want your module to run every time Alfresco is started, set executeOnceOnly to false.
3.2 Properties of an Alfresco module
The module.properties file itself contains the module id, version, title and description of the module. The next table shows a definition of the existing module properties
Alfresco Module properties
The module id acts as a unique identifier for this module. It is important that the module id is globally unique so that it never clashes with other modules when it is installed.
When a module gets renamed, it is necessary to add the original name to the list of aliases. This ensures that the module tool and repository startup can correctly match the new name to one of the old names.
The module version number specifies the current version of the module. This is taken into consideration when installing the module into Alfresco. It will determine whether it is a new install or an update to an existing installation of a previous version.
The title of the module.
The description of the module.
Specifies the minimum and maximum versions of Alfresco that this module can be installed into (defaults to all).
Specifies which edition(s) of Alfresco this module can be installed into (defaults to all). Valid values are "Community" and "Enterprise".
When a module is installed, it may be a requirement that another module is installed. It may be a requirement that a specific version, set of versions or range of versions is present. The dependency has been met as long as the installed version of the dependency matches any of the ranges or versions give.
More information at https://wiki.alfresco.com/wiki/Developing_an_Alfresco_Module#Module_Properties
3.3 Specific properties for an Alfresco share module
In Alfresco 5.1 there is separate versioning of the platform modules (Repo) and Share modules. For that reason, we have 2 new properties that help us to define the minimum and maximum versions of Alfresco share that the module can be installed into.
The specific properties of an alfresco-share module.
Alfresco Share Module properties
Specifies the minimum version of Alfresco Share that this module can be installed into (defaults to all).
Specifies the maximum version of Alfresco Share that this module can be installed into (defaults to all).
3.4 Module-id formatting
An Alfresco module id is linked with the directory naming convention that is enforced when building and deploying a module. Its linked to the /alfresco/module/module-id directory naming. See the module naming on the screenshot below for a cmis-fedsearch module.
On the module.properties the module-id must match the folder name that is defined under src/main/resources/module/<module.id>
Use abbreviations to define your module ids so that they describe the module purpose.
3.5 Module versioning now supports SNAPSHOTS
Since Alfresco 5.1 we support SNAPSHOT module versioning, this is a great add-on that allows us to align our maven project project version with our modules version.
4 AMP modules X Jar modules
This is the controversial topic of this post and the topic that can generate more discussion. I'm expecting to have a lot of comments and opinions of you guys, i promise i will try to reply to them all.
4.1 AMP module extensions
Currently, anything that is considered to be an 'installable' extension to Alfresco should be called a module and packaged as one or more AMP files. An AMP file is ZIP compressed and has a default structure template that maps to locations inside the alfresco web-applications (share or alfresco depending on the type of amp).
AMP files are then installed into the Alfresco and Share WAR files using the Module Management Tool. What MMT does is to extract the contents of the. AMP file into the target web-application.
Once the contents of the AMP file are installed into an Alfresco WAR the platform WAR is changed to included the elements of the AMPs. AMP files can be created via Apache Maven archetypes and have their lifecycle and deployment into Alfresco managed by the Maven Alfresco AMP archetype.
4.2 Jar Module extensions
Jar modules extensions provide the capability of building jar based module packages. Let’s take a look how classloaders work to understand the value of Jar module extensions.
In a Java environment, class loaders are arranged in a parent-child tree. Normally, when a class loader is asked to load a particular class or resource, it delegates the request to a parent class loader first, and then looks in its own repositories only if the parent class loader(s) cannot find the requested class or resource.
A class loader is created for each web application that is deployed in a single application server instance. All unpacked classes and resources live in the /WEB-INF/classes directory of your web application. Other classes and resources are in JAR files under the /WEB-INF/lib directory of your web application, those are made visible to this web application, but not to other ones.
4.2.2 New tomcat Virtual class loaders introduced in Alfresco 5.1
Tomcat introduces the Loader element and it represents the web application class loader that will be used to load Java classes and resources for our web application.Such a class loader must follow the requirements of the Servlet Specification, and load classes from the following locations:
- From the /WEB-INF/classes directory inside the web application.
- From JAR files in the /WEB-INF/lib directory the your web application.
- From resources made available by Tomcat to all web applications globally.
A Loader element MAY be nested inside a Context component. If it is not included, a default Loader configuration will be created automatically, which is sufficient for most requirements.
It extends WebappLoader and supports some additional attributes.
Alfresco 5.1 introduces 2 new virtual web-application classloaders, one for each application. This classloaders are defined in <tomcat_root>/conf/catalina/localhost and they allow the deployment of jars (and jar modules) under <ALFRESCO_INSTALL_DIR>/modules. The modules folder contains 2 sub-folders , platform and share where we can deploy extensions to the repository and share respectively.
The definition of the virtual classloader for Alfresco is the following:
And definition of the virtual classloader for Share is :
We have a relevant option "searchVirtualFirst" that we can set to true if we want the virtual class path to be searched before WEB-INF/classes and WEB-INF/lib. Default value is false.
If searched before, resources located in the virtual class path take precedence over resources with the same name contained in the webapp.
4.3 How to choose between jar and amp extensions
There are several downsides of using AMPS. You cannot depend on a AMP module for classes. This means that you cannot have amps that depend on other amps. That could be done with some changes to the amp archetype in order to produce a separate JAR that could be depended upon. On this situation, the jar modules are much more flexible.
Using only AMPs has the following disadvantages:
- There is no reliable and documented way to uninstall an AMP
- Amps cannot depend on another AMP
- Situations where an AMP customisation does not work when another AMP customisation is installed
Alfresco 5.1 supports deployment of extensions as JAR modules. Although the Alfresco SDK does not have support for generating JAR module projects, its possible to transform the amp archetype into a JAR module, by adapting its folder structure. The screenshot below shows how such a structure looks like. Note that the module directory now exists in src/main/resources.
And next my personal opinion on what type of extensions should be used together with some arguments to support this choice.
4.4 Choose Jars unless there is a good reason not to
Whenever possible i choose to use jar modules. The decoupling from the vanilla distributions is very helpful and it brings a logical separation between the platform and extension implementations.
Ideally the Alfresco repository distributions would remain untouched during the full project LiveCycle. If the project is based on Alfresco 5.1, the alfresco.war , share.war and solr4 web-applications remain the vanilla distributions during the entire project lifecycle.
JAR Modules have a lot of advantages over AMPs:
- They can be easily installed and uninstalled
- Jar modules don’t accidentally overwrite files from the product or other extensions
- Maven likes and integrates very well with JARs
- Development Environments and IDEs are well prepared to work with JARs
- Java Developers generally have knowledge about jar files and how they work
Working with Jar modules would have the following benefits for developers:
- It is easy to get going with the customisation, project can be generated from archetype
- Less error prone implementation than managing AMPs
- Simplified platform upgrade process
- Reduced application downtime by leveraging the hot reload capabilities of the application server
- Jar module extensions can depend on other jar module extensions
- Build process is much faster than with AMPs
Maven natively knows about JARs but not about AMPs, so it is easy to integrate your customisation and depend on your customisation when building a solution. In contrast to AMPs, JARs don't overwrite files from the product distribution or other extensions when deployed, causing unnecessary problems and project delays.
There is only one case where you eventually would need AMPs, and that is when you require to bring in 3rd party JARs that are not already available in WEB-INF/lib of the repository. In this case, you can 2 options :
1 ) have a specific amp project where you manage all extra third-party libraries that you need to include on the deployment.
2) In a SDK based template project, use the repo module to manage all third-party libraries you need. They will get included on your generated war files and your modules can rely on those.
4.5 Jar modules ? How about web-application resources (css,js,html,images) ?
Applying the practices defined on this guide will improve the way we manage Alfresco based deployments by leveraging the capacities of Maven providing a clearer overview and increased control. This best practices promote modularity, simplicity and increased control over the full application lifecycle. With the jar modules approach the Alfresco distributions are seen as platforms and they can remain untouched during the full project LiveCycle.
If the project is based on Alfresco 5.1, the alfresco.war, share.war and solr4 web-applications can remain the vanilla distributions during the entire project lifecycle. This makes the upgrade process much cleaner and simple.
Alfresco deployments that are compliant with this guide take full advantage of Alfresco elasticity in terms of extension management, upgrade management and project lifecycle management. You can :
- Avoid painful upgrades
- Reduce service interruptions
- Intelligent Extension Modularity and Simplicity
- Taking full advantage of Maven and the Alfresco SDK
I hope you enjoyed this post and can use it to drive the success of your own projects. Please leave your comment and stay tuned for more Alfresco related posts. Until then, wishes of great success on your projects and implementations.