New job, new life

Saturday, August 29th, 2009

A couple of weeks ago, I started working at a new company (sorry, I will no more work on Alfresco for those that comes here for that information) and I’m settling in nicely. My colleagues are very easy to talk with, the chatting just flows effortlessly and I love it. It’s so important to work with people where the communication works, especially now when I’m working in a small IT department where we will work closely together all the time.

I got a new laptop (Thinkpad W500), and I could choose my own operating system on it (or as my department manager said, quite accurately: I would probably have done whatever I wanted anyway). That resulted in putting ubuntu on it, and I have enjoyed getting ubuntu to talk to Windows Active directory, setting up the mail towards exchange, getting access to the shared folders, set up citrix client. It has been surprisingly easy. The only downside have been that editing documents in sharepoint using firefox doesn’t work (even though MS claim cross-browser support).

So far I really like the new workplace. I even got my own office, which I haven’t had in a long time. I can look outside, see the weather and the trees. Some of the fun part is watching all the trailers that come here to load and unload goods. Sometimes (everyday) there are so many trailers at the same time, that there is space issues. One bad part though – my butt hurt! I have to take a 10-minute bicycle ride to get to the office, and I have to dress for the weather. It’s going to be interesting to see how I’m going to like it when the winter sets in and the snow piles up.

I had an extended vacation (3 months) before I started at the new job. The time seemed to just flow for the most part, but in the end I was ready to start working again. I used to go to the city, find a cafè and enjoy a mocha everyday. I used to sit there alone, looking at people and reading self-development books. I really loved those moments, and I received so much inspiration (also called juice) making the days fly by. I always had things to do.

Now, when I get back from work I can’t seem to get back to that inspiration. Setting up Linux, learning a new job have given me inspiration on work, but I don’t extend it to my spare time (I don’t want to be too much on the computer during my spare time). Enjoying a mocha and reading self-development books at home doesn’t work since I started working. I have to figure out a new way to get my “juice” after work. I still haven’t been able to figure out what it takes, but I have some suspicion I have to use more time on my spiritual activities. That have worked before. May be that means that the inspiration I get is different from when I work opposed to when I have a vacation.

Alfresco and CIFS troubleshooting on Ubuntu

Wednesday, April 15th, 2009

When installing Alfresco on an Ubuntu machine, CIFS doesn’t work out of the box.
First question: is Samba installed?
sudo apt-get install samba smbfs

The configuration files for file-server setups:
$ALFRESCO_HOME/tomcat/webapps/alfresco/WEB-INF/classes/alfresco/file-servers.xml
$ALFRESCO_HOME/tomcat/webapps/alfresco/WEB-INF/classes/alfresco/file-servers.properties

Uncomment these lines in file-servers.xml (though to make sure this is permanent – create file-servers-custom.xml):
<tcpipSMB port="1445" ipv6="${cifs.ipv6}" platforms="linux,solaris,macosx"/>
<netBIOSSMB sessionPort="1139" namePort="1137" datagramPort="1138" platforms="linux,solaris,macosx"/>

Set iptable rules:
sudo su
echo 1 > /proc/sys/net/ipv4/ip_forward
modprobe iptable_nat
iptables -F
iptables -t nat -F
iptables -P INPUT ACCEPT
iptables -P FORWARD ACCEPT
iptables -P OUTPUT ACCEPT
iptables -t nat -A PREROUTING -p tcp --dport 445 -j REDIRECT --to-ports 1445
iptables -t nat -A PREROUTING -p tcp --dport 139 -j REDIRECT --to-ports 1139
iptables -t nat -A PREROUTING -p udp --dport 137 -j REDIRECT --to-ports 1137
iptables -t nat -A PREROUTING -p udp --dport 138 -j REDIRECT --to-ports 1138

Check iptable rules:
sudo iptables -t nat -L

Troubleshooting options:
To check what ports are listened to:
netstat -a
Look for:
tcp6 0 0 [::]:1445 [::]:* LISTEN
tcp6 0 0 [::]:1139 [::]:* LISTEN

To see who listens at what port:
$ sudo lsof -i :1139 -n
COMMAND PID USER FD TYPE DEVICE SIZE NODE NAME
java 11881 alfresco 296u IPv6 60400 TCP *:1139 (LISTEN)

