Maven For Dummies

cancel
Showing results for 
Search instead for 
Did you mean: 

Maven For Dummies

resplin
Intermediate
0 0 7,598

Obsolete Pages{{Obsolete}}

The official documentation is at: http://docs.alfresco.com



DO NOT USE - This version of the Maven SDK deprecated. See Alfresco Maven SDK and for Enterprise see Using Maven Alfresco SDK with the Enterprise edition


Introduction


This document describes how to use Maven to develop Alfresco customisations. Specifically it will walk you though the creation of a simple multi-module project that will cover Alfresco Repository customisations and Share customisations.

Why is it called 'Maven for Dummies'? It's because I'm fairly inexperienced with Maven and because I struggled to get the Maven Archetypes to work I thought that I would have a go at documenting the process.


Attribution


I've used Jeff Potts' examples from his Developer Series. If you're new to Alfresco Development then I would highly recommend Jeff's excellent tutorials.


References and Useful Sites


Pre-Requisites


Java SDK


You'll need the Java SDK. Download it from the Oracle site. Macs are preinstalled with Java SDK. Linux users - you're capable of sorting yourselves out.


Maven


Obviously you'll need a working Maven instance. At the time of writing the latest versions are 2.2.1 and 3.0.4. I would recommend going with 2.2.1 for now as there is a filtering bug that manifests itself under 3.x and prevents launching Share from Maven.


Eclipse


Maven allows us to work from command line and from within popular IDEs such as Eclipse and Intelli-J IDEA. It's a good idea to download plugins for Maven and Subversion integration. Some IDEs support Maven and Subversion out of the box.

For the purposes of the tutorial I've gone with Eclipse, specifically SpringSource Tool Suite (STS) 2.7.0.


With some Eclipse (and built-in Maven plugin m2e) versions you might encounter some problems setting up some XML validation settings where Maven-related placeholders are mentioned (e.g. jetty/jetty-env.xml). As a workaround, try to relax your pom.xml validation rules:


  1. Access 'Eclipse Preferences' > 'Validation'
  2. Scroll down to XML Validator
  3. Click on '...'
  4. Select 'Exclude Group'
  5. Click on 'Add Rule'
  6. Choose project Nature
  7. Select Maven Nature 'org.eclipse.m2e.core.maven2Nature'

MySQL


You'll need a database for the Alfresco repository. It's not strictly required for development but we'll use this for local functional testing.


Please note that, at the time of writing, the Alfresco SQL setup scripts use the now deprecated 'TYPE' option for 'CREATE TABLE'. The 'TYPE' option was replaced in MySQL 4.0 by the 'ENGINE' option, thereafter use of 'TYPE' generated a warning until MySQL 5.5 where it generates an error. Consequently, I ended up installing MySQL 5.1 to get around this problem.

Please remember to ensure that InnoDB is set as the default storage engine for MySQL. See here for instructions on how to do this.

Once MySQL is running, create a text file called db_setup.sql with the following contents:

create database alf_jetty default character set utf8 collate utf8_bin;
grant all on alf_jetty.* to 'alfresco'@'localhost' identified by 'alfresco' with grant option;
grant all on alf_jetty.* to 'alfresco'@'localhost.localdomain' identified by 'alfresco' with grant option;

Run the SQL script as follows to create a database called alf_jetty:

 mysql -u root -p <dependency>
    <groupId>org.alfresco</groupId>
    <artifactId>alfresco-core</artifactId>
    <version>${alfresco.version}</version>
    <scope>provided</scope>
    <classifier>community</classifier>
</dependency>

Run the following command to create the Eclipse project files:

mvn eclipse:eclipse

Start Eclipse then import the Alfresco Repository project (File | Import | Maven | Existing Maven Projects into Workspace). Once imported you will notice that some configuration folders have been incorrectly identified as source folders. Highlight the 'src/test/resources', 'src/main/resources' and 'src/main/config' folders then right-click and select 'Build Path | Remove from Build Path'.

