Alfresco 5.0, SDK 2.1 and Field Photos

Introduction

This article might be of interest to you if you about to embark on creating a new content model for photos (or any other type of file) in Alfresco, and you want to get started quickly. If you have not already done so, though, you may wish to install Alfresco using a setup wizard first, to see how a fresh install of Alfresco handles photos. By default, when you upload photos, Alfresco will read EXIF data including latitudes and longitudes, and description, author, and a number of other fields. See http://docs.alfresco.com/community/concepts/download-community.html to download and install Alfresco using a set up wizard, and then experiment by uploading photos into the ‘My Files’ area.

If you need to add extra information fields to your photos (or any other file type), the SDK is the recommended way to customise Alfresco, and the RAD (rapid application development) feature of the Alfresco SDK 2.1 is very nice. Rather than going through a cycle where you make a few changes to configuration files, then compile, create .war’s/.amp’s, apply them, and restart your system – which can takes minutes each time – the RAD system detects when you save a config file, and then reloads components of the system relevant to that file – in seconds – allowing you to check the result of your change in the ‘Alfresco Share’ interface almost immediately.

This tutorial is for Mac OSX – it is an accurate record of setting up a MacBook Air with 4 GB of memory. You might be able to use the instructions for linux (eg. Ubuntu), also, with small modifications.

References

Preparation

It is important to have a nice clean install of the latest Java Development Kit (JDK) – not just a JRE – from Oracle. Preferably delete any old installations of java. At the time of writing the package was jdk-8u45-macosx-x64.dmg. Install this and test like so …

java -version
java version "1.8.0_45"
Java(TM) SE Runtime Environment (build 1.8.0_45-b14)
Java HotSpot(TM) 64-Bit Server VM (build 25.45-b02, mixed mode)

Add the JAVA_HOME to ~/.bash_profile – for example ..

#!/bin/bash
export JAVA_HOME="/Library/Java/JavaVirtualMachines/jdk1.8.0_45.jdk/Contents/Home/jre"

Don’t proceed until this is correctly installed.

Optional extras

You do not necessarily need to install LibreOffice and ImageMagick, but you will have more functionality in your Alfresco development environment if you do.

Download and install ImageMagick using a package from http://cactuslab.com/imagemagick/
Download and install LibreOffice using a package from https://www.libreoffice.org/

Put the soffice executable onto the search path

cd /usr/local/bin/
ln -s /Applications/LibreOffice.app/Contents/MacOS/soffice soffice

Correction kindly supplied by Douglas Paes ..
Instead of that, I had to include the property below into the alfresco-global.properties file:
ooo.exe=/Applications/LibreOffice.app/Contents/MacOS/soffice

Also, to enable thumbnails and previewing of photos, add the path to ImageMagick in /runner/target/tomcat/webapps/repo/WEB-INF/classes/alfresco-global.properties like so ..

# Converters
img.root=/opt/ImageMagick
img.exe=/opt/ImageMagick/bin/convert

Maven

Download archive (eg. apache-maven-3.3.3-bin.tar.gz) from http://maven.apache.org/download.cgi and extract files ..

cd /usr/local
curl -O http://mirror.rackcentral.com.au/apache/maven/maven-3/3.3.3/binaries/apache-maven-3.3.3-bin.tar.gz
tar -xvf apache-maven-3.3.3-bin.tar.gz
rm apache-maven-3.3.3-bin.tar.gz

Create link to mvn from a folder in the search path

cd /usr/local/bin
sudo ln -s /usr/local/apache-maven-3.3.3/bin/mvn mvn

Verify that it is correctly installed.

mvn --version
Apache Maven 3.3.3 (7994120775791599e205a5524ec3e0dfe41d4a06; 2015-04-22T21:57:37+10:00)
Maven home: /usr/local/apache-maven-3.3.3
Java version: 1.8.0_45, vendor: Oracle Corporation
Java home: /Library/Java/JavaVirtualMachines/jdk1.8.0_45.jdk/Contents/Home/jre
Default locale: en_US, platform encoding: UTF-8
OS name: "mac os x", version: "10.10.3", arch: "x86_64", family: "mac"