Another way to check if the port is listened to:
$ telnet localhost 1139
Trying 127.0.0.1...
Connected to localhost.
Escape character is '^]'.

Resources:
http://wiki.alfresco.com/wiki/File_Server_Configuration
CIFS Linux
http://wiki.alfresco.com/wiki/Troubleshooting
CIFS Troubleshooting

How to create an Alfresco Module Package (AMP)

Tuesday, April 14th, 2009

In this post I will set up the basic settings to create an Alfresco Module Package (AMP). Ant needs to be installed to make this work. This creates a skeleton AMP module that does nothing except being a module. So the first step is to create a new project in your favorite IDE.

In the Alfresco SDK there are some great examples, and one of them is named SDK Basic AMP. AMP’s have a specific directory structure that it’s wise to use. When deploying AMP’s the Module Management Tool (mmt) maps the files to specific locations in the alfresco tree. This can be a bit confusing when dealing with configuration files and if the SDK samples have solved a problem in a specific way, it’s wise to just follow that road.

1. Create a module.properties file containing these lines:
# Skeleton AMP Module
module.id=skeleton
module.title=Skeleton
module.description=Add a skeleton amp to Alfresco
module.version=1.0

This file contain module information and is to be located in the root of the amp. Usually the file is located in the IDE at config/alfresco/module/modulename/module.properties. (IDE) config/alfresco maps to alfresco_dir/tomcat/webapps/alfresco/WEB-INF/classes/alfresco/.

2. Create a config/alfresco/module/skeleton/module.context file:
<?xml version='1.0' encoding='UTF-8'?>
<!DOCTYPE beans PUBLIC '-//SPRING//DTD BEAN//EN' 'http://www.springframework.org/dtd/spring-beans.dtd'>

<beans>
</beans>

This is where one puts bean initializations, bootstrap resource bundles, adds webclient configuration files etc. when needed.

3. Place class files (if you have any) in source/java/my/namespace/*.java

4. Sample build.xml for ant:
<?xml version="1.0"?>

<project name="Skeleton" default="deploy-war" basedir=".">
<!-- Project directories, REPLACE WITH YOUR SETTINGS -->
<property name="project.dir" value="."/>
<property name="build.dir" value="${project.dir}/build"/>
<property name="jar.file" value="${build.dir}/lib/skeleton.jar" />
<property name="amp.file" value="${build.dir}/dist/skeleton.amp"/>
<property name="tomcat.dir" value="/opt/Alfresco/tomcat" />
<property name="war.file" value="${tomcat.dir}/webapps/alfresco.war"/>
<property name="lib.dir" value="/opt/alfresco-sdk2.9/lib/server" />

<!-- Path to essential libraries -->
<path id="class.path">
<dirset dir="${build.dir}" />
<fileset dir="${lib.dir}" includes="**/*.jar"/>
</path>

<!-- Creates a build directory where the amp and jar files will be located -->
<target name="mkdirs">
<mkdir dir="${build.dir}/dist" />
<mkdir dir="${build.dir}/lib" />
</target>

<target name="package-jar" depends="compile">
<delete file="${jar.file}" />

<jar destfile="${jar.file}">
<fileset dir="${build.dir}" includes="**/faces-config.xml, **/*.class" />
</jar>
</target>

<target name="package-amp" depends="mkdirs, package-jar" description="Packages the amp">
<zip destfile="${amp.file}">
<fileset dir="${project.dir}/build" includes="lib/*.jar" />
<fileset dir="${project.dir}" includes="module.properties" />
<fileset dir="${project.dir}" includes="config/**/*.*" />
</zip>
</target>

<!-- Use when checking what deployment of an AMP will do without actually committing the deployment -->
<target name="preview-install">
<echo>Preview installation of AMP</echo>
<java dir="." fork="true" classname="org.alfresco.repo.module.tool.ModuleManagementTool">
<classpath refid="class.path" />
<arg line="install ${amp.file} ${war.file} -preview -force -verbose"/>
</java>
</target>