Modify 'src/main/config/module-context.xml' to include references to the content model definition file and associated Alfresco Explorer UI configuration by adding the following:

   <bean id='com.someco.someco-repo.dictionaryBootstrap'
         parent='dictionaryModelBootstrap'
         depends-on='dictionaryBootstrap'>
       <property name='models'>
           <list>
               <value>alfresco/module/${artifactId}/model/scModel.xml</value>
           </list>
       </property>
       <property name='labels'>
           <list>
               <value>alfresco/module/${artifactId}/messages/scModel</value>
           </list>
       </property>
   </bean>
   <bean id='com.someco.someco-repo.bootstrapConfigBootstrap'
         class='org.alfresco.web.config.WebClientConfigBootstrap'
         init-method='init'>
       <property name='configs'>
           <list>
               <value>classpath:alfresco/module/${artifactId}/ui/web-client-config.xml</value>
           </list>
       </property>
   </bean>
   <bean id='com.someco.someco-repo.bootstrapMyAmpBundlesBean'
         class='org.alfresco.web.app.ResourceBundleBootstrap'>
       <property name='resourceBundles'>
           <list>
               <value>alfresco.module.${artifactId}.messages.webclient</value>
           </list>
       </property>
   </bean>

Add the file 'src/config/model/scModel.xml' with the following content:

<model name='sc:somecomodel' xmlns='http://www.alfresco.org/model/dictionary/1.0'>
    <description>Someco Model</description>
    <author>Jeff Potts</author>
    <version>1.0</version>
    <imports>
        <import uri='http://www.alfresco.org/model/dictionary/1.0'
            prefix='d' />
        <import uri='http://www.alfresco.org/model/content/1.0' prefix='cm' />
    </imports>
    <namespaces>
        <namespace uri='http://www.someco.com/model/content/1.0' prefix='sc' />
    </namespaces>
    <types>
        <type name='sc:doc'>
            <title>Someco Document</title>
            <parent>cm:content</parent>
            <associations>
                <association name='sc:relatedDocuments'>
                    <title>Related Documents</title>
                    <source>
                        <mandatory>false</mandatory>
                        <many>true</many>
                    </source>
                    <target>
                        <class>sc:doc</class>
                        <mandatory>false</mandatory>
                        <many>true</many>
                    </target>
                </association>
            </associations>
            <mandatory-aspects>
                <aspect>cm:generalclassifiable</aspect>
            </mandatory-aspects>
        </type>
        <type name='sc:whitepaper'>
            <title>Someco Whitepaper</title>
            <parent>sc:doc</parent>
        </type>
       <type name='sc:folder'>
           <title>Someco Folder</title>
           <parent>cm:folder</parent>
       </type>
    </types>
    <aspects>
        <aspect name='sc:webable'>
            <title>Someco Webable</title>
            <properties>
                <property name='sc:published'>
                    <type>d:date</type>
                </property>
                <property name='sc:isActive'>
                    <type>d:boolean</type>
                    <default>false</default>
                </property>
            </properties>
        </aspect>
        <aspect name='sc:productRelated'>
            <title>Someco Product Metadata</title>
            <properties>
                <property name='sc:product'>
                    <type>d:text</type>
                    <mandatory>true</mandatory>
                </property>
                <property name='sc:version'>
                    <type>d:text</type>
                    <mandatory>true</mandatory>
                </property>
            </properties>
        </aspect>
    </aspects>
</model>

Add the file 'src/config/messages/scModel.properties' with the following content:

# content model
sc_somecomodel.description=Someco Content Domain Model
# type sc_folder
sc_somecomodel.type.sc_folder.title=Someco Folder
sc_somecomodel.type.sc_folder.description=Someco Folder
# type sc_doc
sc_somecomodel.type.sc_doc.title=Someco Document
sc_somecomodel.type.sc_doc.description=Someco Document
sc_somecomodel.property.sc_relatedDocuments.title=Related Documents
sc_somecomodel.property.sc_relatedDocuments.description=Related Documents
# type sc_whitepaper
sc_somecomodel.type.sc_whitepaper.title=Someco Whitepaper
sc_somecomodel.type.sc_whitepaper.description=Someco Whitepaper
# aspect sc:webable
sc_somecomodel.aspect.sc_webable.title=Someco Webable
sc_somecomodel.aspect.sc_webabl.descriptione=Someco Webable
sc_somecomodel.property.sc_published.title=Published
sc_somecomodel.property.sc_published.description=Published
sc_somecomodel.property.sc_isActive.title=Is Active
sc_somecomodel.property.sc_isActive.description=Is Active
# aspect sc:productRelated
sc_somecomodel.aspect.sc_productRelated.title=Product Related
sc_somecomodel.aspect.sc_productRelated.description=Product Related
sc_somecomodel.property.sc_product.title=Product
sc_somecomodel.property.sc_product.description=Product
sc_somecomodel.property.sc_version.title=Version
sc_somecomodel.property.sc_version.description=Version

Add the file 'src/config/messages/webclient.properties' with the following content:

# type sc:folder
sc_folder=Someco Folder
# type sc:doc
sc_doc=Someco Document
sc_relatedDocuments=Related Documents
# type sc:whitepaper
sc_whitepaper=Someco Whitepaper
# aspect sc:webable
sc_webable=Someco Webable
sc_published=Published
sc_isActive=Is Active
# aspect sc:productRelated
sc_productRelated=Product Related
sc_product=Product
sc_version=Version

Add the file 'src/config/ui/web-client-config.xml' with the following content:

<alfresco-config>
    <config evaluator='node-type' condition='sc:doc'>
        <property-sheet>
            <show-association name='sc:relatedDocuments' display-label-id='sc_relatedDocuments' />
        </property-sheet>
    </config>
    <config evaluator='aspect-name' condition='sc:webable'>
        <property-sheet>
            <show-property name='sc:published' display-label-id='sc_published' />
            <show-property name='sc:isActive' display-label-id='sc_isActive' read-only='true' />
            <show-association name='sc:relatedDocuments' display-label-id='sc_relatedDocuments' />
        </property-sheet>
    </config>
    <config evaluator='aspect-name' condition='sc:productRelated'>
        <property-sheet>
            <show-property name='sc:product' display-label-id='sc_product' />
            <show-property name='sc:version' display-label-id='sc_version' />
        </property-sheet>
    </config>
    <config evaluator='string-compare' condition='Content Wizards'>
        <content-types>
            <type name='sc:doc' />
            <type name='sc:whitepaper' />
        </content-types>
    </config>
    <config evaluator='string-compare' condition='Space Wizards'>
        <folder-types>
            <type name='sc:folder' />
        </folder-types>
    </config>
    <config evaluator='string-compare' condition='Action Wizards'>
        <aspects>
            <aspect name='sc:webable' />
        </aspects>
        <specialise-types>
            <type name='sc:folder' />
            <type name='sc:doc' />
            <type name='sc:whitepaper' />
        </specialise-types>
    </config>
    <config evaluator='string-compare' condition='Advanced Search'>
        <advanced-search>
            <content-types>
                <type name='sc:doc' />
                <type name='sc:whitepaper' />
            </content-types>
            <folder-types>
                <type name='sc:folder' />
            </folder-types>
            <custom-properties>
                <meta-data aspect='sc:webable' property='sc:published' display-label-id='sc_published' />
                <meta-data aspect='sc:webable' property='sc:isActive' display-label-id='sc_isActive' />
                <meta-data aspect='sc:productRelated' property='sc:product' display-label-id='sc_product' />
                <meta-data aspect='sc:productRelated' property='sc:version' display-label-id='sc_version' />
            </custom-properties>
        </advanced-search>
    </config>
</alfresco-config>

Run the 'mvn install' again or alternatively run this Maven goal from the IDE. You should find that your AMP has been updated with the customisations that we just added. You can now merge the AMP into an alfresco.war using the Module_Management_Tool MMT utility and restart your application server to deploy the content model and associated UI customisations.