If you get an error like so ..

objc[1420]: Class JavaLaunchHelper is implemented in both
/Library/Java/JavaVirtualMachines/jdk1.8.0_45.jdk/Contents/Home/jre/bin/java and /Library/Java/JavaVirtualMachines/jdk1.8.0_45.jdk/Contents/Home/jre/lib/libinstrument.dylib.
One of the two will be used. Which one is undefined.

.. it seems that this has no affect, so ignore it.

Set up MAVEN_OPTS environment string – add the following to ~/.bash_profile

#!/bin/bash
export MAVEN_OPTS="-Xms1024m -Xmx2048m -javaagent:/Users/david/lib/springloaded123.jar -noverify"

Run this script now and check again that maven is working fine ..

source ~/.bash_profile
mvn --version
Apache Maven 3.3.3 (7994120775791599e205a5524ec3e0dfe41d4a06; 2015-04-22T21:57:37+10:00)
Maven home: /usr/local/apache-maven-3.3.3
Java version: 1.8.0_45, vendor: Oracle Corporation
Java home: /Library/Java/JavaVirtualMachines/jdk1.8.0_45.jdk/Contents/Home/jre
Default locale: en_US, platform encoding: UTF-8
OS name: "mac os x", version: "10.10.3", arch: "x86_64", family: "mac"

Generate all-in-one SDK 2.1 project

mkdir ~/alfresco-dev
cd ~/alfresco-dev
mvn archetype:generate -Dfilter=org.alfresco:

1: remote -> org.alfresco.maven.archetype:alfresco-allinone-archetype
6: 2.1.0
au.gov.wta.geoscience             # change this to your organisation identifier
field-photos
au.gov.wta.geoscience.fieldphotos # change this accordingly
cd field-photos/
mvn install

An Aside: Proxy servers make life more difficult. If you are in an office, there is probably a proxy server between you and the internet. If you can avoid working behind a proxy server, then I suggest you do so. An example problem I have experienced is .. when opening http://localhost:8080/share, an error ‘INFO: Unable to retrieve License information from Alfresco: 400‘ appears in the log. When this happens, a login using the default credentials admin/admin fails. If you can’t avoid working behind a proxy server, ensure that your ‘Bypass Proxy’ list includes ‘localhost’ and ‘localhost:8080’.

Create and start up the SDK alfresco instance

chmod +x run.sh
./run.sh

Note that the first time you run this, about 1 GB of files (mainly JARs) will be downloaded, so this might take a long time. Subsequent times that you run this, it will take a few minutes. When run.sh displays the following line, the system is almost ready to use.

INFO: Starting ProtocolHandler ["http-bio-8080"]

After the above line appears, test the SDK Alfresco instance by browsing to http://localhost:8080/share and check that you can log in as admin/admin.

Rapid testing of changes within eclipse

  • Download and install Eclipse IDE for Java Developers from https://www.eclipse.org/downloads/?osType=macosx.
  • Run Eclipse, and choose File > Import > Maven > Existing Maven Projects > Next > Browse
  • Choose ~/alfresco-dev/field-photos
  • Click Finish

Start up the SDK Alfresco instance – if it is not already running ..

cd ~/alfresco-dev/field-photos
./run.sh

Now when you modify and save a config files within Eclipse, the run.sh script will output lines something like ..

Jun 23, 2015 12:51:42 PM org.springframework.extensions.webscripts.DeclarativeRegistry reset
INFO: Registered 369 Web Scripts (+0 failed), 383 URLs
Jun 23, 2015 12:51:42 PM org.springframework.extensions.webscripts.DeclarativeRegistry reset
INFO: Registered 8 Package Description Documents (+0 failed)
Jun 23, 2015 12:51:42 PM org.springframework.extensions.webscripts.DeclarativeRegistry reset
INFO: Registered 0 Schema Description Documents (+0 failed)
Jun 23, 2015 12:51:42 PM org.springframework.extensions.webscripts.AbstractRuntimeContainer reset
INFO: Initialised Spring Surf Container Web Script Container (in 4016.2793ms)

