Monday, January 14, 2013

How to disable localization in Alfresco Share

If you have the requirement that Alfresco Share should be available in only one single language then this is not that trivial. By default Alfresco Share takes the web browser language into account. There is out of the box no way to choose the language. This post describes how to set the language to just the English one. What you need to know is that there is a Spring Bean with the Id 'localeResolver'. So we need to override the Bean by using an own implementation of it.If you do not know the Spring framework, then what you need to know at this point is that you can configure Java Classes as Beans by using XML. An instance of the Class is then available via the Spring Context. So you get get an instance of the Class by asking the Spring Context for a Bean with a specific id. It's possible to have multiple instances with different id-s and parameters. So a lot of stuff  in Alfresco is accessible via Spring Beans. If something is available via the above mentioned context, then you can just override it. This changes Alfresco's default behavior. The reason why it works is that the custom configuration becomes loaded later than the original configuration and so the original Spring Bean definition becomes overridden. Here the steps:
  1. In '${TOMCAT_HOME}/shared/classes/alfresco/web-extension' create a context file by naming it to 'custom-slingshot-application-context.xml'. I believe the only important thing here is that it ends with '-context.xml'.
  2. In this file define a Spring Bean by using the following code:
 <?xml version='1.0' encoding='UTF-8'?>
<beans xmlns="http://www.springframework.org/schema/beans"
       xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
       xmlns:hz="http://www.hazelcast.com/schema/config"
       xsi:schemaLocation="http://www.springframework.org/schema/beans
                http://www.springframework.org/schema/beans/spring-beans-2.5.xsd
                http://www.hazelcast.com/schema/config
                http://www.hazelcast.com/schema/config/hazelcast-spring.xsd">
  
        <bean id='localeResolver' class='de.ecmgeek.alfresco.MyLocaleResolver'/>
  
</beans>


Now you can just implement your own LocaleResolver and put it to the classpath (E.G. as a JAR file):


package de.ecmgeek.alfresco;

import java.util.Locale;
import javax.servlet.http.HttpServletRequest;
import org.springframework.extensions.surf.mvc.LocaleResolver;
import org.springframework.extensions.surf.util.I18NUtil;

public class MyLocaleResolver extends LocaleResolver
{
    @Override
    public Locale resolveLocale(HttpServletRequest request)
    {   

        /* Here we could set the locale by getting the value of the 

           cookie with the name ALFRESCO_UI_PREFLANG or by handling

           a request parameter. For now this value is just null. */

        Locale locale = null;
   
        if (locale == null)
        { 

            //To set a constant value

            locale = I18NUtil.parseLocale("en_EN");

        }     

        

        I18NUtil.setLocale(locale); 

        return locale;
    }
}  

How to externalize the SOLR instance which comes with Alfresco 4.x