Using Maven Features


Up to this point we've apparently done nothing that couldn't have been done using the Ant-based Alfresco SDK. If we have a look at the output of 'mvn install' you should notice that it compiled the sample Java source that was provided by the AMP archetype at 'src/main/java'. Furthermore, it automatically tried to run JUnit tests that would exist under 'src/test/java'. Try running 'mvn javadoc:javadoc' to create Javadoc documentation. This is standard Maven functionality. You get a lot of functionality without any additional effort. See this page for an introduction to basic Maven features.

The AMP archetype features an embedded Jetty instance so that we can run an Alfresco instance directly from Maven. Previously it also featured an embedded database called H2 as well. Support for H2 is no longer available but we can use a local MySQL instance. Earlier in this article we created a database called alf_jetty. Unfortunately, the AMP archetype was written before support for H2 was deprecated so we'll have to modify a couple of configuration files for our project to facilitate MySQL support.

Modify 'jetty/jetty.xml'. Comment out the H2 datasource and add a MySQL datasource:

<New class='com.mysql.jdbc.jdbc2.optional.MysqlConnectionPoolDataSource'>
    <Set name='URL'>${alfresco.db.url}</Set>
    <Set name='User'>${alfresco.db.username}</Set>
    <Set name='Password'>${alfresco.db.password}</Set>
</New>

Modify 'pom.xml' as follows:

Add the following properties to the '/project/properties' element:

<alfresco.db.host>localhost</alfresco.db.host>
<alfresco.db.port>3306</alfresco.db.port>
<alfresco.db.driver>org.gjt.mm.mysql.Driver</alfresco.db.driver>
<alfresco.db.url>jdbc:mysql://${alfresco.db.host}:${alfresco.db.port}/${alfresco.db.name}</alfresco.db.url>
<alfresco.db.hibernate.dialect>org.hibernate.dialect.MySQLInnoDBDialect</alfresco.db.hibernate.dialect>

Comment out the references to H2 support at '/project/profiles/profile/dependencies':



Add a dependency for the MySQL JDBC driver to '/project/profiles/profile/dependencies':

<dependency>
    <groupId>mysql</groupId>
    <artifactId>mysql-connector-java</artifactId>
    <version>5.1.18</version>
</dependency>

Modify 'src/test/properties/local/alfresco-global.properties' as follows:

#db.driver=org.h2.Driver
#db.url=jdbc:h2:${alfresco.data.location}/h2_data/${alfresco.db.name}
db.driver=${alfresco.db.driver}
db.url=${alfresco.db.url}
# the dialect setting is not required for Alfresco 3.4+
#hibernate.dialect=org.hibernate.dialect.H2Dialect

Please note that this alfresco-global.properties file is only used for the embedded Alfresco instance.

Modify JVM memory settings so that we can run Alfresco from Maven:

MAVEN_OPTS='-Xms256m -Xmx512m -XX:MaxPermSize=128m'

Run embedded Alfresco instance:

mvn clean integration-test -P webapp

This will take a while to startup as it downloads the vanilla Alfresco WAR the first time that it is invoked then overlays the contents of the custom AMP. Eventually you will see something like this:

[INFO] Started Jetty Server [INFO] Starting scanner at interval of 10 seconds.

Point your browser at http://localhost:8080/${artifactId}-webapp (in our case this is http://localhost:8080/someco-repo-webapp) and you should be greeted with the Alfresco home page. Press CTRL-C to shutdown the embedded Alfresco instance.

Last but not least, if you come from the ANT world and you like to store MyLogic.java and MyLogic.properties files into the same folder (avoiding the Maven convention of separating them between src/main/java and src/main/resources), you should add the following syntax to your pom.xml