<!-- Deploys the war to Alfresco -->
<target name="deploy-war" depends="package-amp">
<java dir="." fork="true" classname="org.alfresco.repo.module.tool.ModuleManagementTool">
<classpath refid="class.path" />
<arg line="install ${amp.file} ${war.file} -force -verbose"/>
</java>
</target>

</project>

An AMP file is a zipped archive, so if you would like to know the content of the amp then:
unzip skeleton.amp

To view the content of a jar file:
jar -tvf skeleton.jar

SDK Basic AMP example – This is the basic AMP taken from the SDK.

Resources:
Alfresco Module Packages
Alfresco SDK
http://wiki.alfresco.com/wiki/Module_Management_Tool

Alfresco: The first lessons learned

Wednesday, April 8th, 2009

The last couple of weeks I have learned some lessons the hard way.

1. When doing changes to faces-config(-custom).xml, put it in a jar-file.
This is stated in Developing an Alfresco Module, but it’s very easy to forget because so many places one can read about extending Alfresco using faces-config-custom.xml.

There are two options for making changes to faces-config:
- Add a faces-config-custom.xml in the AMP.
In an IDE it would typically ble places in web/WEB-INF/faces-config-custom.xml. When deploying the amp to Alfresco, it doesn’t overwrite the WEB-INF/faces-config-custom.xml on the server as one would expect, it’s as if the changes were never made. In reality Alfresco does some magic, and the changes are available in alfresco, but not in any extensions you have made. So if you try to create a managed bean and access it from within alfresco jsp-files, life is good. But in most cases, extending Alfresco is the best way to go and then the managed bean is suddenly not available. Therefore the next choice is the best way.

- Add faces-config.xml to the jar-file.
Yes, no need for a faces-config-custom.xml here, and the declarations are available all over alfresco, including any third-party extensions. Inside the jar the file is located at META-INF/faces-config.xml.

Alfresco is simply a bit touchy when dealing with faces-config files.

2. Use (unique) IDs on faces components no matter what
I came up in the situation that I had one jsp that only contained two lines:
<%@ taglib uri="/WEB-INF/repo.tld" prefix="r" %>
<r:webScript scriptUrl="/service/mwsearch" />

With just two lines to maintain, one would think it would be difficult to make mistakes… Wrong! It doesn’t matter that even the taglib documentation state that id isn’t required, because it’s simply not true. ID’s are required unless you want erratic behaviour – IllegalStateExceptions (like seen below) that occurs at random, but will definitly stop the show:

javax.faces.FacesException: java.lang.IllegalStateException: Client-id : _idJsp13 is duplicated in the faces tree. Component : browse:_idJsp13, path: {Component-Path : [Class: javax.faces.component.UIViewRoot,ViewId: /jsp/browse/browse.jsp][Class: javax.faces.component.html.HtmlForm,Id: browse][Class: org.alfresco.web.ui.common.component.UIPanel,Id: spaces-panel][Class: org.alfresco.web.ui.common.component.data.UIRichList,Id: spacesList][Class: org.alfresco.web.ui.common.component.data.UIColumn,Id: col1][Class: org.alfresco.web.ui.common.component.UIActionLink,Id: col1-act1][Class: javax.faces.component.UIParameter,Id: _idJsp13]}

3. Any files in the AMP will override files in the Data Dictionary
I had a webscript where I needed to make an url configurable. Now, configurations can be added in a modulename.get.config.xml as stated in the documentation. I removed the file from my AMP, and added the file in Alfresco DM –> Company Home –> Data Dictionary –> Web Scripts Extentions –> Modulefolder –> modulename.get.config.xml. And voila, my Freemarker templates caught on the config changes after a restart of Alfresco.

Hopefully this will have saved at least one person from hours of frustration.

Developer options for extending Alfresco

Thursday, March 19th, 2009

There are three ways of extending Alfresco:

  1. Put the code in the webapp folder (alfresco/tomcat/webapps/alfresco)
  2. Put the code in the alfresco repository
  3. Create an AMP file and add it to alfresco.war

There are different benefits and drawbacks to each method:

Put the code in the webapp folder
It’s an easy way to quickly test the changes one have made, but the moment the war-file is reloaded by tomcat, the added files and changes are lost.

