Packaging And Deploying Extensions
There are several ways of deploying extensions. The best method for your project will depend on how complex your extension is, how many extensions you will be deploying, your environment (such as which app server you are using), which version of Alfresco you are on, and your development culture.
Whatever approach you use, make sure you:
- Track the history of your code using source control,
- Track your static assets,
- Keep your code separate from Alfresco code,
- Use the extension and web-extension folders,
- Isolate multiple customizations,
- Be consistent,
- Test all extensions in a non-production environment.
These habits will pay dividends such as:
- Allow you to remove your customizations when troubleshooting an issue,
- Ask for help from an Alfresco expert without confusing your code and Alfresco code,
- Identify what needs to be audited during an Alfresco upgrade.
Alfresco Module Packages are the recommended way of packaging Alfreco customizations and extensions. AMPs are zip files that follow a specific layout and can be merged with the alfresco.war and/or share.war using the Alfresco Module Management Tool (alfresco-mmt.jar).
Since July 2008 a Sourcesense contribution is available for building and packaging extensions into AMPs using Apache Maven (see Managing Alfresco Lifecyle with Maven).
Unpackaged Files or ZIP
Many development environments employ a build process that can execute a script to move unpackaged modified files from source control into the web application's exploded WAR file. Ant, bash, or some scripting language can all be good ways to do this.
Moving unpackaged files has the advantage of being quick and easy to understand, but it may be better to package the files into a zip artifact that will then be unzipped over the exploded WAR.
Note that this approach is not recommended for QA or production environments, as Tomcat (and potentially other app servers) may re-explode WAR files at unpredictable times, thereby overwriting any changes that have been installed on top. This is one of the reasons that AMP files (see previous section) were created.
To deploy these JARs, it is recommended to place them inside one or more AMPs (see previous section), and deploy them into the share.war file. As mentioned above, installing these JARs directly into the exploded webapp is not recommended as Tomcat (and potentially other app servers) can (and will) overwrite your changes at unpredictable times.
While it's possible to avoid the overwriting problem (at least in Tomcat) by placing these JAR files in tomcat/shared/lib, this is also not recommended as this causes the JARs to be included on the classpath of every webapp installed in that Tomcat server (typically this means at least the Share webapp and the Alfresco repository webapp). In fact since v6.0 Tomcat no longer provides a shared/lib directory by default, specifically because it is so problematic from a webapp isolation perspective.
Any specific change can be deployed to various locations so as to override an Alfresco file.
All locations depend on the application server you are using.
Once the Tomcat server has been started, the application is exploded into
$TOMCAT_HOME/webapps/alfresco. Stop the server if it is running, copy the file to
$TOMCAT_HOME/webapps/alfresco/WEB-INF/ and re-start Tomcat.
Beware that any time your app server re-deploys the alfresco.war file, your extension will be deleted and you will have to re-deploy it.
One solution is to use a permanently exploded deployment (instead of deploying an Alfresco WAR file under
/webapps). Create a directory called alfresco under the
webapps directory and extract the contents of
alfresco.war into it. Then copy your files to
../webapps/alfresco/WEB-INF/ and restart Tomcat. It is then recommended to remove the war file so that Tomcat can't redeploy and overwrite your changes.
Useful background information on how Tomcat resolves classpaths is here.
In JBoss, if you deploy a web application as a WAR file the application gets exploded to a temporary directory each time the app server starts. Thus there is nowhere to copy the JAR file to. One solution is to use an exploded deployment. Create a directory called alfresco.war under the deploy directory and extract the contents of
alfresco.war (the file) into it. Then copy your JAR file to
...deploy/alfresco.war/WEB-INF/lib and restart JBoss.
Many customizations can be placed on your application server's classpath, such as Alfresco configuration files or properties files i.e.
web-client-config-custom.xml, and Spring context files or
- For Tomcat, the shared classloader folder is
- For JBoss, the shared classloader folder is
In this folder there are standard sub-directories:
- extension: for changes to the repository or Alfresco Explorer UI,
- web-extension: for changes to the Share UI,
- messages: for localization strings.
Files which are packaged as a JAR would be placed in the appropriate lib such as
Files placed in these folders will overlay the relevant file in the appropriate WAR.
Be aware that files on the application server classpath will overlay all WARs in the application server. It is more predictable to put your files into the classpath for a specific WAR.
Because of web application sandboxing, Java classes which extend Alfresco's Java classes cannot be placed in the shared class loader. They must be in the class loader for the web application to which they apply.
Also note that in Tomcat 7
$TOMCAT_HOME/shared/lib is no longer on the default classpath as it is recommended to put your library in a context specific to your WAR.
WAR Specific Classpath
A better location for your changes would be in one of:
$TOMCAT_HOME/webapps/alfresco/WEB-INF/lib (for JARs)
$TOMCAT_HOME/webapps/share/WEB-INF/lib (for JARs)
It is most common to patch the Alfresco and Share WAR files in order to put your code in the correct location in a way that is preserved through redeployments. This is what the apply_amps script accomplishes.
Classes which are intended to be extended
Should you be building an Alfresco extension that you plan to redistribute, and you want to allow the consumers to modify your extension, it will need to be placed in the extension folder and not the web-extension folder. If customers want to extend your extension, their customizations will go in web-extension folder which will load after the customization you placed in the extension folder.
Alfresco configuration files
You can only have one identically named file on the classpath as only the last one will be used. For example, if you have multiple JARs with a
web-client-config-custom.xml file in the
alfresco/extension package the ClassLoader will load the last one it finds, which in turn, will result in unpredictable behavior. Furthermore, you can not guarantee the order in which files will be found.
In versions newer than 2.0, you can have multiple
web-client-config-custom.xml files present in the system by placing them in the JAR file's
META-INF folder. This change is part of the module management improvements made in 2.0
JSF configuration files
Unfortunately, to override JSF configuration differs depending on what you want to override. For whatever reason, JSF has a first one wins policy for navigation rules and a last one wins policy for managed beans.
We therefore provide hooks for JSF configuration at the start and the end of JSF initialisation. To hook in at the beginning (i.e. to override a navigation rule,) create a faces-config.xml and package the file within a JAR within the META-INF folder. To hook in at the end, create a faces-config-custom.xml file and copy it to the WEB-INF folder of the Alfresco web application (this should replace our empty placeholder file).
As a guide the table below shows which file JSF config should go to:
|Override||File and Location|
|Overriding navigation rules||faces-config.xml in META-INF|
|Overriding managed beans||faces-config-custom.xml in WEB-INF|
|New navigation rules||Either|
|New managed beans||Either|