2. Copyright (c) 2007 by Alfresco and others.
Information in this document is subject to change without notice. No part of this document may
be reproduced or transmitted in any form or by any means, electronic or mechanical, for any
purpose, without the express written permission of Alfresco. The trademarks, service marks,
logos or other intellectual property rights of Alfresco and others used in this documentation
(“Trademarks”) are the property of Alfresco and their respective owners. The furnishing of this
document does not give you license to these patents, trademarks, copyrights or other intellectual
property except as expressly provided in any written agreement from Alfresco.
The United States export control laws and regulations, including the Export Administration
Regulations of the U.S. Department of Commerce, and other applicable laws and regulations
apply to this documentation which prohibit the export or re-export of content, products, services,
and technology to certain countries and persons. You agree to comply with all export laws,
regulations and restrictions of the United States and any foreign agency or authority and assume
sole responsibility for any such unauthorized exportation.
If you need technical support for this product, contact Customer Support by email at
support@alfresco.com. If you have comments or suggestions about this documentation, contact
us at documentation@alfresco.com.
This edition applies to version 2.1 of the licensed program.
2
3. Contents
Introduction................................................................................................................................ 6
Welcome.............................................................................................................................. 7
How this course is delivered....................................................................................... 7
Course Schedule......................................................................................................... 7
How Prepared are You?..............................................................................................8
Topics not Covered..................................................................................................... 8
Introductions.................................................................................................................8
Getting Started...........................................................................................................................9
Alfresco SDK..................................................................................................................... 10
Introduction.................................................................................................................10
Downloading and Unpacking the Alfresco SDK........................................................ 10
Importing the Alfresco SDK projects into Eclipse......................................................11
Associating Source Code and Javadocs with the Alfresco Libraries......................... 14
SDK samples............................................................................................................. 16
SVN Repository......................................................................................................... 19
SDK Reference.......................................................................................................... 20
Best Practices....................................................................................................................22
Coding Standards...................................................................................................... 22
Alfresco Module Packages (AMP).............................................................................22
Alfresco Repository Architecture....................................................................................... 24
Out of the Box........................................................................................................... 24
Service & Component Architecture........................................................................... 25
Repository Foundation Services API.........................................................................27
Repository APIs......................................................................................................... 28
Repository Server Protocols...................................................................................... 29
Terminology................................................................................................................30
Developing against the Alfresco Repository........................................................................33
Spring Framework............................................................................................................. 34
Introduction.................................................................................................................34
Bean Factory..............................................................................................................34
Inversion of Control (IoC).......................................................................................... 35
Application Context.................................................................................................... 39
Foundation Services API................................................................................................... 40
Introduction.................................................................................................................40
Access to Repository Foundation Services...............................................................40
FirstFoundationClient walkthrough............................................................................ 40
Other Foundation Services........................................................................................ 48
JCR API............................................................................................................................. 50
Introduction.................................................................................................................50
JCR Compliance Levels............................................................................................ 50
JCR Repository Model...............................................................................................50
API Development Course 3
4. FirstJCRClient Walkthrough.......................................................................................51
JCR Transactions...................................................................................................... 53
Web Services API............................................................................................................. 55
Introduction.................................................................................................................55
Available Web Services.............................................................................................55
Access to Web Services in Java...............................................................................55
Web Services Data Types.........................................................................................56
Content Manipulation Language (CML).....................................................................56
FirstWebServiceClient Walkthrough.......................................................................... 57
Separating Concerns using AOP...................................................................................... 61
Public Services and AOP proxies............................................................................. 61
Security Enforcement.................................................................................................61
Transaction Management.......................................................................................... 64
Extending the Alfresco Repository....................................................................................... 69
Repository Policies............................................................................................................ 70
Introduction.................................................................................................................70
Available Policies....................................................................................................... 70
Policy Types...............................................................................................................71
Custom Aspect with Behaviour Howto...................................................................... 71
Repository Actions.............................................................................................................79
Introduction.................................................................................................................79
Repository Action Howto........................................................................................... 79
Repository Action with Parameters Howto................................................................ 85
Content Transformers........................................................................................................91
Introduction.................................................................................................................91
Content Transformer Howto...................................................................................... 91
ContentTransformerRegistry...................................................................................... 95
Further Reading......................................................................................................... 97
Metadata Extractors...........................................................................................................98
Introduction.................................................................................................................98
MetadataExtracterRegistry.........................................................................................98
Metadata Extractor Howto......................................................................................... 99
Further Reading....................................................................................................... 103
Extending the Alfresco Web Client..................................................................................... 105
JavaServer Faces............................................................................................................106
Introduction...............................................................................................................106
Login Page Walkthrough......................................................................................... 106
Actions Framework.......................................................................................................... 116
Introduction...............................................................................................................116
Update UI Action Walkthrough................................................................................ 116
Actions Framework Reference................................................................................ 120
Dialog Framework............................................................................................................123
Introduction...............................................................................................................123
4 Alfresco Enterprise Edition Version 3.2
5. Custom Dialog Howto..............................................................................................123
Further Information.................................................................................................. 128
Dialog Framework Reference.................................................................................. 130
Wizard Framework...........................................................................................................132
Introduction...............................................................................................................132
Custom Wizard Howto.............................................................................................132
Further Reading....................................................................................................... 137
Wizard Framework Reference................................................................................. 139
Packaging Extensions.......................................................................................................... 142
Alfresco Module Packages.............................................................................................. 143
Introduction...............................................................................................................143
Basic AMP Howto....................................................................................................143
Further Reading....................................................................................................... 149
Alfresco Module Package Reference...................................................................... 150
API Development Course 5
7. Introduction
Welcome
Welcome to Alfresco API development. This course has been designed to provide you with the
knowledge and skills necessary to develop against the Alfresco Repository APIs and to develop
extensions for the Alfresco enterprise content management system.
How this course is delivered
This course is delivered in 17 modules, each module focusing on a specific subject. All modules
include a combination of introductory materials, an outline of objectives followed by instructor-
led discussions and walkthroughs. Each module will close with one or more exercises which will
allow students to use and demonstrate what they have learned in each module.
Course objectives
At the conclusion of this course you should be comfortable with all the concepts and tasks
required to competently:
• Set up your own development environment and use the Alfresco SDK
• Develop against the Alfresco APIs (Foundation Services, JCR, Web Services)
• Develop extensions for the Alfresco Repository
• Develop extensions for the Alfresco Web Client
• Package and deploy extensions
Certification track objectives
At the conclusion of this course, you should have also acquired the requisite knowledge and
abilities to pass the Alfresco API developer exam in preparation for the Certified Alfresco ECM
professional certificate.
Course Schedule
Day 1
• Getting Started
• Alfresco SDK
• Best Practices
• Alfresco Repository Architecture
• Developing against the Alfresco Repository
• The Spring Framework
• Foundation Services API
• Java Content Repository (JCR) API
• Web Services API
Day 2
• Developing against the Alfresco Repository
• Separating Concerns using AOP
• Extending the Alfresco Repository
• Repository Policies
• Repository Actions
API Development Course 7
8. Introduction
• Content Transformers
• Metadata Extractors
Day 3
• Extending the Web Client
• JavaServer Faces
• Actions Framework
• Dialog Framework
• Wizard Framework
• Packaging Extensions
• Alfresco Module Packages
How Prepared are You?
• Can you program in Java?
• Do you have a basic understanding of XML?
• Have you followed the Alfresco administration course?
• Have you followed the Alfresco customisation course?
• Are you familiar with the Eclipse IDE?
Topics not Covered
• Installing Alfresco
• Repository configuration
• Web Client configuration
• Customising the Data Dictionary
• Developing JavaScript extensions
• Developing Freemarker templates
• Developing Web Scripts
Introductions
• Name
• Company
• Title, function, job responsibility
• Alfresco experience (API development experience)
• Courses already taken
• Reasons for taking this course
• Expectations
8 Alfresco Enterprise Edition Version 3.2
10. Getting Started
Alfresco SDK
Introduction
The Alfresco SDK provides support for developers who wish to extend or customise the Alfresco
platform. It has been designed for the developer to get developing with minimal fuss for the
following development scenarios:
• Developing extensions for the Alfresco Repository and Web Client.
• Embedding Alfresco into applications via Alfresco's Java Foundation Services API or
standards-compliant JCR API.
• Developing applications against a remote Alfresco Repository via Alfresco's Web Services
API.
Typically, the SDK is used stand-alone, but an Alfresco installation is also required if performing
any of the following:
• Customising the Alfresco Web Client
• Deploying a custom module to a remote Alfresco repository
• Testing a custom application that connects to a remote Alfresco repository
The SDK is not designed for re-building Alfresco since it does not provide full build scripts
and artifacts. If you wish to develop bug fixes or extend the core functionality of the
Alfresco platform, you should use the full Alfresco development environment provided in
the Alfresco SVN Repository. For more information, see SVN Repository on page 19.
Downloading and Unpacking the Alfresco SDK
You will need to install the following software and development tools in order to use the SDK
correctly:
• the Java SE Development Kit (JDK) version 1.5 (5.0) or above;
• a supported database of your choice (MySQL is recommended for development
purposes);
• the Eclipse IDE 3.x (highly recommended).
The Alfresco SDK bundle is provided with each release of Alfresco, for both the Enterprise and
Community Networks.
1. Downloading the Alfresco SDK
The Enterprise SDK is only available to Enterprise clients and partners. The Community
SDK is freely available and can be downloaded from the Download Alfresco Community
Network page on the Alfresco Developer web site. The SDK is provided in both ZIP and
TAR (tar.gz) formats.
2. Unpacking the Alfresco SDK
To install the SDK, simply unpack the downloaded ZIP or TAR bundle to a directory of your
choice.
10 Alfresco Enterprise Edition Version 3.2
11. Getting Started
For a description of the contents of the Alfresco SDK, see SDK Contents on page 20.
Importing the Alfresco SDK projects into Eclipse
When using the Alfresco SDK, the Eclipse IDE is highly recommended. The SDK contains
several pre-configured Eclipse projects that you can import directly into Eclipse with the following
procedure.
1. Setting the Eclipse Compiler Compliance Level
Alfresco uses Java 1.5 (5.0) language features, therefore Eclipse must be configured
appropriately for the Java SE Development Kit (JDK) version 1.5 (5.0) or above.
a. From the Eclipse main menu, select Window # Preferences...
b. In the Preferences dialog, select Java # Compiler in the tree view.
c. In the JDK Compliance panel, set the Compiler compliance level to 5.0 or above:
API Development Course 11
12. Getting Started
d. Click OK
2. Importing the Alfresco SDK projects
a. From the Eclipse main menu, select File # Import...
b. In the Import dialog, select General # Existing Projects into Workspace import
source and click Next >
c. Choose Select root directory option and click Browse...
d. Navigate to the file system directory where you unpacked the Alfresco SDK and click
OK. The Alfresco SDK projects are now listed under Projects.
Do not navigate to the samples sub-directory, otherwise you will not see the SDK
AlfrescoEmbedded and SDK AlfrescoRemote projects in the list.
12 Alfresco Enterprise Edition Version 3.2
13. Getting Started
In order to run the samples or to develop your own extension modules, you must
import at least the SDK AlfrescoEmbedded and SDK AlfrescoRemote projects. The
other SDK projects are samples for common development scenarios that you can
study and run to learn more about developing Alfresco extension modules.
For more information about the available projects, see SDK Eclipse Projects on page
20.
e. Once you have selected the projects you wish to import, click Finish.
The imported projects are displayed in the Package Explorer:
API Development Course 13
14. Getting Started
Associating Source Code and Javadocs with the Alfresco Libraries
Once the Alfresco SDK projects have been imported into Eclipse, it is useful to have access to
Alfresco's source code and Java documentation. The following procedure explains how to do this
by associating the source code and Javadocs with the Alfresco libraries within Eclipse.
1. Expand the SDK AlfrescoEmbedded project in the Project Explorer.
2. Right click on the alfresco-repository.jar and select Properties from the popup
menu.
The JAR files may not be in alphabetical order.
3. Associating source code
a. In the Properties for alfresco-repository.jar dialog, select Java Source
Attachment in the tree view.
b. In the Java Source Attachment panel, click External File...
c. Navigate to src directory within your unpacked Alfresco SDK.
d. Select repository-src.zip and click Open.
14 Alfresco Enterprise Edition Version 3.2
15. Getting Started
4. Associating Javadocs
a. In the Properties for alfresco-repository.jar dialog, select Javadoc Location in the
tree view.
b. In the Javadoc Location panel, select Javadoc in archive and click Browse...
c. Navigate to doc/api directory within your unpacked Alfresco SDK.
d. Select repository-doc.zip and click Open.
e. Click Validate... to validate the Javadoc location, then click either OK to view the
Javadocs in a web browser or Cancel if not.
API Development Course 15
16. Getting Started
5. Click OK, to close the Properties dialog.
Once the source code and Javadocs have been attached, the alfresco-repository.jar icon
changes to include a small document:
The above steps need to be repeated for the following JARs:
• alfresco-core.jar
• alfresco-remote-api.jar
• alfresco-web-client.jar
• alfresco-web-service-client.jar (only Java source code is available)
SDK samples
FirstFoundationClient and JCR Samples
The SDK FirstFoundationClient, SDK FirstJCRClient and SDK JCRSamples sample projects
demonstrate how to access an embedded Alfresco repository via the Foundation Services API
and the standards-compliant JCR API. These samples can be tested directly from within Eclipse
and will automatically start an Alfresco repository in embedded mode.
Before starting, the embedded repository needs to be configured. By default, the sample projects
are configured to use a MySQL database named alfresco and a data directory with a relative
path of ./alf_data. These parameters are defined in the custom-repository.properties
file in the source/alfresco/extension directory of each project. It is good practice to define
an absolute path for the data directory (dir.root parameter) and to configure all of the SDK
projects to share the same database and the same dir.root.
Example custom-repository.properties file:
dir.root=C:/alf_data
16 Alfresco Enterprise Edition Version 3.2
17. Getting Started
#db.username=alfresco
#db.password=alfresco
#
# MySQL connection (This is default and requires mysql-connector-java-3.1.12-
bin.jar, which ships with the Alfresco server)
#
#db.driver=org.gjt.mm.mysql.Driver
#db.url=jdbc:mysql://localhost/alfresco
The alfresco MySQL database also needs to be created using the scripts provided in the
extras/databases/mysql directory of the unpacked Alfresco SDK. To create the database from
the command line:
C:alfresco-enterprise-sdkextrasdatabasesmysql>mysql -u root -p <
db_setup.sql
Enter password: ********
The samples can now be tested by running the main Java classes from within Eclipse. In the
following example, the FirstFoundationClient class is run as a Java Application:
The Alfresco repository is automatically started in embedded mode. Because this is the first time
the repository has been started, the initial bootstrap is executed to create the database tables. As
you can see from the console messages below, the embedded repository uses C:alf_data as
it's data directory (dir.root).
API Development Course 17
18. Getting Started
The other embedded repository samples (SDK FirstJCRClient and SDK JCRSamples) can be
run in the same way.
Web Services Samples
The SDK FirstWebServiceClient and SDK WebServiceSamples sample projects demonstrate
how to access a remote Alfresco repository via the Web Services API. A remote Alfresco
repository needs to be installed and running before testing one of these samples.
Before running one of the Web Services samples, a remote repository needs to be installed
and configured. The easiest solution for development purposes is to install Alfresco on the local
machine and configure it to use the same alfresco MySQL database and the same C:/alf_dir
data directory as the embedded repository used for the other samples.
The location of the remote repository is configured in the webserviceclient.properties
file in the source/alfresco/extension directory of each Web Services project. If the remote
repository is installed on the same machine and configured to use the default 8080 port, you will
not have to modify the default value.
Example webserviceclient.properties file:
#
# Set the following property to reference the Alfresco server that you would
like web service client
# to communicate with
repository.location=http://localhost:8080/alfresco/api
Once the remote repository has been installed and started, the Web Clients samples can be
tested by running the main Java classes from within Eclipse. In the following example, the
FirstWebServiceClient class is run as a Java Application:
Custom Repository Samples
The SDK CustomAction and SDK CustomAspect sample projects demonstrate how to develop
custom modules that may be deployed to an Alfresco repository. Initially, custom repository
18 Alfresco Enterprise Edition Version 3.2
19. Getting Started
modules can be developed and tested using unit tests and an embedded Alfresco repository. The
SDK CustomAspect project has a sample unit test that does this.
An Ant build.xml file is provided for packaging the repository samples. The package target
packages the compiled classes and extension files into a JAR file. To deploy the samples,
copy the JAR file to the WEB-INF/lib folder of an existing Alfresco installation and restart the
application server.
For deployment in a production environment, a custom repository module should be packaged as
an Alfresco Module Package (AMP).
For more information on creating a custom repository action, see the Repository Action Howto
on page 79. For a detailed presentation of the SDK CustomAspect sample, see the Custom
Aspect with Behaviour Howto on page 71.
Custom Web Client Samples
The SDK CustomDialog, SDK CustomJSP, SDK CustomLogin, SDK CustomWizard, and SDK
TaggingSample sample projects demonstrate how to develop custom modules for the Alfresco
Web Client. Custom Web Client modules have to be deployed to an existing Alfresco installation
for testing.
An Ant build.xml file is provided for packaging the Web Client samples. The package-
jar target packages the compiled classes and extension files into a JAR file. The package-
extension target then packages the JAR file along with the JSPs into a ZIP file. The optional
integrate-extension target can be used to integrate the packaged ZIP file into an Alfresco
Web Client WAR file. The alfresco.war file must be copied to the same directory as the
build.xml file before running the Ant build and then re-deployed to the application server.
For deployment in a production environment, a custom Web Client module should be packaged
as an Alfresco Module Package (AMP).
The SDK CustomDialog and SDK CustomWizard are presented in detail in the Custom Dialog
Howto on page 123 and the Custom Wizard Howto on page 132. The SDK TaggingSample
sample is presented in detail in the Repository Action Howto on page 79.
Basic AMP Sample
The SDK Basic AMP sample project demonstrates how to structure a project and how to arrange
classes and configuration files to generate an Alfresco Module Package (AMP). For more
information see Basic AMP Howto on page 143.
SVN Repository
The Alfresco Subversion repository gives you access to all of the Alfresco source code and build
artifacts. It provides the latest work-in-progress developments. It should only be used if you wish
to extend the Alfresco core framework or work on Alfresco bug fixes as it allows you to perform
full re-builds of Alfresco itself. For most requirements, it is best to use the Alfresco SDK.
Public read-only access to the Alfresco Subversion repository is available from the Alfresco web
site. To checkout the source code, use the following procedure:
1. Install Subversion and ensure that svn is on the path.
2. Checkout the HEAD of the code stream:
svn co svn://svn.alfresco.com/alfresco/HEAD
or
svn co http://svn.alfresco.com/repos/alfresco-open-mirror/alfresco/HEAD
3. Keep up to date by issuing the command:
svn update
API Development Course 19
20. Getting Started
SDK Reference
SDK Contents
bin
Supporting dll's, exe's.
doc
Zipped Javadoc's for all pre-built libraries.
extras
Additional files - database setup and migration scripts.
lib
Alfresco pre-built libraries (JAR files).
lib/deployment
Alfresco libraries required for WCM deployment to a remote server.
lib/remote
Alfresco libraries required for access to a remote Alfresco repository via web services.
lib/server
Alfresco libraries required for embedding an Alfresco repository.
licenses
License files.
samples
Sample Eclipse projects for common development scenarios (see SDK Eclipse Projects on
page 20).
src
Zipped source code for all pre-built libraries.
license.txt
Alfresco licence file.
notice.txt
Notices
readme.txt
Alfresco SDK readme.
SDK Eclipse Projects
SDK AlfrescoEmbedded
Project containing all of the Alfresco libraries needed to build a custom module that will be
embedded into the Alfresco repository or Web Client.
SDK AlfrescoRemote
Project containing all of the Alfresco libraries needed to build a custom Web Services client.
SDK Basic AMP
Sample project demonstrating how to build an AMP (Alfresco Module Package) file.
SDK CustomAction
Sample project demonstrating how to develop a custom Action that may be deployed to an
Alfresco repository.
SDK CustomAspect
Sample project demonstrating how to develop a custom Aspect with behaviour that may be
deployed to an Alfresco repository.
20 Alfresco Enterprise Edition Version 3.2
21. Getting Started
SDK CustomDialog
Sample project demonstrating how to develop and configure a custom Dialog for the Alfresco
Web Client.
SDK CustomJSP
Sample project demonstrating how to develop and configure a custom JSP for the Alfresco
Web Client.
SDK CustomLogin
Sample project demonstrating how to override the Login page of the Alfresco Web Client.
SDK CustomWizard
Sample project demonstrating how to develop and configure a custom Wizard for the Alfresco
Web Client.
SDK FirstFoundationClient
Sample project demonstrating how to access an Alfresco (embedded) repository via the
Foundation Services API.
SDK FirstJCRClient
Sample project demonstrating how to access an Alfresco (embedded) repository via the
standards-compliant JCR API.
SDK FirstWebServiceClient
Sample project demonstrating how to access a remote Alfresco repository via the Web
Services API.
SDK JCRSamples
More sample projects demonstrating how to access an Alfresco (embedded) repository via the
standards-compliant JCR API.
SDK TaggingSample
Advanced sample project demonstrating how to develop a custom Action that takes
parameters.
SDK WebServiceSamples
More sample projects demonstrating how to access a remote Alfresco repository via the Web
Services API.
API Development Course 21
22. Getting Started
Best Practices
Coding Standards
Coding Standards - Formatting
• The core coding standards are the standard Java Code Conventions.
• Braces are on new lines.
• 4 space for tabbing, except for Web Client project that uses 3 spaces.
• 120 characters on a line is fine.
• Import declarations are managed by Eclipse's standard ordering rules (CTRL-SHIFT-O).
This helps prevent code merge conflicts.
• XML documents use 3 space tabbing. The Eclipse plug-in, XMLBuddy, is generally used.
Coding Standards - Exceptions
• When generating a new exception, always attach the cause to it.
• Don't log exceptions unless you are adding the logic to absorb the exception.
• Put as much context and formatting into the error message as possible.
• Use RuntimeException derived exceptions, unless there is a really good reason to bother
the client code with a checked exception.
• Pay attention to the Javadoc specification on unchecked exceptions. Don't declare them
on the interface, just in the Javadocs.
Coding Standards - Logging
• Use the Apache Commons Logging API so that all logging output is uniform.
• Use the class hierarchy categories, but where deviations are made, add comments to the
Javadocs.
• INFO messages are only added at the request of Alfresco users. All other informative
messages are DEBUG.
• Put as much context and formatting into the message as time will allow.
• Wrap all calls to logger.debug and logger.info, and only log messages if
logger.isDebugEnabled and logger.isInfoEnabled respectively.
Coding Standards - File Formats
• UTF-8 encoding of all text files
• Windows line endings (CR-LF)
Alfresco Module Packages (AMP)
An Alfresco Module Package (AMP) is a collection of code, XML, images, CSS, etc. that
collectively extend the functionality or data provided by the standard Alfresco Repository. An AMP
file can contain as little as a set of custom templates or a new category. It can contain a custom
model and associated UI customisations. It could contain a complete new set of functionality, for
example records management. As a general rule of thumb, anything that is considered to be an
“installable” extension to the Alfresco repository should be called a module and packaged as an
AMP file.
AMP files can be installed into the Alfresco WAR using the Module Management Tool. An AMP
file has a standard format that can be customised if required.
22 Alfresco Enterprise Edition Version 3.2
23. Getting Started
Once the contents of the AMP file has been mapped into an Alfresco WAR using the Module
Management Tool, the WAR can be deployed to the application server. When the repository
is next started, the installed module configuration will be detected, and the repository will be
bootstrapped to include the new module functionality and data.
AMP Project Structure
An Alfresco Module project can be structured in any way that suits the developer environment. As
long as the resulting AMP file is packaged correctly and the required property and context files
are present, the module will install successfully.
The recommended project structure is as follows:
|-- source
|
|-- java
|-- <module package structure starts here>
|
|-- web
|-- css
|-- images
|-- jsp
|-- scripts
|
|-- config
|-- <resource package structure starts here>
|
|-- build
|-- dist
|-- lib
|
|-- build.xml
source/java/
Contains the Java source for the Alfresco Module.
source/web/
Contains any web UI resources (JSPs, images, CSS, JavaScript).
config/
Contains configuration files and resources used by the module.
build/
Build directory for compiled class files.
build/dist/
Build directory for AMP files.
build/lib/
Build directory for JAR files.
The recommended package structure for Java source (source/java), configuration files and
resources (config) is org.alfresco.module.<moduleid>, where moduleid is the unique
module id of the module.
Alfresco Module Packages are presented in more detail later on in the course. For more details,
see Introduction on page 143.
API Development Course 23
24. Getting Started
Alfresco Repository Architecture
Out of the Box
Out-of-the-box, Alfresco's simple installation procedure provides a pre-configured deployment
aimed at reaching a complete and working Content Management application as quickly and easily
as possible. The deployment is as follows:
This is typical of a web architecture, where an application server houses the logic for both the
user interface and domain. Storage of data and content is provided by persistent back-ends such
as a database or file system. Any number of web browsers can connect to the application without
prior client installation costs.
In this particular case, the application server houses both the Alfresco Application and the
Alfresco Repository. An Alfresco Application provides a complete solution tailored for a specific
area of Content Management such as Document Management (DM), Web Content Management
(WCM) and Records Management (RM). The Alfresco Repository provides a set of reusable
cross-cutting Content Management services such as content storage, query, versioning and
transformation which may be utilised by one or more applications.
Although this is the default installed deployment, it is only one of many ways of utilising the
capabilities and components of Alfresco. When we first set out to design Alfresco, we wanted to
break away from the mould of typical Content Management architectures which are monolithic
and closed. The result is that Alfresco can neatly fit into existing environments and each of its
24 Alfresco Enterprise Edition Version 3.2
25. Getting Started
components may be used in isolation or together to form the basis of many differing Content
Management solutions.
The remainder of this module explores the anatomy of the Alfresco Repository which will give a
good understanding of the concepts and capabilities and how it achieves openness, scalability
and flexibility.
Service & Component Architecture
Every part of the Alfresco Repository is either a component or a service. A component is
an implementation black box that provides a specific feature or capability. A service is an
interface entry point for a client to bind to and use. This fundamental approach allows for existing
components to be switched with new implementations, new components to be added with ease
and for clients to connect and use services without knowledge of how they're implemented.
If there's a feature of Alfresco you don't need, you can take it out, providing a lighter and possibly
faster Alfresco. If there's a feature you wish to re-implement, you can replace it, either by
providing a better implementation, or integrating with your existing environment.
Implementation of this approach is simplified by using the open source project Spring Framework
which Alfresco has taken to heart and has made a core foundation of its architecture. With
Spring, Alfresco components are declaratively configured and bound together. Aspect-oriented
programming allows the weaving of infrastructure concerns such as Transactions and Security
into components without polluting their implementation. Environment touch points are abstracted
such as resource (e.g. database) connections.
The Alfresco Repository structure looks like this:
API Development Course 25
26. Getting Started
The public interface point is the Alfresco Repository Foundation Services. Each service is
exposed as a Java Interface to which a Repository client can bind and invoke without knowledge
of its underlying implementation. A Service Registry lists the available services. Behind services
are the implementation black boxes i.e. components. Each service and component is configured
via the Spring framework in XML “context” files.
The Spring context file public-service-context.xml provides the configuration and
binding of the Alfresco Repository Foundation Services.
The Repository Foundation Services are the lowest level of public interface providing access
to all Repository capabilities. Binding to this interface is possible via the Repository Service
Registry, or via Spring dependency injection if the client is also Spring aware. Access to
Foundation Services is limited to Repository clients who reside in the same process as the
Repository. That is, the Foundation Services are an excellent API for clients who wish to embed
the Repository.
An important point to note is that the Foundation Services are where transaction and security
policies are enforced. The policies themselves are declaratively specified and enforced via the
injection of a transaction and security implementation into each service. Every service of Alfresco
is transactional and secure.
Other forms of API are provided too, however, all public entry points eventually go through this
layer.
Alfresco supports a common scheme for making extensions to the Repository i.e. configuring
a component, adding a new component or service, or removing capabilities. Extensions are
26 Alfresco Enterprise Edition Version 3.2
27. Getting Started
encapsulated outside of the core Repository and plugged-in automatically. This means the core
Repository can be upgraded to a newer version and extensions remain intact.
Repository Foundation Services API
The heart of the Alfresco Repository is responsible for the storage and retrieval of content. This
is split into nodes, content and index information. Nodes provide meta-data and structure to
content. A node may support properties (e.g. author) and relate to other nodes (e.g. represent
folder hierarchies or annotations). Content is the actual information being recorded e.g. a Word
document or XML fragment. Meta-data and content may be structured according to the rules
defined in a Content Model. For example, the Alfresco Document Management application relies
on a model that describes Folders and Files. Indexing information allows the retrieval of meta-
data and content via many different lookup options.
Repository storage and retrieval is provided by the following Foundation Services:
• Node Service for managing meta-data i.e. nodes
• Content Service for managing content
• Search Service for performing queries
By default, Alfresco has chosen to store meta-data in a database and content in a file system.
Using a database immediately brings in the benefits of databases that have been developed over
many years such as transaction support, scaling & administration capabilities. Content is stored in
the file system to allow for very large content, random access, streaming and options for different
storage devices.
The Alfresco out-of-the-box implementations of the above services are built upon strong
open source projects that already have many man-years of development effort and strong
communities: Hibernate and Lucene.
API Development Course 27
28. Getting Started
Apart from the strong Object/Relational mapping that Hibernate provides, it also brings pluggable
caching support and SQL dialects. The first allows for tuning of the Alfresco meta-data store to
provide optimum read and write performance in both single and clustered environments. The
second allows for nearly any SQL database back-end by configuring just two properties; the
Alfresco community has already confirmed working support for MySQL, Oracle, DB2, Sybase,
SQL Server.
By externalising the indexing of meta-data and content and using the Lucene engine as a basis,
it is possible to perform complex queries which combine property, location, classification and
full-text predicates in a single query against any content type. Multiple query languages are
supported including Lucene's native language as well as XPath and a SQL-like language in the
future. To ensure reliable operation, transactional support has been added to both Lucene and
the content file store providing ACID operations across the complete store. Security is woven into
each of the service layer ensuring illegal modifications are not permissible and hidden meta-data
and content are not returned.
Nearly all other Foundation services and clients rely upon these three core building blocks.
Repository APIs
The Alfresco Repository actually provides three APIs. We've already seen one - the Repository
Foundation Services - a set of local Java Interfaces covering all capabilities which are ideal for
clients who wish to embed the Repository.
The two other APIs are:
• JCR
• Web Services
JCR (Content Repository API for Java Technologies) is a standard Java API (as defined by
JSR-170) for accessing Content Repositories. Alfresco provides support for level 1 and level 2
giving standardised read and write access. Supporting this API provides the following benefits:
• No risk: The Alfresco Repository can be trialled and developed against, but swapped out
with another JCR Repository if it does not fit requirements.
• Familiarity: Developers who know JCR, know Alfresco.
• Tools: Tools, Clients and other 3rd Party JCR solutions are immediately available to the
Alfresco community.
Alfresco JCR is implemented as a light facade on top of the Repository Foundation Services.
So, although a familiar API is provided, it sits upon a fully transactional, secure and scalable
Repository which supports many deployment options. Alfresco will continue investment in JCR by
both broadening the compliance of the full specification as well driving forward JSR-283, the next
version of the JCR.
Web Services is the final API provided by the Alfresco Repository. This API supports remote
access and bindings to any client environment, not just Java. For example, the Alfresco
community is already using PHP, Ruby and Microsoft .NET. Numerous standards and integration
efforts are focused around Web Services - SOA is now recognised as a way forward for
integrating disparate systems including Content Management and building new enterprise-wide
solutions. BPEL plays an important role in orchestrating all of these services. Alfresco fits neatly
into this way of thinking.
28 Alfresco Enterprise Edition Version 3.2
29. Getting Started
Once again, the Repository Foundation Services serve as the base. Both the JCR and Web
Services API eventually go through this layer meaning that all encapsulated content model logic
and rules are honoured.
Repository Server Protocols
A Repository is useless if the content it manages cannot be accessed. To provide the widest
possible range of access points, the Alfresco Repository supports a variety of communication
protocols. These are:
• CIFS (Common Internet File System)
• WebDAV
• FTP
• NFS
All of these protocols essentially expose Folders of Files and as such the Alfresco
implementations map neatly onto Folder and File nodes held in the Repository as described by
the Alfresco Document Management content model.
WebDAV, FTP and NFS are well known protocols, but CIFS deserves some more attention.
CIFS transforms the Alfresco Repository into a standard file system. Any tool that understands
how to read and write to a file system, also knows how to directly read and write to the Alfresco
Repository. On the surface, it would seem that a drive mapping to WebDAV provides an
equivalent capability, but this isn't the case. CIFS projects an actual file system giving extra
compatibility with the hosting operating system. For example, in Windows, it's possible to use
Offline Synchronisation and Briefcase features against the Alfresco Repository providing native
and well-known tools for offline Repository working. Many commercial CMS offerings do not
provide this feature. In fact, Alfresco may have the only server-side Java implementation of the
API Development Course 29
30. Getting Started
CIFS protocol having brought on board the engineers who spent 7 years developing such a
capability.
Like every other feature of the Repository, the protocol components are Spring configured and
as with all other components may or may not be included in a deployment. Typically, they are
enabled when the Repository is deployed as a server to provide access points for remote clients.
The various Repository deployment options are explored later in this document.
Protocol components are implemented against the Repository Foundation Services. This is
important to note, as each protocol will honour the behaviour and content logic encapsulated
behind the Foundation Services. In fact, it cannot be bypassed.
Terminology
Store Reference (StoreRef)
A StoreRef is made up of a store protocol and a store id.
30 Alfresco Enterprise Edition Version 3.2
31. Getting Started
public static final String PROTOCOL_WORKSPACE = "workspace";
public static final String PROTOCOL_AVM = "avm";
public static final String URI_FILLER = "://";
The standard store used by the Web Client has the following StoreRef:
workspace://SpacesStore
Node Reference (NodeRef)
A NodeRef is made up a store reference and a node id.
private static final String URI_FILLER = "/";
The node id is a 16 byte (128 bit) A “Universally Unique Identifier” or UUID.
Example NodeRef:
workspace://SpacesStore/808b2b34-a99f-11db-b572-8337f65f7e0d
Qualified Name (QName)
A QName represents the qualified name of a Repository item. Each QName consists of a local
name qualified by a namespace.
API Development Course 31
32. Getting Started
Namespace scoped Name Format {URI}localname or prefix:localName
Examples
{http://www.alfresco.org/model/content/1.0}auditable
or
cm:auditable
Node Browser
The Node Browser is your friend!
32 Alfresco Enterprise Edition Version 3.2
33. Developing against the Alfresco Repository
Developing against the Alfresco Repository
API Development Course 33
34. Developing against the Alfresco Repository
Spring Framework
Introduction
The Spring Framework is a full-stack Java/JEE application framework. Spring's main aim is to
make J2EE easier to use and promote good programming practise. It does this by enabling a
POJO-based programming model remaining faithful to the fundamental ideas of Expert One-on-
One J2EE Design and Development. Spring is portable between application servers.
Bean Factory
A Spring BeanFactory is a generic factory that enables objects to be retrieved by name, and
which can manage relationships between objects. Bean factories support two modes of object:
• Singleton: in this case, there's one shared instance of the object with a particular name.
• Prototype or non-singleton: in this case, each retrieval will result in the creation of an
independent object.
Beans are defined in an XML bean definition file that is loaded when a new Bean Factory is
created.
Bean Factory Example
1. Writing a simple JavaBean class
Here's the simplest Java Bean you can get!
package ex01_simplebean;
public class Bean1
{
}
2. Defining the Spring beans
Two Spring beans are defined for the same class. bean1 is a singleton bean and
multibean1 is a prototype bean (singleton="false"):
<beans>
<bean id="bean1"
class="ex01_simplebean.Bean1" />
<bean id="multibean1"
class="ex01_simplebean.Bean1"
singleton="false" />
</beans>
3. Testing with a Main program
a. Creating a new Spring Bean Factory
The bean definition file is loaded into the Spring Bean Factory:
ClassPathResource res = new ClassPathResource(
"ex01_simplebean/ApplicationContext.xml");
XmlBeanFactory factory = new XmlBeanFactory(res);
The following messages are written to the console:
15:13:26,515 INFO [XmlBeanDefinitionReader] Loading XML
bean definitions from class path resource [ex01_simplebean/
ApplicationContext.xml]
15:13:26,593 INFO [XmlBeanFactory] Creating shared instance of
singleton bean 'bean1'
b. Getting bean1 from the Bean Factory
34 Alfresco Enterprise Edition Version 3.2
35. Developing against the Alfresco Repository
We retrieve bean1 from the Bean Factory using the getBean() method:
Bean1 bean1a = (Bean1) factory.getBean("bean1");
System.out.println("Retrieved Bean1: " + bean1a.toString());
Bean1 bean1b = (Bean1) factory.getBean("bean1");
System.out.println("Retrieved Bean1: " + bean1b.toString());
Each call retrieves the same bean (there is only one instance):
Retrieved Bean1: ex01_simplebean.Bean1@471e30
Retrieved Bean1: ex01_simplebean.Bean1@471e30
c. Getting multibean1 from the Bean Factory
Now we retrieve multibean1 from the Bean Factory.
Bean1 bean1a = (Bean1) factory.getBean("multibean1");
System.out.println("Retrieved MultiBean1: " + bean1a.toString());
Bean1 bean1b = (Bean1) factory.getBean("multibean1");
System.out.println("Retrieved MultiBean1: " + bean1b.toString());
This time each call retrieves a new instance of the bean:
Retrieved MultiBean1: ex01_simplebean.Bean1@10ef90c
Retrieved MultiBean1: ex01_simplebean.Bean1@a32b
Inversion of Control (IoC)
Through its bean factory concept, Spring is an Inversion of Control container. Spring is most
closely identified with a flavour of Inversion of Control known as Dependency Injection. The
concept behind Inversion of Control is often expressed in the Hollywood Principle: “Don't call me,
I'll call you.” IoC moves the responsibility for making things happen into the framework, and away
from application code. Whereas your code calls a traditional class library, an IoC framework calls
your code.
Dependency Injection
Dependency Injection is a form of IoC that removes explicit dependencies on container APIs.
Ordinary Java methods are used to inject dependencies such as collaborating objects or
configuration values into application object instances. The two major flavors of Dependency
Injection are:
• Setter Injection (injection via JavaBean setters)
• Constructor Injection (injection via constructor arguments).
Spring provides sophisticated support for both, and even allows you to mix the two when
configuring the one object.
Setter Injection Example
1. Writing a simple JavaBean class
This simple JavaBean supports properties. The values of the properties are set by the
Spring Bean Factory when the bean is instantiated.
package ex02_setter;
public class Bean1
{
public void setString(String val) { m_strVal = val; }
public String getString() { return m_strVal; }
public void setInt(int val) { m_intVal = val; }
public int getInt() { return m_intVal; }
API Development Course 35
36. Developing against the Alfresco Repository
public void setList(List strings) { m_strings = strings; }
public List getList() { return m_strings; }
private String m_strVal;
private int m_intVal;
private List m_strings;
}
2. Defining the Spring beans
A single bean is defined with initial values for the properties that will be initialised via the
“setter” methods on the JavaBean:
<beans>
<bean id="bean1" class="ex02_setter.Bean1">
<property name="string">
<value>a string</value>
</property>
<property name="int">
<value>125</value>
</property>
<property name="list">
<list>
<value>item1</value>
<value>item2</value>
<value>item3</value>
</list>
</property>
</bean>
</beans>
3. Testing with a Main program
We retrieve bean1 from the Bean Factory and print out the values of the properties:
Bean1 bean1a = (Bean1) factory.getBean("bean1");
System.out.println("Retrieved Bean1: " + bean1a.toString());
String strVal = bean1a.getString();
System.out.println("String property: " + strVal);
int intVal = bean1a.getInt();
System.out.println("Int property: " + intVal);
List strings = bean1a.getList();
System.out.println("List property: " + strings);
The properties have automatically been initialised by the Bean Factory:
Retrieved Bean1: ex02_setter.Bean1@21b6d
String property: a string
Int property: 125
List property: [item1, item2, item3]
Constructor Injection Example
1. Writing a simple JavaBean class
This time the JavaBean has a constructor and some properties.
The String property is passed to the constructor and the int property has a “setter”
method.
package ex03_constructor;
public class Bean1
{
public Bean1(String val)
{
m_strVal = val;
}
public String getString() { return m_strVal; }
36 Alfresco Enterprise Edition Version 3.2
37. Developing against the Alfresco Repository
public void setInt(int val) { m_intVal = val; }
public int getInt() { return m_intVal; }
private String m_strVal;
private int m_intVal;
}
2. Defining the Spring beans
This time a bean is defined with a constructor argument.
The String property will be initialised via the constructor and the int property via the
“setter” method on the JavaBean:
<beans>
<bean id="bean1" class="ex03_constructor.Bean1">
<constructor-arg index="0">
<value>a string</value>
</constructor-arg>
<property name="int">
<value>125</value>
</property>
</bean>
</beans>
3. Testing with a Main program
We retrieve bean1 from the Bean Factory and print out the values of the properties:
Bean1 bean1a = (Bean1) factory.getBean("bean1");
System.out.println("Retrieved Bean1: " + bean1a.toString());
String strVal = bean1a.getString();
System.out.println("String property: " + strVal);
int intVal = bean1a.getInt();
System.out.println("Int property: " + intVal);
The properties have automatically been initialised by the Bean Factory:
Retrieved Bean1: ex03_constructor.Bean1@12152e6
String property: a string
Int property: 125
Dependency Injection Example
1. Writing the JavaBean classes
a. Two more simple JavaBean classes
These two JavaBeans will be used as dependencies:
package ex04_dependency;
public class Bean2
{
}
package ex04_dependency;
public class Bean3
{
}
b. Establish a constructor dependency
The Bean1 class depends on the Bean2 class via the constructor:
package ex04_dependency;
API Development Course 37
38. Developing against the Alfresco Repository
public abstract class Bean1
{
public Bean1(Bean2 bean2)
{
m_bean2 = bean2;
}
...
public Bean2 getBean2()
{
return m_bean2;
}
...
private Bean2 m_bean2;
}
c. Establish a setter dependency
The Bean1 class depends on the Bean3 class via a property setter:
public void setBean3(Bean3 bean3)
{
m_bean3 = bean3;
}
public Bean3 getBean3()
{
return m_bean3;
}
private Bean3 m_bean3;
2. Defining the Spring beans
bean1 depends on bean2 and bean3. The Bean Factory will instantiate the bean2 and
bean3 objects before “injecting” them into bean1 via the constructor property setter
respectively:
<beans>
<bean id="bean1" class="ex04_dependency.Bean1">
<constructor-arg index="0">
<ref bean="bean2"/>
</constructor-arg>
<property name="bean3">
<ref bean="bean3"/>
</property>
</bean>
<bean id="bean2" class="ex04_dependency.Bean2"/>
<bean id="bean3" class="ex04_dependency.Bean3"/>
</beans>
3. Testing with a Main program
We retrieve bean1 from the Bean Factory and print out the dependencies:
Bean1 bean1 = (Bean1) factory.getBean("bean1");
System.out.println("Retrieved Bean1: " + bean1.toString());
Bean2 bean2 = bean1.getBean2();
Bean3 bean3 = bean1.getBean3();
System.out.println("Retrieved Bean2 Dependency: " + bean2.toString());
System.out.println("Retrieved Bean3 Dependency: " + bean3.toString());
The dependencies have automatically been injected by the Bean Factory:
Retrieved Bean1: ex04_dependency.Bean1$$EnhancerByCGLIB$$d8a83b@1cb25f1
Retrieved Bean2 Dependency: ex04_dependency.Bean2@2808b3
Retrieved Bean3 Dependency: ex04_dependency.Bean3@535b58
38 Alfresco Enterprise Edition Version 3.2
39. Developing against the Alfresco Repository
Application Context
To start using Spring you either instantiate a Spring BeanFactory or an ApplicationContext.
ApplicationContext is derived from BeanFactory and provides all of the BeanFactory
funtionality and more including:
• MessageSource, providing access to messages in, i18n-style
• Access to resources, such as URLs and files
• Event propagation to beans implementing the ApplicationListener interface
• Loading of multiple (hierarchical) contexts, allowing each to be focused on one particular
layer, for example the web layer of an application
Web Application Context
A Spring WebApplicationContext is just an ordinary ApplicationContext that has some extra
features necessary for web applications. It is bound in the ServletContext and is created by a
ContextLoaderListener.
Context Loader Listener
The Spring ContextLoaderListener is declared in WEB-INF/web.xml:
<listener>
<listener-class>
org.springframework.web.context.ContextLoaderListener
</listener-class>
</listener>
Spring contextConfigLocation
Use the contextConfigLocation <context-param> to set which context files to load:
<context-param>
<param-name>contextConfigLocation</param-name>
<param-value>
classpath:alfresco/web-client-application-context.xml
classpath:web-services-application-context.xml
classpath:alfresco/application-context.xml
</param-value>
<description>Spring config file locations</description>
</context-param>
API Development Course 39
40. Developing against the Alfresco Repository
Foundation Services API
Introduction
The Foundation Services API is a set of services providing full access to the capabilities of the
Alfresco Repository. It is an in-process API meaning that the client must run within the same
process as the Repository. For example, the Alfresco Web Client uses this API and is packaged
together with the Repository in a single WAR file for deployment to an application server.
Access to Repository Foundation Services
The Foundation Services API is comprised of a set of interfaces; each interface represents a
function of the Repository. A Spring Framework Bean is provided as the implementation for each
interface.
The list of available public services (i.e. Spring beans) can be found in:
• the Spring configuration file public-services-context.xml
• the Service Registry interface org.alfresco.service.ServiceRegistry
There are three ways to access Foundation Services:
1. use Spring IoC to directly inject services into your code (If your layer is also Spring
enabled);
2. use the Alfresco Service Registry;
3. manually access services via the Spring getBean() method.
FirstFoundationClient walkthrough
Before getting started, you should be familiar with the Introduction on page 34.
The sample uses several of the key foundation services, including the ServiceRegistry,
TransactionService, AuthenticationService, SearchService, NodeService and
ContentService. After initialising the Spring Application Context and starting the repository in
embedded mode, we will use the Spring getBean() method to access the ServiceRegistry.
We will then use the ServiceRegistry to access the other foundation services.
After authenticating to the repository using the AuthenticationService, we will search for
the “Company Home” node using the SearchService. We will then create a new node with
properties and add an aspect using the NodeService. Finally, we will write some content to the
new node using the ContentService. The sample will be wrapped in a single user transaction
with the help of the TransactionService.
1. Getting the ServiceRegistry
The Service Registry maintains a list of available foundation services and some meta-data
about each. In particular, the Service Registry provides access to each service interface.
The registry is a service itself and is therefore accessed using either Spring IoC or the
Spring getBean() method. The static variable SERVICE_REGISTRY found on the interface
org.alfresco.service.ServiceRegistry provides the Spring Bean name to lookup by.
The FirstFoundationClient sample uses the getBean() method on the Spring
Application Context to retrieve the ServiceRegistry:
ApplicationContext ctx =
ApplicationContextHelper.getApplicationContext();
final ServiceRegistry serviceRegistry = (ServiceRegistry)
ctx.getBean(ServiceRegistry.SERVICE_REGISTRY);
40 Alfresco Enterprise Edition Version 3.2
41. Developing against the Alfresco Repository
2. Using the TransactionService to run the example in a user transaction
By default, all repository foundation services are transactional and each invocation of
a service method is wrapped in its own transaction. These transactions are defined
declaratively in Spring configuration files and not in your Java code. In most cases,
declarative transactions are preferred to user transactions since they are less invasive.
There are situations, however, when user transactions do need to be used explicitly in your
code.
The FirstFoundationClient uses a RetryingTransactionHelper to run the example
as a unit of work inside a user transaction. The work is defined as an instance of the
RetryingTransactionCallback class. The doInTransaction() method is then called to
run the unit of work in a transaction.
The RetryingTransactionHelper is obtained via the
getRetryingTransactionHelper() method on the TransactionService.
For clarity, not all of the available methods are shown. For a complete description,
please consult the Javadocs: Interface TransactionService
The TransactionService and RetryingTransactionHelper are presented in more
detail in the section on Transactions.
The following example runs the example work in a user transaction via the
RetryingTransactionHelper:
TransactionService transactionService =
serviceRegistry.getTransactionService();
RetryingTransactionCallback<Object> exampleWork =
new RetryingTransactionCallback<Object>()
{
public Object execute() throws Exception
{
doExample(serviceRegistry);
return null;
}
};
transactionService.
getRetryingTransactionHelper().doInTransaction(exampleWork);
3. Using the AuthenticationService for authentication
API Development Course 41
42. Developing against the Alfresco Repository
Before making any call to the repository through the public Foundation Services API,
a user must first be authenticated. This is done via the AuthenticationService by
using the authenticate() method and providing a username and password. Once
authenticated, a ticket can be requested using either the getNewTicket() or the
getCurrentTicket() method. The ticket can then be used to re-validate the user using
the validate() method.
The AuthenticationService defines the API for managing authentication information
against a username.
For clarity, not all of the available methods are shown. For a complete description,
please consult the Javadocs: Interface AuthenticationService
In the example, the authenticate() method is used to authenticate as the “admin” user.
The password must be passed as a character array.
AuthenticationService authenticationService =
serviceRegistry.getAuthenticationService();
authenticationService.authenticate("admin", "admin".toCharArray());
4. Using the SearchService to locate the “Company Home” node
The SearchService provides many methods for searching the Alfresco repository using
any of the available query languages: Lucene, XPath or JCR-XPath. The Lucene query
language allows you to run powerful searches, including full text searches on the content
and node properties.
To run a Lucene search using the query() method, you must specify the StoreRef of the
store you wish to search, the query language (using one of the static attributes defined on
the SearchService interface - LANGUAGE_LUCENE for example) and the query as a String.
The parameters can either be passed directly to the query() method, or be defined on a
new SearchParameters object which is then passed to the query() method. The query
results are returned as a ResultSet object.
42 Alfresco Enterprise Edition Version 3.2
43. Developing against the Alfresco Repository
For clarity, not all of the available methods are shown. For a complete description,
please consult the Javadocs: Interface SearchService
The following example runs a Lucene query using the PATH syntax to locate the
“Company Home” by it's absolute path. The getNodeRef(0) call is used to retrieve the first
NodeRef from the ResultSet. In theory, the query should only return one result.
SearchService searchService = serviceRegistry.getSearchService();
StoreRef storeRef = new StoreRef(StoreRef.PROTOCOL_WORKSPACE,
"SpacesStore");
ResultSet resultSet = searchService.query(
storeRef,
SearchService.LANGUAGE_LUCENE,
"PATH:"/app:company_home"");
NodeRef companyHome = resultSet.getNodeRef(0);
For more information on using the SearchService and on query string syntax, see the
Search page on the Alfresco Wiki.
5. Using the NodeService to create a node
The NodeService provides methods for operations on nodes and stores.
Stores are created with createStore().
Nodes are created with createNode() and deleted with deleteNode(). Properties
are set with either setProperty() or setProperties(). Properties are removed
with removeProperty(). Aspects are applied with addAspect() and removed with
removeAspect().
Associations are created and removed with createAssociation() and
removeAssociation(). Associations can be navigated with getSourceAssocs() or
getTargetAssocs(). Child associations can be navigated with getChildAssocs() and
getParentAssoc().
Almost all NodeService methods take a NodeRef as an argument. A NodeRef is obtained
either by navigation or from the results of a search. Otherwise a new NodeRef object can
be created from the node's unique UUID.
API Development Course 43
44. Developing against the Alfresco Repository
For clarity, not all of the available methods are shown. For a complete description,
please consult the Javadocs: Interface NodeService
a. Setting properties
Properties are set on nodes using either the setProperty() or setProperties()
methods. setProperty() allows a single property to be set, whilst setProperties()
takes a Map of properties and sets all of the node's properties at once. Each property
is identified by it's QName and it's value must be Serializable.
public void setProperty(
NodeRef nodeRef,
QName qname,
Serializable value)
public void setProperties(
NodeRef nodeRef,
Map<QName, Serializable> properties)
nodeRef
NodeRef of the node to set the property on.
44 Alfresco Enterprise Edition Version 3.2
45. Developing against the Alfresco Repository
qname
QName of the property to set.
value
Value of the property. The value must be Serializable.
properties
Map of all the properties of the node keyed by QName.
The property QNames are usually defined as a static constants on the dictionary
model interfaces. For example, the cm:name property is defined by the static constant
ContentModel.PROP_NAME.
The following example creates a Map containing the cm:name property that will be
used in the next step:
String name = "Foundation API sample (" + System.currentTimeMillis() +
")";
Map<QName, Serializable> contentProps = new HashMap<QName,
Serializable>();
contentProps.put(ContentModel.PROP_NAME, name);
b. Creating a node
Nodes are created using the createNode() method. A node is created as a child
of a parent node. The child association name and child association type have to be
supplied as QName objects, as well as the QName of the type of node to create and
optionally a Map of properties to set on the newly created node.
public ChildAssociationRef createNode(
NodeRef parentRef,
QName assocTypeQName,
QName assocQName,
QName nodeTypeQName,
Map<QName, Serializable> properties)
parentRef
NodeRef of the parent node. The created node will be one of it's children.
assocTypeQName
QName of the type of association to create. This is used for verification against the
data dictionary.
assocQName
QName of the association.
nodeTypeQName
QName of the node type.
properties
Optional Map of properties to set keyed by QName.
The association and node type QName objects are usually defined as a static constants
on the dictionary model interfaces. For example, the cm:contains association type is
defined by the static constant ContentModel.ASSOC_CONTAINS and the cm:content
node type is defined by the static constant ContentModel.TYPE_CONTENT. If a
constant does not exist, a QName can be created using the QName.createQName()
static method as in the example below.
The createNode() method returns a ChildAssociationRef to the newly created
child association. The NodeRef of the newly created node is obtained by calling the
getChildRef() on the ChildAssociationRef object.
API Development Course 45
46. Developing against the Alfresco Repository
The following example creates a new node of type cm:content, using the standard
cm:contains child association. The Map created in the previous step sets the
cm:name property on the newly created node.
NodeService nodeService = serviceRegistry.getNodeService();
ChildAssociationRef association = nodeService.createNode(companyHome,
ContentModel.ASSOC_CONTAINS,
QName.createQName(NamespaceService.CONTENT_MODEL_PREFIX,
name),
ContentModel.TYPE_CONTENT,
contentProps);
NodeRef content = association.getChildRef();
c. Adding an aspect
Aspects are applied to nodes using the addAspect() method. The node is identified
by it's NodeRef and the aspect by it's QName. The property values are provided as a
Map.
public void addAspect(
NodeRef nodeRef,
QName aspectTypeQName,
Map<QName, Serializable> aspectProperties)
nodeRef
NodeRef of the node to apply the aspect to.
aspectTypeQName
QName of the aspect to apply.
aspectProperties
Map containing a minimum of the mandatory properties required for the aspect.
The aspect QNames are usually defined as a static constants on the dictionary model
interfaces. For example, the cm:titled aspect is defined by the static constant
ContentModel.ASPECT_TITLED.
The following example applies the cm:titled aspect and sets the cm:title and
cm:description properties:
Map<QName, Serializable> titledProps = new HashMap<QName,
Serializable>();
titledProps.put(ContentModel.PROP_TITLE, name);
titledProps.put(ContentModel.PROP_DESCRIPTION, name);
nodeService.addAspect(content, ContentModel.ASPECT_TITLED,
titledProps);
6. Using the ContentService to write content
The ContentService provides methods for reading, writing and transforming content.
In order to read or write content from and to a node, you must first obtain a
ContentReader or a ContentWriter via the getReader() and getWriter() methods
respectively. Methods can then be used on the ContentReader or ContentWriter to
read and write content. Both the ContentReader and the ContentWriter implement the
methods defined by the ContentAccessor interface. These methods allow you to get and
set information about the content, for example to set the mime type, the encoding or to get
the size.
The actual content is stored on the cm:content property (ContentModel.PROP_CONTENT)
of each node. When requesting a ContentReader or a ContentWriter, the NodeRef
needs to be supplied along with the ContentModel.PROP_CONTENT QName.
The ContentService is also used for transforming content. A suitable transformer can
be obtained for a given transformation (defined by a source and target mime type) using
46 Alfresco Enterprise Edition Version 3.2
47. Developing against the Alfresco Repository
the getTransformer() and getImageTransformer() methods. The transformation can
then be performed by calling transform directly on the content transformer. Otherwise,
a transformation can be attempted from a source ContentReader object to target
ContentWriter object by calling the transform() method on the ContentService.
For more information, see Introduction on page 91.
For clarity, not all of the available methods are shown. For a complete description,
please consult the Javadocs:
• Interface ContentService
• Interface ContentReader
• Interface ContentWriter
• Interface ContentAccessor
The following example gets a ContentWriter to the newly created node. The property
to be updated is defined by the QName ContentModel.PROP_CONTENT. The boolean true
value is to request that the content is updated atomically when the content write stream
is closed. The content mime type and encoding are set before writing the content with the
putContent() method.
ContentService contentService = serviceRegistry.getContentService();
ContentWriter writer = contentService.getWriter(content,
ContentModel.PROP_CONTENT, true);
writer.setMimetype(MimetypeMap.MIMETYPE_TEXT_PLAIN);
writer.setEncoding("UTF-8");
String text = "The quick brown fox jumps over the lazy dog";
writer.putContent(text);
API Development Course 47
48. Developing against the Alfresco Repository
Once completed, the newly created node may be viewed via the Web client.
The web client will need to be re-started after executing the sample to see the changes in
effect.
Other Foundation Services
FileFolderService
The FileFolderService provides methods specific to manipulating Alfresco defined content
files and folders. The methods can be more convenient and easier to use than the equivalent
NodeService and ContentService methods. Certain methods, such as create(), return a
FileInfo object. A NodeRef can then be retrieved using the FileInfo.getNodeRef() method.
48 Alfresco Enterprise Edition Version 3.2
49. Developing against the Alfresco Repository
For clarity, not all of the available methods are shown. For a complete description, please
consult the Javadocs:
• Interface FileFolderService
• Interface FileInfo
API Development Course 49
50. Developing against the Alfresco Repository
JCR API
Introduction
The JCR API (Java Content Repository) specifies a standard, implementation independent API to
access content repositories in Java. It is defined by the Java Specification Request (JSR) 170 as
part of the Java Community Process (JCP). The official JSR-170 Specification can be found on
the JCP web site at the following address: http://jcp.org/en/jsr/detail?id=170
Alfresco implements the JCR API against its own scalable repository and is actively contributing
to the next version of JCR defined by the Java Specification Request (JSR) 283.
JCR Compliance Levels
The JSR 170 specification defines two compliance levels and a set of additional optional features
which repositories of either level may support.
Level 1 provides for read functions and includes:
• Retrieval and traversal of nodes and properties
• Reading the values of properties
• Transient namespace remapping
• Export to XML/SAX
• Query facility with XPath syntax
• Discovery of available node types
• Discovery of access control permissions
Level 2 adds additional write functions:
• Adding and removing nodes and properties
• Writing the values of properties
• Persistent namespace changes
• Import from XML/SAX
• Assigning node types to nodes
Optionally, any combination of the following features may be added to an implementation of either
level:
• Transactions
• Versioning
• Observation (Events)
• Locking
• SQL syntax for query
JCR Repository Model
Like the Alfresco repository, a JCR repository consists of one or more workspaces, each of
which contains a tree of items. An item is either a node or a property. Each node may have
zero or more child nodes and zero or more child properties. There is a single root node per
workspace, which has no parent. Unlike the Alfresco repository, all other nodes have only one
parent. Properties have one parent (a node) and cannot have children; they are the leaves of the
tree. All of the actual content in the repository is stored within the values of the properties.
50 Alfresco Enterprise Edition Version 3.2
51. Developing against the Alfresco Repository
Any item in the tree hierarchy can be identified by either an absolute or a relative path using
a Unix style path syntax. The path / refers to the root node of a workspace and the path /
app:company_home refers to the “Company Home” space in the standard Alfresco SpacesStore
workspace. The special paths “.” and “..” (meaning respectively, “this” and “parent”) are also
supported.
FirstJCRClient Walkthrough
Before getting started, you should be familiar with the Introduction on page 34.
The sample uses several of the basic JCR APIs, including Repository, Session and Node. After
initialising the Spring Application Context and starting the repository in embedded mode, we will
use the Spring getBean() method to access the JCR.Repository.
After logging into the JCR repository, we will navigate to the “Company Home” node. We will then
create a new node with properties, add an aspect and write some content. Finally, we will mix the
JCR API calls with the Alfresco Foundation Services API calls to set the content mime type. The
sample is wrapped by an implicit JCR transaction.
1. Getting the JCR.Repository
The JCR repository as a whole is represented by a Repository object. JSR-170 does not
dictate how to obtain the Repository object. In Alfresco, the JSR repository is a Spring
bean called JCR.Repository.
The JCR.Repository bean is defined in jcr-api-context.xml. It has one configuration
parameter; the default workspace name. This is used when a JCR client performs a login
without specifying the workspace. The default workspace is SpacesStore, the same one
used by the Alfresco Web Client.
<bean id="JCR.Repository"
class="org.alfresco.jcr.repository.RepositoryImpl"
init-method="init">
<property name="serviceRegistry">
<ref bean="ServiceRegistry"/>
</property>
<property name="importerComponent">
<ref bean="importerComponent"/>
</property>
<property name="defaultWorkspace">
<value>SpacesStore</value>
</property>
</bean>
The following example uses the Spring getBean() method to access the JCR Repository:
ApplicationContext context = new
ClassPathXmlApplicationContext("classpath:alfresco/application-
context.xml");
Repository repository = (Repository)context.getBean("JCR.Repository");
2. Logging into the repository (creating a Session)
A client connects to the repository by calling the login() method on the Repository
object. The client must supply a Credentials object and optionally a workspace name.
Behind the scenes, Alfresco uses the authentication system of the Alfresco repository
which by default is Alfresco's own, but it could also be NTLM, LDAP or your own
depending on how the repository has been configured.
If a workspace is not provided, the default as defined earlier will be used. The Session
returned from login is tied to the workspace and allows read and write operations upon
that workspace. By default, the Session is also backed by a transaction. Work performed
API Development Course 51