<resources>
  <resource>
    <filtering>true</filtering>
    <directory>src/main/java</directory>
    <includes>
      <include>**/*.properties</include>
    </includes>
  </resource>
  ...

Using Git


If you'd like to use Git as SCM (e.g. github), you can simply follow this very detailed guide provided by Sonatype, taking in consideration the following details:


  • Latest (and advised) version of maven-release-plugin to use is 2.2.2
  • Maven-release-plugin by default performs a deploy of artifact(s) and, if no <distributionManagement> is configured it fails; you can force the release plugin to just perform the install goal, using the following syntax:
<plugin>
  <groupId>org.apache.maven.plugins</groupId>
  <artifactId>maven-release-plugin</artifactId>
  <version>2.2.2</version>
  <configuration>
    <goals>install</goals>
  </configuration>
</plugin>

Feel free to browse my Alfresco AMP Github project as additional reference.


Create Basic Share WAR Project


Create Share Project Structure from Template


Run the following command from the parent folder of the someco-repo project:

mvn archetype:generate -DarchetypeGroupId=org.alfresco.maven -DarchetypeArtifactId=maven-alfresco-share-archetype \
-DarchetypeVersion=3.9.1 -DgroupId=com.someco -DartifactId=someco-share -Dversion=1.0-SNAPSHOT \
-DarchetypeRepository=https://artifacts.alfresco.com/nexus/content/repositories/releases -DinteractiveMode=false

The above command has created a project under the sub-directory someco-share that is configured to build a custom Share WAR.

Share-archetype.png

The Share archetype has generated a typical Maven project structure.


  •   /pom.xml - the project configuration file (similar to Ant build.xml) that defines properties, dependencies, etc including the version of Alfresco Share to build against
  •   /src/main/properties - contains environment specific configurations in property files named application.properties
  •   /resources/alfresco - contains configuration files such as a custom Share configuration file and sample Spring context files

Let's try out the build process from the command line:

cd someco-share
mvn install

Once Maven has finished you should find that a Share WAR has been created at 'target/someco-share.war'.

Modify '/src/main/properties/local/application.properties' as follows to ensure that share is able to communicate with the Alfresco repository:

#alfresco.webapp.name=alfresco
alfresco.webapp.name=someco-repo-webapp



Rename '/src/main/resources/alfresco/web-extension/share-config-custom.xml.sample' to '/src/main/resources/alfresco/web-extension/share-config-custom.xml'. Edit 'share-config-custom.xml', search for the block that starts with '<config evaluator='string-compare' condition='Remote'>'. Change the value of the '<endpoint-url>' value from..

${alfresco.server.scheme}://${alfresco.server.name}:${alfresco.server.port}/alfresco/s

..to..

${alfresco.server.scheme}://${alfresco.server.name}:${alfresco.server.port}/${alfresco.webapp.name}/s

This ensures that the Share webapp is able to communicate with the embedded Alfresco instance.

Run the below command to run the Share WAR within a separate embedded Jetty instance that runs on port 8081. Please note that the Alfresco repository must be running (see above for instructions). The Alfresco repository will be running on port 8080.

mvn install -Prun

Once you see the following output, Share is ready to use:

[INFO] Starting jetty 6.1.21 ...

Point your browser at http://localhost:8081/${artifactId} (in our case this is http://localhost:8081/someco-share) and you should be greeted with the Share home page. Press CTRL-C to shutdown the embedded Alfresco instance.

At the time of writing there is a bug that causes the warning 'Unable to retrieve License information from Alfresco: 404' to be written to the console as an error. This is fixed in later versions of Alfresco.


Develop Alfresco Share UI Modifications


Let's add some Share UI customisations so that it supports our custom content model. Before we do, let's create the Eclipse project files and import the project into Eclipse.



Run the following command to create the Eclipse project files:

mvn eclipse:eclipse

Start Eclipse then import the Share project (File | Import | Maven | Existing Maven Projects into Workspace). Once imported you will notice that some configuration folders have been incorrectly identified as source folders. Highlight the 'src/main/properties/ci' and 'src/main/properties/local' folders then right-click and select 'Build Path | Remove from Build Path'.

Add the following content to '/main/resources/alfresco/web-extension/share-config-custom.xml':

TODO..

Developer Guide