This chapter supplies you with the basic knowledge of templates, UI extension, APIs in Content. Throughout this chapter, you can build your own content. Also, with the step-by-step instructions, you can create UI extension, deploy a workflow in Content and do many different actions.
This chapter consists of the main following contents:
Information about Content types and a list of Contents used in the Content function.
Introduction to the CSS files and CKEditor applied into the Content function.
Knowledge of extensions in the Content function, such as REST services, UI extensions, authoring extensions and more.
Examples of the CMIS usage code which may be useful for developers who need to access a repository.
Information (such as name, service URL, parameter, and description) of Public REST APIs used in the Content function.
Information about public Java APIs used in the Content function.
A list of deprecated portlets in the Content function.
A list of reference links for xCMIS project and CMIS.
A list of FAQs related to the product.
Details of 2 template types (dialog and view) applied to a node type or a metadata mixin type.
Description about Content List and Category Navigation templates which are commonly used in Content.
See also
Overview
The templates are applied to a node type or a metadata mixin type. There are two types of templates:
Dialogs: are in the HTML form that allows creating node instances.
Views: are in the HTML fragments which are used to display nodes.
From the ECM admin portlet, the Manage Template lists existing node types associated to Dialog and/or View templates. These templates can be attached to permissions (in the usual membership:group form), so that a specific one is displayed according to the rights of the user (very useful in a content validation workflow activity).
Document Type
The checkbox defines if the node type should be considered as the Document type or not. Sites Explorer considers such nodes as user content and applies the following behavior:
View template will be used to display the document type nodes.
Document types nodes can be created by the 'Add Document' action.
Non-document types are hidden (unless the 'Show non document types' option is checked).
Templates are written by using Groovy Templates that requires some experiences with JCR API and HTML notions.
Dialogs are Groovy templates that generate forms by mixing static HTML fragments and Groovy calls to the components responsible for building the UI at runtime. The result is a simple but powerful syntax.
These following parameters are common and can be used for all input fields.
| Parameter | Type | Required | Example | Description |
|---|---|---|---|---|
| jcrPath | string |
![]() |
jcrPath=/node/exo:title |
The relative path inside the current node. |
| mixintype | string with the commas (,) character. |
|
|
The list of mixin types you want to initialize when creating the content. |
| validate | string with the comma (,) character |
|
|
The list of validators you want to apply to the input. Possible values are: name, email, number, empty, null, datetime, length OR validator classes. To know how to pass parameters to validators, refer here |
| editable | string |
![]() |
editable=if-null |
The input will be editable only if the value of this parameter is if-null and the value of this input is null or blank. |
| multiValues | boolean |
![]() |
multiValues=true |
Show a multi-valued component if true and must be used only with corresponding multi-valued properties. The default value of this parameter is false. |
| visible | boolean |
![]() |
visible=true |
The input is visible if this value is true. |
| options | String separated by the commas (,) character. |
![]() |
A list of parameters which are input while the content templates are initialized. |
"options=toolbar:CompleteWCM,height:'410px',noSanitization" |
"name" validator:
String[] webContentFieldTitle = ["jcrPath=/node/exo:title", "validate=name", "editable=if-null"];
uicomponent.addTextField("title", webContentFieldTitle) ;
"email" validator:
String[] webContentFieldTitle = ["jcrPath=/node/exo:title", "validate=email", "editable=if-null"];
uicomponent.addTextField("title", webContentFieldTitle) ;
"number" validator:
String[] webContentFieldTitle = ["jcrPath=/node/exo:title", "validate=number", "editable=if-null"];
uicomponent.addTextField("title", webContentFieldTitle) ;
"empty" validator:
String[] webContentFieldTitle = ["jcrPath=/node/exo:title", "validate=empty", "editable=if-null"];
uicomponent.addTextField("title", webContentFieldTitle) ;
"null" validator:
String[] webContentFieldTitle = ["jcrPath=/node/exo:title", "validate=null", "editable=if-null"];
uicomponent.addTextField("title", webContentFieldTitle) ;
"datetime" validator:
String[] webContentFieldTitle = ["jcrPath=/node/exo:title", "validate=datetime", "editable=if-null"];
uicomponent.addTextField("title", webContentFieldTitle) ;
"length" validator:
For a maximum length of 50 characters:
String[] webContentFieldTitle = ["jcrPath=/node/exo:title", "validate=empty,length(50;int)", "editable=if-null"];
uicomponent.addTextField("title", webContentFieldTitle) ;
For a minimum length of 6 characters and maximum length of 50 characters:
String[] webContentFieldTitle = ["jcrPath=/node/exo:title", "validate=empty,length(6;50;int)", "editable=if-null"];
uicomponent.addTextField("title", webContentFieldTitle) ;
See also
The mixintype can be used only in the root node field (commonly known as the name field).
Additional parameters See also: Common parameters
<%
String[] fieldTitle = ["jcrPath=/node/exo:title", "validate=empty"] ;
uicomponent.addTextField("title", fieldTitle) ;
%>
See also: Common parameters
String[] hiddenField5 = ["jcrPath=/node/jcr:content/dc:date", "visible=false"];
uicomponent.addCalendarField("hiddenInput5", hiddenField5);
| Parameter | Type | Required | Description | Example |
|---|---|---|---|---|
| rows | Number |
|
The initial text area's number of rows. The value is 10 by default. |
rows=20 |
| cols | Number |
|
The initial text area's number of cols. The value is 30 by default . |
cols=50 |
See also: Common parameters
<%
String[] fieldDescription = ["jcrPath=/node/exo:description", "validate=empty"] ;
uicomponent.addTextAreaField("description", fieldDescription) ;
%>
| Parameter | Type | Required | Description | Example |
|---|---|---|---|---|
| options |
string with the semicolon (;) character |
![]() |
Some options for CKEditor field: toolbar, width and height. |
options=CompleteWCM;width:'100%';height:'200px';
|
| toolbar |
string
|
![]() |
The predefined toolbar for CKEditor. The value can be: Default, Basic, CompleteWCM, BasicWCM, SuperBasicWCM. |
options=CompleteWCM
|
| width |
string
|
![]() |
The width of CKEditor. Its value can be the percent of pixel. |
options=width:'100%'
|
| height |
string
|
![]() |
The height of CKEditor. Its value can be the percent of pixel. |
options=height:'200px'
|
See also: Common parameters
<%
String[] fieldSummary = ["jcrPath=/node/exo:summary", "options=toolbar:CompleteWCM,width:'100%',height:'200px'", "validate=empty"] ;
uicomponent.addRichtextField("summary", fieldSummary) ;
%>
| Parameter | Type | Required | Description | Example |
|---|---|---|---|---|
| options | string |
|
An option for the calendar field: Display time. | options=displaytime |
See also: Common parameters
<%
String[] fieldPublishedDate = ["jcrPath=/node/exo:publishedDate", "options=displaytime", "validate=datetime", "visible=true"] ;
uicomponent.addCalendarField("publishedDate", fieldPublishedDate) ;
%>
See also: Common parameters
When you create an upload form, you can store an image by two main ways:
If you want to store the image as a property, use the following code:
<%
String[] fieldMedia = ["jcrPath=/node/exo:image"] ;
uicomponent.addUploadField("media", fieldMedia) ;
%>
If you want to store the image as a node, use the following code:
<%
String[] hiddenField1 = ["jcrPath=/node/exo:image", "nodetype=nt:resource", "visible=false"] ;
String[] hiddenField2 = ["jcrPath=/node/exo:image/jcr:encoding", "visible=false", "UTF-8"] ;
String[] hiddenField3 = ["jcrPath=/node/exo:image/jcr:lastModified", "visible=false"] ;
uicomponent.addHiddenField("hiddenInput1", hiddenField1) ;
uicomponent.addHiddenField("hiddenInput2", hiddenField2) ;
uicomponent.addHiddenField("hiddenInput3", hiddenField3) ;
String[] fieldMedia = ["jcrPath=/node/exo:image"] ;
uicomponent.addUploadField("media", fieldMedia) ;
%>
But, this code is not complete. If you want to display the upload field, the image must be blank, otherwise you can display the image and an action enables you to remove it. You can do as follows:
<%
def image = "image";
// If you're trying to edit the document
if(uicomponent.isEditing()) {
def curNode = uicomponent.getNode();
// If the image existed
if (curNode.hasNode("exo:image")) {
def imageNode = curNode.getNode("exo:image") ;
// If the image existed and available
if (imageNode.getProperty("jcr:data").getStream().available() > 0 && (uicomponent.findComponentById(image) == null)) {
def imgSrc = uicomponent.getImage(curNode, "exo:image");
def actionLink = uicomponent.event("RemoveData", "/exo:image");
%>
<div>
<img src="$imgSrc" width="100px" height="80px"/>
<a href="$actionLink">
<img src="/eXoResources/skin/DefaultSkin/background/Blank.gif" alt="" class="ActionIcon Remove16x16Icon"/>
</a>
</div>
<%
} else {
String[] fieldImage = ["jcrPath=/node/exo:image/jcr:data"] ;
uicomponent.addUploadField(image, fieldImage) ;
}
} else {
String[] fieldImage = ["jcrPath=/node/exo:image/jcr:data"] ;
uicomponent.addUploadField(image, fieldImage) ;
}
} else if(uicomponent.dataRemoved()) {
String[] fieldImage = ["jcrPath=/node/exo:image/jcr:data"] ;
uicomponent.addUploadField(image, fieldImage) ;
} else {
String[] fieldImage = ["jcrPath=/node/exo:image/jcr:data"] ;
uicomponent.addUploadField(image, fieldImage) ;
}
%>
To have multiple upload fields, you just add the multiValues=true parameter to fieldProperty in dialog1.gtmpl:
# Multi upload
fieldProperty = ["jcrPath=/node/exo:value", "multiValues=true"];
uicomponent.addUploadField("/node/exo_value", fieldProperty);
In this case, you must be sure that the node type definition of the document you are currently editing should allow the document to have a child node named 'exo:value' whose node type is 'nt:unstructured'. All uploaded files of this upload component are stored in this 'exo:value' child node.
| Parameter | Type | Required | Description | Example |
|---|---|---|---|---|
| options | string with the comma (,) characters |
|
Some radio values. | options=radio1,radio2,radio3 |
See also: Common parameters
<%
String[] fieldDeep = ["jcrPath=/node/exo:isDeep", "defaultValues=true", "options=radio1,radio2,radio3"];
uicomponent.addRadioBoxField("isDeep", fieldDeep);
%>
| Parameter | Type | Required | Description | Example |
|---|---|---|---|---|
| options | string with the comma (,) characters |
|
Some option values. | options=option1,option2,option3 |
See also: Common parameters
<%
String[] fieldDeep = ["jcrPath=/node/exo:isDeep", "defaultValues=true", "options=checkbox1,checkbox2,checkbox3"];
uicomponent.addCheckBoxField("isDeep", fieldDeep);
%>
| Parameter | Type | Required | Description | Example |
|---|---|---|---|---|
| options | string with the comma (,) characters |
|
Some checkbox values. | options=checkbox1,checkbox2,checkbox3 |
See also: Common parameters
<%
String[] fieldDeep = ["jcrPath=/node/exo:isDeep", "defaultValues=true", "options=checkbox1,checkbox2,checkbox3"];
uicomponent.addCheckBoxField("isDeep", fieldDeep);
%>
See also: Common parameters
<%
String[] fieldId = ["jcrPath=/node", "editable=false", "visible=if-not-null"] ;
uicomponent.addMixinField("id", fieldId) ;
%>
| Parameter | Type | Required | Description | Example |
|---|---|---|---|---|
| selectorClass | string |
|
The component to display. | selectorClass=org.exoplatform.ecm.webui.tree.selectone.UIOneNodePathSelector |
| selectorIcon | string |
|
The action icon. | selectorIcon=SelectPath24x24Icon |
Depending on the selectorClass, some other parameters can be added.
For example, the component org.exoplatform.ecm.webui.tree.selectone.UIOneNodePathSelector needs the following parameter:
| Parameter | Type | Required | Description | Example |
|---|---|---|---|---|
| workspaceField | string |
|
The field which enables you to select a workspace. | workspaceField=targetWorkspace |
The component org.exoplatform.ecm.webui.selector.UIPermissionSelector does not need any special parameters.
See also: Common parameters
<%
String[] fieldPath = ["jcrPath=/node/exo:targetPath", "selectorClass=org.exoplatform.ecm.webui.tree.selectone.UIOneNodePathSelector", "workspaceField=targetWorkspace", "selectorIcon=SelectPath24x24Icon"] ;
uicomponent.addActionField("targetPath", fieldPath) ;
%>
To add an interceptor to a dialog, you can use this method
uicomponent.addInterceptor(String scriptPath, String type)
| Parameters | Type | Description |
|---|---|---|
| scriptPath | string |
The relative path to the script file. |
| type | string |
The type of interceptor: prev or post. |
<%
uicomponent.addInterceptor("ecm-explorer/interceptor/PreNodeSaveInterceptor.groovy", "prev");
%>
To avoid refreshing the first tab for every action execution, add a new private function to the template with tabs. In the template, you must insert a new piece of code like the following:
private String getDisplayTab(String selectedTab) {
if ((uicomponent.getSelectedTab() == null && selectedTab.equals("mainWebcontent"))
|| selectedTab.equals(uicomponent.getSelectedTab())) {
return "display:block";
}
return "display:none";
}
private String getSelectedTab(String selectedTab) {
if (getDisplayTab(selectedTab).equals("display:block")) {
return "SelectedTab";
}
return "NormalTab";
}
Changing in every event of onClick must be done like the following:
<div class="UITab NormalTabStyle">
<div class="<%=getSelectedTab("mainWebcontent")%>
">
<div class="LeftTab">
<div class="RightTab">
<div class="MiddleTab" onClick="<%=uicomponent.event("ChangeTab", "mainWebcontent")%>"><%=_ctx.appRes("WebContent.dialog.label.MainContent")%></div>
</div>
</div>
</div>
</div>
<div class="UITab NormalTabStyle">
<div class="<%=getSelectedTab("illustrationWebcontent")%>
">
<div class="LeftTab">
<div class="RightTab">
<div class="MiddleTab" onClick="<%=uicomponent.event("ChangeTab", "illustrationWebcontent")%>"><%=_ctx.appRes("WebContent.dialog.label.Illustration")%></div>
</div>
</div>
</div>
</div>
<div class="UITab NormalTabStyle">
<div class="<%= getSelectedTab("contentCSSWebcontent")%>
">
<div class="LeftTab">
<div class="RightTab">
<div class="MiddleTab" onClick="<%=uicomponent.event("ChangeTab", "contentCSSWebcontent")%>"><%=_ctx.appRes("WebContent.dialog.label.Advanced")%></div>
</div>
</div>
</div>
</div>Finally, to display the selected tab, simply add it to the style of UITabContent class.
<div class="UITabContent" style="<%=getDisplayTab("mainWebcontent")%>">In the content management sytem, its typical feature is enabling JavaScript in a content. This causes the XSS (Cross-site Scripting) attacks to the content displayed in the HTML format.
However, there is no solution to keep JavaScript and to prevent the XSS attacks at the same time, so Content allows you to decide whether JavaScript is allowed to run on a field of the content template or not by using the option parameter.
To allow JavaScript to execute, add "options = noSanitization" to the dialog template file. Normally, this file is named dialog1.gtmpl.
For example: The following code shows how to enable JavaScript in the Main Content field of the Free Layout Wecontent content:
String [] htmlArguments = ["jcrPath = / node / default.html / JCR: content / JCR: data", "options = toolbar: CompleteWCM, height: '410px ', noSanitization" htmlContent];
By default, there is no "options = noSanitization" parameter in the dialog template file and this helps you prevent the XSS attacks. When end-users input JavaScript into a content, the JavaScript is automatically deleted when the content is saved.
The following is a sample code of the View template of a content node:
Get a content node to display:
<%
def node = uicomponent.getNode() ;
def originalNode = uicomponent.getOriginalNode()
%>
Display the name of the content node:
<%=node.getName()%>
Display the exo:title property of the content node:
<%
if(node.hasProperty("exo:title")) {
%>
<%=node.getProperty("exo:title").getString()%>
<%
}
%>
Display the exo:date property of the content node in a desired format. For example: "MM DD YYYY" or "YYYY MM DD".
<%
import java.text.SimpleDateFormat ;
SimpleDateFormat dateFormat = new SimpleDateFormat() ;
%>
...
<%
if(node.hasProperty("exo:date")) {
dateFormat.applyPattern("MMMMM dd yyyy") ;
%>
<%=dateFormat.format(node.getProperty("exo:date").getDate().getTime())%>
<%
}
%>
Display the translation of the Sample.view.label.node-name message in different languages.
<%=_ctx.appRes("Sample.view.label.node-name")%>
The Content List Template allows you to view the content list with various templates. eXo Platform supports the following content list templates:
| Template | Description |
|---|---|
| BigHotNewsTemplateCLV.gtmpl | Display contents under one column with a content list. The illustration of each content is displayed above the content. |
| ContentListViewerDefault.gtmpl | Its function is similar to BigHotNewsTemplateCLV.gtmpl. The illustration of each content is bigger. |
| DocumentsTemplate.gtmpl | Display contents under a content list with a NodeType icon or the illustration on the left of the corresponding content. |
| EventsTemplateCLV.gtmpl | Its function is similar to BigHotNewsTemplateCLV.gtmpl, but the illustration of each content is smaller. |
| OneColumnCLVTemplate.gtmpl | Display contents under one column. The illustration of each content is displayed on its left. |
| TwoColumnsCLVTemplate.gtmpl | Display contents under two columns. The illustration of each content is displayed on its left. |
| UIContentListPresentationBigImage.gtmpl | Its function is similar to BigHotNewsTemplateCLV.gtmpl, but the illustration of each content is bigger than the image displayed with ContentListViewerDefault.gtmpl and the text font is different. |
| UIContentListPresentationDefault.gtmpl | Its function is similar to BigHotNewsTemplateCLV.gtmpl, but the illustration of each content is smaller and the text font is different. |
| UIContentListPresentationSmall.gtmpl | Display contents under one column with a content list. The images are displayed on the left of the corresponding content and smaller than the images of the other templates. |
The Category Navigation Template displays all contents under the categories.
| Template | Description |
|---|---|
| CategoryList.gtmpl | Display categories as a navigation bar. |
| CategoryTree.gtmpl | Display categories as a tree. |
| TagsCloud.gtmpl | Display all tags of the contents. |
By using WCM, all the stylesheets of each site can be managed online easily. You do not need to access the file system to modify and wait until the server has been restarted. For the structure, each site has its own CSS folder which can contain one or more CSS files. These CSS files have the data, and the priority. If they have the same CSS definition, the higher priority will be applied. You can also disable some of them to make sure the disabled style will no longer be applied into the site.
For example, a WCM demo package has two sites by default: ACME and Classic. The Classic site has a CSS folder which contains a CSS file called DefaultStylesheet. Most of the stylesheets of this site are defined within this stylesheet. Moreover, the ACME site has two CSS files called BlueStylesheet and GreenStylesheet. The blue one is enabled and the green one is disabled by default. All you need to test is to disable the blue one (by editing it and setting Available to 'false') and enable the green one. Now, back to the homepage and see the magic.
Remember the cache and refresh the browser first if you do not see any changes. Normally, this is the main reason why the new style is not applied.
Basically, if you want to add a rich text area to your dialogs, you can use the addRichtextField method. However, in case you want to add the rich text editor manually, you first need to use the addTextAreaField method and some additional Javascripts as shown below:
<%
String[] fieldDescription = ["jcrPath=/node/exo:description"] ;
uicomponent.addTextAreaField("description", fieldDescription)
%>
<script>
var instances = CKEDITOR.instances['description'];
if (instances) instances.destroy(true);
CKEDITOR.replace('description', {
toolbar : 'CompleteWCM',
uiColor : '#9AB8F3'
});
</script>