.. and then you can switch back to your browser at http://localhost:8080/share and test the change you have made. (We will do this in a following section.)

Time-saver – In Eclipse, hold down the Option(Alt) key while expanding a folder, and all sub-folders will be expanded – so that you can see ALL files in the sub-folders under that folder – don’t use this for a top-level folder, though – you can hang the system.

Important note about share-config-custom.xml

If share-config-custom.xml is located in its standard location .. /share-amp/src/main/resources/META-INF/
.. then changes made to it in Eclipse will not flow through the the SDK Alfresco instance on the fly.
If you move it in the following folder .. /share-amp/src/main/amp/config/alfresco/web-extension
.. then the rapid testing will work fine.
https://github.com/Alfresco/alfresco-sdk/issues/299
(Later, when your development is finished, and you are creating a production AMP, you should move this file back to the META-INF folder.)

Create a field photo content model

Add the content below to /share-amp/src/main/amp/config/alfresco/web-extension/messages/custom.properties

type.gs_fieldphoto=Field Photo

This will allow you to change the type of an uploaded photo to ‘Field Photo’.

Add the content below to /repo-amp/src/main/amp/config/alfresco/module/repo-amp/model/content-model.xml
This defines the metadata fields for photos – this includes exif information.

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

<!-- Definition of new Model -->

<!-- The important part here is the name - Note: the use of the my: namespace
	which is defined further on in the document -->
<model name="gs:fieldphoto" xmlns="http://www.alfresco.org/model/dictionary/1.0">

	<!-- Optional meta-data about the model -->
	<description>Field Photo Custom Model</description>
	<author>Riley</author>
	<version>1.0</version>

	<imports>
		<!-- 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" />
		<!-- Import Alfresco EXIF Definitions -->
        <import uri="http://www.alfresco.org/model/exif/1.0" prefix="exif"/>
	</imports>

	<!-- Introduction of new namespaces defined by this model -->
	<namespaces>
		<namespace uri="http://www.geoscience.nsw.gov.au/model/gs/1.0" prefix="gs" />
	</namespaces>

	<constraints>
		<constraint name="gs:photoCategoryConstraint" type="LIST">
			<parameter name="allowedValues">
				<list>
					<value>outcrop</value>
					<value>drillcore</value>
					<value>social</value>
				</list>
			</parameter>
		</constraint>
		<constraint name="gs:photoSystemConstraint" type="LIST">
			<parameter name="allowedValues">
				<list>
					<value>fieldobs</value>
					<value>petrology</value>
					<value>drillcore</value>
				</list>
			</parameter>
		</constraint>
	</constraints>

	<types>
		<!-- Enterprise-wide generic document type -->
		<type name="gs:fieldphoto">
			<title>Field Photo</title>
			<parent>cm:content</parent>
			<properties>
                <property name="gs:photoCategory">
                    <title>Category</title>
                    <type>d:text</type>
                    <mandatory>true</mandatory>
                    <constraints>
                        <constraint ref="gs:photoCategoryConstraint" />
                    </constraints>
                </property>
                <property name="gs:photoSystem">
                    <title>System</title>
                    <type>d:text</type>
                    <mandatory>true</mandatory>
                    <constraints>
                        <constraint ref="gs:photoSystemConstraint" />
                    </constraints>
                </property>
                <property name="gs:dbLink">
                    <title>Link</title>
                    <type>d:text</type>
                </property>
                <property name="gs:extraData">
                    <title>Extra Data</title>
                    <type>d:text</type>
                </property>
                <property name="gs:confidential">
                    <title>Confidential</title>
                    <type>d:boolean</type>
                </property>
			</properties>

			<mandatory-aspects>
				<aspect>cm:titled</aspect>
				<aspect>cm:author</aspect>
				<aspect>cm:geographic</aspect>
				<aspect>exif:exif</aspect>
			</mandatory-aspects>
		</type>

	</types>

</model>

Customize the ‘Edit Properties’ form