Put the code in the alfresco repository
When logging into Alfresco Explorer as Admin, one get access to the Data Dictionary space located within Company Home. The data dictionary contains code used by Alfresco users like email and Freemarker templates which notifies users of an invitation to a space, RSS feeds, searches, scripts, web scripts and space templates. The data dictionary space can be used to create our own custom actions on documents, spaces etc.

This option is an easy way for most users to create their own actions and test them out without restarting Alfresco, but can be a bit of a hassle when one need to change the script, upload it and test it out.

Create an AMP (Alfresco Module Package) file and add it to alfresco.war
This is the recommended way for creating modules in Alfresco. Creating a package makes the deployment of modules easy, but when tomcat notices the alfresco war-file has changed then Alfresco is reloaded and all users are kicked out of their session. The bad part is that it usually takes about a minute to reload alfresco on a development machine. One minute for every change… well, it does hurt sometimes.

Another thing that hurts.. when writing this there are no way of uninstalling an amp. The way of uninstalling a module is to revert to the alfresco.war file that was saved as backup before installing the amp. So, if one installs other modules afterwards, then one have to revert to the backup war-file, then install all the other modules again…. Ridiculous! AND – after removing a module from alfresco, one get a nice warning text in the log about Alfresco not being able to find the module. I really hope Alfresco will add uninstall functionality in the near future to its Module Management Tool that installs the amps.

The good/bad part (you decide) is that once the amp is deployed, alfresco has reloaded and installed the module, one can edit the deployed files and alfresco *should* (add some grain of salt here) recognize changes made without any restart/reload. But then suddenly we are back into option number one.

Create new document type in Alfresco

Wednesday, March 18th, 2009

Alfresco have many options to extend their document management system and one of them is to create a new document type as seen in the picture below. The new document is a Whitepaper, but we could have added other document types like a functional specification, meeting minutes, risk matrix and whatever that tingles our needs.

All documents that are uploaded or created in alfresco is by default marked as “content”, a generic term that can encompass everything. To create a document type is an easy way of setting documents apart/a way of categorizing and structuring the content itself. A developer can add certain functionality/behavior to a document type like a doc type having certain metadata connected to it, workflow (review, acceptance, publish), add versioning, that certain people shall be notified of changes or add permission so that only specific people can create and edit the document. One can add advanced search capabilities like searching for a specific document type.

screenshot_003

So, down to the gritty details. First one have to define the document type (custom content model) (config/extension/model/whitepaper.xml):


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

<!-- Definition of new Model -->
<model name="mb:mybusiness.whitepaper.model" xmlns="http://www.alfresco.org/model/dictionary/1.0">
    <description>My business Whitepaper</description>
    <author>Helene Klungvik</author>
    <version>1.0</version>

    <!--
		Imports are required to allow references to definitions in other
		models
	-->
	<imports>
		<!-- Import Alfresco System Definitions -->
		<import uri="http://www.alfresco.org/model/system/1.0" prefix="sys"/>
		<!-- Import Alfresco Dictionary Definitions -->
		<import uri="http://www.alfresco.org/model/dictionary/1.0" prefix="d" />
		<!-- Import Alfresco Content Domain Model Definitions -->
		<import uri="http://www.alfresco.org/model/content/1.0" prefix="cm" />
	</imports>

	<namespaces>
		<namespace uri="mybusiness.whitepaper.model" prefix="mb" />
	</namespaces>

    <types>
		<type name="mb:doc">
			<title>Whitepaper</title>
			<parent>cm:content</parent>
		</type>
   </types>

</model>

Then create a spring bean that imports the whitepaper model (config/alfresco/extension/module-context.xml):

<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE beans PUBLIC '-//SPRING//DTD BEAN//EN' 'http://www.springframework.org/dtd/spring-beans.dtd'>
<!--
    Document   : module-context.xml
    Created on : March 11, 2009, 10:00 AM
    Author     : Helene Klungvik
    Description:
        Define a new document type for whitepapers
-->

<beans>
    <bean id="mybusiness.dictionaryBootstrap"
        parent="dictionaryModelBootstrap" depends-on="dictionaryBootstrap">
        <property name="models">
            <list>
                <value>alfresco/extension/model/rwhitepaper.xml</value>
            </list>
        </property>
    </bean>
</beans>

And that’s it.