See also
Introduction to Rest Services, and details (including HTTP Methods, formats, data format, REST configuration) of Restful Web Service, and how to create a REST service.
How to make your own ECMS UI Extensions
Instructions on how to make your own UI extension by creating the new action and its corresponding listener, registering with UIExtensionManager and running your UI extension sample. This section also provides information on filtering action with exsiting filters or creating your new filter.
Information about the extended publication plugin and publication manager.
Auxiliary attributes for documents
Details of how to create the DocumentContext which stores some auxiliary attributes of the document and helps document listeners make decision based on these attributes.
See also
REST-style architectures consist of clients and servers. Clients initiate requests to servers; servers process requests and return appropriate responses. Requests and responses are built around the transfer of "representations" of "resources". A resource can be essentially any coherent and meaningful concept that may be addressed. A representation of a resource is typically a document that captures the current or intended state of a resource.
At any particular time, a client can either be in transition between application states or "at rest". A client in a REST state is able to interact with its users, but creates no load and consumes no per-client storage on the set of servers or on the network.
The client begins sending requests when it is ready to make the transition to a new state. While one or more requests are outstanding, the client is considered to be in transition. The representation of each application state contains links that may be used the next time, the client chooses to initiate a new state transition.
REST is initially described in the context of HTTP, but is not limited to that protocol. RESTful architectures can be based on other Application Layer protocols if they already provide a rich and uniform vocabulary for applications based on the transfer of meaningful representational state. RESTful applications maximize the use of the pre-existing, well-defined interface and other built-in capabilities provided by the chosen network protocol, and minimize the addition of new application-specific features on its top.
This section provides you the following topics:
Here is the convention you should follow:
| Method | Definition |
|---|---|
| GET | Get a Resource. Its state should not be modified. |
| POST | Create a Resource (or anything that does not fit elsewhere). |
| PUT | Update a Resource. |
| DELETE | Delete a Resource. |
The followings are formats which need to be supported for all your APIs:
The default format is JSON.
The response format can be specified by a parameter in the request: "format". You need to specify the format requested.
First, you need to register the REST service class to the configuration file in the package named conf.portal.
<configuration xmlns="http://www.exoplaform.org/xml/ns/kernel_1_1.xsd" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://www.exoplaform.org/xml/ns/kernel_1_1.xsd http://www.exoplaform.org/xml/ns/kernel_1_1.xsd">
<component>
<type>org.exoplatform.services.ecm.publication.REST.presentation.document.publication.PublicationGetDocumentRESTService</type>
</component>
</configuration>
You can start creating GetEditedDocumentRESTService that implements from the ResourceContainer interface as follows:
@Path("/presentation/document/edit/")
public class GetEditedDocumentRESTService implements ResourceContainer {
@Path("/{repository}/")
@GET
public Response getLastEditedDoc(@PathParam("repository") String repository,
@QueryParam("showItems") String showItems) throws Exception {
........
}
}
| Parameters | Definition |
|---|---|
| @Path("/presentation/document/edit/") | Specify the URI path which a resource or class method will serve requests for. |
| @PathParam("repository") | Bind the value repository of a URI parameter or a path segment containing the template parameter to a resource method parameter, resource class field, or resource class bean property. |
| @QueryParam("showItems") | Bind the value showItems of a HTTP query parameter to a resource method parameter, resource class field, or resource class bean property. |
There are many places inside ECMS which are built basing on the UI Extensions framework as described in Extend eXo applications, so you can add your own actions packaged in external jars to them. They are:
Action bar

Side bar

Admin control panel

Context menu in the main working area

File viewer

This section shows you how to add own actions to the ECMS. In the following example, you are going to add a new action on the ECMS action toolbar to view the node path.
Follow the below process to add a new action to the action toolbar:
Create a new project for action extension
Create a Maven project which has the following directory structure:

Navigating in the project's folder, you will see the following structure:
pom.xml: The project's POM file.
src/main/java/.../ExampleActionComponent.java: A simple action supporting user to view the wiki markup of a page.
src/main/resources/conf/portal/configuration.xml: The configuration file to register your actions with the org.exoplatform.webui.ext.UIExtensionManager service.
Here is the content of the pom.xml file:
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<groupId>com.acme</groupId>
<artifactId>example</artifactId>
<version>1.0-SNAPSHOT</version>
<packaging>jar</packaging>
<name>example</name>
<url>ECMS action example</url>
<properties>
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
</properties>
<dependencies>
<dependency>
<groupId>org.exoplatform.portal</groupId>
<artifactId>exo.portal.webui.core</artifactId>
<version>3.2.5-PLF-SNAPSHOT</version>
<scope>provided</scope>
</dependency>
<dependency>
<groupId>org.exoplatform.commons</groupId>
<artifactId>exo.platform.commons.webui.ext</artifactId>
<version>1.1.9-SNAPSHOT</version>
<scope>provided</scope>
</dependency>
<dependency>
<groupId>org.exoplatform.ecms</groupId>
<artifactId>exo-ecms-core-webui-explorer</artifactId>
<version>2.3.8-SNAPSHOT</version>
</dependency>
</dependencies>
<build>
<plugins>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-compiler-plugin</artifactId>
<configuration>
<source>1.5</source>
<target>1.5</target>
</configuration>
</plugin>
</plugins>
</build>
</project>
Create new action and its corresponding listener
Edit the ExampleActionComponent class as below:
package com.acme;
import javax.jcr.Node;
import org.exoplatform.ecm.webui.component.explorer.UIJCRExplorer;
import org.exoplatform.ecm.webui.component.explorer.control.listener.UIActionBarActionListener;
import org.exoplatform.web.application.ApplicationMessage;
import org.exoplatform.webui.config.annotation.ComponentConfig;
import org.exoplatform.webui.config.annotation.EventConfig;
import org.exoplatform.webui.core.UIComponent;
import org.exoplatform.webui.event.Event;
@ComponentConfig(
events = { @EventConfig(listeners = ExampleComponent.ExampleActionListener.class)
})
public class ExampleComponent extends UIComponent {
public static class ExampleActionListener extends UIActionBarActionListener<ExampleComponent> {
@Override
protected void processEvent(Event<ExampleComponent> event) throws Exception {
UIJCRExplorer uiJCRExplorer = event.getSource().getAncestorOfType(UIJCRExplorer.class);
Node node = uiJCRExplorer.getCurrentNode();
event.getRequestContext()
.getUIApplication()
.addMessage(new ApplicationMessage("Node path:" node.getPath(), null, ApplicationMessage.INFO));
}
}
}
Register new action with UIExtensionManager
Edit the configuration.xml file as below:
<configuration xmlns="http://www.exoplatform.org/xml/ns/kernel_1_2.xsd" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://www.exoplatform.org/xml/ns/kernel_1_2.xsd http://www.exoplatform.org/xml/ns/kernel_1_2.xsd">
<external-component-plugins>
<target-component>org.exoplatform.webui.ext.UIExtensionManager</target-component>
<component-plugin>
<name>add.action</name>
<set-method>registerUIExtensionPlugin</set-method>
<type>org.exoplatform.webui.ext.UIExtensionPlugin</type>
<init-params>
<object-param>
<name>Example</name>
<object type="org.exoplatform.webui.ext.UIExtension">
<field name="type">
<string>org.exoplatform.ecm.dms.UIActionBar</string>
</field>
<field name="name">
<string>Example</string>
</field>
<field name="component">
<string>com.acme.ExampleComponent</string>
</field>
</object>
</object-param>
</init-params>
</component-plugin>
</external-component-plugins>
</configuration>
Follow these steps to deploy your new action extension:
1. Build the project by using the mvn clean install command.
2. Copy the target/example-1.0-SNAPSHOT.jar file into the TOMCAT-HOME/lib/ directory.
3. Run Tomcat and go to Content explorer.
4. Add the deployed action to the WCM View. You will get the results:



Define a label in ECM Administration
Edit the $TOMCAT-HOME/webapps/ecmadmin/WEB-INF/classes/locale/portlet/administration/ECMAdminPortlet_en.xml file (for English which is also the default language) and add the label as below:
...
<UIViewFormTabPane>
...
<label>
<example>Example action</example>
...
</label>
...
</UIViewFormTabPane>
...
Define a label in the File Explorer
Edit the $TOMCAT-HOME/webapps/ecmexplorer/WEB-INF/classes/locale/portlet/explorer/JCRExplorerPortlet_en.xml file (for English which is also the default language) and add the label as below:
...
<UIActionBar>
...
<tooltip>
<example>Example action</example>
...
</tooltip>
...
</UIActionBar>
...
Define Logos
Edit the $TOMCAT-HOME/webapps/ecmexplorer/skin/icons/24x24/DefaultStylesheet.css file (for the default Skin) and add the icon definition as below (in this case, the "ManageUnLock" icon is re-used but you could add your own picture into the $TOMCAT-HOME/webapps/ecmexplorer/skin/icons/24x24/DefaultSkin directory):
.ExampleIcon{
width: 24px; height: 24px;
background: url('DefaultSkin/ManageUnLock.gif') no-repeat left center; /* orientation=lt */
background: url('DefaultSkin/ManageUnLock.gif') no-repeat right center; /* orientation=rt */
}
With the UI Extension framework, you can use internal and external (existing) filters. The internal filters are parts of the business logic of your component. For example, if your component is only dedicated to articles, you will add an internal filter to your component that will check the type of the current document. The external filters are mainly used to add new filters that are not related to the business logic, to your component. A good example is the UserACLFilter which allows you to filter by access permissions.
It is very simple to apply a filter in an UI component:
public class ExampleComponent extends UIComponent {
private static final List<UIExtensionFilter> FILTERS = Arrays.asList(new UIExtensionFilter[] {new MyUIFilter()});
@UIExtensionFilters
public List<UIExtensionFilter> getFilters() {
return FILTERS;
}
...
There are many useful built-in filters in ECMS:
org.exoplatform.webui.ext.filter.impl.UserACLFilter: Filter all nodes that do not have any permission on the current context.
org.exoplatform.webui.ext.filter.impl.FileFilter: Filter all nodes that do not exist in the given MIME type list.
org.exoplatform.ecm.webui.component.explorer.control.filter: This package includes the following filters.
| Filters | Description |
|---|---|
CanAddCategoryFilter
|
Filter nodes to which it is impossible to add categories. |
CanCutNodeFilter
|
Filter nodes which cannot be cut. |
CanAddNodeFilter
|
Filter nodes to which it is impossible to add nodes. |
CanDeleteNodeFilter
|
Filter nodes that cannot be deleted. |
CanRemoveNodeFilter
|
Filter nodes that cannot be removed. |
CanEnableVersionFilter
|
Filter nodes which do not allow versioning. |
CanSetPropertyFilter
|
Filter nodes that cannot be modified. |
HasMetadataTemplatesFilter
|
Filter nodes that do not have metadata templates. |
HasPublicationLifecycleFilter
|
Filter all nodes that do not have the publication plugins. |
HasRemovePermissionFilter
|
Filter nodes that do not have the Remove permission. |
IsFavouriteFilter
|
Filter nodes that are not favorite. |
IsNotFavouriteFilter
|
Filter nodes that are favorite. |
IsNotNtFileFilter
|
Filter nodes that are of nt:file. |
IsHoldsLockFilter
|
Filter nodes which do not hold lock. |
IsNotHoldsLockFilter
|
Filter nodes which are holding lock. |
IsNotRootNodeFilter
|
Filter the root node. |
IsInTrashFilter
|
Filter nodes that are not in the trash node. |
IsNotInTrashFilter
|
Filter nodes that are in the trash node. |
IsNotSameNameSiblingFilter
|
Filter nodes that allow the same name siblings. |
IsMixCommentable
|
Filter nodes that do not allow commenting. |
IsMixVotable
|
Filter nodes that do not allow voting. |
IsNotSimpleLockedFilter
|
Filter nodes that are locked. |
IsNotSymlinkFilter
|
Filter nodes that are symlinks. |
IsNotCategoryFilter
|
Filter nodes that are of the category type. |
IsNotSystemWorkspaceFilter
|
Filter actions of the system-typed workspace. |
IsNotCheckedOutFilter
|
Filter nodes that are checked out. |
IsTrashHomeNodeFilter
|
Filter nodes that are not trash ones. |
IsNotTrashHomeNodeFilter
|
Filter a node that is the trash one. |
IsNotEditingDocumentFilter
|
Filter nodes that are being edited. |
IsPasteableFilter
|
Filter nodes where the paste action is not allowed. |
IsReferenceableNodeFilter
|
Filter nodes that do not allow adding references. |
IsNotFolderFilter
|
Filter nodes that are folders. |
IsCheckedOutFilter
|
Filter nodes that are not checked out. |
IsVersionableFilter
|
Filter nodes which do not allow versioning. |
IsVersionableOrAncestorFilter
|
Filter nodes and ancestor nodes which do not allow versioning. |
IsDocumentFilter
|
Filter nodes that are not documents. |
IsEditableFilter
|
Filter nodes that are not editable. |
Beside using existing ones, you can also create new filters. See the example code below:
public class MyUIFilter implements UIExtensionFilter {
/**
* This method checks if the current node is of the right type
*/
public boolean accept(Map<String, Object> context) throws Exception {
// Retrieve the current node from the context
Node currentNode = (Node) context.get(Node.class.getName());
return currentNode.isNodeType("exo:article");
}
/**
* This is the type of the filter
*/
public UIExtensionFilterType getType() {
return UIExtensionFilterType.MANDATORY;
}
/**
* This is called when the filter has failed
*/
public void onDeny(Map<String, Object> context) throws Exception {
System.out.println("This document has been rejected");
}
}
Working with other toolbars is quite similar to UIActionbar, except configurations and resources.
Side bar
Sample configuration
<object-param>
<name>Example</name>
<object type="org.exoplatform.webui.ext.UIExtension">
<field name="type"><string>org.exoplatform.ecm.dms.UISideBar</string></field>
<field name="name"><string>Example</string></field>
<field name="rank"><int>110</int></field>
<field name="component"><string>com.acme.ExampleActionComponent</string></field>
</object>
</object-param>
Resources are located at $TOMCAT-HOME/webapps/ecmexplorer/WEB-INF/classes/locale/portlet/explorer/JCRExplorerPortlet_en.xml (for English which is also the default language):
...
<UISideBar>
...
<label>
<example>Example action</example>
...
</label>
...
</UISideBar>
...
Admin control panel
Sample configuration
<object-param>
<name>Example</name>
<object type="org.exoplatform.webui.ext.UIExtension">
<field name="type"><string>org.exoplatform.ecm.dms.UIECMAdminControlPanel</string></field>
<field name="rank"><int>110</int></field>
<field name="name"><string>Example</string></field>
<field name="category"><string>Ontologies</string></field>
<field name="component"><string>com.acme.ExampleActionComponent</string></field>
</object>
</object-param>
The "category" field specifies the category where your extension action is performed. There are 4 options:
Ontology

ContentPresentation

Content Type

Advanced Configuration

Resources are located at $TOMCAT-HOME/webapps/ecmadmin/WEB-INF/classes/locale/portlet/administration/ECMAdminPortlet_en.xml (for English which is also the default language):
...
<UIECMAdminControlPanel>
...
<label>
<example>Example panel</example>
...
</label>
...
</UIECMAdminControlPanel>
...
Context menu
Sample configuration
<object-param>
<name>Example</name>
<object type="org.exoplatform.webui.ext.UIExtension">
<field name="type"><string>org.exoplatform.ecm.dms.UIWorkingArea</string></field>
<field name="rank"><int>105</int></field>
<field name="name"><string>Example</string></field>
<field name="category"><string>ItemContextMenu_SingleSelection</string></field>
<field name="component"><string>com.acme.ExampleActionComponent</string></field>
</object>
</object-param>
The "category" field specifies the category where your extension action is performed. There are many options:
ItemContextMenu_SingleSelection: This menu has only one item when Trash Folder is right-clicked.
ItemContextMenu: The menu appears when the user selects one or many items.
GroundContextMenu & ItemGroundContextMenu: The menu appears when the user right-clicks the ground of node.
Resources are located at $TOMCAT-HOME/webapps/ecmexplorer/WEB-INF/classes/locale/portlet/explorer/JCRExplorerPortlet_en.xml (for English which is also the default language):
<UIWorkingArea>
...
<label>
<example>Example action</example>
...
</label>
...
</UIWorkingArea>
File Viewer
Sample configuration
<object-param>
<name>Example</name>
<object type="org.exoplatform.webui.ext.UIExtension">
<field name="type"><string>org.exoplatform.ecm.dms.FileViewer</string></field>
<field name="rank"><int>100</int></field>
<field name="name"><string>Example</string></field>
<field name="category"><string>FileViewer</string></field>
<field name="component"><string>com.acme.ExampleActionComponent</string></field>
<field name="extendedFilters">
<collection type="java.util.ArrayList">
<value>
<object type="org.exoplatform.webui.ext.filter.impl.FileFilter">
<field name="mimeTypes">
<collection type="java.util.ArrayList">
<value><string>foo/bar</string></value>
</collection>
</field>
</object>
</value>
</collection>
</field>
</object>
</object-param>
Resources are located at $TOMCAT-HOME/webapps/ecm-wcm-extension/WEB-INF/classes/locale/ecm/views_en.xml (for English which is also the default language):
<File>
<view>
<example>Example view</example>
...
</view>
</File>
Details of an extended Publication plugin used to manage the lifecycles of documents in Content, including:
Information about new states and new profiles of the extended publication that are enabled in Content.
Introduction to new properties added to the new publication plugin that allows you to manage the content publication in a defined period.
Introduction to the new authoring mixin that supplies more information about the document creator.
Introduction to Publication Manager which manages lifecycles and contexts in Content and its details, including:
Sample code of lifecycle, information about 3 lifecycles, and instructions on how to listen to a lifecycle and to perform tasks when a content's state is updated.
Details of context, its sample code and rules.
Introduction to the new authoring mixin that supplies more information about the document creator, its sample code and details of querying based on publication status.
This section covers the following topics:
This extended publication has new states and new profiles that are enabled in Content.
Profiles
Author: This profile can edit a content and mark this content as redacted.
Approver: This profile approves a pending content (marked by the Author).
Publisher: This profile publishes contents or marks them as "Ready for publication" in multi-server mode.
Archiver: An administrative profile which moves contents to an archive storage.
States
enrolled: It is a pure technical state, generally used for content creation.
draft (Author): Content is in editing phase.
pending (Author): The author validates the content.
approved (Approver): A content is approved by the manager.
inreview (Manager): This state can be used when a second approval state is needed (for i18 translation for example).
staged (Publisher): A content is ready for publication (multi-server mode).
published (Publisher or Automatic): A content is published and visible in the Live mode.
unpublished (Publisher or Automatic): A content is not visible in the Live mode.
obsolete: A content can still be published but it is not in an editing lifecycle anymore.
archived (Automatic): A content is archived and ready to be moved in the archive workspace if enabled.
In most cases, you do not want to publish a content directly, but at a defined date and you can also want the content to be unpublished automatically after that. New properties are added to the new publication plugin, that allows you to manage this:
publication:startPublishedDate
publication:endPublishedDate
The Content rendering engine does not know anything about publication dates, so another service needs to manage that. When the publisher sets start/end publication dates, he can "stage" the content. The content will go automatically to the "published" state when the start date arrives and to the "unpublished" state after end date. A cron job checks every hour (or less) all contents which need to be published (the start date in the past and the "staged" state) or unpublished (the end date in the past and the "published" state).
Thus, the publication dates are not mandatory and a content can go to:
Staged: in multi-server mode, the publisher can only put the content to the "staged" state and wait for auto-publication.
Published: in single-server mode, the publisher can directly publish a content (with or without publication dates).
<nodeType hasOrderableChildNodes="false" isMixin="true" name="publication:authoringPublication" primaryItemName="">
<supertypes>
<supertype>publication:stateAndVersionBasedPublication</supertype>
</supertypes>
<propertyDefinitions>
<propertyDefinition autoCreated="false" mandatory="true" multiple="false" name="publication:startPublishedDate" onParentVersion="IGNORE" protected="false" requiredType="Date">
<valueConstraints/>
</propertyDefinition>
<propertyDefinition autoCreated="false" mandatory="true" multiple="false" name="publication:endPublishedDate" onParentVersion="IGNORE" protected="false" requiredType="Date">
<valueConstraints/>
</propertyDefinition>
</propertyDefinitions>
</nodeType>
Note that some labels containing special or non-ASCII characters could not be well displayed in the publication UI. You can extend the width of the current UI State button by adding:
.UIPublicationPanel .StatusTable .ActiveStatus {
width: 75px !important;
}Also, for the publication date inputs, UIPublicationPanel should not initialize the dates to any default value. The publishing and unpublish CRON jobs will do this:
A staged document with null publication start date is published instantly.
A document with null publication end date is published forever.
See the export section for more information about the CRON jobs.
The Publication Manager manages lifecycles and contexts in the Content platform. It allows managing different lifecycles based on different publication plugin in the platform.
public interface PublicationManager {
public List<Lifecycle> getLifecycles();
public List<Context> getContexts();
public Context getContext(String name);
public Lifecycle getLifecycle(String name);
public List<Lifecycle> getLifecyclesFromUser(String remoteUser, String state);
}
In which:
getLifecycles: returns a list of lifecycles (see below), with lifecycle name, publication plugin involved and possible states.
getContexts: returns a list of context, with name, related Lifecycle and other properties (see below).
getContext: returns a context by its name.
getLifecycle: returns a lifecycle by its name.
getLifecycleFromUser: returns a list of lifecycles in which the user has rights (based on membership property).
A lifecycle is defined by a simple vertical workflow with steps (states) and profiles (membership). Each lifecycle is related to a Publication plugin (compliant with the JBPM or Bonita business processes).
For example: Two lifecycles with/without states
<external-component-plugins>
<target-component>org.exoplatform.services.wcm.extensions.publication.PublicationManager</target-component>
<component-plugin>
<name>AddLifecycle</name>
<set-method>addLifecycle</set-method>
<type>org.exoplatform.services.wcm.extensions.publication.lifecycle.StatesLifecyclePlugin</type>
<init-params>
<object-param>
<name>lifecycles</name>
<object type="org.exoplatform.services.wcm.extensions.publication.lifecycle.impl.LifecyclesConfig">
<field name="lifecycles">
<collection type="java.util.ArrayList">
<value>
<object type="org.exoplatform.services.wcm.extensions.publication.lifecycle.impl.LifecyclesConfig$Lifecycle">
<field name="name">
<string>lifecycle1</string>
</field>
<field name="publicationPlugin">
<string>States and versions based publication</string>
</field>
</object>
</value>
<value>
<object type="org.exoplatform.services.wcm.extensions.publication.lifecycle.impl.LifecyclesConfig$Lifecycle">
<field name="name">
<string>lifecycle2</string>
</field>
<field name="publicationPlugin">
<string>Authoring publication</string>
</field>
<field name="states">
<collection type="java.util.ArrayList">
<value>
<object type="org.exoplatform.services.wcm.extensions.publication.lifecycle.impl.LifecyclesConfig$State">
<field name="state">
<string>draft</string>
</field>
<field name="memberships">
<collection type="java.util.ArrayList">
<value>
<string>author:/communication</string>
</value>
<value>
<string>author:/sanitaryAlert</string>
</value>
<value>
<string>author:/informations</string>
</value>
</collection>
</field>
</object>
</value>
<value>
<object type="org.exoplatform.services.wcm.extensions.publication.lifecycle.impl.LifecyclesConfig$State">
<field name="state">
<string>pending</string>
</field>
<field name="membership">
<string>author:/platform/web-contributors</string>
</field>
</object>
</value>
<value>
<object type="org.exoplatform.services.wcm.extensions.publication.lifecycle.impl.LifecyclesConfig$State">
<field name="state">
<string>approved</string>
</field>
<field name="membership">
<string>manager:/platform/web-contributors</string>
</field>
</object>
</value>
<value>
<object type="org.exoplatform.services.wcm.extensions.publication.lifecycle.impl.LifecyclesConfig$State">
<field name="state">
<string>staged</string>
</field>
<field name="membership">
<string>publisher:/platform/web-contributors</string>
</field>
</object>
</value>
<value>
<object type="org.exoplatform.services.wcm.extensions.publication.lifecycle.impl.LifecyclesConfig$State">
<field name="state">
<string>published</string>
</field>
<field name="membership">
<string>automatic</string>
</field>
</object>
</value>
</collection>
</field>
</object>
</value>
<value>
<object type="org.exoplatform.services.wcm.extensions.publication.lifecycle.impl.LifecyclesConfig$Lifecycle">
<field name="name">
<string>lifecycle3</string>
</field>
<field name="publicationPlugin">
<string>Authoring publication</string>
</field>
<field name="states">
<collection type="java.util.ArrayList">
<value>
<object type="org.exoplatform.services.wcm.extensions.publication.lifecycle.impl.LifecyclesConfig$State">
<field name="state">
<string>draft</string>
</field>
<field name="membership">
<string>author:/platform/web-contributors</string>
</field>
</object>
</value>
<value>
<object type="org.exoplatform.services.wcm.extensions.publication.lifecycle.impl.LifecyclesConfig$State">
<field name="state">
<string>published</string>
</field>
<field name="memberships">
<collection type="java.util.ArrayList">
<value>
<string>publisher:/communication</string>
</value>
<value>
<string>publisher:/sanitaryAlert</string>
</value>
<value>
<string>publisher:/informations</string>
</value>
</collection>
</field>
</object>
</value>
</collection>
</field>
</object>
</value>
</collection>
</field>
</object>
</object-param>
</init-params>
</component-plugin>
</external-component-plugins>
In the last example, there are three lifecycles:
Lifecycle 1: Based on StatesAndVersionsPublicationPlugin .
This allows to be backward compliant with older Content releases. If all your site contents are using an existing plugin, you can create a lifecycle for it and it will work.
For new instances, you should use the new plugin with dynamic states capabilities.
Lifecycle 2: Based on AuthoringPublicationPlugin .
Visibility: Define only the "visible" steps. In this example, there is no step for "enrolled". Even if this step exists, it will not be displayed in the UI.
Automatic: Set a step as "automatic". In this mode, the step will be visible in the UI but it will be managed by the system (e.g. a cron job).
Lifecycle 3: Simulates the StatesAndVersionsPublicationPlugin plugin. Note that this simple lifecycle will work in a single server configuration.
When a state is changed, you can broadcast an event to add features. The event could look like this:
listenerService.broadcast(AuthoringPlugin.POST_UPDATE_STATE_EVENT, null, node);
Listener declaration could look like this:
<external-component-plugins>
<target-component>org.exoplatform.services.listener.ListenerService</target-component>
<component-plugin>
<name>PublicationService.event.postUpdateState</name>
<set-method>addListener</set-method>
<type>org.exoplatform.services.wcm.extensions.publication.listener.post.PostUpdateStateEventListener</type>
<description>this listener will be called every time a content changes its current state</description>
</component-plugin>
</external-component-plugins>
To perform some tasks when a content's state is updated, you need to create a listener that handles the task and configure it. Following is the general configuration:
<external-component-plugins>
<target-component>org.exoplatform.services.listener.ListenerService</target-component>
<component-plugin>
<name>PublicationService.event.postUpdateState</name>
<set-method>addListener</set-method>
<type>my.package.MyListener</type>
<description>Your listener description</description>
</component-plugin>
</external-component-plugins>
With this configuration, your listener my.package.MyListener will be executed each time a content's state is changed.
For example, eXo provides a listener which automatically sends email notifications about the new state to all users of defined groups: org.exoplatform.wcm.authoring.listener.PostUpdateStateEventListener. So, the configuration will be:
<external-component-plugins>
<target-component>org.exoplatform.services.listener.ListenerService</target-component>
<component-plugin>
<name>PublicationService.event.postUpdateState</name>
<set-method>addListener</set-method>
<type>org.exoplatform.wcm.authoring.listener.PostUpdateStateEventListener</type>
<description>This listener will send a mail when there are changes in a content's state</description>
</component-plugin>
</external-component-plugins>
A context is defined by simple rules. In Content, you can select to enroll the content in a specific lifecycle (for example, publication plugin) based on context parameters. There are three parameters used to define contexts:
Remote User: The current user who can create/edit the content.
Current site name: The site from where the content is created (not the storage but the navigation).
Node: The node which you want to enroll.
From these parameters, you can easily connect and define contexts based on:
Membership: Does the current user have this membership?
Site: On this particular site, you want to enroll contents in a specific lifecycle.
Path: You can enroll contents in the lifecycles based on their path (from the Node).
Type of content: You can enroll contents in the lifecycles based on their nodetype (from the Node).
Because each site has a content storage (categories + physical storage), you can select the right lifecycle for the right storage/site. To avoid conflicts on contexts, you can set a priority (the less is the best).
For example, Different Contexts:
<external-component-plugins>
<target-component>org.exoplatform.services.wcm.extensions.publication.PublicationManager</target-component>
<component-plugin>
<name>AddContext</name>
<set-method>addContext</set-method>
<type>org.exoplatform.services.wcm.extensions.publication.context.ContextPlugin</type>
<init-params>
<object-param>
<name>contexts</name>
<object type="org.exoplatform.services.wcm.extensions.publication.context.impl.ContextConfig">
<field name="contexts">
<collection type="java.util.ArrayList">
<value>
<object type="org.exoplatform.services.wcm.extensions.publication.context.impl.ContextConfig$Context">
<field name="name">
<string>contextdefault</string>
</field>
<field name="priority">
<string>200</string>
</field>
<field name="lifecycle">
<string>lifecycle1</string>
</field>
</object>
<object type="org.exoplatform.services.wcm.extensions.publication.context.impl.ContextConfig$Context">
<field name="name">
<string>context1</string>
</field>
<field name="priority">
<string>100</string>
</field>
<field name="lifecycle">
<string>lifecycle1</string>
</field>
<field name="membership">
<string>*:/platform/web-contributors</string>
</field>
<field name="site">
<string>acme</string>
</field>
<field name="path">
<string>repository:collaboration:/sites content/live/acme/categories</string>
</field>
</object>
<object type="org.exoplatform.services.wcm.extensions.publication.context.impl.ContextConfig$Context">
<field name="name">
<string>context2</string>
</field>
<field name="priority">
<string>100</string>
</field>
<field name="lifecycle">
<string>lifecycle1</string>
</field>
<field name="site">
<string>classic</string>
</field>
</object>
<object type="org.exoplatform.services.wcm.extensions.publication.context.impl.ContextConfig$Context">
<field name="name">
<string>context3</string>
</field>
<field name="priority">
<string>80</string>
</field>
<field name="lifecycle">
<string>lifecycle3</string>
</field>
<field name="membership">
<string>manager:/company/finances</string>
</field>
<field name="path">
<string>repository:collaboration:/documents/company/finances</string>
</field>
</object>
<object type="org.exoplatform.services.wcm.extensions.publication.context.impl.ContextConfig$Context">
<field name="name">
<string>context4</string>
</field>
<field name="priority">
<string>50</string>
</field>
<field name="lifecycle">
<string>lifecycle4</string>
</field>
<field name="memberships">
<collection type="java.util.ArrayList">
<value>
<string>manager:/communication</string>
</value>
<value>
<string>manager:/sanitaryAlert</string>
</value>
<value>
<string>manager:/informations</string>
</value>
</collection>
</field>
<field name="path">
<string>repository:collaboration:/documents/company/finances</string>
</field>
<field name="nodetype">
<string>exo:article</string>
</field>
</object>
</value>
</collection>
</field>
</object>
</object-param>
</init-params>
</component-plugin>
</external-component-plugins>
The logic is very simple. When creating a content, it should be attached a lifecycle with the lifecycle priority:
context4 is the most important (priority=50): you will enroll the content in the lifecycle "lifecycle4" if:
The content creator has the manager:/company/finances membership.
The content is stored in repository:collaboration:/documents/company/finances or any subfolders.
The content is a 'exo:article'.
If not, you will continue with context3.
The contexts will be used only when the content is created and when you want to enroll it in a lifecycle for the first time. Once you have the corresponding lifecycle, you will set the lifecycle inside the content (see New Authoring Mixin) and the context service will not be called again for this content.
<nodeType hasOrderableChildNodes="false" isMixin="true" name="publication:authoring" primaryItemName="">
<propertyDefinitions>
<propertyDefinition autoCreated="false" mandatory="false" multiple="false" name="publication:lastUser" onParentVersion="IGNORE" protected="false" requiredType="String">
<valueConstraints/>
</propertyDefinition>
<propertyDefinition autoCreated="false" mandatory="false" multiple="false" name="publication:lifecycle" onParentVersion="IGNORE" protected="false" requiredType="String">
<valueConstraints/>
</propertyDefinition>
</propertyDefinitions>
</nodeType>
When adding the content in a lifecycle, set the publication:lifecycle_ property with the corresponding lifecycle.
A content can be in one lifecycle only.
Each time you change from one state to another, set the user who changed the state in publication:lastUser.
Querying based on publication status:
By adding this mixin to contents, you can access contents by simple queries based on the current user profile. For example:
All your draft contents:
query: select * from nt:base where publication:currentState"draft" and publication:lastUser="benjamin".
All the contents you have to approve.
call: PublicationManager.getLifecycles('benjamin','approved') => returns lifecycles where you can go to the 'approved' state.
query: select * from nt:base where publication:currentState="pending" and publication:lifecycle="lifecycle1" or publication:lifecycle="lifecycle3".
All the content that will be published tomorrow.
query: select * from nt:base where publication:currentState="staged" and publication:startPublishedDate="xxxx".
By default, your activities, such as writing a document, and uploading a file, are published on the activity stream. However, you can decide to publish these activities or not by creating a context named DocumentContext for a specific document. This context stores some auxiliary attributes of the document and helps document listeners make decision based on these attributes.
This context looks like:
public class DocumentContext {
private static ThreadLocal<DocumentContext> current = new ThreadLocal<DocumentContext>();
public static DocumentContext getCurrent() {
if (current.get() == null) {
setCurrent(new DocumentContext());
}
return current.get();
}
....
//Each time, attributes are able to set and got via:
/**
* @return the attributes
*/
public HashMap<String, Object> getAttributes() {
return attributes;
}
/**
* @param attributes the attributes to set
*/
public void setAttributes(HashMap<String, Object> attributes) {
this.attributes = attributes;
}
}
For example:
When you upload a document to a drive by using ManageDocumentService, but do not want to publish this activity on the activity stream, you can do as follows:
DocumentContext.getCurrent().getAttributes().put(DocumentContext.IS_SKIP_RAISE_ACT, true);
Then, this activity is skipped at:
Object isSkipRaiseAct = DocumentContext.getCurrent().getAttributes().get(DocumentContext.IS_SKIP_RAISE_ACT);
if (isSkipRaiseAct != null && Boolean.valueOf(isSkipRaiseAct.toString())) {
return;
}
The DocumentContext class is able to help developers manage various kinds of actions with a document based on its auxiliary attributes. You can be free to define new attributes for yourself.
Example of using Java to login to repository.
List of documents (folder, files)
Description about the usage of several methods to get the documents lists, such as getChildren(), getFolderTree() and getDescentants().
Read document properties and content-stream
Instructions on how to read and get the document properties and content stream.
Search of data and syntax examples
Examples of using Java and Javascript to search for data and syntax in CMIS.
Modification of document properties or content
Instructions on how to use Java and Javascript to update and get document properties or content in CMIS.
The examples of the CMIS usage may be useful for developers who need to access a repository. CMIS access code snippets are built using Apache HTTP Client for Java, or using Google gadgets (gadgets.io) for JavaScript examples. For examples of CURL, visit http://code.google.com/p/xcmis/wiki/xCMISusesWithCurl.
See also
The CMIS service uses the default authentication in general case, but it can be overridden in case of embedding CMIS into an Application Service. In these examples, only the Basic HTTP authentication is covered.
import org.apache.commons.httpclient.HttpClient;
import org.apache.commons.httpclient.UsernamePasswordCredentials;
import org.apache.commons.httpclient.auth.AuthScope;
import org.apache.commons.httpclient.methods.GetMethod;
HttpClient client = new HttpClient();
client.getState().setCredentials(
new AuthScope("localhost", 8080, "realm"),
new UsernamePasswordCredentials("root", "exo");
....
There are several methods to get the documents lists, such as getChildren(), getFolderTree() and getDescentants(), their usage will be described below. The difference between them is the usage of different URL segments to get data ("/children" for getChildren(), "/foldertree" for getFolderTree(), "/descendants" for getDescentants()), and a different kind of results (getChildren() returns a flat structure, while a getFolderTree() and getDescentants() have a tree of items in response).
import org.apache.commons.httpclient.HttpClient;
import org.apache.commons.httpclient.methods.GetMethod;
import org.apache.commons.httpclient.MultiThreadedHttpConnectionManager;
String url = "http://localhost:8080/rest/private/cmisatom/";
url += repository;
url += "/children/";
url += obj_id;
HttpClient client = new HttpClient(new MultiThreadedHttpConnectionManager());
client.getHttpConnectionManager().
getParams().setConnectionTimeout(10000);
GetMethod get = new GetMethod(url);
try {
int result = client.executeMethod(get);
final String strResponse = get.getResponseBodyAsString();
} finally {
get.releaseConnection();
}
Creating an URL to make a request (consists of repository name, the method name, for example "/children/", and folderID to get children from):
var url = "http://localhost:8080/rest/private/cmisatom/";
url += repository;
url += "/children/";
url += obj_id;
Performing request:
var params = {};
params[gadgets.io.RequestParameters.METHOD] = gadgets.io.MethodType.GET;
params[gadgets.io.RequestParameters.CONTENT_TYPE] = gadgets.io.ContentType.FEED;
gadgets.io.makeRequest(url, handler, params);
Processing results (the code is located in the handler is specified while making a request, the same way it might be used for all examples in this chapter):
var handler = function(resp) {
var data = eval(resp.data.Entry);
for (var i = 0; i < data.length; i++) {
var doc = data[i];
alert(doc.Title);
alert(doc.Date);
...etc..
}
}
Reading the Document properties and content stream are two separate operations. Getting the content stream is possible after the properties set have been read and the content stream ID was extracted from it.
Get document properties.
import org.apache.commons.httpclient.HttpClient;
import org.apache.commons.httpclient.methods.GetMethod;
import org.apache.commons.httpclient.MultiThreadedHttpConnectionManager;
String url = "http://localhost:8080/rest/private/cmisatom/";
url += repository;
url += "/object/";
url += obj_id;
HttpClient client = new HttpClient(new MultiThreadedHttpConnectionManager());
client.getHttpConnectionManager().
getParams().setConnectionTimeout(10000);
GetMethod get = new GetMethod(url);
try {
int result = client.executeMethod(get);
final String strResponse = get.getResponseBodyAsString();
// use response...
} finally {
get.releaseConnection();
}
Get document content-stream.
To get the Document's content stream, an URL must contain "/file" part, object ID, and optionally the content stream ID, which can be used, for example, to obtain renditions. If no stream ID is specified, the default stream will be returned.
import org.apache.commons.httpclient.HttpClient;
import org.apache.commons.httpclient.methods.PostMethod;
String url = "http://localhost:8080/rest/private/cmisatom/";
url += repository;
url += "/file/";
url += obj_id;
//Optionally
url += "?";
url += "streamid=";
url += streamID;
HttpClient client = new HttpClient();
client.getHttpConnectionManager().
getParams().setConnectionTimeout(10000);
GetMethod get = new GetMethod(url);
try {
int result = client.executeMethod(get);
final InputStream stream = get.getResponseBodyAsStream();
try {
// use stream...
int dataByte = stream.read();
} finally {
stream.close();
}
} finally {
get.releaseConnection();
}
Get document properties.
Creating an URL to make a request (consists of repository name, method name, for example "/children/", and folder ID to get the children from):
var url = "http://localhost:8080/rest/private/cmisatom/";
url += repository;
url += "/object/";
url += obj_id;
Performing request:
var params = {};
params[gadgets.io.RequestParameters.METHOD] = gadgets.io.MethodType.GET;
params[gadgets.io.RequestParameters.CONTENT_TYPE] = gadgets.io.ContentType.FEED;
gadgets.io.makeRequest(url, handler, params);
You can also use the ContentType.DOM parameter to parse the feed in your application (Using DOMParser for example).
Get document content-stream.
Performing a content stream request in JavaScript will cause the browser dialog for a file download.
var url = "http://localhost:8080/rest/private/cmisatom/";
url += repository;
url += "/file/";
url += obj_id;
//Optionally
url += "?";
url += "streamid=";
url += streamID;
CMIS supports SQL queries for more handful content search. Query service can handle both GET and POST requests. URL for query consists of repository name and method name "/query". The GET request must contain query as a parameter named "q", in case of POST request query must be located in a request body.
For more detailed instructions how to construct queries, refer to the Query examples chapter.
import org.apache.commons.httpclient.HttpClient;
import org.apache.commons.httpclient.methods.PostMethod;
import org.apache.commons.httpclient.methods.StringRequestEntity;
String url = "http://localhost:8080/rest/private/cmisatom/";
url += repository;
url += "/query/";
HttpClient client = new HttpClient();
client.getHttpConnectionManager().
getParams().setConnectionTimeout(10000);
PostMethod post = new PostMethod(url);
String s = "<?xml version='1.0' encoding='utf-8'?>"
+ "<cmis:query xmlns='http://www.w3.org/2005/Atom' xmlns:cmis='http://docs.oasis-open.org/ns/cmis/core/200908/'>"
+ "<cmis:statement>SELECT * FROM cmis:document</cmis:statement>"
+ "<cmis:maxItems>10</cmis:maxItems>"
+ "<cmis:skipCount>0</cmis:skipCount>"
+ "<cmis:searchAllVersions>true</cmis:searchAllVersions>"
+ "<cmis:includeAllowableActions>true</cmis:includeAllowableActions>"
+ "</cmis:query>";
RequestEntity entity = new StringRequestEntity(s, "text/xml","utf-8");
try {
post.setRequestEntity(entity);
int result = client.executeMethod(post);
final String strResponse = post.getResponseBodyAsString();
// use response...
} finally {
post.releaseConnection();
}
var url = "http://localhost:8080/rest/private/cmisatom/";
url += repository;
url += "/query/";
var params = {};
params[gadgets.io.RequestParameters.METHOD] = gadgets.io.MethodType.POST;
params[gadgets.io.RequestParameters.POST_DATA] = gadgets.io.encodeValues(someQuery);
gadgets.io.makeRequest(url, handler, params);
The command of property update uses PUT method. The URL is the same as the one for reading properties, the difference is only in the HTTP method used. The body of the request must be an Atom document with specified properties (see spec. 2.2.4.12 for detailed constructing document).
Sending of content stream can be executed via PUT or POST requests. Content-type of the request must be an "multipart/form-data".
Update properties:
import org.apache.commons.httpclient.HttpClient;
import org.apache.commons.httpclient.methods.StringRequestEntity;
import org.apache.commons.httpclient.methods.PostMethod;
import org.apache.commons.httpclient.methods.RequestEntity;
String url = "http://localhost:8080/rest/private/cmisatom/";
url += repository;
url += "/object/";
url += obj_id;
HttpClient client = new HttpClient();
client.getHttpConnectionManager().
getParams().setConnectionTimeout(10000);
String atomDoc = "<?xml version='1.0' encoding='utf-8'?>"
+ "<entry xmlns='http://www.w3.org/2005/Atom'"
+ " xmlns:cmis='http://docs.oasis-open.org/ns/cmis/core/200908/'"
+ " xmlns:cmisra='http://docs.oasis-open.org/ns/cmis/restatom/200908/'>"
+ "<cmisra:object><cmis:properties>"
+ "<cmis:propertyString queryName='cmis:name' localName='cmis:name' propertyDefinitionId='cmis:name'>"
+ "<cmis:value>newName</cmis:value>"
+ "</cmis:propertyString>"
+ "</cmis:properties></cmisra:object>"
+ "</entry>";
PutMethod put = new PutMethod(url);
RequestEntity entity = new StringRequestEntity(atomDoc, "text/xml", "utf-8");
put.setRequestEntity(entity);
try {
int result = client.executeMethod(put);
final String strResponse = put.getResponseBodyAsString();
} finally {
put.releaseConnection();
}
Set content stream:
import org.apache.commons.httpclient.HttpClient;
import org.apache.commons.httpclient.methods.InputStreamRequestEntity;
import org.apache.commons.httpclient.methods.PostMethod;
import org.apache.commons.httpclient.methods.RequestEntity;
String url = "http://localhost:8080/rest/private/cmisatom/";
url += repository;
url += "/file/";
url += obj_id;
HttpClient client = new HttpClient();
client.getHttpConnectionManager().
getParams().setConnectionTimeout(10000);
PostMethod post = new PostMethod(url);
RequestEntity entity = new InputStreamRequestEntity(inputStream, "text/xml; charset=ISO-8859-1");
post.setRequestEntity(entity);
try {
int result = client.executeMethod(post);
final String strResponse = post.getResponseBodyAsString();
} finally {
post.releaseConnection();
}
Update properties:
var url = "http://localhost:8080/rest/private/cmisatom/";
url += repository;
url += "/object/";
url += obj_id;
//constructing document
String atomDoc = "<?xml version='1.0' encoding='utf-8'?>";
atomDoc += "<entry xmlns='http://www.w3.org/2005/Atom'";
atomDoc += " xmlns:cmis='http://docs.oasis-open.org/ns/cmis/core/200908/'";
atomDoc += " xmlns:cmisra='http://docs.oasis-open.org/ns/cmis/restatom/200908/'>";
atomDoc += "<cmisra:object><cmis:properties>";
atomDoc += "<cmis:propertyString queryName='cmis:name' localName='cmis:name' propertyDefinitionId='cmis:name'>";
atomDoc += "<cmis:value>newName</cmis:value>";
atomDoc += "</cmis:propertyString>";
atomDoc += "</cmis:properties></cmisra:object></entry>";
var params = {};
params[gadgets.io.RequestParameters.METHOD] = gadgets.io.MethodType.PUT;
params[gadgets.io.RequestParameters.POST_DATA] = atomDoc;
gadgets.io.makeRequest(url, handler, params);
Set content stream:
var url = "http://localhost:8080/rest/private/cmisatom/";
url += repository;
url += "/file/";
url += obj_id;
var params = {};
params[gadgets.io.RequestParameters.METHOD] = gadgets.io.MethodType.POST;
params[gadgets.io.RequestParameters.CONTENT_TYPE] = "multipart/form-data";
params[gadgets.io.RequestParameters.POST_DATA] = contentStream;
gadgets.io.makeRequest(url, handler, params);
Return a responding data as a thumbnail image.
Generate an RSS feed.
Get a list of files and folders, and create a folder and upload files.
Get the bundle basing on the key and the locale.
Return and set a vote value of a given node in the sent parameter.
Return a drive list, a folder list and a document list in a specified location for a given user. Also, it processes the file uploading action.
Instantiate a new gadget connector.
Return a page URI for a given location.
Return the latest edited documents.
PublicationGetDocumentRESTService
Return a list of published documents.
Return a list of favorite documents of a given user.
Get the image binary data of a given image node.
Return a list of contents in a given state range of the publication lifecycle.
Copy a file.
Return the PDF content to display on the web page
Allow performing some actions on a folder or a file, such as creating, deleting a folder/file, or uploading a file.
Enable downloading the content of nt:file.
See also
| Resource | Description |
|---|---|
| GET /medium/{repoName}/{workspaceName}/{nodePath:.*}/ | Return an image at a medium size (64x64). For example: /portal/rest/thumbnailImage/medium/repository/collaboration/test.gif/ |
| GET /big/{repoName}/{workspaceName}/{nodePath:.*}/ | Return an image at a big size. |
| GET /large/{repoName}/{workspaceName}/{nodePath:.*}/ | Return an image at a large size (300x300). |
| GET /small/{repoName}/{workspaceName}/{nodePath:.*}/ | Return an image at a small size (32x32). |
| GET /custom/{size}/{repoName}/{workspaceName}/{nodePath:.*}/ | Return an image at a custom size. |
| GET /origin/{repoName}/{workspaceName}/{nodePath:.*}/ | Return an image at an original size. |
Return an image at a medium size (64x64). For example: /portal/rest/thumbnailImage/medium/repository/collaboration/test.gif/
URL:
http://{domain_name}/{rest_context_name}/private/thumbnailImage/medium/{repoName}/{workspaceName}/{nodePath:.*}/
Parameters:
Required (path parameters):
| Parameter | Description |
|---|---|
| repoName | The name of repository. |
| workspaceName | The name of workspace. |
| nodePath | The node path. |
Optional (query parameters): No
Return an image at a big size.
URL:
http://{domain_name}/{rest_context_name}/private/thumbnailImage/big/{repoName}/{workspaceName}/{nodePath:.*}/
Parameters:
Required (path parameters):
| Parameter | Description |
|---|---|
| repoName | The name of repository. |
| workspaceName | The name of workspace. |
| nodePath | The node path. |
Optional (query parameters): No
Return an image at a large size (300x300).
URL:
http://{domain_name}/{rest_context_name}/private/thumbnailImage/large/{repoName}/{workspaceName}/{nodePath:.*}/
Parameters:
Required (path parameters):
| Parameter | Description |
|---|---|
| repoName | The name of repository. |
| workspaceName | The name of workspace. |
| nodePath | The node path. |
Optional (query parameters): No
Return an image at a small size (32x32).
URL:
http://{domain_name}/{rest_context_name}/private/thumbnailImage/small/{repoName}/{workspaceName}/{nodePath:.*}/
Parameters:
Required (path parameters):
| Parameter | Description |
|---|---|
| repoName | The name of repository. |
| workspaceName | The name of workspace. |
| nodePath | The node path. |
Optional (query parameters): No
Return an image at a custom size.
URL:
http://{domain_name}/{rest_context_name}/private/thumbnailImage/custom/{size}/{repoName}/{workspaceName}/{nodePath:.*}/
Parameters:
Required (path parameters):
| Parameter | Description |
|---|---|
| size | The customized size of the image. |
| repoName | The name of repository. |
| workspaceName | The name of workspace. |
| nodePath | The node path. |
Optional (query parameters): No
Return an image at an original size.
URL:
http://{domain_name}/{rest_context_name}/private/thumbnailImage/origin/{repoName}/{workspaceName}/{nodePath:.*}/
Parameters:
Required (path parameters):
| Parameter | Description |
|---|---|
| repoName | The name of repository. |
| workspaceName | The name of workspace. |
| nodePath | The node path. |
Optional (query parameters): No
| Resource | Description |
|---|---|
| GET /rss/ | Generate an RSS feed. |
Generate an RSS feed.
URL:
http://{domain_name}/{rest_context_name}/private/feed/rss/
Parameters:
Required (path parameters): No
Optional (query parameters):
| Parameter | Description |
|---|---|
| repository | The name of repository. |
| workspace | The name of workspace. |
| server | The server. |
| siteName | The name of site. |
| title | The title of the feed. |
| desc | The description of the feed. |
| folderPath | The folder path of the feed. |
| orderBy | The criteria to order the content. |
| orderType | The descending or ascending order. |
| lang | The language of the feed. |
| detailPage | The page used to open the content. |
| detailParam | The parameters is the key in the URL to let CLV know which really is the path in the current URL. |
| recursive | This param is deprecated and will be moved soon. |
| Resource | Description |
|---|---|
| GET /getFoldersAndFiles/ | Return folders and files in the current folder. |
| GET /createFolder/ | Create a folder under the current folder. |
| POST /uploadFile/upload/ | Upload a file with the HttpServletRequest. |
| GET /uploadFile/control/ | Control the process of uploading a file, such as aborting, deleting or progressing the file. |
Return folders and files in the current folder.
URL:
http://{domain_name}/{rest_context_name}/private/fckconnector/jcr/getFoldersAndFiles/
Parameters:
Required (path parameters): No
Optional (query parameters):
| Parameter | Description |
|---|---|
| repositoryName | The name of repository. |
| workspaceName | The name of workspace. |
| currentFolder | The current folder. |
| command | The command. |
| type | The type. |
Create a folder under the current folder.
URL:
http://{domain_name}/{rest_context_name}/private/fckconnector/jcr/createFolder/
Parameters:
Required (path parameters): No
Optional (query parameters):
| Parameter | Description |
|---|---|
| repositoryName | The name of repository. |
| workspaceName | The name of workspace. |
| currentFolder | The current folder. |
| newFolderName | The name of the new folder. |
| language | The language. |
Upload a file with the HttpServletRequest.
URL:
http://{domain_name}/{rest_context_name}/private/fckconnector/jcr/uploadFile/upload/
Parameters:
Required (path parameters): No
Optional (query parameters): No
Control the process of uploading a file, such as aborting, deleting or progressing the file.
URL:
http://{domain_name}/{rest_context_name}/private/fckconnector/jcr/uploadFile/control/
Parameters:
Required (path parameters): No
Optional (query parameters):
| Parameter | Description |
|---|---|
| repositoryName | The repository name. |
| workspaceName | The workspace name. |
| currentFolder | The current folder. |
| action | The process of the upload file, such as saving or cancelling the file. |
| language | The language of the file. |
| fileName | The file name. |
| uploadId | The Id of the upload. |
| Resource | Description |
|---|---|
| GET /getBundle/ | Get the bundle that is based on the key and the locale. |
Get the bundle that is based on the key and the locale.
URL:
http://{domain_name}/{rest_context_name}/private/bundle/getBundle/
Parameters:
Required (path parameters): No
Optional (query parameters):
| Parameter | Description |
|---|---|
| key | The key used to get the bundle. |
| locale | The locale used to get the bundle. |
| Resource | Description |
|---|---|
| POST /star/ | Set a vote value for a given content. |
| GET /star/ | Return a vote value for a given content. |
| GET /postVote/ | Set a vote value for a given content. |
| GET /getVote/ | Return a vote value for a given content. |
Set a vote value for a given content.
URL:
http://{domain_name}/{rest_context_name}/private/contents/vote/star/
Parameters:
Required (path parameters): No
Optional (query parameters): No
Return a vote value for a given content.
URL:
http://{domain_name}/{rest_context_name}/private/contents/vote/star/
Parameters:
Required (path parameters): No
Optional (query parameters):
| Parameter | Description |
|---|---|
| repositoryName | The name of repository. |
| workspaceName | The name of workspace. |
| jcrPath | The path of the content. |
Set a vote value for a given content.
URL:
http://{domain_name}/{rest_context_name}/private/contents/vote/postVote/
Parameters:
Required (path parameters): No
Optional (query parameters):
| Parameter | Description |
|---|---|
| repositoryName | The name of repository. |
| workspaceName | The name of workspace. |
| jcrPath | The path of the content. |
| vote | The vote value. |
| lang | The language of the content. |
Return a vote value for a given content.
URL:
http://{domain_name}/{rest_context_name}/private/contents/vote/getVote/
Parameters:
Required (path parameters): No
Optional (query parameters):
| Parameter | Description |
|---|---|
| repositoryName | The name of repository. |
| workspaceName | The name of workspace. |
| jcrPath | The path of the content. |
| Resource | Description |
|---|---|
| GET /getDrivers/ | Return a list of drives for the current user. |
| GET /getFoldersAndFiles/ | Return all folders and files in a given location. |
| POST /uploadFile/upload/ | Upload a file. |
| GET /uploadFile/control/ | Control the process of uploading a file, such as aborting, deleting or progressing the file. |
Return a list of drives for the current user.
URL:
http://{domain_name}/{rest_context_name}/private/wcmDriver/getDrivers/
Parameters:
Required (path parameters): No
Optional (query parameters):
| Parameter | Description |
|---|---|
| lang | The language of the drive name. |
Return all folders and files in a given location.
URL:
http://{domain_name}/{rest_context_name}/private/wcmDriver/getFoldersAndFiles/
Parameters:
Required (path parameters): No
Optional (query parameters):
| Parameter | Description |
|---|---|
| driverName | The name of drive. |
| currentFolder | The current folder. |
| currentPortal | The current portal. |
| repositoryName | The name of repository. |
| workspaceName | The name of workspace. |
| filterBy | The type of filter. |
Upload a file.
URL:
http://{domain_name}/{rest_context_name}/private/wcmDriver/uploadFile/upload/
Parameters:
Required (path parameters): No
Optional (query parameters):
| Parameter | Description |
|---|---|
| uploadId | The Id of upload. |
Control the process of uploading a file, such as aborting, deleting or progressing the file.
URL:
http://{domain_name}/{rest_context_name}/private/wcmDriver/uploadFile/control/
Parameters:
Required (path parameters): No
Optional (query parameters):
| Parameter | Description |
|---|---|
| repositoryName | The name of repository. |
| workspaceName | The name of workspace. |
| driverName | The name of drive. |
| currentFolder | The current folder. |
| currentPortal | The current portal. |
| userId | The user identity. |
| jcrPath | The path of the file. |
| action | The action. |
| language | The language. |
| fileName | The name of file. |
| uploadId | The Id of upload. |
| Resource | Description |
|---|---|
| GET /getFoldersAndFiles/ | Get folders and files. |
Get folders and files.
URL:
http://{domain_name}/{rest_context_name}/private/wcmGadget/getFoldersAndFiles/
Parameters:
Required (path parameters): No
Optional (query parameters):
| Parameter | Description |
|---|---|
| currentFolder | The current folder. |
| lang | The language. |
| host | The server address on which the gadget is deployed. |
| Resource | Description |
|---|---|
| GET /getFoldersAndFiles/ | Get the page URI. |
| Resource | Description |
|---|---|
| GET /{repository}/ | Return the latest edited documents. |
Return the latest edited documents.
URL:
http://{domain_name}/{rest_context_name}/private/presentation/document/edit/{repository}/
Parameters:
Required (path parameters):
| Parameter | Description |
|---|---|
| repository | The name of repository. |
Optional (query parameters):
| Parameter | Description |
|---|---|
| showItems | Return the number of items in each page. |
| showGadgetWs | Show the gadget workspace or not. |
| Resource | Description |
|---|---|
| GET /{repository}/{workspace}/{state}/ | Return a list of published documents by the default plugin. For example: /portal/rest/publication/presentation/{repository}/{workspace}/{state}?showItems={numberOfItem} |
| GET /{repository}/{workspace}/{publicationPluginName}/{state}/ | Return a list of published documents by a specific plugin. For example: /portal/rest/publication/presentation/{repository}/{workspace}/{publicationPluginName}/{state}?showItems={numberOfItem} |
Return a list of published documents by the default plugin. For example: /portal/rest/publication/presentation/{repository}/{workspace}/{state}?showItems={numberOfItem}
URL:
http://{domain_name}/{rest_context_name}/private/publication/presentation/{repository}/{workspace}/{state}/
Parameters:
Required (path parameters):
| Parameter | Description |
|---|---|
| repository | The name of repository. |
| workspace | The name of workspace. |
| state | The state is specified to classify the process. |
Optional (query parameters):
| Parameter | Description |
|---|---|
| showItems | Show the number of items per page. |
Return a list of published documents by a specific plugin. For example: /portal/rest/publication/presentation/{repository}/{workspace}/{publicationPluginName}/{state}?showItems={numberOfItem}
URL:
http://{domain_name}/{rest_context_name}/private/publication/presentation/{repository}/{workspace}/{publicationPluginName}/{state}/
Parameters:
Required (path parameters):
| Parameter | Description |
|---|---|
| repository | The repository name. |
| workspace | The workspace name. |
| publicationPluginName | The name of the plugin. |
| state | The state is specified to classify the process. |
Optional (query parameters):
| Parameter | Description |
|---|---|
| showItems | Show the number of items per page. |
| Resource | Description |
|---|---|
| GET /all/{repoName}/{workspaceName}/{userName} | Return a list of favorite documents of a given user. |
Return a list of favorite documents of a given user.
URL:
http://{domain_name}/{rest_context_name}/private/favorite/all/{repoName}/{workspaceName}/{userName}
Parameters:
Required (path parameters):
| Parameter | Description |
|---|---|
| repoName | The name of repository. |
| workspaceName | The name of workspace. |
| userName | The username. |
Optional (query parameters):
| Parameter | Description |
|---|---|
| showItems | Show the number of items per page. |
| Resource | Description |
|---|---|
| GET /{repositoryName}/{workspaceName}/{nodeIdentifier} | Get the image binary data of a given image node. |
Get the image binary data of a given image node.
URL:
http://{domain_name}/{rest_context_name}/private/images/{repositoryName}/{workspaceName}/{nodeIdentifier}
Parameters:
Required (path parameters):
| Parameter | Description |
|---|---|
| repositoryName | The repository name. |
| workspaceName | The workspace name. |
| nodeIdentifier | The node identifier. |
Optional (query parameters):
| Parameter | Description |
|---|---|
| param | Check if the document is a file or not. |
| Resource | Description |
|---|---|
| GET /bystate/ | Return a list of content from a given to the last state. For example: http://localhost:8080/ecmdemo/rest-ecmdemo/authoring/bystate/?fromstate =draft&user=root&lang=en&workspace=collaboration |
| GET /tostate/ | Return a list of content from the beginning to the last state. For example: http://localhost:8080/ecmdemo/rest-ecmdemo/authoring/tostate/?fromstate =draft&tostate=pending&user=root&lang=en&workspace=collaboration |
| GET /bydate/ | Return a list of content from the given beginning to published state and before the given date. For example: http://localhost:8080/ecmdemo/rest-ecmdemo/authoring/bydate/?fromstate =staged&date=2&lang=en&workspace=collaboration |
Return a list of content from a given to the last state. For example: http://localhost:8080/ecmdemo/rest-ecmdemo/authoring/bystate/?fromstate =draft&user=root&lang=en&workspace=collaboration
URL:
http://{domain_name}/{rest_context_name}/private/authoring/bystate/
Parameters:
Required (path parameters): No
Optional (query parameters):
| Parameter | Description |
|---|---|
| fromstate | The beginning state of the content. |
| user | The author of the content. |
| lang | The language of the content. |
| workspace | The workspace name which contains the content. |
| json | The format of the returned data. |
Return a list of content from the beginning to the last state. For example: http://localhost:8080/ecmdemo/rest-ecmdemo/authoring/tostate/?fromstate =draft&tostate=pending&user=root&lang=en&workspace=collaboration
URL:
http://{domain_name}/{rest_context_name}/private/authoring/tostate/
Parameters:
Required (path parameters): No
Optional (query parameters):
| Parameter | Description |
|---|---|
| fromstate | The beginning state of the content. |
| tostate | The destination state of the content. |
| user | The author of the content. |
| lang | The language of the content. |
| workspace | The workspace name which contains the content. |
| json | The format of the returned data. |
Return a list of content from the given beginning to published state and before the given date. For example: http://localhost:8080/ecmdemo/rest-ecmdemo/authoring/bydate/?fromstate =staged&date=2&lang=en&workspace=collaboration
URL:
http://{domain_name}/{rest_context_name}/private/authoring/bydate/
Parameters:
Required (path parameters): No
Optional (query parameters):
| Parameter | Description |
|---|---|
| fromstate | The beginning state of the content. |
| date | The date before when the content is published. |
| lang | The language of the content. |
| workspace | The workspace name which contains the content. |
| json | The format of the returned data. |
| Resource | Description |
|---|---|
| POST /copy/ | Copy a file. |
| Resource | Description |
|---|---|
| GET | Return a thumbnail image for a PDF document. |
Return a thumbnail image for a PDF document.
Parameters:
Required (path parameters):
| Parameter | Description |
|---|---|
| repoName | The name of repository. |
| workspaceName | The name of workspace. |
| uuid | The identifier of the document. |
| pageNumber | The page number. |
| rotation | The page rotation. The valid values are: 0.0f, 90.0f, 180.0f, 270.0f. |
| scale | The Zoom factor which is applied to the rendered page. |
Optional (query parameters): No
| Resource | Description |
|---|---|
| GET /getDrives/ | Get all drives by type (General, Group or Personal). |
| GET /getFoldersAndFiles/ | Get all folders and files which can be viewed by the current user. |
| GET /deleteFolderOrFile/ | Delete a folder/file. |
| GET /createFolder/ | Create a new folder and return its information. |
| POST /uploadFile/upload/ | Upload a file to the server. |
| GET /uploadFile/control/ | Return information about the upload status of a file (upload percentage, file name, and more). |
Get all drives by type (General, Group or Personal).
URL:
http://{domain_name}/{rest_context_name}/private/managedocument/getDrives/
Parameters:
Required (path parameters): No
Optional (query parameters):
| Parameter | Description |
|---|---|
| driveType | The types of drive (General, Group, or Personal). |
| showPrivate | Show the Private drive or not. The default value is false. |
| showPersonal | Show the Personal drive or not. The default value is false. |
Get all folders and files which can be viewed by the current user.
URL:
http://{domain_name}/{rest_context_name}/private/managedocument/getFoldersAndFiles/
Parameters:
Required (path parameters): No
Optional (query parameters):
| Parameter | Description |
|---|---|
| driveName | The name of drive. |
| workspaceName | The name of workspace. |
| currentFolder | The path to the folder to achieve its folders and files. |
| showHidden | Show the hidden items or not. The default value is false. |
Delete a folder/file.
URL:
http://{domain_name}/{rest_context_name}/private/managedocument/deleteFolderOrFile/
Parameters:
Required (path parameters): No
Optional (query parameters):
| Parameter | Description |
|---|---|
| driveName | The name of drive. |
| workspaceName | The name of workspace. |
| itemPath | The path to the folder/file. |
Create a new folder and return its information.
URL:
http://{domain_name}/{rest_context_name}/private/managedocument/createFolder/
Parameters:
Required (path parameters): No
Optional (query parameters):
| Parameter | Description |
|---|---|
| driveName | The name of drive. |
| workspaceName | The name of workspace. |
| currentFolder | The path to the folder where a child folder is added . |
| folderName | The name of folder. |
Upload a file to the server.
URL:
http://{domain_name}/{rest_context_name}/private/managedocument/uploadFile/upload/
Parameters:
Required (path parameters): No
Optional (query parameters):
| Parameter | Description |
|---|---|
| uploadId | The Id of uploaded resource. |
Return information about the upload status of a file (upload percentage, file name, and more).
URL:
http://{domain_name}/{rest_context_name}/private/managedocument/uploadFile/control/
Parameters:
Required (path parameters): No
Optional (query parameters):
| Parameter | Description |
|---|---|
| workspaceName | The name of workspace. |
| driveName | The name of drive. |
| currentFolder | The path to the current folder . |
| currentPortal | The name of the current site. |
| action | The action to perform (saving, processing, and more). |
| language | The language of user. |
| fileName | The name of file. |
| uploadId | The Id of the uploaded resource. |
| Resource | Description |
|---|---|
| GET /download/{workspace}/{path:.*}/ | Return to browser a stream got from jcr:content/jcr:data for downloading the content of the node. |
Return to browser a stream got from jcr:content/jcr:data for downloading the content of the node.
URL:
http://{domain_name}/{rest_context_name}/private/contents/download/{workspace}/{path:.*}/
Parameters:
Required (path parameters):
| Parameter | Description |
|---|---|
| workspace | The workspace where to store the document node |
| path | The path to the document node |
Optional (query parameters):
| Parameter | Description |
|---|---|
| version | The version name |
Include many functions which allow adding, finding, or deleting taxonomies from a node.
Provide APIs to work with the linked node or the link included in a node.
Manage the content publication.
Get content inside the WCM product.
Manage all the tag and tag style. Currently it just supports adding/editing/removing Private and Public tags.
Manage dynamic groovy templates for WCM-based products.
Find a node with a given path.
Convert documents into different office formats.
Get all documents by time frame (day, month, year).
Allow finding all information matching with a given keyword.
Provide APIs to manage SEO data of a page or a content.
Include many functions which allow adding, editing, deleting, and getting views.
See also
Taxonomy service is used to work with taxonomies. In this service, there are many functions which enable you to add, find, or delete taxonomies from a node.
| Method | Param | Return | Description |
|---|---|---|---|
| getTaxonomyTree(String repository, String taxonomyName, boolean system) throws ReposioryException; |
|
node |
Return the root node of the given taxonomy tree. |
| getTaxonomyTree(String repository, String taxonomyName) throws RepositoryException; |
|
node |
Return the root node of the given taxonomy tree with the user session. |
| getAllTaxonomyTrees(String repository, boolean system) throws RepositoryException; |
|
List<Node>
|
Return the list of all the root nodes of the taxonomy tree available. |
| getAllTaxonomyTrees(String repository) throws RepositoryException; |
repository: The name of repository. |
List<Node> |
Return the list of all the root nodes of the taxonomy tree available with the user session. |
| hasTaxonomyTree(String repository, String taxonomyName) throws RepositoryException; |
|
boolean |
Check if a taxonomy tree with the given name has already been defined. |
| addTaxonomyTree(Node taxonomyTree) throws RepositoryException, TaxonomyAlreadyExistsException; |
taxonomyTree: The taxonomy tree to define. |
void |
Define a node as a new taxonomy tree. |
| updateTaxonomyTree(String taxonomyName, Node taxonomyTree) throws RepositoryException; |
|
void |
Re-define a node as a taxonomy tree. |
| removeTaxonomyTree(String taxonomyName) throws RepositoryException |
taxonomyName: The name of the taxonomy to remove. |
void |
Remove the taxonomy tree definition. |
| addTaxonomyNode(String repository, String workspace, String parentPath, String taxoNodeName, String creator) throws RepositoryException, TaxonomyNodeAlreadyExistsException; |
|
void |
Add a new taxonomy node at the given location. |
| removeTaxonomyNode(String repository, String workspace, String absPath) throws RepositoryException; |
|
void |
Remove the taxonomy node located at the given absolute path. |
| moveTaxonomyNode(String repository, String workspace, String srcPath, String destPath, String type) throws RepositoryException; |
|
void |
Copy or cut the taxonomy node from the source path to the destination path. The parameter type indicates if the node must be cut or copied. |
| hasCategories(Node node, String taxonomyName) throws RepositoryException; |
|
boolean |
Return true if the given node has categories in the given taxonomy. |
| hasCategories((Node node, String taxonomyName, boolean system) throws RepositoryException; |
|
boolean |
Return true if the given node has categories in the given taxonomy. |
| getCategories (Node node, String taxonomyName) throws RepositoryException; |
|
List<Node> |
Return all the paths of the categories (relative to the root node of the given taxonomy) which have been associated to the given node for the given taxonomy. |
| getCategories(Node node, String taxonomyName, boolean system) throws RepositoryException; |
|
List<Node> |
Return all the paths of the categories(relative to the root node of the given taxonomy) which have been associated to the given node for the given taxonomy. |
| getAllCategories(Node node) throws RepositoryException; |
|
List<Node> |
Return all the paths of the categories which have been associated to the given node. |
| getAllCategories(Node node, boolean system) throws RepositoryException; |
|
List<Node> |
Return all the paths of the categories which have been associated to the given node. |
| removeCategory(Node node, String taxonomyName, String categoryPath) throws RepositoryException; |
|
void |
Remove a category to the given node. |
| removeCategory(Node node, String taxonomyName, String categoryPath, boolean system) throws RepositoryException; |
|
void |
Remove a category to the given node. |
| addCategories(Node node, String taxonomyName, String[] categoryPaths) throws RepositoryException; |
|
void |
Add several categories to the given node. |
| addCategories(Node node, String taxonomyName, String[] categoryPaths, boolean system) throws RepositoryException; |
|
void |
Add several categories to the given node. |
| addCategory(Node node, String taxonomyName, String categoryPath) throws RepositoryException; |
|
void |
Add a new category path to the given node. |
| addCategory(Node node, String taxonomyName, String categoryPath, boolean system) throws RepositoryException; |
|
void |
Add a new category path to the given node. |
| getTaxonomyTreeDefaultUserPermission(); | N/A | Map<String, String[]> | Get the default permission for the user in taxonomy tree. |
| addTaxonomyPlugin(ComponentPlugin plugin); |
plugin: The plugin to add. |
void |
Add a new taxonomy plugin to the service. |
| init(String repository) throws Exception; | repository: The name of repository. |
void |
Initialize all taxonomy plugins that have been already configured in .xml files. |
| getCategoryNameLength(); | N/A |
string |
Get the limited length of the category name. |
Supply API to work with the linked node or the link included in a node.
Package org.exoplatform.services.cms.link.LinkManager
| Method | Param | Return | Description |
|---|---|---|---|
| createLink(Node parent, String linkType, Node target)throws RepositoryException; |
|
Node |
Create a new link that is added to the parent node and return the link. |
| createLink(Node parent, Node target)throws RepositoryException; |
|
Node |
Create a new node of type exo:symlink, then add it to the parent node and return the link node. |
| createLink(Node parent, String linkType, Node target, String linkName) throws RepositoryException; |
|
Node |
Create a new link that is added to the parent node and return the link. |
| updateLink(Node link, Node target)throws RepositoryException; |
|
Node |
Update the target node of the given link. |
| getTarget(Node link, boolean system) throws ItemNotFoundException, RepositoryException; |
|
Node |
Get the target node of the given link. |
| getTarget(Node link)throws ItemNotFoundException, RepositoryException; |
link: The node of type exo:symlink. |
Node |
Get the target node of the given link using the user. |
| isTargetReachable(Node link) throws RepositoryException; | link: The node of type exo:symlink. |
boolean |
Check if the target node of the given link can be reached using the user session. |
| isTargetReachable(Node link, boolean system)throws RepositoryException; |
|
boolean |
Check if the target node of the given link can be reached using the user session. |
| isLink(Item item) throws RepositoryException; |
item: The item to test. |
boolean |
Indicate whether the given item is a link. @return <code>true</code>: if the node is a link, <code>false</code> otherwise. |
| getTargetPrimaryNodeType(Node link)throws RepositoryException; | link: The node of type exo:symlink. |
string |
Return the primary node type of the target. |
| getAllLinks(Node targetNode, String linkType, String repoName)throws Exception |
|
List<Node> - the list of link of the target node with given type. |
Return all links of the given node. (Deprecated) |
| getAllLinks(Node targetNode, String linkType, SessionProvider sessionProvider) throws Exception; |
|
List<Node> - the list of link of the target node with given type. |
Return all links of the given node. |
PublicationService is to manage the publication.
| Method | Param | Return | Description |
|---|---|---|---|
| addLifecycle(ComponentPlugin plugin) | plugin |
void |
Add publication plugin to the publication service. |
| removeLifecycle(ComponentPlugin plugin) | plugin
|
void
|
Remove publication plugin from the publication service. |
| addContext(ComponentPlugin plugin) | plugin
|
void
|
Add publication plugin context to the publication service. |
| removeContext(ComponentPlugin plugin) | plugin
|
void
|
Remove publication plugin context from the publication service. |
| getLifecycle(String name) | name - The name of the wanted lifecycle. |
Lifecycle |
Get a specific lifecycle with the given name. |
| getLifecycles() |
N/A
|
List<Lifecycle> |
Get all the lifecycles which were added to service instances. |
| getContext(String name) | name |
Context |
Get a specific context with the given names. |
| getContexts() |
N/A |
List<Context> |
Get all the contexts which were added to service instances. |
| getContents(String fromstate, String tostate, String date, String user, String lang , String workspace) throws Exception; |
|
List<Node> |
Get all the nodes. |
| getLifecyclesFromUser(String remoteUser, String state); |
|
List<Lifecycle> |
Get all the Lifecycle of a specific user. |
This class is used to get content inside the WCM product. You should not access content directly from the JCR on the front side.
In general, this service stands between publication and cache.
Package org.exoplatform.services.wcm.publication.WCMComposer
| Method | Param | Return | Description |
|---|---|---|---|
| getContent(String workspace, String nodeIdentifier, HashMap<String, String> filters, SessionProvider sessionProvider)throws Exception; |
|
Node |
Return content at the specified path based on filters. |
| getContents(String workspace, String path, HashMap<String, String> filters, SessionProvider sessionProvider)throws Exception; |
|
List<Node> |
Return content at the specified path based on filters. |
| updateContent(String workspace, String nodeIdentifier, HashMap<String, String> filters)throws Exception; |
|
boolean |
Update content. |
| updateContents(String workspace, String nodeIdentifier, HashMap<String, String> filters)throws Exception; |
|
boolean |
Update content. |
| getPaginatedContents(NodeLocation nodeLocation,HashMap<String, String> filters, SessionProvider sessionProvider) throws Exception; |
|
boolean |
Return content at the specified path based on filters. |
| getAllowedStates(String mode)throws Exception; |
mode
|
List<String> |
Return the allowed states for a specified mode. |
| cleanTemplates()throws Exception; | N/A |
void |
Initialize the template hashmap. |
| isCached()throws Exception; | N/A |
boolean |
Check isCache or not. |
| updateTemplatesSQLFilter()throws Exception; | N/A |
String |
Update all document nodetypes and write a query cause. It returns a part of the query that allows to search all document nodes and taxonomy links. Return null if there is any exception. |
This service is used to manage all tags and their styles. Currently, it just supports adding/editing/removing the Private & Public tags.
Package org.exoplatform.services.cms.folksonomy.NewFolksonomyService;
| Method | Return | Prototype | Description |
|---|---|---|---|
| addPrivateTag(String[] tagsName, Node documentNode, String repository, String workspace, String userName) throws Exception ; |
|
void |
Add a private tag to a document. A folksonomy link will be created in a tag node. |
| addGroupsTag(String[] tagsName, Node documentNode,String repository, String workspace, String[] roles) throws Exception ; |
|
void |
Add a group tag to a document. A folksonomy link will be created in a tag node. |
| addPublicTag(String treePath, String[] tagsName, Node documentNode, String repository, String workspace) throws Exception ; |
|
void |
Add a public tag to a document. A folksonomy link will be created in a tag node. |
| addSiteTag(String siteName, String[] tagsName, Node node, String repository, String workspace) throws Exception ; |
|
void |
Add a site tag to a document. A folksonomy link will be created in a tag node. |
| getAllPrivateTags(String userName, String repository, String workspace) throws Exception ; |
|
List<Node> |
Get all private tags. |
| getAllPublicTags(String treePath, String repository, String workspace) throws Exception ; |
|
List<Node> |
Get all public tags. |
| getAllGroupTagsString[] roles, String repository, String workspace) throws Exception ; |
|
List<Node> |
Get all tags by groups. |
| getAllGroupTags(String role, String repository, String workspace) throws Exception ; |
|
List<Node> |
Get all tags by a group. |
| getAllSiteTags(String siteName, String repository, String workspace) throws Exception ; |
|
List<Node> |
Get all tags of Site. |
| getAllDocumentsByTag(String tagPath, String repository, String workspace, SessionProvider sessionProvider) throws Exception ; |
|
List<Node>
|
Get all documents which are stored in a tag and return a list of documents in a tag. |
| getTagStyle(String tagPath, String repository, String workspace) throws Exception ; |
|
string |
Get HTML_STYLE_PROP property in styleName node in the repository. |
| addTagStyle(String styleName, String tagRange, String htmlStyle, String repository, String workspace) throws Exception ; |
|
void |
Update the properties TAG_RATE_PROP and HTML_STYLE_PROP, following the values tagRate, htmlStyle for a node in tagPath in repository. |
| updateTagStyle(String styleName, String tagRange, String htmlStyle, String repository, String workspace) throws Exception ; |
|
void |
Update the properties TAG_RATE_PROP and HTML_STYLE_PROP, following the value tagRate, htmlStyle for a node in tagPath in repository. |
| getAllTagStyle(String repository, String workspace) throws Exception ; |
|
List<Node> |
Get all tag style bases of a folksonomy tree. |
| init(String repository) throws Exception ; |
repository: The repository name. |
void |
Initialize all TagStylePlugin with session in repository name. |
| removeTagOfDocument(String tagPath, Node document, String repository, String workspace) throws Exception; |
|
void |
Remove a tag of a given document. |
| removeTag(String tagPath, String repository, String workspace) throws Exception; |
|
void |
Remove a tag. |
| modifyTagName(String tagPath, String newTagName, String repository, String workspace) throws Exception; |
|
Node |
Modify the tag name. |
| getLinkedTagsOfDocument(Node documentNode, String repository, String workspace) throws Exception; |
|
List<Node> |
Get all tags linked to a given document. |
| getLinkedTagsOfDocumentByScope(int scope, String value, Node documentNode, String repository, String workspace) throws Exception; |
|
List<Node> |
Get all tags linked to a given document by scope. |
| removeTagsOfNodeRecursively(Node node, String repository, String workspace, String username, String groups) throws Exception; |
|
void |
Remove all tags linked to the child nodes of a given node. |
| addTagPermission(String usersOrGroups); |
usersOrGroups |
void |
Add given users or groups to tagPermissionList. |
| removeTagPermission(String usersOrGroups); |
usersOrGroups |
void |
Remove given users or groups from tagPermissionList. |
| getTagPermissionList(); | N/A |
List<String> |
Return tagPermissionList. |
| canEditTag(int scope, List<String> memberships); |
|
boolean |
Set the permission to edit a tag for a user. |
| getAllTagNames(String repository, String workspace, int scope, String value) throws Exception; |
|
List<String> |
Get all tag names which start within a given scope. |
This class is used to manage dynamic groovy templates for WCM-based products.
Package org.exoplatform.services.cms.views.ApplicationTemplateManager;
| Method | Param | Return | Description |
|---|---|---|---|
| addPlugin(PortletTemplatePlugin portletTemplatePlugin) throws Exception |
portletTemplatePlugin |
void |
Add the plugin.. |
| getAllManagedPortletName(String repository) throws Exception |
repository |
List<String> |
Retrieve all the portlet names that have dynamic groovy templates managed by service. |
| getTemplatesByApplication(String repository, String portletName, SessionProvider provider)throws Exception; |
|
List<String> |
Retrieve the templates node by application. |
| getTemplatesByCategory(String repository, String portletName, String category, SessionProvider sessionProvider) throws Exception; |
|
List<String> |
Retrieve the templates node by category. |
| getTemplateByName(String repository, String portletName, String category, String templateName, SessionProvider sessionProvider)throws Exception; |
|
node |
Retrieve the template by name. |
| getTemplateByPath(String repository, String templatePath, SessionProvider sessionProvider)throws Exception ; |
|
node |
Get the template by path. |
addTemplate(node portletTemplateHome, PortletTemplateConfig config)throws Exception; |
|
void |
Add the template. |
| removeTemplate(String repository, String portletName, String catgory, String templateName, SessionProvider sessionProvider)throws Exception; |
|
void |
Remove the template. |
NodeFinder is used to find a node with a given path. If the path to the node contains sub-paths to exo:symlink nodes, find the real link node.
| Method | Param | Return | Description |
|---|---|---|---|
| getNode(Node ancestorNode, String relativePath) throws PathNotFoundException, RepositoryException; |
|
node
|
Return the node at relPath related to the ancestor node. |
| getNode(Node ancestorNode, String relativePath, boolean giveTarget) throws PathNotFoundException, RepositoryException; |
|
node |
Return the node at relPath related to the ancestor node. If the node is a link and giveTarget has been set to <code>true</code>, the target node will be returned. |
| getItem(String repository, String workspace, String absPath) throws PathNotFoundException, RepositoryException; |
|
item
|
Return the item at the specified absolute path. |
| getItemSys(String repository, String workspace, String absPath, boolean system) throws PathNotFoundException, RepositoryException; |
|
item
|
Return the item at the specified absolute path. |
| getItem(String repository, String workspace, String : absPath, boolean giveTarget) throws PathNotFoundException, RepositoryException; |
|
item |
Return the item at the specified absolute path. If the item is a link and giveTarget has been set to <code>true</code>, the target node will be returned. |
| getItemGiveTargetSys(String repository, String workspace, String absPath, boolean giveTarget, boolean system) throws PathNotFoundException, RepositoryException; |
|
Item |
Return the item at the specified absolute path. If the item is a link and giveTarget has been set to <code>true</code>, the target node will be returned. |
| getItem(Session session, String absPath) throws PathNotFoundException, RepositoryException; |
|
item
|
Return the item at the specified absolute path. |
| getItem(Session session, String absPath, boolean giveTarget) throws PathNotFoundException, RepositoryException; |
|
item |
Return the item at the specified absolute path. If the item is a link and giveTarget has been set to <code>true</code>, the target node will be returned. |
| getItemTarget(Session session, String absPath, boolean giveTarget, boolean system) throws PathNotFoundException, RepositoryException; |
|
item |
Return the item at the specified absolute path. If the item is a link and giveTarget has been set to <code>true</code>, the target node will be returned. |
| itemExists(Session session, String absPath) throws RepositoryException; |
|
boolean |
Return <code>true</code> if an item exists at absPath; otherwise returns <code>false</code>. Also returns <code>false</code> if the specified absPath is malformed. |
JodConverter is used to convert documents into different office formats.
Package org.exoplatform.services.cms.jodconverter.JodConverterService
| Method | Param | Return | Description |
|---|---|---|---|
| convert(InputStream input, String formatInput, OutputStream out, String formatOutput) throws Exception; |
|
void |
Convert InputStream in the formatInput format to OutputStream with the formatOutput format. Deprecate: This method is not supported by JODConverter 3.0 anymore, please use convert(File, File, String) instead. |
| convert(File input, File output, String outputFormat) throws OfficeException; |
|
boolean |
Convert input File to output File with the outputFormat. |
TimelineService is used to get all documents by time frame (day, month, year).
| Method | Param | Return | Description |
|---|---|---|---|
| getDocumentsOfToday(String nodePath,String repository,String workspace, SessionProvider sessionProvider, String userName, boolean byUser) throws Exception; |
|
List<Node>
|
Get all documents of today. (Deprecated) |
| getDocumentsOfToday(String nodePath,String workspace, SessionProvider sessionProvider, String userName, boolean byUser) throws Exception; |
|
List<Node>
|
Get all documents of today. |
| getDocumentsOfToday(String nodePath,String workspace, SessionProvider sessionProvider, String userName, boolean byUser, boolean isLimit) throws Exception; |
|
List<Node>
|
Get all documents of today. |
| getDocumentsOfYesterday(String nodePath,String repository,String workspace, SessionProvider sessionProvider, String userName, boolean byUser) throws Exception; |
|
List<Node>
|
Get all documents of yesterday. (Deprecated) |
| getDocumentsOfYesterday(String nodePath,String workspace, SessionProvider sessionProvider, String userName, boolean byUser) throws Exception; |
|
List<Node>
|
Get all documents of yesterday. |
| getDocumentsOfYesterday(String nodePath,String workspace, SessionProvider sessionProvider, String userName, boolean byUser, boolean isLimit) throws Exception; |
|
List<Node>
|
Get all documents of yesterday. |
| getDocumentsOfEarlierThisWeek(String nodePath,String repository,String workspace, SessionProvider sessionProvider, String userName, boolean byUser) throws Exception; |
|
List<Node>
|
Get all documents from earlier this week to yesterday. (Deprecated) |
| getDocumentsOfEarlierThisWeek(String nodePath,String workspace, SessionProvider sessionProvider, String userName, boolean byUser) throws Exception; |
|
List<Node>
|
Get all documents from earlier this week to yesterday. |
| getDocumentsOfEarlierThisWeek(String nodePath,String workspace, SessionProvider sessionProvider, String userName, boolean byUser, boolean isLimit) throws Exception; |
|
List<Node>
|
Get all documents from earlier this week to yesterday. |
| getDocumentsOfEarlierThisMonth(String nodePath,String repository,String workspace, SessionProvider sessionProvider, String userName, boolean byUser) throws Exception; |
|
List<Node>
|
Get all documents from earlier this month to earlier this week. (Deprecated) |
| getDocumentsOfEarlierThisMonth(String nodePath,String workspace, SessionProvider sessionProvider, String userName, boolean byUser) throws Exception; |
|
List<Node>
|
Get all documents from earlier this month to earlier this week. |
| getDocumentsOfEarlierThisMonth(String nodePath,String workspace, SessionProvider sessionProvider, String userName, boolean byUser, boolean isLimit) throws Exception; |
|
List<Node>
|
Get all documents since earlier this month to earlier this week. |
| getDocumentsOfEarlierThisYear(String nodePath,String repository,String workspace, SessionProvider sessionProvider, String userName, boolean byUser) throws Exception; |
|
List<Node>
|
Get all documents from earlier this year to earlier this month. (Deprecated) |
| getDocumentsOfEarlierThisYear(String nodePath,String workspace, SessionProvider sessionProvider, String userName, boolean byUser) throws Exception; |
|
List<Node>
|
Get all documents from earlier this year to earlier this month. |
| getDocumentsOfEarlierThisYear(String nodePath,String workspace, SessionProvider sessionProvider, String userName, boolean byUser, boolean isLimit) throws Exception; |
|
List<Node>
|
Get all documents from earlier this year to earlier this month. |
| getItemPerTimeline() |
N/A |
int |
Get the number of documents per category displayed in the Timeline view. |
SiteSearchService is used in the Search portlet that allows users to find all information matching with your given keyword.
| Method | Param | Return | Description |
|---|---|---|---|
| addExcludeIncludeDataTypePlugin(ExcludeIncludeDataTypePlugin plugin) | plugin: The plugin. |
void |
Filter mimetypes data in the search results. |
| searchSiteContents(SessionProvider sessionProvider, QueryCriteria queryCriteria, int pageSize, boolean isSearchContent) throws Exception; |
|
AbstractPageList<ResultNode>
|
Find all child nodes whose contents match with the given keyword. These nodes will be put in the list of search results. |
SEOService supplies APIs to manage SEO data of a page or a content. This service includes some major functions which enables you to add, store, get or remove the metadata of a page or a content.
| Method | Param | Return | Description |
|---|---|---|---|
storePageMetadata(PageMetadataModel metaModel, String portalName, boolean onContent) throws Exception |
|
void
|
Store the metadata of a page/content. |
| getMetadata(ArrayList<String> params, String pageReference) throws Exception |
|
PageMetadataModel |
Return the metadata of a portal page or a content page. |
| getPageMetadata (String pageReference) throws Exception | pageReference: The reference of the page. |
PageMetadataModel
|
Return the metadata of a portal page. |
| getContentMetadata(ArrayList<String> params) throws Exception |
params: The parameters list of a content page. |
PageMetadataModel
|
Return the metadata of a content page. |
removePageMetadata(PageMetadataModel metaModel, String portalName, boolean onContent) throws Exception |
|
void
|
Remove the metadata of a page. |
| getContentNode(String contentPath) throws Exception | contentPath: The content path. |
Node |
Return the content node by the content path. |
| getHash(String uri) throws Exception |
uri: The page reference of the UUID of a node. |
string
|
Create a key from the page reference or the UUID of the node. |
| getSitemap(String portalName) throws Exception |
portalName: The portal name. |
string
|
Return a sitemap's content of a specific portal. |
| getRobots(String portalName) throws Exception |
portalName: The portal name. |
string
|
Return Robots' content of a specific portal. |
| getRobotsIndexOptions() throws Exception | N/A |
List<String> |
Return a list of options (INDEX and NOINDEX) for robots to index. |
| getRobotsFollowOptions() throws Exception | N/A |
List<String> |
Return a list of options (FOLLOW and NOFOLLOW) for robots to follow. |
| getFrequencyOptions() throws Exception |
N/A |
List<String> |
Return a list of options for frequency. |
ManageViewService is used to work with views. This service has many functions which allow you to add, edit, delete, and get views.
| Method | Param | Return | Description |
|---|---|---|---|
| addView(String name, String permissions, String template, List<?> tabs, String repository) throws Exception; |
|
void
|
Insert a new view to the system. (Deprecated) |
| addView(String name, String permissions, String template, List<?> tabs) throws Exception; |
|
void
|
Insert a new view to the system. |
| getViewByName(String viewName, String repository, SessionProvider provider) throws Exception; |
|
node
|
Specify a new view depending on the view name. (Deprecated) |
| getViewByName(String viewName, SessionProvider provider) throws Exception; |
|
node
|
Specify a new view depending on the view name. |
| getButtons() throws Exception; | N/A |
List<?> |
Return all strings of buttons. |
| removeView(String viewName, String repository) throws Exception; |
|
void |
Remove a view from the views list in the system. (Deprecated) |
| removeView(String viewName) throws Exception; | viewName
|
void |
Remove a view from the views list in the system. |
| getAllViews(String repository) throws Exception; | repository
|
List<ViewConfig> |
Return all views of the repository configured in the XML file. (Deprecated) |
| getAllViews() throws Exception; | N/A
|
List<ViewConfig> |
Return all views of the repository configured in the XML file. |
| hasView(String name, String repository) throws Exception; |
|
boolean |
Return true if the given repository has a view. (Deprecated) |
| hasView(String name) throws Exception; | N/A
|
boolean |
Return true if the given repository has a view. |
| getTemplateHome(String homeAlias, String repository, SessionProvider provider) throws Exception; |
|
Node |
Get a template node that has the path. (Deprecated) |
| getTemplateHome(String homeAlias, SessionProvider provider) throws Exception; |
|
Node |
Get a template node that has the path. |
| getAllTemplates(String homeAlias, String repository, SessionProvider provider) throws Exception; |
|
List<Node> |
Get all template nodes that have the path. (Deprecated) |
| getAllTemplates(String homeAlias, SessionProvider provider) throws Exception; |
|
List<Node> |
Get all template nodes that have the path. |
| getTemplate(String path, String repository, SessionProvider provider) throws Exception; |
|
Node |
Return a node that has the path of the repository. (Deprecated) |
| getTemplate(String path, SessionProvider provider) throws Exception; |
|
Node |
Return a node that has the path of the repository. |
| addTemplate(String name, String content, String homePath, String repository) throws Exception; |
|
String |
Insert a new template to a node by specifying its path. (Deprecated) |
| addTemplate(String name, String content, String homePath) throws Exception; |
|
String |
Insert a new template to a node by a specified path. |
| updateTemplate(String name, String content, String homePath, String repository) throws Exception; |
|
String |
Update a template for a node by specifying its path. (Deprecated) |
| updateTemplate(String name, String content, String homePath) throws Exception; |
|
String |
Update a template for a node by specifying its path. |
| removeTemplate(String templatePath, String repository) throws Exception; |
|
void |
Remove the template from the given node by specifying its path. (Deprecated) |
| removeTemplate(String templatePath) throws Exception; | templatePath |
void |
Remove the template from the given node by specifying its path. |
| addTab(Node view, String name, String buttons) throws Exception ; |
|
void |
Insert a new tab to the given view node. |
| init(String repository) throws Exception ; | repository |
void |
Get all templates that are configured in the XML file of a specified repository. (Deprecated) |
| init() throws Exception ; | N/A
|
void |
Get all templates that are configured in the XML file of a specified repository. |
In Content, there are some deprecated portlets, including Browse Content (BC), Parameterized Content Viewer (PCV), Parameterized Content List Viewer (PCLV), Category Navigation (CN), Newsletter Viewer, Newsletter Manager, Form Builder.
In which:
The BC, Newsletter Viewer, Newsletter Manager and Form Builder portlets are not used anymore.
The PCV portlet is still used, but its java class named UIPCVPortlet is replaced by UISingleContentViewerPortlet of the Single Content Viewer (SCV) portlet.
The PCLV portlet is still used, but its java class named UIPCLVPortlet is replaced by UICLVPortlet of the Content List Viewer (CLV) porlet.
The CN portlet is still used, but its java class named UICategoryNavigationPortlet is replaced by UICLVPortlet of the CLV porlet.
See also
xCMIS project links:
CMIS-related links:
See also
This section provides FAQs related to the product.
The addPlugin() function of WorkflowServiceContainer service is used to register a Business Process when a workflow is implemented. Thus, if you want to use a workflow, you are required to configure the workflow service to invoke the addPlugin() function by adding the external-component-plugins element to the configuration file.
You have to set values for the name and location of the workflow which you want to use. There are two ways to configure the location of the workflow.
You can use "war:(FOLDER_PATH)" to configure which .jar files contain your workflow processes inside the .war file.
<external-component-plugins>
<target-component>org.exoplatform.services.workflow.WorkflowServiceContainer</target-component>
<component-plugin>
<name>deploy.predefined.processes</name>
<set-method>addPlugin</set-method>
<type>org.exoplatform.services.workflow.PredefinedProcessesPlugin</type>
<init-params>
<object-param>
<name>predefined.processes</name>
<description>load of default business processes</description>
<object type="org.exoplatform.services.workflow.ProcessesConfig">
<field name="processLocation">
<string>war:/conf/bp</string>
</field>
<field name="predefinedProcess">
<collection type="java.util.HashSet">
<value>
<string>/exo-ecms-ext-workflow-bp-jbpm-content-2.1.1.jar</string>
</value>
<value>
<string>/exo-ecms-ext-workflow-bp-jbpm-payraise-2.1.1.jar</string>
</value>
<value>
<string>/exo-ecms-ext-workflow-bp-jbpm-holiday-2.1.1.jar</string>
</value>
</collection>
</field>
</object>
</object-param>
</init-params>
</component-plugin>
</external-component-plugins>
You can use classpath: to configure which .jar files contain your workflow processes inside the .jar file.
<external-component-plugins>
<target-component>org.exoplatform.services.workflow.WorkflowServiceContainer</target-component>
<component-plugin>
<name>deploy.predefined.processes</name>
<set-method>addPlugin</set-method>
<type>org.exoplatform.services.workflow.PredefinedProcessesPlugin</type>
<init-params>
<object-param>
<name>predefined.processes</name>
<description>load of default business processes</description>
<object type="org.exoplatform.services.workflow.ProcessesConfig">
<field name="processLocation">
<string>classpath:</string>
</field>
<field name="predefinedProcess">
<collection type="java.util.HashSet">
<value>
<string>/exo-ecms-ext-workflow-bp-jbpm-content-myworkflow.jar</string>
</value>
</collection>
</field>
</object>
</object-param>
</init-params>
</component-plugin>
</external-component-plugins>
The notification message is displayed when you deploy a workflow on Jboss. If you use classpath: to register, you must put your workflow in the .jar files inside the gatein.ear/lib folder (instead of the lib folder) to make it work.
See also