As mentioned above, move share-config-custom.xml from /share-amp/src/main/resources/META-INF/ to /share-amp/src/main/amp/config/alfresco/web-extension
Add the content below. This will order the fields on the Edit Properties form, puts the fields into 4 groups, and defines drop-down list values for 2 of the fields.

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

<!-- Share configuration related to this particular Share module extension,
	such as: - Doclib action config - Form config - Aspect and Type config Note.
	Any configuration related to the whole Share.war webapp (i.e. not specific
	to this share extension) should be placed in the environment specific config:
	alfresco-allinone/share/src/main/resources/alfresco/web-extension/share-config-custom.xml
	file -->
<alfresco-config>

	<!-- Form customization for fieldphoto - removed all 'force="true"'s The
		force attribute forces the NodeFormProcessor to search the entire Alfresco
		content model for the property or association definition before returning
		anything. -->
	<config replace="true" evaluator="node-type" condition="gs:fieldphoto">
		<forms>
			<!-- <default-controls> <type name="association:cm:description" template="/org/alfresco/components/form/controls/textarea.ftl">
				<control-param name="rows">10</control-param> </type> </default-controls> -->

			<form>
				<field-visibility>
					<show id="cm:name" />
					<show id="cm:title" />
					<show id="cm:description" force="true" />

					<!-- 'transient' properties - not in the model -->
					<show id="mimetype" />
					<show id="size" />

					<show id="cm:author" />
					<show id="gs:photoCategory" />
					<show id="gs:photoSystem" />
					<show id="gs:dbLink" />
					<show id="gs:extraData" />
					<show id="gs:confidential" />

					<show id="cm:latitude" />
					<show id="cm:longitude" />

					<show id="exif:dateTimeOriginal" />
					<show id="exif:pixelXDimension" />
					<show id="exif:pixelYDimension" />
					<show id="exif:exposureTime" />
					<show id="exif:fNumber" />
					<show id="exif:flash" />
					<show id="exif:focalLength" />
					<show id="exif:isoSpeedRatings" />
					<show id="exif:manufacturer" />
					<show id="exif:model" />
					<show id="exif:software" />
					<show id="exif:orientation" />
					<show id="exif:xResolution" />
					<show id="exif:yResolution" />
					<show id="exif:resolutionUnit" />
				</field-visibility>

				<appearance>
					<!-- Group controls together -->
					<set id="text" appearance="fieldset" label="Data Entry" />
					<set id="number" appearance="panel" label="Location" />
					<set id="exif" appearance="panel" label="Camera" />
					<set id="others" appearance="fieldset" label="Others" />

					<field id="cm:name" set="text" />
					<field id="cm:title" set="text" />
					<!-- give the description field more rows -->
					<field id="cm:description" set="text">
						<control template="/org/alfresco/components/form/controls/textarea.ftl">
							<control-param name="rows">10</control-param>
						</control>
					</field>
					<field id="gs:photoCategory" set="text" />
					<field id="gs:extraData" set="text" />
					<field id="gs:confidential" set="text" />

					<field id="cm:latitude" set="number" />
					<field id="cm:longitude" set="number" />

					<field id="cm:author" set="others" />
					<field id="gs:photoSystem" set="others" />
					<field id="gs:dbLink" set="others" />
					<field id="mimetype" set="others" />
					<field id="size" set="others" />

					<field id="exif:dateTimeOriginal" set="exif" />
					<field id="exif:pixelXDimension" set="exif" />
					<field id="exif:pixelYDimension" set="exif" />
					<field id="exif:exposureTime" set="exif" />
					<field id="exif:fNumber" set="exif" />
					<field id="exif:flash" set="exif" />
					<field id="exif:focalLength" set="exif" />
					<field id="exif:isoSpeedRatings" set="exif" />
					<field id="exif:manufacturer" set="exif" /> <!-- for‐mode="view" -->
					<field id="exif:model" set="exif" />
					<field id="exif:software" set="exif" />
					<field id="exif:orientation" set="exif" />
					<field id="exif:xResolution" set="exif" />
					<field id="exif:yResolution" set="exif" />
					<field id="exif:resolutionUnit" set="exif" />

				</appearance>

			</form>
		</forms>
	</config>

	<!-- Document Library config section -->
	<config evaluator="string-compare" condition="DocumentLibrary" replace="true">

		<tree>
			<!-- Whether the folder Tree component should enumerate child folders
				or not. This is a relatively expensive operation, so should be set to "false"
				for Repositories with broad folder structures. -->
			<evaluate-child-folders>false</evaluate-child-folders>

			<!-- Optionally limit the number of folders shown in treeview throughout
				Share. -->
			<maximum-folder-count>-1</maximum-folder-count>
		</tree>

		<!-- Used by the "Change Type" action Define valid subtypes using the following
			example: <type name="cm:content"> <subtype name="cm:mysubtype" /> </type>
			Remember to also add the relevant i18n string(s): cm_mysubtype=My SubType -->
		<types>
			<type name="cm:content">
				<!-- Custom sub-type added -->
				<subtype name="gs:fieldphoto" />
			</type>
		</types>

		<!-- If set, will present a WebDAV link for the current item on the Document
			and Folder details pages. Also used to generate the "View in Alfresco Explorer"
			action for folders. -->
		<repository-url>http://localhost:8080/alfresco</repository-url>

	</config>