Alfresco 4.x uses SOLR instead Lucene. In fact SOLR is just a Lucene index with a service on top of it. Furthermore it provides meanwhile some new features (search facettes, joins, ...) If you install Alfresco Enterprise 4.x by using the installation package (bundled with PostgreSQL and Apache Tomcat), then it is already configured to use the bundled SOLR 1.4. The search service is then deployed as a web application to the Tomat servlet container. A better idea is to deploy SOLR to an own Tomcat server which then has its own Java environment and so on. The second Tomcat instance is running on the same server host, but now a little bit more isolated from the Alfresco instance. Here the steps:

  1. Make a new directory 'tomcat_solr' in the Alfresco installation directory $ALF_HOME
  2. Copy the contents of the folder 'tomcat' to the folder 'tomcat_solr'
  3. In 'tomcat_solr/webapps' undeploy the 'share' and 'alfresco' applications, by removing the folders. Also remove the files 'alfresco.war' and 'share.war' to avoid that Alfresco becomes redeployed.
  4.  In 'tomcat_solr/webapps/shared/classes' and 'tomcat_solr/logs' remove everything below it. Also remove 'tomcat_solr/conf/Catalina/localhost/alfresco.xml'. You now have a kind of clean Tomcat instance.
  5. Edit the server's configuration by changing the ports. The shutdown port should be '8095', the connector port should be '8090', the SSL port should be '8449', the AJP port should be 8099. You now have a Tomcat instance which does not conflict with the Alfresco one.
  6. Open the file 'tomcat_solr/conf/Catalina/localhost/solr.xml'. You can see that the home directory of SOLR is set to 'alf_data/solr'. You can change this if you want to store the index files at another location. Also the SOLR web app archive is stored there.
  7. SOLR is configured to use 2 cores. This means that you can find the 2 subfolders 'alf_data/solr/archive-SpacesStore' and 'workspace-SpacesStore'. You can see this maps to Alfresco's content stores. Each SOLR core has its own configuration. In the 'solcore.properties' file you can specify where the index files should be stored. The property 'data.dir.root' points to 'alf_data/solr' for both stores. The 'alfresco.*' settings are used to define which Alfresco instance (host, port, store, interval, ...) is used.
  8. More about the keystore is available here  http://docs.alfresco.com/4.1/topic/com.alfresco.enterprise.doc/tasks/generate-keys-solr.html, currently it's just important that you know that your new Tomcat instance is already configured to use the already existing one. It is located under 'alf_data/keystore'. Also the file 'tomcat_solr/conf/tomcat-users.xml' does already contain the required user definition.
  9. Finally you need to remove the Solr stuff from the old Tomcat installation, and to change the Alfresco configuration (tomcat/shared/classes/alfresco-global.properties' to use the SSL port which was specified for SOLR (8849). Therefore the property 'solr.port' should be changed. If you also moved the index keystore then you need to change the 'dir.keystore' property.
  10. Now start Alfresco!
  11. Now start the Tomcat which hosts the SOLR instance. There should be no error in the log file.
  12. Log-in to Share, create a new document by setting some attributes.
  13. Wait a few seconds (SOLR polls Alfresco!) and then check the log files of SOLR's Tomcat! Afterwards perform a search by using Alfresco Share!

Sunday, December 23, 2012

Mixing Bootstrap with JSP

A few days ago I wrote a blog post about my first contact with Twitter's Bootstrap UI framework. What I showed was how to create a simple static web site which uses java script in order to set a content area. The article can be found here: http://ecmgeek.blogspot.de/2012/12/first-contact-with-bootstrap.html

This article will show how to mix Bootstrap with JSP pages to bring a bit more dynamic into the page. Here some requirements:

  • A simple HTML template which uses Bootstrap should be used to show a web site.
  • A site should have multiple pages. The site navigation should allow to navigate to the pages.
  • It should be possible to navigate through a page by using a simple navigation menu.
  • A page should show some HTML content.
So we can derive the following Java classes :
  • Site: A site has a name and a description. One site is associated to multiple pages.
  • Page: A page has a name, an id and a target URL. It also has exactly one SubMenu and one HTMLContent item.
  • SubMenu: A sub menu has multiple menu items.
  • SubmenuItem: A sub menu item has a  name and a target URL.
  • HTMLContent: Has just a String property to store the HTML. May be used as Base class for other Content items.

 So what can now do is to create a Site instance (which is indeed kept on the server side - and so a servlet container is required to host the application) in order to provide our site template with the required content.

package de.ecmgeek.bootstrap;

public class Demo {

    private Site site;
    
    public Demo() {
       
     site = new Site("Demo", "This is a demo page");
    
     Page home = new Page("Home",new HTMLContent("<b> Home ... </b>"));
     Submenu homeSubMenu = new Submenu();
     SubmenuItem homeItem1 = new SubmenuItem("HomeSection1","#section1");
     SubmenuItem homeItem2 = new SubmenuItem("HomeSection2","#section2");
     SubmenuItem homeItem3 = new SubmenuItem("HomeSection3","#section3");
     homeSubMenu.addItem(homeItem1);
     homeSubMenu.addItem(homeItem2);
     homeSubMenu.addItem(homeItem3);
     home.setSubmenu(homeSubMenu);
    
     Page about = new Page("About",new HTMLContent("<b> About ... </b>"));
     Submenu aboutSubMenu = new Submenu();
     SubmenuItem aboutItem1 = new SubmenuItem("AboutSection1","#section1");
     SubmenuItem aboutItem2 = new SubmenuItem("AboutSection2","#section2");
     SubmenuItem aboutItem3 = new SubmenuItem("AboutSection3","#section3");
     aboutSubMenu.addItem(aboutItem1);
     aboutSubMenu.addItem(aboutItem2);
     aboutSubMenu.addItem(aboutItem3);
     about.setSubmenu(aboutSubMenu);
    
     Page contact = new Page("Contact",new HTMLContent("<b> Contact ... </b>"));
     Submenu contactSubMenu = new Submenu();
     SubmenuItem contactItem1 = new SubmenuItem("ContactSection1","#section1");
     SubmenuItem contactItem2 = new SubmenuItem("ContactSection2","#section2");
     SubmenuItem contactItem3 = new SubmenuItem("ContactSection3","#section3");
     contactSubMenu.addItem(contactItem1);
     contactSubMenu.addItem(contactItem2);
     contactSubMenu.addItem(contactItem3);
     contact.setSubmenu(contactSubMenu);
    
     site.add(home);
     site.add(about);
     site.add(contact);
    
    }
    
    public Site getSite() {
        return site;
    };
}

The class Demo is only used for demonstration purposes. Usually we would use a persistence layer like Hibernate or JPA to read the site data from a database.

The next step is to  change our more or less static web site to use a Site which is provided from the server. For this purposes we use J(ava)S(erver)P(ages). It's just easy to use and to learn and you can access your beans directly via Scriptlets and expressions. Another, the more new school way, would be to export the site data via a RESTFul Web Service which talks J(ava)S(ript)O(bject)N(otation). The advantage of the second way is that you can use the data out of the box after you got it from the server with Java Script without the need to use something like JSP scriptlets to "inject" the whole data into your HTML. However, let's go with JSP here.

So our previous HTML page becomes now a JSP page, which looks like the following one:

<!-- (0) Create an empty HTML page -->
<!DOCTYPE html>
<%@page import="de.ecmgeek.bootstrap.SubmenuItem"%>
<%@page import="de.ecmgeek.bootstrap.Page"%>
<%@page import="de.ecmgeek.bootstrap.Demo"%>
<%@page import="de.ecmgeek.bootstrap.Site"%>
<%@page import="de.ecmgeek.bootstrap.HTMLContent"%>
<html>
    <!-- (1) Some basic header info -->
    <head>
        <meta charset="utf-8">
            <title>BootstrapMeetsJSP</title>
            <meta name="viewport" content="width=device-width, initial-scale=1.0">
            <meta name="description" content="">
            <meta name="author" content="">

        <!-- (2) Import the provided CSS file -->
        <link href="css/bootstrap.min.css" rel="stylesheet" media="screen">    
    </head>
    
    <body>
        <!-- Do some JAVA initialization work -->
        <%
            //Build some demo data
            Site site = new Demo().getSite();
        %>
    
         <!-- (3) Import jQuery and Bootstrap -->
        <script src="js/jquery-latest.js"></script>
        <script src="js/bootstrap.min.js"></script>
        
        <!-- (5) At last add some JavaScript (jQuery) here to fill the page with life -->
        <script>
        
        $(document).ready(function(){
          
            
            //Inject some JAVA code into the JavaScript calls
            <%
              for (Page p : site.getPages())
              {
                      out.println("$('#"+ p.getId()  +"').click(function(){");    
                      out.println("$('div.my-content').empty();");
                      out.println("$('ul.nav-list').empty();");
                      out.println("$('div.my-content').html('"+p.getContent().getHtml()+"');");
                      
                    //Set the content and the submenu    
                    for (SubmenuItem sm : p.getSubmenu().getItems())
                    {
                        out.println("$('ul.nav-list').append('<li><a href=\"" + sm.getTarget() +"\"><i class=\"icon-chevron-right\"></i>"+ sm.getName() +"</a></li>');");
                    
                    }
                    
                    out.println("});");
              }
            %>            
               
         });      
        

        </script>

        
        <!-- (4) Bootstrap decorated HTML here -->
        <div id="container">

           <!-- A navigation header bar which is fixed to the top -->
           <div class="navbar navbar-fixed-top navbar-inverse">
                   <div class="navbar-inner">
                       <a class="brand" href="#"><%=site.getName()%></a>
                       
                       <ul id="header" class="nav">
                       
                           <%
                               for (Page p : site.getPages())
                               {
                                   out.print("<li><a href='"+p.getTarget()+"'id='"+p.getId()+"'>"+p.getName()+"</a></li>");                       
                               }
                           %>
                    
                    </ul>
                         </div>
               </div>
        
             <!-- (4.1) A simple web site header -->        
           <div class="hero-unit">
                <h1><%=site.getName()%></h1>
                <p><%=site.getDesc()%></p>
                <p>
                </p>
               </div>
          

           <!-- (4.2) A HTML grid with 12 columns, in this case we -->
             <div class="row">
            <!-- 4 columns are used for the left hand side navigation bar -->
                <div class="span4 bs-docs-sidebar">
                <ul class="nav nav-list bs-docs-sidenav">
                </ul>
            </div>
                
            <!-- (4.3) 8 columns are used for the right hand side content area -->
            <div class="span8">
                
                <!-- (4.4) The content area which can be decorated by own css -->
                <div class="my-content">
                </div>
            </div>
               </div>
            </div>    
    </body>
</html>
The result looks quite identical to the static page, but with the difference that the site data is now provided from the server to the client.



In summary the following happens:

  • Java code is used to generate the JavaScript code dependent on the site data which is provided by the server
  • The generated JavaScript code is used in order to manipulate the web site's HTML code dependent on the actions (click on the header menu item)
  • The HTML will be rendered on the client side (browser, ...)

It's easy to see that these are the basics to build a very simple W(eb)C(ontent)M(anagement) system which is based on Bootstrap. A next article will follow where I will describe how to add a database connection in order to retrieve the site data from a database. I can even imagine to create a simple Bootstrap based authoring web application which can be used to add data to this database.


Saturday, December 22, 2012

Site tracking with Piwik

I used Piwik in a previous Web Community project. So when I was asked how to add web statistics to Alfresco, my first idea was to integrate it with Piwik. So let's start to try it out:

At first a Piwik installation is required. My target test system is an OpenSuse 12.1 and so all the dependencies are available from the software repository. They are further described here: http://piwik.org/docs/requirements/ .

So after you installed an Apache, all required PHP modules and a MySQL database (BTW: This is something which I do not like regarding Piwik. The only supported database is MySQL. I would like to see at least Postgres support. ) you can begin to install your Piwik instance. Therefore you can follow the following instructions: http://piwik.org/docs/installation/ .

The most interesting part may be the database setup:

mysql> CREATE USER 'piwik'@'localhost' IDENTIFIED BY '${Your pwd here}';
mysql> CREATE DATABASE piwikdb;
mysql> GRANT ALL PRIVILEGES ON piwikdb.* TO 'piwik'@'localhost' WITH GRANT OPTION;


Then unzip the latest Piwik zip to your Apache2 web server and open the URL 'http://localhost/piwik'. For OpenSuse the htdocs folder is located at '/srv/www'.

If calling Piwik the first time it will prompt you to perform the following file permission changes:

chown -R www-data:www-data /srv/www/htdocs/piwik
chmod -R 0777 /srv/www/htdocs/piwik/tmp
chmod -R 0777 /srv/www/htdocs/piwik/tmp/templates_c/
chmod -R 0777 /srv/www/htdocs/piwik/tmp/cache/
chmod -R 0777 /srv/www/htdocs/piwik/tmp/assets/
chmod -R 0777 /srv/www/htdocs/piwik/tmp/tcpdf/

It's maybe required to create the user, group or directories above. You should also enable a temp. write access to '/srv/www/htdocs/piwik/config/'.

An error occurs that your php installation need zlib-suppot. You can find 'php5-zlib' in the OpenSuse software repository. Do not forget to restart Apache after installing this extension.

The next steps are quite easy. Just follow the Installation Wizard by entering your database connection details.

Also part of the installation is the generation of the tracking code. The installer says: "Here is the JavaScript Tracking code to include on all your pages, just before the </body> tag"

<!-- Piwik --> 

<script type="text/javascript">

var pkBaseURL = (("https:" == document.location.protocol) ? "https://localhost/piwik/" : "http://localhost/piwik/");

document.write(unescape("%3Cscript src='" + pkBaseURL + "piwik.js' type='text/javascript'%3E%3C/script%3E"));

</script><script type="text/javascript">

try {

var piwikTracker = Piwik.getTracker(pkBaseURL + "piwik.php", 1);

piwikTracker.trackPageView();

piwikTracker.enableLinkTracking();

} catch( err ) {}

</script><noscript><p><img 
src="http://localhost/piwik/piwik.php?idsite=1" style="border:0" alt="" 
/></p></noscript>

<!-- End Piwik Tracking Code -->

Important is the 'idsite' property. The value '1' is the id of the site which I configured as 'http://localhost:8080/share'. OK, Piwik is now up and running. Now let's investigate how to customize Alfresco in order to use it.

So to enable global tracking we can search a header or footer element which is used by every page of Alfresco. So let's check which site web scripts are available and let's see if we can put our snippet to one of the freemarker templates.

One good candidate seems to be '${WEBAPPS}/share/WEB-INF/classes/alfresco/site-webscripts/org/alfresco/components/header'.  So I just placed the script above after the first other '<script>' block.

A test showed the following result:


Piwik can do a lot more. But for now this shows exactly what we required. It answers the question which site was accessed how often.







Thursday, December 20, 2012

First contact with Bootstrap

Insprired by Thomas Glaser and Jan Pfitzner, I thought it could be a good idea to get in contact with Twitter's Bootstrap framework. So here a simple skeleton page which uses Bootstrap components to reflect a simple web site. jQuery is used to interact with menu and the content area.

Here the result:



And finally the code:

<!-- (0) Create an empty HTML page -->
<!DOCTYPE html>
<html>
    <!-- (1) Some basic header info -->
    <head>
        <meta charset="utf-8">
            <title>Basic web site</title>
            <meta name="viewport" content="width=device-width, initial-scale=1.0">
            <meta name="description" content="">
            <meta name="author" content="">

        <!-- (2) Import the provided CSS file -->
        <link href="css/bootstrap.min.css" rel="stylesheet" media="screen">   
    </head>
   
    <body>
         <!-- (3) Import jQuery and Bootstrap -->
        <script src="js/jquery-latest.js"></script>
        <script src="js/bootstrap.min.js"></script>
       
        <!-- (5) At last add some JavaScript (jQuery) here to fill the page with life -->
        <script>
        $(document).ready(function(){
         
           $("#header-home").click(function() {
            $('div.my-content').html('<p>Home ...</p>');
            });

          $("#header-contact").click(function() {
            $('div.my-content').html('<p>Contact ...</p>');
            });


          $("#header-about").click(function() {
            $('div.my-content').html('<p>About ...</p>');
            });

          $("#header-contact").click(function() {
            $('div.my-content').html('<p>Contact ...</p>');
            });

         });     
            </script>

       
        <!-- (4) Bootstrap decorated HTML here -->
        <div id="container">

           <!-- A navigation header bar which is fixed to the top -->
           <div class="navbar navbar-fixed-top navbar-inverse">
                   <div class="navbar-inner">
                       <a class="brand" href="#"> Basic web site</a>
                       <ul id="header" class="nav">
                           <li class="active"><a href="#" id="header-home">Home</a></li>
                        <li><a href="#about" id="header-about">About</a></li>
                        <li><a href="#contact" id="header-contact">Contact</a></li>
                    </ul>
                         </div>
               </div>
       
             <!-- (4.1) A simple web site header -->       
           <div class="hero-unit">
                <h1>Basic web site</h1>
                <p>This site explains the Twitter Bootstrap a little bit.</p>
                <p>
                </p>
               </div>
         

           <!-- (4.2) A HTML grid with 12 columns, in this case we -->
             <div class="row">
            <!-- 4 columns are used for the left hand side navigation bar -->
                <div class="span4 bs-docs-sidebar">
                <ul class="nav nav-list bs-docs-sidenav">
                     <li><a href="#Marker1"><i class="icon-chevron-right"></i> Marker 1</a></li>
                     <li><a href="#Marker2"><i class="icon-chevron-right"></i> Marker 2</a></li>
                     <li><a href="#Marker2"><i class="icon-chevron-right"></i> Marker 3</a></li>
                </ul>
            </div>
               
            <!-- (4.3) 8 columns are used for the right hand side content area -->
            <div class="span8">
               
                <!-- (4.4) The content area which can be decorated by own css -->
                <div class="my-content">
                      <p> Home ...</p>
                </div>
            </div>
               </div>
            </div>   
    </body>
</html>

Friday, December 14, 2012

About the anatomy of ArchiveLink

Preamble

I just played arround with ArchiveLink, and so I decided to read the specification to inform myself how it internally works. What you can use in order to archive your SAP documents (invoices, ...) is an ArchiveLink speaking HTTP Content Server. So here a short summary of what I understood from the ArchiveLink specification so far.

Terms

We want to store documents inside a content repository. I guess it is not required to explain this term further. ArchiveLink knows the term 'component', whereby a component represents a content unit on a administrative level. Several component types are used (for instance 'data'),  Components are summarized via a document header. So here a scenario:

  • One Content Repository contains multiple document headers
  • One document header references multiple components
  • One component contains one content unit
A document header (id, status, date, ...) and a component (content type, status, ...) has some adminstrative meta data attached.

So an archive needs to reflect that terms somehow. The most intuitive way seems to reflect it by using folders. So the content repository contains a folder of the type header which contains component folders those are containing documents to keep the content. Important is that ArchiveLink does by design not transfer any SAP business object related meta data. Only administrative meta data is transfered to the archive.

The protocol

HTTP is used to exchange date on a lower level. So we are speaking about a kind of RESTFul service access. The format is 'http://${server}:${port}/${service name}/${command}?${command parameters}. If we take security into account (more about it later) and take a spot on the get command by retrieving the data component then the URL has the following format:

http://${host}:${port}/${service name}?get&contRep=${repo id}&docId=${doc id}&compId=data&accessMode=r&authId=${user id}&expiration=${time}?secKey=${base64 encoded security key}.

The following commands are available:

  • get: get a content unit
  • info: get info about a document
  • docGet: get the whole content
  • create: Create a new document
  • update: Modify an existing document
  • append: Append data to a content unit
  • search: Search by using a pattern inside a content unit (full text search)
  • attrSearch: Search for a specific attribute value
  • mCreate: Create new documents
  • serverInfo: Retrieve information about the content server
  • putCert: Transfer the client certificate
The resonse is a little bit old scool (the specification document is from 2001) and so does not return JSON, but Multipart Form Data.

Here an example response from the publically available specification document:

HTTP/1.1 200 (OK)
Server: Microsoft-IIS/4.0
Date: Wed, 04 Nov 1998 07:41:03 GMT
Content-Type: multipart/form-data; boundary=A495ukjfasdfddrg4hztzu...
...some more header informations...
Content-Length: 32413
X-dateC: 1998-10-07
X-timeC: 07:55:57
X-dateM: 1998-10-07
X-timeM: 07:55:57
X-contRep: K1
X-numComps: 2
X-docId: ID
X-docStatus: online
X-pVersion: 0045
--A495ukjfasdfddrg4hztzu898aA0jklmAxcvla12319981147528895
Content-Type: application/x-alf; charset=
Content-Length: 2591
X-compId: descr
X-Content-Length: 2591
X-compDateC: 1998-10-07
X-compTimeC: 07:55:57
X-compDateM: 1998-10-07
SAP AG SAP ArchiveLink (BC-SRV-ARL)
docGet
April 2001 265
X-compTimeM: 07:55:57
X-compStatus: online
X-pVersion: 0045
...component data ...
--A495ukjfasdfddrg4hztzu898aA0jklmAxcvla12319981147528895
Content-Type: application/x-alf; charset=
Content-Length: 29313
X-compId: data
X-Content-Length: 29213
X-compDateC: 1998-10-07
X-compTimeC: 07:55:57
X-compDateM: 1998-10-07
X-compTimeM: 07:55:57
X-compStatus: online
X-compStatus: online
X-pVersion: 0045
...component data ...
--A495ukjfasdfddrg4hztzu898aA0jklmAxcvla12319981147528895--
Beim docGet-Kommando auf ein leeres Dokument steht im Response-Body beispielsweise:
--A495ukjfasdfddrg4hztzu898aA0jklmAxcvla1231999102562159269
--A495ukjfasdfddrg4hztzu898aA0jklmAxcvla1231999102562159269--
Summary

This is the furst article of several ones those are focusing on ArchiveLink. What we should have learned is the following: An ArchiveLink archive can be realized by using a HTTP Content Server. The Content Server then could speak with a simple File System or even better an DMS. The content server provides several commands and functions to store and access content items. There are several kinds of content items, wrapped by components. A specific URL pattern is used on side of the HTTP Content Server. The response of the HTTP Content Server has the Multipart Form Data format.


Monday, December 3, 2012

How to setup an Alfresco Maven project in a few steps

 Install the tools and libraries
  1.  Install Maven (E.G. use 'sudo apt-get install maven2')
  2. Install Subversion (E.G. use 'sudo apt-get install subversion')
  3. Install the Subversion Java bindinds (E.G. use 'sudo apt-get install  libsvn-java)
 Install Eclipse and the required plug-ins (optional)
  1. Install Eclipse (you will need it as the I(ntegrated) D(evelopment) E(nvironment)
  2. Install the Eclipse Maven plug-in (The download site is 'http://download.eclipse.org/technology/m2e/releases'
  3. Install the Subversion plug-in (The easisest is to enter subversion in the Eclipse Market Place)
  4. In Eclipse create a new workspace
Create the project for the repository extensions
  1.  Change the directory to the Eclipse workspace
  2. Then run the following command
mvn archetype:generate -DarchetypeGroupId=org.alfresco -DarchetypeArtifactId=maven-alfresco-amp-archetype \
-DarchetypeVersion=3.9.1 -DgroupId=${Your domain here, E.G. de.ecg} -DartifactId=${Your project name -repo here, E.G. my-repo} -Dversion=1.0-SNAPSHOT \
-DarchetypeRepository=https://artifacts.alfresco.com/nexus/content/repositories/releases -DinteractiveMode=false
 
 The above command contains 2 place holders. One specifies your domain the other one should name the project. For example the project 'my-repo' will be created.

Create the project for the Share extensions
  1.  Change the directory to the Eclipse workspace
  2. Then run the following command

mvn archetype:generate -DarchetypeGroupId=org.alfresco.maven -DarchetypeArtifactId=maven-alfresco-share-archetype \
-DarchetypeVersion=3.9.1 -DgroupId=${Your domain here} -DartifactId=${Your project name -share here} -Dversion=1.0-SNAPSHOT \
-DarchetypeRepository=https://artifacts.alfresco.com/nexus/content/repositories/releases -DinteractiveMode=false
 
Create the Eclipse projects
  1. Open Eclipse
  2. Click on 'Import -> Maven -> Existing Maven Project into Workspace'
  3. Navigate into the folder of the repo project and confirm
  4. The download of the several dependent artifacts / libraries to your local Maven cache may take a while
  5. Do the same for the Share project
A really cool and easy way to get an Alfresco project set up quite simpler than with ANT script. In the pom.xml you can see that the referenced Alfresco version is 4.0.2b which seems to be an older Community Edition release. An open question is how to setup a similar project for the Alfresco Enterprise Edition.