As we know, Alfresco implements Content Management Interoperability Services (CMIS) standard which allows our application to manage content and its metadata in Alfresco repository or in Alfresco cloud.
Here, we will see how we can use Mule to integrate Alfresco into Enterprise Architecture using CMIS.
And mule provides developer tooling RESTful API Modeling Language (RAML) which enables us to build the design-first approach to REST APIs.
We will implement simple HTTP service which gets content metadata from Alfresco as following
- Design and write our API definition in RAML
- Use this RAML file to create simple REST API using Anypoint studio
- Use CMIS connector to connect to Alfresco repository
- Get metadata of given node and display it in JSON format.
Assumption: You
have already installed Alfresco and AnypointStudio.
I have executed this example with Alfresco 4.2.1EE, Mule server 3.5.1 EE
Our URL and Response will look like:
Script URL: http://localhost:8080/mule/test/content/props?nodeRef=c76fe91c-c1f1-45cb-9b75-6742398482a6
Response:
{
"title" : "test
content",
"name" :
"test.ppt",
"creator" :
"admin",
"description" : "My first RAML
file"
}
Write API Definition in RAML:
We will use API web designer to write our RAML file
- Please create API Portal account -http://www.mulesoft.org/documentation/display/current/Setting+Up+Your+API+Portal
- Login in to designer on API Portal - http://api-portal.anypoint.mulesoft.com/raml/api-designer
- Click on New File and give any name to your new raml file. Ex: alfrescoContentMetaData.raml
- Our RAML file contains mainly title, URI, HTTP method – get/post etc… query parameter and response.
- Below is RAML file for our example.
- Once your RAML file is ready you can test it.
- Click on Get which will show Request, Response and Try it tab
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#%RAML 0.8 | |
title: Alfresco get content properties | |
version: 1.0 | |
baseUri: http://localhost:8080/mule/test/content | |
mediaType: application/json | |
/props: | |
displayName: getContentProperties | |
get: | |
description: Get given content properties | |
queryParameters: | |
nodeRef: | |
type: string | |
example: "78d05557-29ee-4c51-b8cc-378e3bfbe186" | |
responses: | |
200: | |
body: | |
application/json: | |
example: | | |
{ | |
"title" : "test content", | |
"name" : "test.ppt", | |
"creator" : "admin", | |
"description" : "My first RAML file" | |
} | |
500: | |
description: | |
Given noderef is not valid | |
body: | |
application/json: | |
example: | | |
{ | |
"status" : "Please check your noderef." | |
} |
- Request shows description and query parameter detail that we have provided in our RAML file
- Response is static response that we have provided as example in RAML file with proper HTTP status code 200 and if any error occurs then 500
- Try it – You can try your script and check its response. Click on GET which will show you Response.
- Once your RAML file is ready then save it on your local drive.
- We are done with RAML file.
Create Mule Project:
We will create a mule project and will import this RAML file which will automatically generate the flow.
- Click on File - New – Mule Project
- Provide name of your project
- Check Add APIkit Component and select From RAML file or URL
- Select RAML file that you have saved in your local drive.
- Click Finish.
- Studio creates new project and it automatically generates Main flow from RAML file and you can check your RAML file under – src/main/api
- In Flows you can see:
- Main Flow with HTTP end point and API Kir Router
- Global exception strategy mappings
- Backend flow for each resource-action pairing
- In backend flow, it initially sets up hard coded parameter and response in payload.
- In Main flow, click on HTTP connector which will open its properties. Click on Advanced tab.
- Check studio has not populated address as per baseUri of our RAML file. Change its values as per RAML file - http://localhost:8080/mule/test/content and save it.
- Let’s first run this project and test in console
- Right click on Project- Run as – Mule Application.
- On startup of server, it will launch APIkit Console.
- You can verify your script same as we did before.
- We are done with importing RAML file and creating flow.
CMIS Connector:
Now, we will implement actual logic for our flow to connect Alfresco using CMIS connector and to get metadata of given content.
Now, we will implement actual logic for our flow to connect Alfresco using CMIS connector and to get metadata of given content.
- In your flow get:/props:alfrescoContentMetaData-config add CMIS connector.
- Open CMIS connector properties window
- In General tab, in Connector Configurations click on plus sign to add Alfresco cmis repository and add properties as following. Here we will use alfresco cmis 1.1
- Name: CMIS [Provide any name]
- UserName: admin
- Password : admin
- BaseURL: http://localhost:9090/alfresco/api/-default-/public/cmis/versions/1.1/atom
- Repository id: -default-
- Use Alfresco Extension: true [Default value is false. You need to make it true if you need to access alfresco open cmis extension API. Our example will work with true/false both value.]
- Once done Test connection
- If everything is OK then Click on OK
- In Basic Settings, Select Operation – Here we want to get CMIS node object from given nodeId so Select “Get object by Id”
- In General: In object id, we need to provide noderef. You can test it by giving any hard coded noderef of your alfresco’s content . But we want to access it from parameter so give it as below- #groovy:message.getProperty('nodeRef',org.mule.api.transport.PropertyScope.INBOUND)]
- We are done with CMIS connector configurations.
- For testing run your project and hit URL - http://localhost:8080/mule/test/content/props?nodeRef=c76fe91c-c1f1-45cb-9b75-6742398482a6 with actual noderef this will give hard coded JSON response that we have provided in RAML file as I mentioned earlier when we import RAML file, in payload it sets this hardcoded message.
Process CMIS object:
Now we need to Process CMIS object to get required properties as per our JSON response
- CMIS connector and its operation Get object by Id gives us CMIS object
- You can process it with either js like groovy or java. Here I will show you with JAVA
- Add java component as shown in image and add class com.test.mule.alfresco.cmis.content.GetContentProps
- In src/main/java add GetContentProps class and also add ContentPropsBean. Below is source code for both classes.
- GetContentProps class will process CMIS object to get required properties and it will set to instance of ContentPropsBean
- Now add Object to Json transformer as shown in image to get our response in JSON format.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
package com.test.mule.alfresco.cmis.content; | |
import org.apache.chemistry.opencmis.client.api.Document; | |
import org.mule.api.MuleEventContext; | |
import org.mule.api.MuleMessage; | |
import org.mule.api.lifecycle.Callable; | |
import com.test.mule.alfresco.cmis.bean.ContentPropsBean; | |
/** | |
* Class to process CMIS object | |
* | |
* @author niketa.patel | |
*/ | |
public class GetContentProps implements Callable | |
{ | |
@Override | |
public Object onCall(final MuleEventContext eventContext) throws Exception | |
{ | |
final MuleMessage incomingMessage = eventContext.getMessage(); | |
final Document cmisAlfrescoDocObject = (Document) incomingMessage.getPayload();// get cmisObject | |
final ContentPropsBean contentPropObject = new ContentPropsBean(); | |
contentPropObject.setTitle(cmisAlfrescoDocObject.getProperty("cm:title").getValueAsString());// set title | |
contentPropObject.setName(cmisAlfrescoDocObject.getName()); // set name | |
contentPropObject.setDescription(cmisAlfrescoDocObject.getProperty("cm:description").getValueAsString());// set description | |
contentPropObject.setCreator(cmisAlfrescoDocObject.getProperty("cmis:createdBy").getValueAsString());// set created by | |
return contentPropObject; | |
} | |
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
package com.test.mule.alfresco.cmis.bean; | |
import com.fasterxml.jackson.annotation.JsonAutoDetect; | |
@JsonAutoDetect | |
public class ContentPropsBean | |
{ | |
String title; | |
String name; | |
String creator; | |
String description; | |
public String getTitle() | |
{ | |
return this.title; | |
} | |
public void setTitle(final String title) | |
{ | |
this.title = title; | |
} | |
public String getName() | |
{ | |
return this.name; | |
} | |
public void setName(final String name) | |
{ | |
this.name = name; | |
} | |
public String getCreator() | |
{ | |
return this.creator; | |
} | |
public void setCreator(final String creator) | |
{ | |
this.creator = creator; | |
} | |
public String getDescription() | |
{ | |
return this.description; | |
} | |
public void setDescription(final String description) | |
{ | |
this.description = description; | |
} | |
} |
- And also remove/comment payload.
- We are done with our coding. Below is our main Flow.
- Run your mule project.
- Hit mule service with actual noderef. Make sure Alfresco is Up and running : http://localhost:8080/mule/test/content/props?nodeRef=c76fe91c-c1f1-45cb-9b75-6742398482a6
- Verify your JSON response.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
<?xml version="1.0" encoding="UTF-8"?> | |
<mule xmlns:json="http://www.mulesoft.org/schema/mule/json" xmlns:tracking="http://www.mulesoft.org/schema/mule/ee/tracking" xmlns:cmis="http://www.mulesoft.org/schema/mule/cmis" xmlns:doc="http://www.mulesoft.org/schema/mule/documentation" xmlns="http://www.mulesoft.org/schema/mule/core" xmlns:apikit="http://www.mulesoft.org/schema/mule/apikit" xmlns:http="http://www.mulesoft.org/schema/mule/http" xmlns:spring="http://www.springframework.org/schema/beans" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://www.mulesoft.org/schema/mule/core http://www.mulesoft.org/schema/mule/core/current/mule.xsd | |
http://www.mulesoft.org/schema/mule/http http://www.mulesoft.org/schema/mule/http/current/mule-http.xsd | |
http://www.mulesoft.org/schema/mule/apikit http://www.mulesoft.org/schema/mule/apikit/current/mule-apikit.xsd | |
http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-3.1.xsd | |
http://www.mulesoft.org/schema/mule/cmis http://www.mulesoft.org/schema/mule/cmis/current/mule-cmis.xsd | |
http://www.mulesoft.org/schema/mule/ee/tracking http://www.mulesoft.org/schema/mule/ee/tracking/current/mule-tracking-ee.xsd | |
http://www.mulesoft.org/schema/mule/json http://www.mulesoft.org/schema/mule/json/current/mule-json.xsd" version="EE-3.5.1"> | |
<apikit:config name="alfrescoContentMetaData-config" raml="alfrescoContentMetaData.raml" consoleEnabled="true" consolePath="console" doc:name="Router"/> | |
<apikit:mapping-exception-strategy name="alfrescoContentMetaData-apiKitGlobalExceptionMapping" doc:name="Mapping Exception Strategy"> | |
<apikit:mapping statusCode="404"> | |
<apikit:exception value="org.mule.module.apikit.exception.NotFoundException" /> | |
<set-property propertyName="Content-Type" value="application/json" doc:name="Property"/> | |
<set-payload value="{ "message": "Resource not found" }" doc:name="Set Payload"/> | |
</apikit:mapping> | |
<apikit:mapping statusCode="405"> | |
<apikit:exception value="org.mule.module.apikit.exception.MethodNotAllowedException" /> | |
<set-property propertyName="Content-Type" value="application/json" doc:name="Property"/> | |
<set-payload value="{ "message": "Method not allowed" }" doc:name="Set Payload"/> | |
</apikit:mapping> | |
<apikit:mapping statusCode="415"> | |
<apikit:exception value="org.mule.module.apikit.exception.UnsupportedMediaTypeException" /> | |
<set-property propertyName="Content-Type" value="application/json" doc:name="Property"/> | |
<set-payload value="{ "message": "Unsupported media type" }" doc:name="Set Payload"/> | |
</apikit:mapping> | |
<apikit:mapping statusCode="406"> | |
<apikit:exception value="org.mule.module.apikit.exception.NotAcceptableException" /> | |
<set-property propertyName="Content-Type" value="application/json" doc:name="Property"/> | |
<set-payload value="{ "message": "Not acceptable" }" doc:name="Set Payload"/> | |
</apikit:mapping> | |
<apikit:mapping statusCode="400"> | |
<apikit:exception value="org.mule.module.apikit.exception.BadRequestException" /> | |
<set-property propertyName="Content-Type" value="application/json" doc:name="Property"/> | |
<set-payload value="{ "message": "Bad request" }" doc:name="Set Payload"/> | |
</apikit:mapping> | |
</apikit:mapping-exception-strategy> | |
<cmis:config name="CMIS" username="admin" password="admin" baseUrl="http://localhost:9090/alfresco/api/-default-/public/cmis/versions/1.1/atom" doc:name="CMIS" repositoryId="-default-" useAlfrescoExtension="true"/> | |
<flow name="alfrescoContentMetaData-main" doc:name="alfrescoContentMetaData-main"> | |
<http:inbound-endpoint address="http://localhost:8080/mule/test/content" doc:name="HTTP" exchange-pattern="request-response"/> | |
<apikit:router config-ref="alfrescoContentMetaData-config" doc:name="APIkit Router"/> | |
<exception-strategy ref="alfrescoContentMetaData-apiKitGlobalExceptionMapping" doc:name="Reference Exception Strategy"/> | |
</flow> | |
<flow name="get:/props:alfrescoContentMetaData-config" doc:name="get:/props:alfrescoContentMetaData-config"> | |
<cmis:get-object-by-id config-ref="CMIS" doc:name="CMIS" objectId="#[groovy:message.getProperty('nodeRef',org.mule.api.transport.PropertyScope.INBOUND)]" connectionTimeout=" "/> | |
<component class="com.test.mule.alfresco.cmis.content.GetContentProps" doc:name="Java"/> | |
<json:object-to-json-transformer doc:name="Object to JSON"/> | |
<!-- <set-payload value="{
 "title" : "test content",
 "name" : "test.ppt",
 "creator" : "admin",
 "description" : "My first RAML file"
}" doc:name="Set Payload"/> | |
--> | |
</flow> | |
</mule> |
You can download source code of this example from GitHub