</alfresco-config>

Test your system using Alfresco share

  • Download the photo below. Then browse to http://localhost:8080/share and go to the ‘My Files’ page. Upload the photo to Alfresco.
  • Click on the name of the photo to display a full view of the photo. To the right of the photo, choose ‘Change Type’ and choose ‘Field Photo’.
  • Click ‘Edit Properties’ – you should now see a list of all photo metadata fields grouped into 4 groups. Click ‘Cancel’ at the base of the properties form.
  • Click ‘View on Google Maps’ – note the location recorded by the phone is quite inaccurate – the photo was taken on the shore line. Note also that the iPhone 4S that took this photo only records longitudes and latitude to 4 decimal places. Alfresco stores the coordinates to 6 decimal places.
  • Experiment with /share-amp/src/main/amp/config/alfresco/web-extension/share-config-custom.xml and test the result in Alfresco Share – http://localhost:8080/share.
Lichen-covered rocks - west coast, Tasmania

Lichen-covered rocks – west coast, Tasmania

Handy source code list command

The following shows a useful command to list only the files under the share-amp and repo-amp src folders. Run this from the top folder of your project – in my example this is ‘field-photos’.

MacBook-Air:field-photos david$ find . -name "*" | grep ".*-amp/src/.*\." | grep -v "DS_Store"
./repo-amp/src/main/amp/config/alfresco/extension/templates/webscripts/fieldphoto.get.desc.xml
./repo-amp/src/main/amp/config/alfresco/extension/templates/webscripts/fieldphoto.get.html.ftl
./repo-amp/src/main/amp/config/alfresco/extension/templates/webscripts/fieldphoto.get.js
./repo-amp/src/main/amp/config/alfresco/extension/templates/webscripts/helloworld.get.desc.xml
./repo-amp/src/main/amp/config/alfresco/extension/templates/webscripts/helloworld.get.html.ftl
./repo-amp/src/main/amp/config/alfresco/extension/templates/webscripts/helloworld.get.js
  .. and so on ..

Further reading

1 thought on “Alfresco 5.0, SDK 2.1 and Field Photos

  1. Douglas C. R. Paes

    I wasn’t able to use LibreOffice using your symbolic link idea.

    Instead of that, I had to include the property bellow into the alfresco-global.properties file:
    ooo.exe=/Applications/LibreOffice.app/Contents/MacOS/soffice

    Like

    Reply

Leave a Reply to Douglas C. R. Paes Cancel reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out /  Change )

Google photo

You are commenting using your Google account. Log Out /  Change )

Twitter picture

You are commenting using your Twitter account. Log Out /  Change )

Facebook photo

You are commenting using your Facebook account. Log Out /  Change )

Connecting to %s