One of the libraries provided by theSDK for out-of-process extensionsis the Java ReST API wrapper library. It enables you to work with theAlfresco ReST APIfrom a Java client with standard Java classes. There is no need to parse JSON or create HTTP requests.
To set up a project with the Java ReST API library follow theseinstructions.
There are some common parameters in the different API calls. They are documented here instead of repeating the docs forthem under multiple sections:
| Parameter | Description | Usage |
|---|---|---|
include | Use this parameter to return additional information about the node. The following optional fields can be requested:allowableOperations,aspectNames,association,isLink,isFavorite,isLocked,path,properties,permissions. | List<String> include = new ArrayList<>(); include.add("permissions"); |
fields | You can use this parameter to restrict the fields returned within a response if, for example, you want to save on overall bandwidth. The list applies to a returned individual entity or entries within a collection. If the API method also supports theinclude parameter, then the fields specified ininclude parameter are returned in addition to those specified in thefields parameter. | List<String> fields = new ArrayList<>(); fields.add("content,createdAt");Note that all fields have to be added as one item comma separated. |
where | Optionally filter the node list. | Here are some examples:(isFolder=true)(isFile=true)(nodeType='my:specialNodeType')(nodeType='my:specialNodeType INCLUDESUBTYPES')(id BETWEEN ('1', '79')) |
includeSource | Also includesource in addition toentries with folder information on the parent node – either the specified parent nodeId, or as resolved byrelativePath | Boolean includeSource = false; |
orderBy | A string to control the order of the entities returned in a list. The default sort order for the returned list is for folders to be sorted before files, and by ascending name. You can override the default usingorderBy to specify one or more fields to sort by. The default order is always ascending, but you can use an optionalASC orDESC modifier to specify an ascending or descending sort order. For example, specifyingorderBy=name DESC returns a mixed folder/file list in descending name order. You can use any of the following fields to order the results:isFolder,name,mimeType,nodeType,sizeInBytes,modifiedAt,createdAt,modifiedByUser,createdByUser | List<String> orderBy = new ArrayList<>(); orderBy.add("title"); |
skipCount | The number of entities that exist in the collection before those included in this list, useful when implementing paging scenarios. If not supplied then the default value is0. | Integer skipCount = 0; |
maxItems | The maximum number of items to return in the list, useful when implementing paging scenarios. If not supplied then the default value is100. | Integer maxItems = 100; |
autoRename | Iftrue, then a name clash will cause an attempt to auto rename by finding a unique name using an integer suffix. | Boolean autoRename = true; |
versioningEnabled | Should versioning of files be enabled at all? | Boolean versioningEnabled = true; |
majorVersion | Iftrue, then it will be a major version, such as 1.0, 2.0 etc. Iffalse, then the version change will be 1.1, 1.2, which is a minor version change. | Boolean majorVersion = true; |
updateComment | Add a version comment which will appear in version history. Setting this parameter also enables versioning of this node, if it is not already versioned. | String updateComment = "A comment"; |
updatedName | Optional new name of the node, setscm:name. This should include the file extension. The name must not contain spaces or the following special characters:* " < > \ / ? : |. The character. must not be used at the end of the name. | String updatedName = null; if not updating or set to new name. |
The following sections walk through how to use the Java ReST API wrapper services when managing folders and files.
To list contents of a folder in the repository use thelistNodeChildren method of theNodesApi,which is one of the main APIs used when you want to manipulate folders and files.
More info about this ReST API endpoint
For a description of the common parameters, such asinclude, see thissection.
import org.alfresco.core.handler.NodesApi;import org.alfresco.core.model.*;import org.slf4j.Logger;import org.slf4j.LoggerFactory;import org.springframework.beans.factory.annotation.Autowired;import org.springframework.stereotype.Component;import java.io.IOException;import java.util.List;@Componentpublic class ListFolderContent { static final Logger LOGGER = LoggerFactory.getLogger(ListFolderContent.class); @Autowired NodesApi nodesApi; public void execute() throws IOException { NodeChildAssociationPagingList nodes = listFolderContent("-root-", null); NodeChildAssociationPagingList nodes2 = listFolderContent("-root-", "/Data Dictionary"); } /** * List contents (i.e. folders and files) of a folder. * * @param rootNodeId the id of the folder node that is the root. If relativeFolderPath is null, then content in this folder will be listed. Besides node ID the aliases -my-, -root- and -shared- are also supported. * @param relativeFolderPath path relative rootNodeId, if this is not null, then the content of this folder will be listed * @return a list of child node objects contained in the folder, or null if not found */ private NodeChildAssociationPagingList listFolderContent(String rootNodeId, String relativeFolderPath) { Integer skipCount = 0; Integer maxItems = 100; List<String> include = null; List<String> fields = null; List<String> orderBy = null; String where = null; Boolean includeSource = false; LOGGER.info("Listing folder {}{}", rootNodeId, relativeFolderPath); NodeChildAssociationPagingList result = nodesApi.listNodeChildren(rootNodeId, skipCount, maxItems, orderBy, where, include, relativeFolderPath, includeSource, fields).getBody().getList(); for (NodeChildAssociationEntry childNodeAssoc: result.getEntries()) { LOGGER.info("Found node [name=" + childNodeAssoc.getEntry().getName() + "]"); } return result; }}See alsomanage associations for information on how to list secondary child associations for a node.
To filter listed contents of a folder in the repository use thelistNodeChildren method of theNodesApiand set thewhere clause parameter.
More info about this ReST API endpoint
For a description of the common parameters, such aswhere andinclude, see thissection.
import org.alfresco.core.handler.NodesApi;import org.alfresco.core.model.*;import org.slf4j.Logger;import org.slf4j.LoggerFactory;import org.springframework.beans.factory.annotation.Autowired;import org.springframework.stereotype.Component;import java.io.IOException;import java.util.List;@Componentpublic class ListFolderContent { static final Logger LOGGER = LoggerFactory.getLogger(ListFolderContent.class); @Autowired NodesApi nodesApi; public void execute() throws IOException { NodeChildAssociationPagingList nodes = listFolderContent("-root-", null); NodeChildAssociationPagingList nodes2 = listFolderContent("-root-", "/Data Dictionary"); } /** * List sub-folders of a folder. * * @param rootNodeId the id of the folder node that is the root. If relativeFolderPath is null, then content in this folder will be listed. Besides node ID the aliases -my-, -root- and -shared- are also supported. * @param relativeFolderPath path relative rootNodeId, if this is not null, then the content of this folder will be listed * @return a list of child folder node objects contained in the folder, or null if not found */ private NodeChildAssociationPagingList listFolderContent(String rootNodeId, String relativeFolderPath) { Integer skipCount = 0; Integer maxItems = 100; List<String> include = null; List<String> fields = null; List<String> orderBy = null; String where = "(isFolder=true)"; Boolean includeSource = false; LOGGER.info("Listing folder {}{} with filter {}", rootNodeId, relativeFolderPath, where); NodeChildAssociationPagingList result = nodesApi.listNodeChildren(rootNodeId, skipCount, maxItems, orderBy, where, include, relativeFolderPath, includeSource, fields).getBody().getList(); for (NodeChildAssociationEntry childNodeAssoc: result.getEntries()) { LOGGER.info("Found folder node [name=" + childNodeAssoc.getEntry().getName() + "]"); } return result; }}To get metadata for a node, such as a file or folder, in the repository use thegetNode method of theNodesApi,which is one of the main APIs used when you want to manipulate folders and files.
More info about this ReST API endpoint
For a description of the common parameters, such asinclude, see thissection.
import org.alfresco.core.handler.NodesApi;import org.alfresco.core.model.NodeEntry;import org.alfresco.core.model.Node;import org.slf4j.Logger;import org.slf4j.LoggerFactory;import org.springframework.beans.factory.annotation.Autowired;import org.springframework.stereotype.Component;import java.io.IOException;import java.util.List;@Componentpublic class GetNodeMetadataCmd { static final Logger LOGGER = LoggerFactory.getLogger(GetNodeMetadataCmd.class); @Autowired NodesApi nodesApi; public void execute() throws IOException { Node node = getNode("-root-", null); Node node2 = getNode("-root-", "/Data Dictionary"); } /** * Get a node (file/folder). * * @param nodeId the id of the node that we want to fetch metadata for. If relativeFolderPath is specified, then metadata for this node will be returned. Besides node ID the aliases -my-, -root- and -shared- are also supported. * @param relativeFolderPath A path relative to the nodeId, if this is not null, then metadata is returned on the node resolved by this path * @return Node object if exist, or null if does not exist */ private Node getNode(String nodeId, String relativeFolderPath) { List<String> include = null; List<String> fields = null; NodeEntry result = nodesApi.getNode(nodeId, include, relativeFolderPath, fields).getBody(); LOGGER.info("Got node {}", result.getEntry()); return result.getEntry(); }}Executing this code would give the following result:
% java -jar target/rest-api-0.0.1-SNAPSHOT.jar get-node 2021-04-29 08:09:22.215 INFO 18370 --- [ main] o.a.tutorial.restapi.RestApiApplication : Started RestApiApplication in 3.536 seconds (JVM running for 4.449)2021-04-29 08:09:22.217 INFO 18370 --- [ main] o.a.tutorial.restapi.RestApiApplication : args[0]: get-node2021-04-29 08:09:22.485 INFO 18370 --- [ main] o.a.tutorial.restapi.GetNodeMetadataCmd : Got node class Node { id: e439190c-3fe0-48a1-8a9a-374fbc54b570 name: Company Home nodeType: cm:folder isFolder: true isFile: false isLocked: false modifiedAt: 2021-04-28T11:48:08.325Z modifiedByUser: class UserInfo { displayName: System id: System } createdAt: 2021-04-28T11:47:59.098Z createdByUser: class UserInfo { displayName: System id: System } parentId: null isLink: null isFavorite: null content: null aspectNames: [cm:titled, cm:auditable, app:uifacets] properties: {cm:title=Company Home, cm:description=The company root space, app:icon=space-icon-default} allowableOperations: null path: null permissions: null definition: null}2021-04-29 08:09:22.538 INFO 18370 --- [ main] o.a.tutorial.restapi.GetNodeMetadataCmd : Got node class Node { id: 1219e0ff-941f-49df-9151-997b84a8359b name: Data Dictionary nodeType: cm:folder isFolder: true isFile: false isLocked: false modifiedAt: 2021-04-28T11:48:17.700Z modifiedByUser: class UserInfo { displayName: System id: System } createdAt: 2021-04-28T11:47:59.199Z createdByUser: class UserInfo { displayName: System id: System } parentId: e439190c-3fe0-48a1-8a9a-374fbc54b570 isLink: null isFavorite: null content: null aspectNames: [cm:titled, cm:auditable, app:uifacets] properties: {cm:title=Data Dictionary, cm:description=User managed definitions, app:icon=space-icon-default} allowableOperations: null path: null permissions: null definition: null}See alsomanage associations for information on how to list associations for a node.
To create a folder in the repository use thecreateNode method of theNodesApi,which is one of the main APIs used when you want to manipulate folders and files.
More info about this ReST API endpoint
For a description of the common parameters, such asinclude, see thissection.
import org.alfresco.core.handler.NodesApi;import org.alfresco.core.model.Node;import org.alfresco.core.model.NodeBodyCreate;import org.slf4j.Logger;import org.slf4j.LoggerFactory;import org.springframework.beans.factory.annotation.Autowired;import org.springframework.stereotype.Component;import java.io.IOException;import java.util.*;@Componentpublic class CreateFolder { static final Logger LOGGER = LoggerFactory.getLogger(CreateFolder.class); @Autowired NodesApi nodesApi; public void execute() throws IOException { Node folderInCompanyHome = createFolder("Folder1", "Title1", "Desc1", ""); Node folderInFolder1 = createFolder("Folder2", "Title2", "Desc2", "/Folder1"); } /** * Make the remote call to create a folder in the repository, if it does not exist. * * @param folderName the name of the folder * @param folderTitle the title of the folder * @param folderDescription the description of the folder * @param relativeFolderPath path relative to /Company Home * @return a node object for the newly created node, contains the ID, * such as e859588c-ae81-4c5e-a3b6-4c6109b6c905 */ private Node createFolder(String folderName, String folderTitle, String folderDescription, String relativeFolderPath) throws IOException { Objects.requireNonNull(folderName); String rootPath = "-root-"; // /Company Home String folderType = "cm:folder"; // Standard out-of-the-box folder type List<String> folderAspects = new ArrayList<String>(); folderAspects.add("cm:titled"); Map<String, String> folderProps = new HashMap<>(); folderProps.put("cm:title", folderTitle); folderProps.put("cm:description", folderDescription); String nodeId = rootPath; // The id of a node. You can also use one of these well-known aliases: -my-, -shared-, -root- NodeBodyCreate nodeBodyCreate = new NodeBodyCreate(); nodeBodyCreate.setName(folderName); nodeBodyCreate.setNodeType(folderType); nodeBodyCreate.setAspectNames(folderAspects); nodeBodyCreate.setProperties(folderProps); nodeBodyCreate.setRelativePath(relativeFolderPath); List<String> include = null; List<String> fields = null; Boolean autoRename = true; Boolean majorVersion = true; // Should versioning be enabled at all? Boolean versioningEnabled = true; Node folderNode = nodesApi.createNode(nodeId, nodeBodyCreate, autoRename, majorVersion, versioningEnabled, include, fields).getBody().getEntry(); LOGGER.info("Created new folder: {}", folderNode); return folderNode; }}See alsomanage associations for more examples of node creation.
To upload a file to the repository use first theNodesApi.createNodemethod, which will create the metadata for the file, and then theNodesApi.updateNodeContentmethod that will set the content for the file.
At the moment it’s necessary to make two calls to upload a file, but enhancements are being developed in a new versionof SDK 5 to provide a one method approach as this issupported in the ReST API.
For a description of the common parameters, such asinclude, see thissection.
import org.alfresco.core.handler.NodesApi;import org.alfresco.core.model.Node;import org.alfresco.core.model.NodeBodyCreate;import org.apache.commons.io.FileUtils;import org.slf4j.Logger;import org.slf4j.LoggerFactory;import org.springframework.beans.factory.annotation.Autowired;import org.springframework.stereotype.Component;import java.io.File;import java.io.IOException;import java.util.ArrayList;import java.util.HashMap;import java.util.List;import java.util.Map;@Componentpublic class CreateFile { static final Logger LOGGER = LoggerFactory.getLogger(CreateFile.class); private List<String> include = null; private List<String> fields = null; private String contentType = "cm:content"; // Out-of-the-box content type for generic file content private Boolean autoRename = true; private Boolean majorVersion = true; private Boolean versioningEnabled = true; private String updateComment = null; private String updatedName = null; @Autowired NodesApi nodesApi; public void execute() throws IOException { // Create a text file under the /Company Home/Guest Home folder Node newTextFile = createTextFile("-root-", "somestuff.txt", "TextfileTitle", "TextfileDesc", "/Guest Home", "Some text for the file"); // Upload a file from disk to the '/Company Home/Guest Home' folder, the file that is being uploaded, 'somepicture.png' // in this case, is located in the same directory as we are running the app from Node newFile = uploadFile("-root-", "somepicture.png", "PicturefileTitle", "PicturefileDesc", "/Guest Home", "somepicture.png"); } /** * Upload a file from disk */ private Node uploadFile(String parentFolderId, String fileName, String title, String description, String relativeFolderPath, String filePath) { Node fileNode = createFileMetadata(parentFolderId, fileName, title, description, relativeFolderPath); // Get the file bytes File someFile = new File(filePath); byte[] fileData = null; try { fileData = FileUtils.readFileToByteArray(someFile); } catch (IOException e) { e.printStackTrace(); } // Add the file node content Node updatedFileNode = nodesApi.updateNodeContent(fileNode.getId(), fileData, majorVersion, updateComment, updatedName, include, fields).getBody().getEntry(); LOGGER.info("Created file with content: {}", updatedFileNode.toString()); return updatedFileNode; } /** * Create a text file */ private Node createTextFile(String parentFolderId, String fileName, String title, String description, String relativeFolderPath, String textContent) { Node fileNode = createFileMetadata(parentFolderId, fileName, title, description, relativeFolderPath); // Add the file node content Node updatedFileNode = nodesApi.updateNodeContent(fileNode.getId(), textContent.getBytes(), majorVersion, updateComment, updatedName, include, fields).getBody().getEntry(); LOGGER.info("Created file with content: {}", updatedFileNode.toString()); return updatedFileNode; } /** * Create metadata for a file node * * @param parentFolderId the parent folder node ID where the file should be stored * @param fileName the name for the new file * @param title the title property value for the new file * @param description the description property value for the new file * @param relativeFolderPath path relative to /Company Home * @return a Node object with file metadata and the Node ID */ private Node createFileMetadata(String parentFolderId, String fileName, String title, String description, String relativeFolderPath) { List<String> fileAspects = new ArrayList<String>(); fileAspects.add("cm:titled"); Map<String, String> fileProps = new HashMap<>(); fileProps.put("cm:title", title); fileProps.put("cm:description", description); NodeBodyCreate nodeBodyCreate = new NodeBodyCreate(); nodeBodyCreate.setName(fileName); nodeBodyCreate.setNodeType(contentType); nodeBodyCreate.setAspectNames(fileAspects); nodeBodyCreate.setProperties(fileProps); nodeBodyCreate.setRelativePath(relativeFolderPath); // Create the file node metadata Node fileNode = nodesApi.createNode(parentFolderId, nodeBodyCreate, autoRename, majorVersion, versioningEnabled, include, fields).getBody().getEntry(); return fileNode; }}See alsomanage associations for more examples of uploading and creating nodes.
Uploading a file with a custom type to the Repository means creating a node with a type other thancm:content. Seeupload a file for info on how to upload a file with the out-of-the-box content typecm:content set.There’s actually not much difference to how you upload a file with a custom type. Let’s say we have a content model typeacme:document and an aspectacme:securityClassified and these are defined as follows:
<type name="acme:document"> <title>Sample Document Type</title> <parent>cm:content</parent> <properties> <property name="acme:documentId"> <title>Document Identification Number</title> <type>d:text</type> </property> </properties> <mandatory-aspects> <aspect>acme:securityClassified</aspect> </mandatory-aspects></type><aspect name="acme:securityClassified"> <title>ACME Security Classified</title> <description>Content has been security classified</description> <properties> <property name="acme:securityClassification"> <type>d:text</type> <index enabled="true"> <atomic>true</atomic> <stored>false</stored> <tokenised>false</tokenised> </index> <constraints> <constraint ref="acme:securityClassificationOptions"/> </constraints> </property> </properties></aspect>We got two custom propertiesacme:documentId andacme:securityClassification. For more information on how toimplement and deploy this custom content model seethis documentation.
Now, to upload a file and set this custom type and aspect we use the same code as forupload a file withminor updates to thecontentType variable and thecreateFileMetadata method:
import org.alfresco.core.handler.NodesApi;import org.alfresco.core.model.Node;import org.alfresco.core.model.NodeBodyCreate;import org.apache.commons.io.FileUtils;import org.slf4j.Logger;import org.slf4j.LoggerFactory;import org.springframework.beans.factory.annotation.Autowired;import org.springframework.stereotype.Component;import java.io.File;import java.io.IOException;import java.util.ArrayList;import java.util.HashMap;import java.util.List;import java.util.Map;@Componentpublic class CreateFileCustomTypeCmd { static final Logger LOGGER = LoggerFactory.getLogger(CreateFileCustomTypeCmd.class); private String contentType = "acme:document"; // Set custom content type private Boolean autoRename = true; private Boolean majorVersion = true; private Boolean versioningEnabled = true; private String updateComment = null; private String updatedName = null; private List<String> include = null; private List<String> fields = null; @Autowired NodesApi nodesApi; public void execute() throws IOException { // Create a text file under the /Company Home/Guest Home folder Node newTextFile = createTextFile("-root-", "somestuff2.txt", "TextfileTitle2", "TextfileDesc2", "/Guest Home", "Some text for the file2"); // Upload a file from disk to the /Company Home/Guest Home folder, file resides in app dir Node newFile = uploadFile("-root-", "somepicture2.png", "PicturefileTitle2", "PicturefileDesc2", "/Guest Home", "somepicture.png"); } /** * Upload a file from disk */ private Node uploadFile(String parentFolderId, String fileName, String title, String description, String relativeFolderPath, String filePath) { Node fileNode = createFileMetadata(parentFolderId, fileName, title, description, relativeFolderPath); // Get the file bytes File someFile = new File(filePath); byte[] fileData = null; try { fileData = FileUtils.readFileToByteArray(someFile); } catch (IOException e) { e.printStackTrace(); } // Add the file node content Node updatedFileNode = nodesApi.updateNodeContent(fileNode.getId(), fileData, majorVersion, updateComment, updatedName, include, fields).getBody().getEntry(); LOGGER.info("Created file with content: {}", updatedFileNode.toString()); return updatedFileNode; } /** * Create a text file */ private Node createTextFile(String parentFolderId, String fileName, String title, String description, String relativeFolderPath, String textContent) { Node fileNode = createFileMetadata(parentFolderId, fileName, title, description, relativeFolderPath); // Add the file node content Node updatedFileNode = nodesApi.updateNodeContent(fileNode.getId(), textContent.getBytes(), majorVersion, updateComment, updatedName, include, fields).getBody().getEntry(); LOGGER.info("Created file with content: {}", updatedFileNode.toString()); return updatedFileNode; } /** * Create metadata for a file node * * @param parentFolderId the parent folder node ID where the file should be stored * @param fileName the name for the new file * @param title the title property value for the new file * @param description the description property value for the new file * @param relativeFolderPath path relative to /Company Home * @return a Node object with file metadata and the Node ID */ private Node createFileMetadata(String parentFolderId, String fileName, String title, String description, String relativeFolderPath) { List<String> fileAspects = new ArrayList<String>(); fileAspects.add("cm:titled"); fileAspects.add("acme:securityClassified"); Map<String, String> fileProps = new HashMap<>(); fileProps.put("cm:title", title); fileProps.put("cm:description", description); fileProps.put("acme:documentId", "DOC-001"); // custom prop from type fileProps.put("acme:securityClassification", "Company Confidential"); // custom prop from aspect NodeBodyCreate nodeBodyCreate = new NodeBodyCreate(); nodeBodyCreate.setName(fileName); nodeBodyCreate.setNodeType(contentType); nodeBodyCreate.setAspectNames(fileAspects); nodeBodyCreate.setProperties(fileProps); nodeBodyCreate.setRelativePath(relativeFolderPath); // Create the file node metadata Node fileNode = nodesApi.createNode(parentFolderId, nodeBodyCreate, autoRename, majorVersion, versioningEnabled, include, fields).getBody().getEntry(); return fileNode; }}See alsomanage associations for more examples of uploading and creating nodes.
To upload a new version of a file to the repository use theNodesApi.updateNodeContentmethod, which will set the new content for the file.
More info about this ReST API endpoint
For a description of the common parameters, such asmajorVersion, see thissection.
import org.alfresco.core.handler.NodesApi;import org.alfresco.core.model.Node;import org.alfresco.core.model.NodeBodyCreate;import org.apache.commons.io.FileUtils;import org.slf4j.Logger;import org.slf4j.LoggerFactory;import org.springframework.beans.factory.annotation.Autowired;import org.springframework.stereotype.Component;import java.io.File;import java.io.IOException;import java.util.ArrayList;import java.util.HashMap;import java.util.List;import java.util.Map;@Componentpublic class UploadNewFileVersionCmd { static final Logger LOGGER = LoggerFactory.getLogger(UploadNewFileVersionCmd.class); private Boolean majorVersion = true; private String updateComment = null; private String updatedName = null; private List<String> include = null; private List<String> fields = null; @Autowired NodesApi nodesApi; public void execute(String textFileNodeId, String binFileNodeId) throws IOException { // Update text content for a file Node newTextFile = updateTextFileContent(textFileNodeId,"Some UPDATED text for the file"); // Upload a file as new content Node newFile = uploadNewFileVersion(binFileNodeId, "updatedpicture.png"); } /** * Upload a file from disk as a new version */ private Node uploadNewFileVersion(String fileNodeId, String filePath) { // Get the file bytes File someFile = new File(filePath); byte[] fileData = null; try { fileData = FileUtils.readFileToByteArray(someFile); } catch (IOException e) { e.printStackTrace(); } // Update the file node content Node updatedFileNode = nodesApi.updateNodeContent(fileNodeId, fileData, majorVersion, updateComment, updatedName, include, fields).getBody().getEntry(); LOGGER.info("Uploaded new content for file: {}", updatedFileNode.toString()); return updatedFileNode; } /** * Update text content for a file */ private Node updateTextFileContent(String fileNodeId, String textContent) { // Update the file node content Node updatedFileNode = nodesApi.updateNodeContent(fileNodeId, textContent.getBytes(), majorVersion, updateComment, updatedName, include, fields).getBody().getEntry(); LOGGER.info("Updated text content for file: {}", updatedFileNode.toString()); return updatedFileNode; }}We would execute this command class something like this, passing in the command name, text file Node ID, and thebinary file node id:
% java -jar target/rest-api-0.0.1-SNAPSHOT.jar upload-new-version 0492460b-6269-4ca1-9668-0d934d2f3370 48413f7a-066d-4e38-b2e6-c84ede6354932021-04-28 13:44:51.437 INFO 15466 --- [ main] o.a.tutorial.restapi.RestApiApplication : Started RestApiApplication in 2.782 seconds (JVM running for 3.471)2021-04-28 13:44:51.439 INFO 15466 --- [ main] o.a.tutorial.restapi.RestApiApplication : args[0]: upload-new-version2021-04-28 13:44:51.441 INFO 15466 --- [ main] o.a.tutorial.restapi.RestApiApplication : args[1]: 0492460b-6269-4ca1-9668-0d934d2f33702021-04-28 13:44:51.441 INFO 15466 --- [ main] o.a.tutorial.restapi.RestApiApplication : args[2]: 48413f7a-066d-4e38-b2e6-c84ede6354932021-04-28 13:44:51.981 INFO 15466 --- [ main] o.a.t.restapi.UploadNewFileVersionCmd : Updated text content for file: class Node { id: 0492460b-6269-4ca1-9668-0d934d2f3370 name: somestuff2.txt nodeType: acme:document isFolder: false isFile: true isLocked: false modifiedAt: 2021-04-28T12:44:51.578Z modifiedByUser: class UserInfo { displayName: Administrator id: admin } createdAt: 2021-04-28T12:02:33.143Z createdByUser: class UserInfo { displayName: Administrator id: admin } parentId: 8fa4e27d-35aa-411d-8bbe-831b6ed0c445 isLink: null isFavorite: null content: class ContentInfo { mimeType: text/plain mimeTypeName: Plain Text sizeInBytes: 30 encoding: ISO-8859-1 } aspectNames: [rn:renditioned, cm:versionable, cm:titled, cm:auditable, acme:securityClassified, cm:author, cm:thumbnailModification] properties: {cm:title=TextfileTitle2, cm:versionType=MAJOR, acme:documentId=DOC-001, cm:versionLabel=3.0, acme:securityClassification=Company Confidential, cm:lastThumbnailModification=[doclib:1619611506701], cm:description=TextfileDesc2} allowableOperations: null path: null permissions: null definition: null}2021-04-28 13:44:56.783 INFO 15466 --- [ main] o.a.t.restapi.UploadNewFileVersionCmd : Uploaded new content for file: class Node { id: 48413f7a-066d-4e38-b2e6-c84ede635493 name: somepicture2.png nodeType: acme:document isFolder: false isFile: true isLocked: false modifiedAt: 2021-04-28T12:44:52.055Z modifiedByUser: class UserInfo { displayName: Administrator id: admin } createdAt: 2021-04-28T12:02:33.621Z createdByUser: class UserInfo { displayName: Administrator id: admin } parentId: 8fa4e27d-35aa-411d-8bbe-831b6ed0c445 isLink: null isFavorite: null content: class ContentInfo { mimeType: image/png mimeTypeName: PNG Image sizeInBytes: 23174 encoding: UTF-8 } aspectNames: [rn:renditioned, cm:versionable, cm:titled, cm:auditable, acme:securityClassified, cm:author, cm:thumbnailModification, exif:exif] properties: {cm:title=PicturefileTitle2, cm:versionType=MAJOR, acme:documentId=DOC-001, cm:versionLabel=3.0, exif:pixelYDimension=256, acme:securityClassification=Company Confidential, exif:pixelXDimension=256, cm:lastThumbnailModification=[doclib:1619611506392, imgpreview:1619611515611], cm:description=PicturefileDesc2} allowableOperations: null path: null permissions: null definition: null}Note how thecm:versionLabel has bumped up to3.0. Version 1.0 and 2.0 were created when the files werecreated in twosteps.
To get the version history for a file use theVersionsApi.listVersionHistorymethod, which will retrieve a list of all the node versions.
More info about this ReST API endpoint
For a description of the common parameters, such asinclude, see thissection.
import org.alfresco.core.handler.VersionsApi;import org.alfresco.core.model.*;import org.slf4j.Logger;import org.slf4j.LoggerFactory;import org.springframework.beans.factory.annotation.Autowired;import org.springframework.stereotype.Component;import java.io.IOException;import java.util.List;@Componentpublic class ListVersionHistoryCmd { static final Logger LOGGER = LoggerFactory.getLogger(ListVersionHistoryCmd.class); @Autowired VersionsApi versionsApi; public void execute(String fileNodeId) throws IOException { VersionPagingList nodes = listVersionHistory(fileNodeId); } /** * List the version history for a file node. * * @param fileNodeId the id of the file node * @return a list of child node objects contained in the folder, or null if not found */ private VersionPagingList listVersionHistory(String fileNodeId) { Integer skipCount = 0; Integer maxItems = 100; List<String> include = null; List<String> fields = null; LOGGER.info("Listing versions for file node ID {}", fileNodeId); VersionPagingList result = versionsApi.listVersionHistory(fileNodeId, include, fields, skipCount, maxItems).getBody().getList(); for (VersionEntry versionEntry: result.getEntries()) { LOGGER.info("Node version " + versionEntry.getEntry().toString()); } return result; }}We would execute this command class something like this, passing in the file Node ID:
% java -jar target/rest-api-0.0.1-SNAPSHOT.jar list-file-versions 0492460b-6269-4ca1-9668-0d934d2f3370 2021-04-29 08:04:48.145 INFO 18326 --- [ main] o.a.tutorial.restapi.RestApiApplication : Started RestApiApplication in 6.498 seconds (JVM running for 7.686)2021-04-29 08:04:48.148 INFO 18326 --- [ main] o.a.tutorial.restapi.RestApiApplication : args[0]: list-file-versions2021-04-29 08:04:48.152 INFO 18326 --- [ main] o.a.tutorial.restapi.RestApiApplication : args[1]: 0492460b-6269-4ca1-9668-0d934d2f33702021-04-29 08:04:48.152 INFO 18326 --- [ main] o.a.t.restapi.ListVersionHistoryCmd : Listing versions for file node ID 0492460b-6269-4ca1-9668-0d934d2f33702021-04-29 08:04:48.990 INFO 18326 --- [ main] o.a.t.restapi.ListVersionHistoryCmd : Node version class Version { id: 3.0 versionComment: null name: somestuff2.txt nodeType: acme:document isFolder: false isFile: true modifiedAt: 2021-04-28T12:44:51.578Z modifiedByUser: class UserInfo { displayName: Administrator id: admin } content: class ContentInfo { mimeType: text/plain mimeTypeName: Plain Text sizeInBytes: 30 encoding: ISO-8859-1 } aspectNames: null properties: null}2021-04-29 08:04:48.990 INFO 18326 --- [ main] o.a.t.restapi.ListVersionHistoryCmd : Node version class Version { id: 2.0 versionComment: null name: somestuff2.txt nodeType: acme:document isFolder: false isFile: true modifiedAt: 2021-04-28T12:02:33.526Z modifiedByUser: class UserInfo { displayName: Administrator id: admin } content: class ContentInfo { mimeType: text/plain mimeTypeName: Plain Text sizeInBytes: 23 encoding: ISO-8859-1 } aspectNames: null properties: null}2021-04-29 08:04:48.990 INFO 18326 --- [ main] o.a.t.restapi.ListVersionHistoryCmd : Node version class Version { id: 1.0 versionComment: null name: somestuff2.txt nodeType: acme:document isFolder: false isFile: true modifiedAt: 2021-04-28T12:02:33.143Z modifiedByUser: class UserInfo { displayName: Administrator id: admin } content: class ContentInfo { mimeType: text/plain mimeTypeName: Plain Text sizeInBytes: 0 encoding: UTF-8 } aspectNames: null properties: null}Note theid property that contains the file version number. TheversionComment property would contain any commentsmade when uploading a new version of the file. Folder nodes does not have content.
To download a file use theNodesApi.getNodeContentmethod, which will download the content bytes for the file.
More info about this ReST API endpoint
import org.alfresco.core.handler.NodesApi;import org.apache.commons.io.FileUtils;import org.slf4j.Logger;import org.slf4j.LoggerFactory;import org.springframework.beans.factory.annotation.Autowired;import org.springframework.core.io.Resource;import org.springframework.stereotype.Component;import java.io.File;import java.io.IOException;import java.time.OffsetDateTime;@Componentpublic class GetNodeContentCmd { static final Logger LOGGER = LoggerFactory.getLogger(GetNodeContentCmd.class); @Autowired NodesApi nodesApi; public void execute(String fileNodeId, String filePathOnDisk) throws IOException { Resource nodeContent = getNodeContent(fileNodeId); // Write file to disk File targetFile = new File(filePathOnDisk); FileUtils.copyInputStreamToFile(nodeContent.getInputStream(), targetFile); } /** * Get a file node content bytes (folders does not have content). * * @param nodeId the id of the file node that we want to fetch content for. * @return Node content info object */ private Resource getNodeContent(String nodeId) throws IOException { // Relevant when using API call from web browser, true is the default Boolean attachment = true; // Only download if modified since this time, optional OffsetDateTime ifModifiedSince = null; // The Range header indicates the part of a document that the server should return. // Single part request supported, for example: bytes=1-10., optional String range = null; Resource result = nodesApi.getNodeContent(nodeId, attachment, ifModifiedSince, range).getBody(); LOGGER.info("Got node {} size: {}", result.getFilename(), result.contentLength()); return result; }}To download multiple files use theDownloadsApi.createDownloadmethod to create a ZIP download on the server side, then check the status of the ZIP download withDownloadsApi.getDownload.When the download is ready get it withNodesApi.getNodeConent
More info about this ReST API endpoint
For a description of the common parameters, such asfields, see thissection.
import org.alfresco.core.handler.DownloadsApi;import org.alfresco.core.handler.NodesApi;import org.alfresco.core.model.Download;import org.alfresco.core.model.DownloadBodyCreate;import org.alfresco.core.model.DownloadEntry;import org.apache.commons.io.FileUtils;import org.slf4j.Logger;import org.slf4j.LoggerFactory;import org.springframework.beans.factory.annotation.Autowired;import org.springframework.core.io.Resource;import org.springframework.stereotype.Component;import java.io.File;import java.io.IOException;import java.time.OffsetDateTime;import java.util.List;@Componentpublic class GetMultipleNodeContentCmd { static final Logger LOGGER = LoggerFactory.getLogger(GetMultipleNodeContentCmd.class); @Autowired DownloadsApi downloadsApi; @Autowired NodesApi nodesApi; public void execute(String[] fileNodeIds, String zipFilePathOnDisk) throws IOException, InterruptedException { DownloadEntry downloadEntry = createZipDownload(fileNodeIds); Resource zipNodeContent = getNodeContent(downloadEntry.getEntry().getId()); // Write ZIP file to disk File targetFile = new File(zipFilePathOnDisk); FileUtils.copyInputStreamToFile(zipNodeContent.getInputStream(), targetFile); } /** * Create a ZIP download with multiple file nodes. This method waits until download is ready. * * @param nodeIds the node ids for the files we want to download in one ZIP * @return download entry info object for the ZIP */ private DownloadEntry createZipDownload(String[] nodeIds) throws InterruptedException { List<String> fields = null; // Set up POST data with node IDs we want to download DownloadBodyCreate downloads = new DownloadBodyCreate(); for (String nodeId : nodeIds) { downloads.addNodeIdsItem(nodeId); } // First create the download on the server side DownloadEntry result = downloadsApi.createDownload(downloads, fields).getBody(); LOGGER.info("Created ZIP download: {}", result.getEntry().toString()); // Check the download status DownloadEntry download = downloadsApi.getDownload(result.getEntry().getId(), fields).getBody(); while (!download.getEntry().getStatus().equals(Download.StatusEnum.DONE)) { LOGGER.info("Checking ZIP download status: {}", download.getEntry().getStatus()); Thread.sleep(1000); // do nothing for 1000 milliseconds (1 second) download = downloadsApi.getDownload(result.getEntry().getId(), fields).getBody(); } LOGGER.info("ZIP download is READY: {}", result.getEntry().getId()); return download; } /** * Get a file node content bytes (folders does not have content). * * @param nodeId the id of the file node that we want to fetch content for. * @return Node content info object */ private Resource getNodeContent(String nodeId) throws IOException { // Relevant when using API call from web browser, true is the default Boolean attachment = true; // Only download if modified since this time, optional OffsetDateTime ifModifiedSince = null; // The Range header indicates the part of a document that the server should return. // Single part request supported, for example: bytes=1-10., optional String range = null; Resource result = nodesApi.getNodeContent(nodeId, attachment, ifModifiedSince, range).getBody(); LOGGER.info("Got node {} size: {}", result.getFilename(), result.contentLength()); return result; }}Executing the code gives a result looking something like this:
% java -jar target/rest-api-0.0.1-SNAPSHOT.jar get-multiple-file-content 0492460b-6269-4ca1-9668-0d934d2f3370 48413f7a-066d-4e38-b2e6-c84ede635493 mydownload.zip2021-04-29 12:58:53.560 INFO 19432 --- [ main] o.a.tutorial.restapi.RestApiApplication : Started RestApiApplication in 2.956 seconds (JVM running for 3.436)2021-04-29 12:58:53.562 INFO 19432 --- [ main] o.a.tutorial.restapi.RestApiApplication : args[0]: get-multiple-file-content2021-04-29 12:58:53.564 INFO 19432 --- [ main] o.a.tutorial.restapi.RestApiApplication : args[1]: 0492460b-6269-4ca1-9668-0d934d2f33702021-04-29 12:58:53.564 INFO 19432 --- [ main] o.a.tutorial.restapi.RestApiApplication : args[2]: 48413f7a-066d-4e38-b2e6-c84ede6354932021-04-29 12:58:53.564 INFO 19432 --- [ main] o.a.tutorial.restapi.RestApiApplication : args[3]: mydownload.zip2021-04-29 12:58:54.150 INFO 19432 --- [ main] o.a.t.restapi.GetMultipleNodeContentCmd : Created ZIP download: class Download { filesAdded: 0 bytesAdded: 0 id: b73c36e5-112b-48a0-baa6-fa225bd9d53d totalFiles: 0 totalBytes: 0 status: PENDING}2021-04-29 12:58:54.167 INFO 19432 --- [ main] o.a.t.restapi.GetMultipleNodeContentCmd : Checking ZIP download status: PENDING2021-04-29 12:58:55.194 INFO 19432 --- [ main] o.a.t.restapi.GetMultipleNodeContentCmd : ZIP download is READY: b73c36e5-112b-48a0-baa6-fa225bd9d53d2021-04-29 12:58:55.223 INFO 19432 --- [ main] o.a.t.restapi.GetMultipleNodeContentCmd : Got node archive.zip size: 23111In this example we pass in two file node identifiers that will be requested in the zip download. The zip download filewill be stored in current directory under the namemydownload.zip. Note that right after we have initialized thecreation of the zip download there are no files added to the zip (filesAdded: 0), we have to wait for the zip downloadto be created on the server side. Then we can download with the usualgetNodeContent method.
To list content renditions for a file use theRenditionsApi.listRenditionsmethod.
More info about this ReST API endpoint
For a description of the common parameters, such aswhere, see thissection.
import org.alfresco.core.handler.RenditionsApi;import org.alfresco.core.model.RenditionEntry;import org.alfresco.core.model.RenditionPagingList;import org.slf4j.Logger;import org.slf4j.LoggerFactory;import org.springframework.beans.factory.annotation.Autowired;import org.springframework.stereotype.Component;import java.io.IOException;import java.util.List;@Componentpublic class ListRenditionsCmd { static final Logger LOGGER = LoggerFactory.getLogger(ListRenditionsCmd.class); @Autowired RenditionsApi renditionsApi; public void execute(String fileNodeId) throws IOException { RenditionPagingList nodeRenditions = listRenditions(fileNodeId); } /** * List renditions for a file node. * * @param fileNodeId the id of the file node * @return a list of renditions, or null if not found */ private RenditionPagingList listRenditions(String fileNodeId) { String where = null; // filter renditions LOGGER.info("Listing versions for file node ID {}", fileNodeId); RenditionPagingList result = renditionsApi.listRenditions(fileNodeId, where).getBody().getList(); for (RenditionEntry renditionEntry: result.getEntries()) { LOGGER.info("Node rendition: " + renditionEntry.getEntry().toString()); } return result; }}Executing this code looks like this, here we are listing renditions for a text file:
% java -jar target/rest-api-0.0.1-SNAPSHOT.jar list-renditions 0492460b-6269-4ca1-9668-0d934d2f3370 2021-04-29 13:58:25.387 INFO 19701 --- [ main] o.a.tutorial.restapi.RestApiApplication : Started RestApiApplication in 3.131 seconds (JVM running for 3.822)2021-04-29 13:58:25.389 INFO 19701 --- [ main] o.a.tutorial.restapi.RestApiApplication : args[0]: list-renditions2021-04-29 13:58:25.390 INFO 19701 --- [ main] o.a.tutorial.restapi.RestApiApplication : args[1]: 0492460b-6269-4ca1-9668-0d934d2f33702021-04-29 13:58:25.391 INFO 19701 --- [ main] o.a.tutorial.restapi.ListRenditionsCmd : Listing versions for file node ID 0492460b-6269-4ca1-9668-0d934d2f33702021-04-29 13:58:25.703 INFO 19701 --- [ main] o.a.tutorial.restapi.ListRenditionsCmd : Node rendition: class Rendition { id: avatar content: class ContentInfo { mimeType: image/png mimeTypeName: PNG Image sizeInBytes: null encoding: null } status: NOT_CREATED}2021-04-29 13:58:25.703 INFO 19701 --- [ main] o.a.tutorial.restapi.ListRenditionsCmd : Node rendition: class Rendition { id: avatar32 content: class ContentInfo { mimeType: image/png mimeTypeName: PNG Image sizeInBytes: null encoding: null } status: NOT_CREATED}2021-04-29 13:58:25.703 INFO 19701 --- [ main] o.a.tutorial.restapi.ListRenditionsCmd : Node rendition: class Rendition { id: doclib content: class ContentInfo { mimeType: image/png mimeTypeName: PNG Image sizeInBytes: 222 encoding: UTF-8 } status: CREATED}2021-04-29 13:58:25.703 INFO 19701 --- [ main] o.a.tutorial.restapi.ListRenditionsCmd : Node rendition: class Rendition { id: imgpreview content: class ContentInfo { mimeType: image/jpeg mimeTypeName: JPEG Image sizeInBytes: null encoding: null } status: NOT_CREATED}2021-04-29 13:58:25.703 INFO 19701 --- [ main] o.a.tutorial.restapi.ListRenditionsCmd : Node rendition: class Rendition { id: medium content: class ContentInfo { mimeType: image/jpeg mimeTypeName: JPEG Image sizeInBytes: null encoding: null } status: NOT_CREATED}2021-04-29 13:58:25.703 INFO 19701 --- [ main] o.a.tutorial.restapi.ListRenditionsCmd : Node rendition: class Rendition { id: pdf content: class ContentInfo { mimeType: application/pdf mimeTypeName: Adobe PDF Document sizeInBytes: 8472 encoding: UTF-8 } status: CREATED}We can see the renditionsid, such aspdf. Some renditions are for things you see in the UI, such asthumbnail and preview of document.
To get the content for a file rendition theRenditionsApi.getRenditionContentmethod, which will download the content bytes for the file rendition.
More info about this ReST API endpoint
import org.alfresco.core.handler.RenditionsApi;import org.apache.commons.io.FileUtils;import org.slf4j.Logger;import org.slf4j.LoggerFactory;import org.springframework.beans.factory.annotation.Autowired;import org.springframework.core.io.Resource;import org.springframework.stereotype.Component;import java.io.File;import java.io.IOException;import java.time.OffsetDateTime;@Componentpublic class GetRenditionContentCmd { static final Logger LOGGER = LoggerFactory.getLogger(GetRenditionContentCmd.class); @Autowired RenditionsApi renditionsApi; public void execute(String fileNodeId, String renditionId, String filePathOnDisk) throws IOException { Resource nodeContent = getRenditionContent(fileNodeId, renditionId); // Write rendition file to disk File targetFile = new File(filePathOnDisk); FileUtils.copyInputStreamToFile(nodeContent.getInputStream(), targetFile); } /** * Get rendition content info. * * @param nodeId the id for the node that the rendition is for * @param renditionId the id of the rendition that we want to fetch content for, such as doclib, pdf etc * @return Rendition content info object */ private Resource getRenditionContent(String nodeId, String renditionId) throws IOException { // Relevant when using API call from web browser, true is the default Boolean attachment = true; // Only download if modified since this time, optional OffsetDateTime ifModifiedSince = null; // The Range header indicates the part of a rendition that the server should return. // Single part request supported, for example: bytes=1-10., optional String range = null; // If true and there is no rendition for this nodeId and renditionId, then the placeholder image for the // mimetype of this rendition is returned, rather than a 404 response Boolean placeholder = false; Resource result = renditionsApi.getRenditionContent( nodeId, renditionId, attachment, ifModifiedSince, range, placeholder).getBody(); LOGGER.info("Got rendition {} size: {}", result.getFilename(), result.contentLength()); return result; }}Executing this code and getting apdf rendition for a text file looks like this:
% java -jar target/rest-api-0.0.1-SNAPSHOT.jar get-rendition-content 0492460b-6269-4ca1-9668-0d934d2f3370 pdf mytext.pdf 2021-04-29 16:05:25.501 INFO 20077 --- [ main] o.a.tutorial.restapi.RestApiApplication : Started RestApiApplication in 3.324 seconds (JVM running for 3.867)2021-04-29 16:05:25.504 INFO 20077 --- [ main] o.a.tutorial.restapi.RestApiApplication : args[0]: get-rendition-content2021-04-29 16:05:25.506 INFO 20077 --- [ main] o.a.tutorial.restapi.RestApiApplication : args[1]: 0492460b-6269-4ca1-9668-0d934d2f33702021-04-29 16:05:25.506 INFO 20077 --- [ main] o.a.tutorial.restapi.RestApiApplication : args[2]: pdf2021-04-29 16:05:25.506 INFO 20077 --- [ main] o.a.tutorial.restapi.RestApiApplication : args[3]: mytext.pdf2021-04-29 16:05:25.657 INFO 20077 --- [ main] o.a.t.restapi.GetRenditionContentCmd : Got rendition pdf size: 8472To update metadata for a node, such as a file or folder, use theNodesApi.updateNodemethod.
More info about this ReST API endpoint
For a description of the common parameters, such asinclude, see thissection.
import org.alfresco.core.handler.NodesApi;import org.alfresco.core.model.Node;import org.alfresco.core.model.NodeBodyUpdate;import org.alfresco.core.model.NodeEntry;import org.alfresco.core.model.PermissionsBody;import org.slf4j.Logger;import org.slf4j.LoggerFactory;import org.springframework.beans.factory.annotation.Autowired;import org.springframework.stereotype.Component;import java.io.IOException;import java.util.HashMap;import java.util.List;import java.util.Map;@Componentpublic class UpdateNodeMetadataCmd { static final Logger LOGGER = LoggerFactory.getLogger(UpdateNodeMetadataCmd.class); @Autowired NodesApi nodesApi; public void execute(String nodeId) throws IOException { Map<String, Object> properties = new HashMap<>(); properties.put("cm:title", "UPDATED title"); properties.put("cm:description", "UPDATED description"); Node node = updateNode(nodeId, "newname.txt", properties, null, null); } /** * Update a node (such as file/folder). * * @param nodeId the id of the node that we want to update metadata for. * @param newName a new name for the node (sets cm:name) * @param properties the properties we want to update and their new values * @param aspectNames a list of aspect names to set the node, not that it needs to include all aspects as it will overwrite * @param permissionsBody permissions to set on the node * @return updated Node object */ private Node updateNode(String nodeId, String newName, Map<String, Object> properties, List<String> aspectNames, PermissionsBody permissionsBody) { List<String> include = null; List<String> fields = null; NodeBodyUpdate nodeBodyUpdate = new NodeBodyUpdate(); nodeBodyUpdate.setName(newName); nodeBodyUpdate.setProperties(properties); nodeBodyUpdate.setAspectNames(aspectNames); nodeBodyUpdate.setPermissions(permissionsBody); NodeEntry result = nodesApi.updateNode(nodeId, nodeBodyUpdate, include, fields).getBody(); LOGGER.info("Updated node {}", result.getEntry()); return result.getEntry(); }}With theupdateNode call we can update properties, aspects, and permissions for a node. Note that when updatingaspects you need to include the complete list of aspects that should be set on the node as this call overwrites. You canfetch existing aspects with thegetNodeMetadata call. If you are adding an aspect that has properties,then you can just add the properties and the aspect will be added automatically for you.
Executing this code result in this for a text file example:
% java -jar target/rest-api-0.0.1-SNAPSHOT.jar update-metadata 0492460b-6269-4ca1-9668-0d934d2f33702021-04-29 16:27:42.303 INFO 20246 --- [ main] o.a.tutorial.restapi.RestApiApplication : Started RestApiApplication in 3.185 seconds (JVM running for 3.683)2021-04-29 16:27:42.306 INFO 20246 --- [ main] o.a.tutorial.restapi.RestApiApplication : args[0]: update-metadata2021-04-29 16:27:42.308 INFO 20246 --- [ main] o.a.tutorial.restapi.RestApiApplication : args[1]: 0492460b-6269-4ca1-9668-0d934d2f33702021-04-29 16:27:43.089 INFO 20246 --- [ main] o.a.t.restapi.UpdateNodeMetadataCmd : Updated node class Node { id: 0492460b-6269-4ca1-9668-0d934d2f3370 name: newname.txt nodeType: acme:document isFolder: false isFile: true isLocked: false modifiedAt: 2021-04-29T15:27:42.528Z modifiedByUser: class UserInfo { displayName: Administrator id: admin } createdAt: 2021-04-28T12:02:33.143Z createdByUser: class UserInfo { displayName: Administrator id: admin } parentId: 8fa4e27d-35aa-411d-8bbe-831b6ed0c445 isLink: null isFavorite: null content: class ContentInfo { mimeType: text/plain mimeTypeName: Plain Text sizeInBytes: 30 encoding: ISO-8859-1 } aspectNames: [rn:renditioned, cm:versionable, cm:titled, cm:auditable, acme:securityClassified, cm:author, cm:thumbnailModification] properties: {cm:title=UPDATED title, cm:versionType=MAJOR, acme:documentId=DOC-001, cm:versionLabel=3.0, acme:securityClassification=Company Confidential, cm:lastThumbnailModification=[doclib:1619613896873, pdf:1619701086215], cm:description=UPDATED description} allowableOperations: null path: null permissions: null definition: null}We can see the updated name and properties in the returned node object.
To add aspects to a node, use theNodesApi.updateNodemethod. The way you do this is described in theupdate metadata for a node section. Note that youonly need to add aspects to a node when they are so called “marker” aspects without properties.
More info about this ReST API endpoint
To remove aspects from a node, use theNodesApi.updateNodemethod. The way you do this is described in theupdate metadata for a node section.
Removing an aspect from a node is similar to how you add a “marker” aspect. You first get the list of aspects currentlyapplied to the node. Then you remove the aspect from the list. And finally you use an update node call with the updatedaspect list.
More info about this ReST API endpoint
To manage permissions for a node, use theNodesApi.updateNodemethod.
More info about this ReST API endpoint
For a description of the common parameters, such asinclude, see thissection.
In the following example we show how a node can be updated with new permissions for a group and a user.
import org.alfresco.core.handler.NodesApi;import org.alfresco.core.model.*;import org.slf4j.Logger;import org.slf4j.LoggerFactory;import org.springframework.beans.factory.annotation.Autowired;import org.springframework.stereotype.Component;import java.io.IOException;import java.util.ArrayList;import java.util.List;@Componentpublic class SetNodePermissionsMetadataCmd { static final Logger LOGGER = LoggerFactory.getLogger(SetNodePermissionsMetadataCmd.class); @Autowired NodesApi nodesApi; public void execute(String nodeId) throws IOException { // First get current permissions PermissionsInfo currentPermissions = getNodePermissions(nodeId); // Update with permissions for a user and a group // Add current permissions first, it will overwrite so we need to add what's already set PermissionsBody permissionsBody = new PermissionsBody(); permissionsBody.setIsInheritanceEnabled(true); permissionsBody.setLocallySet(currentPermissions.getLocallySet()); PermissionElement engineeringGroupPermission = new PermissionElement(); engineeringGroupPermission.setName("Collaborator"); engineeringGroupPermission.setAuthorityId("GROUP_engineering"); engineeringGroupPermission.setAccessStatus(PermissionElement.AccessStatusEnum.ALLOWED); permissionsBody.addLocallySetItem(engineeringGroupPermission); PermissionElement testUserPermission = new PermissionElement(); testUserPermission.setName("Contributor"); testUserPermission.setAuthorityId("tester"); testUserPermission.setAccessStatus(PermissionElement.AccessStatusEnum.ALLOWED); permissionsBody.addLocallySetItem(testUserPermission); // Update permissions for node Node node = updateNodePermissions(nodeId, permissionsBody); } /** * Get node permissions. * * @param nodeId the id of the node that we want to get permissions for. * @return updated Node object */ private PermissionsInfo getNodePermissions(String nodeId) { String relativePath = null; List<String> fields = null; List<String> include = new ArrayList<>(); include.add("permissions"); NodeEntry result = nodesApi.getNode(nodeId, include, relativePath, fields).getBody(); LOGGER.info("Got node including permissions {}", result.getEntry()); return result.getEntry().getPermissions(); } /** * Update node permissions. * * @param nodeId the id of the node that we want to update permissions for. * @param permissionsBody permissions to set on the node * @return updated Node object */ private Node updateNodePermissions(String nodeId, PermissionsBody permissionsBody) { List<String> include = new ArrayList<>(); include.add("permissions"); List<String> fields = null; NodeBodyUpdate nodeBodyUpdate = new NodeBodyUpdate(); nodeBodyUpdate.setPermissions(permissionsBody); NodeEntry result = nodesApi.updateNode(nodeId, nodeBodyUpdate, include, fields).getBody(); LOGGER.info("Updated node permissions {}", result.getEntry()); return result.getEntry(); }}Note that you have to first get the currently set permissions before you set the new ones. This is because theupdate call will overwrite permissions already set. So we use thegetNodeMetadata call to getalready set node permissions.
Executing this code result in this for a text file example:
% java -jar target/rest-api-0.0.1-SNAPSHOT.jar update-permissions 0492460b-6269-4ca1-9668-0d934d2f33702021-04-30 09:32:02.206 INFO 21515 --- [ main] o.a.tutorial.restapi.RestApiApplication : Started RestApiApplication in 3.4 seconds (JVM running for 3.957)2021-04-30 09:32:02.208 INFO 21515 --- [ main] o.a.tutorial.restapi.RestApiApplication : args[0]: update-permissions2021-04-30 09:32:02.210 INFO 21515 --- [ main] o.a.tutorial.restapi.RestApiApplication : args[1]: 0492460b-6269-4ca1-9668-0d934d2f33702021-04-30 09:32:02.509 INFO 21515 --- [ main] o.a.t.r.SetNodePermissionsMetadataCmd : Got node including permissions class Node { id: 0492460b-6269-4ca1-9668-0d934d2f3370 name: newname.txt nodeType: acme:document isFolder: false isFile: true isLocked: false modifiedAt: 2021-04-29T15:27:42.528Z modifiedByUser: class UserInfo { displayName: Administrator id: admin } createdAt: 2021-04-28T12:02:33.143Z createdByUser: class UserInfo { displayName: Administrator id: admin } parentId: 8fa4e27d-35aa-411d-8bbe-831b6ed0c445 isLink: null isFavorite: null content: class ContentInfo { mimeType: text/plain mimeTypeName: Plain Text sizeInBytes: 30 encoding: ISO-8859-1 } aspectNames: [rn:renditioned, cm:versionable, cm:titled, cm:auditable, acme:securityClassified, cm:author, cm:thumbnailModification] properties: {cm:title=UPDATED title, cm:versionType=MAJOR, acme:documentId=DOC-001, cm:versionLabel=3.0, acme:securityClassification=Company Confidential, cm:lastThumbnailModification=[doclib:1619613896873, pdf:1619701086215], cm:description=UPDATED description} allowableOperations: null path: null permissions: class PermissionsInfo { isInheritanceEnabled: true inherited: [class PermissionElement { authorityId: GROUP_EVERYONE name: Consumer accessStatus: ALLOWED }, class PermissionElement { authorityId: guest name: Consumer accessStatus: ALLOWED }] locallySet: null settable: [Contributor, Collaborator, Coordinator, Editor, Consumer] } definition: null}2021-04-30 09:32:02.708 INFO 21515 --- [ main] o.a.t.r.SetNodePermissionsMetadataCmd : Updated node permissions class Node { id: 0492460b-6269-4ca1-9668-0d934d2f3370 name: newname.txt nodeType: acme:document isFolder: false isFile: true isLocked: false modifiedAt: 2021-04-30T08:32:02.635Z modifiedByUser: class UserInfo { displayName: Administrator id: admin } createdAt: 2021-04-28T12:02:33.143Z createdByUser: class UserInfo { displayName: Administrator id: admin } parentId: 8fa4e27d-35aa-411d-8bbe-831b6ed0c445 isLink: null isFavorite: null content: class ContentInfo { mimeType: text/plain mimeTypeName: Plain Text sizeInBytes: 30 encoding: ISO-8859-1 } aspectNames: [rn:renditioned, cm:versionable, cm:titled, cm:auditable, acme:securityClassified, cm:author, cm:thumbnailModification] properties: {cm:title=UPDATED title, cm:versionType=MAJOR, acme:documentId=DOC-001, cm:versionLabel=3.0, acme:securityClassification=Company Confidential, cm:lastThumbnailModification=[doclib:1619613896873, pdf:1619701086215], cm:description=UPDATED description} allowableOperations: null path: null permissions: class PermissionsInfo { isInheritanceEnabled: true inherited: [class PermissionElement { authorityId: guest name: Consumer accessStatus: ALLOWED }, class PermissionElement { authorityId: GROUP_EVERYONE name: Consumer accessStatus: ALLOWED }] locallySet: [class PermissionElement { authorityId: GROUP_engineering name: Collaborator accessStatus: ALLOWED }, class PermissionElement { authorityId: tester name: Contributor accessStatus: ALLOWED }] settable: [Contributor, Collaborator, Coordinator, Editor, Consumer] } definition: null}We can see that before the permission update there were no locally set permissions for the node, onlyinherited. Afterthe update we see also thelocallySet returned with the newly set permissions. Note that for the permission informationto be returned with each call we have to addpermissions to theinclude parameter.
To manage relationships (referred to as associations) between nodes use theNodesApiand the following methods:
| Method | Description |
|---|---|
| listNodeChildren | List primary parent-child associations, seelist folder content |
| createSecondaryChildAssociation | Create secondary parent-child association |
| deleteSecondaryChildAssociation | Delete secondary parent-child association |
| listSecondaryChildren | List secondary parent-child associations |
| createAssociation | Create peer-2-peer association |
| deleteAssociation | Delete peer-2-peer association(s) |
| listSourceAssociations | List source peer-2-peer associations |
| listTargetAssociations | List target peer-2-peer associations |
More info about this ReST API endpoint
For a description of the common parameters, such asinclude, see thissection.
Assuming we have deployed theFDK content modelwith secondary parent-child and peer-2-peer association types, then the following code examples shows how to create thosetypes of associations (it also shows how to upload files, create folder, create node of different type):
Note. this code assumes the following two files exists in current directory:
somepicture.pngandsometext.txt.
import org.alfresco.core.handler.NodesApi;import org.alfresco.core.model.*;import org.apache.commons.io.FileUtils;import org.slf4j.Logger;import org.slf4j.LoggerFactory;import org.springframework.beans.factory.annotation.Autowired;import org.springframework.stereotype.Component;import java.io.File;import java.io.IOException;import java.util.*;@Componentpublic class ManageAssociationsCmd { static final Logger LOGGER = LoggerFactory.getLogger(ManageAssociationsCmd.class); @Autowired NodesApi nodesApi; private Boolean autoRename = true; private Boolean majorVersion = true; private Boolean versioningEnabled = true; private String updateComment = null; private String updatedName = null; private List<String> include = null; private List<String> fields = null; private List<String> orderBy = null; private Integer skipCount = 0; private Integer maxItems = 100; private String where = null; private Boolean includeSource = false; public void execute() throws IOException { // List all folders and files (primary parent-child associations) in /Company Home/Data Dictionary NodeChildAssociationPagingList primaryChildAssociations = listPrimaryChildAssociations("-root-", "/Data Dictionary"); // Create gadget folder, gadget image, and gadget review Node gadgetFolderNode = createFolder("My Gadgets", ""); Node gadgetPictureNode = uploadFile(gadgetFolderNode.getId(), "gadget-picture.png", "somepicture.png"); Node gadgetReviewNode = uploadFile(gadgetFolderNode.getId(), "gadget-review.txt", "sometext.txt"); // Create the Gadget company node Map<String, Object> properties = new HashMap<>(); properties.put("fdk:email", "info@coolgadgets.com"); properties.put("fdk:url","www.coolgadgets.com"); properties.put("fdk:city","London"); Node companyNode = createNode(gadgetFolderNode.getId(), "Cool Gadgets Inc","fdk:company", properties); // Create a gadget node with associations using the FDK content model List<ChildAssociationBody> secondaryParentChildAssociations = new ArrayList<>(); ChildAssociationBody childAssoc = new ChildAssociationBody(); childAssoc.assocType("fdk:images"); childAssoc.setChildId(gadgetPictureNode.getId()); secondaryParentChildAssociations.add(childAssoc); List<AssociationBody> peer2peerAssociations = new ArrayList<>(); AssociationBody peer2peerAssoc = new AssociationBody(); peer2peerAssoc.assocType("fdk:reviews"); peer2peerAssoc.setTargetId(gadgetReviewNode.getId()); peer2peerAssociations.add(peer2peerAssoc); AssociationBody peer2peerAssoc2 = new AssociationBody(); peer2peerAssoc2.assocType("fdk:company"); peer2peerAssoc2.setTargetId(companyNode.getId()); peer2peerAssociations.add(peer2peerAssoc2); Node gadgetNode = createNodeWithAssociations( gadgetFolderNode.getId(),"My Gadget", "fdk:gadget", secondaryParentChildAssociations, peer2peerAssociations); // List secondary parent-child associations for a node NodeChildAssociationPagingList secondaryAssoc = listSecondaryChildAssociations(gadgetNode.getId()); // List peer-2-peer associations for a node NodeAssociationPagingList targetAssoc = listPeer2PeerAssociations(gadgetNode.getId()); } /** * List primary parent-child associations. Basically list folder contents. * * @param rootNodeId the id of the folder node that is the root. If relativeFolderPath is null, then content in this folder will be listed. Besides node ID the aliases -my-, -root- and -shared- are also supported. * @param relativeFolderPath path relative rootNodeId, if this is not null, then the content of this folder will be listed * @return a list of child node objects contained in the folder, or null if not found */ private NodeChildAssociationPagingList listPrimaryChildAssociations(String rootNodeId, String relativeFolderPath) { LOGGER.info("Listing primary child associations for folder {}{}", rootNodeId, relativeFolderPath); NodeChildAssociationPagingList result = nodesApi.listNodeChildren(rootNodeId, skipCount, maxItems, orderBy, where, include, relativeFolderPath, includeSource, fields).getBody().getList(); for (NodeChildAssociationEntry childNodeAssoc: result.getEntries()) { LOGGER.info("Found primary child [name=" + childNodeAssoc.getEntry().getName() + "]"); } return result; } /** * List secondary parent-child associations. * * @param nodeId the node to list assoc for * @return a list of child node objects contained in the node, or null if not found */ private NodeChildAssociationPagingList listSecondaryChildAssociations(String nodeId) { LOGGER.info("Listing secondary child associations for node {}", nodeId); NodeChildAssociationPagingList result = nodesApi.listSecondaryChildren( nodeId, where, include, skipCount, maxItems, includeSource, fields).getBody().getList(); for (NodeChildAssociationEntry childNodeAssoc: result.getEntries()) { LOGGER.info("Found secondary child [name=" + childNodeAssoc.getEntry().getName() + "]"); } return result; } /** * List peer-2-peer associations. * * @param nodeId the node to list assoc for * @return a list of assoc objects associated with the node */ private NodeAssociationPagingList listPeer2PeerAssociations(String nodeId) { LOGGER.info("Listing peer-2-peer associations for node {}", nodeId); NodeAssociationPagingList result = nodesApi.listTargetAssociations( nodeId, where, include, fields).getBody().getList(); for (NodeAssociationEntry targetAssoc: result.getEntries()) { LOGGER.info("Found target [name=" + targetAssoc.getEntry().getName() + "]"); } return result; } /** * Create a node with associations. * * @param parentNodeId the parent node id * @param nodeName the name of the node * @param nodeType the type of the node * @param secondaryParentChildAssociations a list of secondary parent-child associations that should be set up * @param peer2peerAssociations a list of peer-2-peer associations that should be set up * @return a node object for the newly created node, contains the ID, * such as e859588c-ae81-4c5e-a3b6-4c6109b6c905 */ private Node createNodeWithAssociations( String parentNodeId, String nodeName, String nodeType, List<ChildAssociationBody> secondaryParentChildAssociations, List<AssociationBody> peer2peerAssociations) { NodeBodyCreate nodeBodyCreate = new NodeBodyCreate(); nodeBodyCreate.setName(nodeName); nodeBodyCreate.setNodeType(nodeType); nodeBodyCreate.setSecondaryChildren(secondaryParentChildAssociations); nodeBodyCreate.setTargets(peer2peerAssociations); Node node = nodesApi.createNode(parentNodeId, nodeBodyCreate, autoRename, majorVersion, versioningEnabled, include, fields).getBody().getEntry(); LOGGER.info("Created new node with associations: {}", node); return node; } /** * Make the remote call to create a folder in the repository, if it does not exist. * * @param folderName the name of the folder * @param relativeFolderPath path relative to /Company Home * @return a node object for the newly created node, contains the ID, * such as e859588c-ae81-4c5e-a3b6-4c6109b6c905 */ private Node createFolder(String folderName, String relativeFolderPath) { String nodeId = "-root-"; NodeBodyCreate nodeBodyCreate = new NodeBodyCreate(); nodeBodyCreate.setName(folderName); nodeBodyCreate.setNodeType("cm:folder"); nodeBodyCreate.setRelativePath(relativeFolderPath); Node folderNode = nodesApi.createNode(nodeId, nodeBodyCreate, autoRename, majorVersion, versioningEnabled, include, fields).getBody().getEntry(); LOGGER.info("Created new folder: {}", folderNode); return folderNode; } /** * Create a node * * @param parentNodeId the node id for parent folder * @param nodeName the name of the node * @param nodeType the type of the node * @return a node object for the newly created node, contains the ID, * such as e859588c-ae81-4c5e-a3b6-4c6109b6c905 */ private Node createNode(String parentNodeId, String nodeName, String nodeType, Map<String, Object> properties) { NodeBodyCreate nodeBodyCreate = new NodeBodyCreate(); nodeBodyCreate.setName(nodeName); nodeBodyCreate.setNodeType(nodeType); nodeBodyCreate.setProperties(properties); Node node = nodesApi.createNode( parentNodeId, nodeBodyCreate, autoRename, majorVersion, versioningEnabled, include, fields).getBody().getEntry(); LOGGER.info("Created new node: {}", node); return node; } /** * Upload a file from disk */ private Node uploadFile(String folderId, String fileName, String filePath) { // Create the file node metadata NodeBodyCreate nodeBodyCreate = new NodeBodyCreate(); nodeBodyCreate.setName(fileName); nodeBodyCreate.setNodeType("cm:content"); Node fileNode = nodesApi.createNode( folderId, nodeBodyCreate, autoRename, majorVersion, versioningEnabled, include, fields).getBody().getEntry(); // Get the file bytes File someFile = new File(filePath); byte[] fileData = null; try { fileData = FileUtils.readFileToByteArray(someFile); } catch (IOException e) { e.printStackTrace(); } // Add the file node content Node updatedFileNode = nodesApi.updateNodeContent(fileNode.getId(), fileData, majorVersion, updateComment, updatedName, include, fields).getBody().getEntry(); LOGGER.info("Created file with content: {}", updatedFileNode.toString()); return updatedFileNode; }}Executing the above code will result in logs such as follows:
% java -jar target/rest-api-0.0.1-SNAPSHOT.jar manage-associations 2021-04-30 16:26:22.678 INFO 22647 --- [ main] o.a.tutorial.restapi.RestApiApplication : Started RestApiApplication in 2.93 seconds (JVM running for 3.402)2021-04-30 16:26:22.680 INFO 22647 --- [ main] o.a.tutorial.restapi.RestApiApplication : args[0]: manage-associations2021-04-30 16:26:22.681 INFO 22647 --- [ main] o.a.t.restapi.ManageAssociationsCmd : Listing primary child associations for folder -root-/Data Dictionary2021-04-30 16:26:23.071 INFO 22647 --- [ main] o.a.t.restapi.ManageAssociationsCmd : Found primary child [name=Email Templates]2021-04-30 16:26:23.071 INFO 22647 --- [ main] o.a.t.restapi.ManageAssociationsCmd : Found primary child [name=Imap Configs]2021-04-30 16:26:23.071 INFO 22647 --- [ main] o.a.t.restapi.ManageAssociationsCmd : Found primary child [name=Messages]2021-04-30 16:26:23.071 INFO 22647 --- [ main] o.a.t.restapi.ManageAssociationsCmd : Found primary child [name=Models]2021-04-30 16:26:23.071 INFO 22647 --- [ main] o.a.t.restapi.ManageAssociationsCmd : Found primary child [name=Node Templates]2021-04-30 16:26:23.071 INFO 22647 --- [ main] o.a.t.restapi.ManageAssociationsCmd : Found primary child [name=Presentation Templates]2021-04-30 16:26:23.071 INFO 22647 --- [ main] o.a.t.restapi.ManageAssociationsCmd : Found primary child [name=Rendering Actions Space]2021-04-30 16:26:23.071 INFO 22647 --- [ main] o.a.t.restapi.ManageAssociationsCmd : Found primary child [name=Replication Actions Space]2021-04-30 16:26:23.071 INFO 22647 --- [ main] o.a.t.restapi.ManageAssociationsCmd : Found primary child [name=RSS Templates]2021-04-30 16:26:23.071 INFO 22647 --- [ main] o.a.t.restapi.ManageAssociationsCmd : Found primary child [name=Saved Searches]2021-04-30 16:26:23.072 INFO 22647 --- [ main] o.a.t.restapi.ManageAssociationsCmd : Found primary child [name=Scheduled Actions]2021-04-30 16:26:23.072 INFO 22647 --- [ main] o.a.t.restapi.ManageAssociationsCmd : Found primary child [name=Scripts]2021-04-30 16:26:23.072 INFO 22647 --- [ main] o.a.t.restapi.ManageAssociationsCmd : Found primary child [name=Smart Folder Downloads]2021-04-30 16:26:23.072 INFO 22647 --- [ main] o.a.t.restapi.ManageAssociationsCmd : Found primary child [name=Smart Folder Templates]2021-04-30 16:26:23.072 INFO 22647 --- [ main] o.a.t.restapi.ManageAssociationsCmd : Found primary child [name=Solr Facets Space]2021-04-30 16:26:23.072 INFO 22647 --- [ main] o.a.t.restapi.ManageAssociationsCmd : Found primary child [name=Space Templates]2021-04-30 16:26:23.072 INFO 22647 --- [ main] o.a.t.restapi.ManageAssociationsCmd : Found primary child [name=Transfers]2021-04-30 16:26:23.072 INFO 22647 --- [ main] o.a.t.restapi.ManageAssociationsCmd : Found primary child [name=Web Client Extension]2021-04-30 16:26:23.072 INFO 22647 --- [ main] o.a.t.restapi.ManageAssociationsCmd : Found primary child [name=Web Scripts]2021-04-30 16:26:23.072 INFO 22647 --- [ main] o.a.t.restapi.ManageAssociationsCmd : Found primary child [name=Web Scripts Extensions]2021-04-30 16:26:23.072 INFO 22647 --- [ main] o.a.t.restapi.ManageAssociationsCmd : Found primary child [name=Workflow Definitions]2021-04-30 16:26:23.184 INFO 22647 --- [ main] o.a.t.restapi.ManageAssociationsCmd : Created new folder: class Node { id: e6bacba5-0dba-40af-afa0-ff25e10a18bb name: My Gadgets nodeType: cm:folder isFolder: true isFile: false isLocked: false modifiedAt: 2021-04-30T15:26:23.129Z modifiedByUser: class UserInfo { displayName: Administrator id: admin } createdAt: 2021-04-30T15:26:23.129Z createdByUser: class UserInfo { displayName: Administrator id: admin } parentId: e439190c-3fe0-48a1-8a9a-374fbc54b570 isLink: null isFavorite: null content: null aspectNames: [cm:auditable] properties: null allowableOperations: null path: null permissions: null definition: null}2021-04-30 16:26:23.482 INFO 22647 --- [ main] o.a.t.restapi.ManageAssociationsCmd : Created file with content: class Node { id: b9bf8f12-269f-46a3-97a8-16900644a7d6 name: gadget-picture.png nodeType: cm:content isFolder: false isFile: true isLocked: false modifiedAt: 2021-04-30T15:26:23.404Z modifiedByUser: class UserInfo { displayName: Administrator id: admin } createdAt: 2021-04-30T15:26:23.218Z createdByUser: class UserInfo { displayName: Administrator id: admin } parentId: e6bacba5-0dba-40af-afa0-ff25e10a18bb isLink: null isFavorite: null content: class ContentInfo { mimeType: image/png mimeTypeName: PNG Image sizeInBytes: 14799 encoding: UTF-8 } aspectNames: [cm:versionable, cm:auditable] properties: {cm:versionLabel=2.0, cm:versionType=MAJOR} allowableOperations: null path: null permissions: null definition: null}2021-04-30 16:26:23.716 INFO 22647 --- [ main] o.a.t.restapi.ManageAssociationsCmd : Created file with content: class Node { id: bb35fdd6-f2f3-44e4-84c9-30e48efaf3d5 name: gadget-review.txt nodeType: cm:content isFolder: false isFile: true isLocked: false modifiedAt: 2021-04-30T15:26:23.644Z modifiedByUser: class UserInfo { displayName: Administrator id: admin } createdAt: 2021-04-30T15:26:23.507Z createdByUser: class UserInfo { displayName: Administrator id: admin } parentId: e6bacba5-0dba-40af-afa0-ff25e10a18bb isLink: null isFavorite: null content: class ContentInfo { mimeType: text/plain mimeTypeName: Plain Text sizeInBytes: 30 encoding: ISO-8859-1 } aspectNames: [cm:versionable, cm:auditable] properties: {cm:versionLabel=2.0, cm:versionType=MAJOR} allowableOperations: null path: null permissions: null definition: null}2021-04-30 16:26:23.918 INFO 22647 --- [ main] o.a.t.restapi.ManageAssociationsCmd : Created new node: class Node { id: 01c5e298-a6c2-4b5c-81e0-195172626e22 name: Cool Gadgets Inc nodeType: fdk:company isFolder: false isFile: true isLocked: false modifiedAt: 2021-04-30T15:26:23.772Z modifiedByUser: class UserInfo { displayName: Administrator id: admin } createdAt: 2021-04-30T15:26:23.772Z createdByUser: class UserInfo { displayName: Administrator id: admin } parentId: e6bacba5-0dba-40af-afa0-ff25e10a18bb isLink: null isFavorite: null content: class ContentInfo { mimeType: application/octet-stream mimeTypeName: Binary File (Octet Stream) sizeInBytes: 0 encoding: UTF-8 } aspectNames: [cm:versionable, cm:auditable] properties: {fdk:email=info@coolgadgets.com, fdk:url=www.coolgadgets.com, cm:versionType=MAJOR, cm:versionLabel=1.0, fdk:city=London} allowableOperations: null path: null permissions: null definition: null}2021-04-30 16:26:24.133 INFO 22647 --- [ main] o.a.t.restapi.ManageAssociationsCmd : Created new node with associations: class Node { id: c5f329e8-7872-4e92-abe1-e7dd5f5f48ba name: My Gadget nodeType: fdk:gadget isFolder: false isFile: true isLocked: false modifiedAt: 2021-04-30T15:26:23.950Z modifiedByUser: class UserInfo { displayName: Administrator id: admin } createdAt: 2021-04-30T15:26:23.950Z createdByUser: class UserInfo { displayName: Administrator id: admin } parentId: e6bacba5-0dba-40af-afa0-ff25e10a18bb isLink: null isFavorite: null content: class ContentInfo { mimeType: application/octet-stream mimeTypeName: Binary File (Octet Stream) sizeInBytes: 0 encoding: UTF-8 } aspectNames: [cm:versionable, cm:auditable] properties: {cm:versionLabel=1.0, cm:versionType=MAJOR} allowableOperations: null path: null permissions: null definition: null}2021-04-30 16:26:24.134 INFO 22647 --- [ main] o.a.t.restapi.ManageAssociationsCmd : Listing secondary child associations for node c5f329e8-7872-4e92-abe1-e7dd5f5f48ba2021-04-30 16:26:24.156 INFO 22647 --- [ main] o.a.t.restapi.ManageAssociationsCmd : Found secondary child [name=gadget-picture.png]2021-04-30 16:26:24.157 INFO 22647 --- [ main] o.a.t.restapi.ManageAssociationsCmd : Listing peer-2-peer associations for node c5f329e8-7872-4e92-abe1-e7dd5f5f48ba2021-04-30 16:26:24.239 INFO 22647 --- [ main] o.a.t.restapi.ManageAssociationsCmd : Found target [name=gadget-review.txt]2021-04-30 16:26:24.239 INFO 22647 --- [ main] o.a.t.restapi.ManageAssociationsCmd : Found target [name=Cool Gadgets Inc]To create associations for existing nodes use thecreateSecondaryChildAssociation andcreateAssociation methods.
To manage comments for a node, use theCommentsApiand the following methods:
| Method | Description |
|---|---|
| createComment | Create a comment for a node |
| deleteComment | Delete a comment for a node |
| listComments | List comments for a node |
| updateComment | Update a comment for a node |
More info about this ReST API endpoint
For a description of the common parameters, such asinclude, see thissection.
import org.alfresco.core.handler.CommentsApi;import org.alfresco.core.model.*;import org.slf4j.Logger;import org.slf4j.LoggerFactory;import org.springframework.beans.factory.annotation.Autowired;import org.springframework.stereotype.Component;import java.io.IOException;import java.util.ArrayList;import java.util.List;@Componentpublic class ManageCommentsCmd { static final Logger LOGGER = LoggerFactory.getLogger(ManageCommentsCmd.class); private Integer skipCount = 0; private Integer maxItems = 100; private List<String> fields = new ArrayList<>(); // Fetch only the fields we are interested in public ManageCommentsCmd() { fields.add("content,createdAt"); } @Autowired CommentsApi commentsApi; public void execute(String nodeId) throws IOException { Comment firstComment = createComment(nodeId, "First comment"); Comment secondComment = createComment(nodeId, "Second comment"); LOGGER.info("Listing comments: "); CommentPagingList comments = commentsApi.listComments(nodeId, skipCount, maxItems, fields).getBody().getList(); for (CommentEntry commentEntry: comments.getEntries()) { LOGGER.info(" {}", commentEntry.getEntry()); } } private Comment createComment(String nodeId, String text) { CommentBody commentBody = new CommentBody(); commentBody.setContent(text); Comment comment = commentsApi.createComment(nodeId, commentBody, fields).getBody().getEntry(); LOGGER.info("{}", comment); return comment; }}Note the use of thefields parameter to limit the number of fields returned with each call, which saves bandwidth.
Executing the code gives a log like follows:
% java -jar target/rest-api-0.0.1-SNAPSHOT.jar manage-comments 0492460b-6269-4ca1-9668-0d934d2f33702021-05-03 18:54:48.085 INFO 26804 --- [ main] o.a.tutorial.restapi.RestApiApplication : Started RestApiApplication in 3.075 seconds (JVM running for 3.55)2021-05-03 18:54:48.087 INFO 26804 --- [ main] o.a.tutorial.restapi.RestApiApplication : args[0]: manage-comments2021-05-03 18:54:48.088 INFO 26804 --- [ main] o.a.tutorial.restapi.RestApiApplication : args[1]: 0492460b-6269-4ca1-9668-0d934d2f33702021-05-03 18:54:48.373 INFO 26804 --- [ main] o.a.tutorial.restapi.ManageCommentsCmd : class Comment { id: null title: null content: First comment createdBy: null createdAt: 2021-05-03T17:54:48.224Z edited: null modifiedBy: null modifiedAt: null canEdit: null canDelete: null}2021-05-03 18:54:48.492 INFO 26804 --- [ main] o.a.tutorial.restapi.ManageCommentsCmd : class Comment { id: null title: null content: Second comment createdBy: null createdAt: 2021-05-03T17:54:48.417Z edited: null modifiedBy: null modifiedAt: null canEdit: null canDelete: null}2021-05-03 18:54:48.492 INFO 26804 --- [ main] o.a.tutorial.restapi.ManageCommentsCmd : Listing comments: 2021-05-03 18:54:48.545 INFO 26804 --- [ main] o.a.tutorial.restapi.ManageCommentsCmd : class Comment { id: null title: null content: Second comment createdBy: null createdAt: 2021-05-03T17:54:48.417Z edited: null modifiedBy: null modifiedAt: null canEdit: null canDelete: null}2021-05-03 18:54:48.545 INFO 26804 --- [ main] o.a.tutorial.restapi.ManageCommentsCmd : class Comment { id: null title: null content: First comment createdBy: null createdAt: 2021-05-03T17:54:48.224Z edited: null modifiedBy: null modifiedAt: null canEdit: null canDelete: null}To manage tags for a node, use theTagsApiand the following methods:
| Method | Description |
|---|---|
| createTagForNode | Create a tag for a node |
| deleteTagFromNode | Delete a tag from a node |
| getTag | Get a tag |
| listTags | List tags |
| listTagsForNode | List tags for a node |
| updateTag | Update a tag |
More info about this ReST API endpoint
For a description of the common parameters, such asinclude, see thissection.
import org.alfresco.core.handler.TagsApi;import org.alfresco.core.model.*;import org.slf4j.Logger;import org.slf4j.LoggerFactory;import org.springframework.beans.factory.annotation.Autowired;import org.springframework.stereotype.Component;import java.io.IOException;import java.util.ArrayList;import java.util.List;@Componentpublic class ManageTagsCmd { static final Logger LOGGER = LoggerFactory.getLogger(ManageTagsCmd.class); private Integer skipCount = 0; private Integer maxItems = 100; private List<String> fields = null; private List<String> include = new ArrayList<>(); // Include an extra field with tag count public ManageTagsCmd() { include.add("count"); } @Autowired TagsApi tagsApi; public void execute(String nodeId) throws IOException { Tag firstTag = createTag(nodeId, "tag-one"); Tag secondTag = createTag(nodeId, "tag-two"); LOGGER.info("Listing tags for the whole repository: "); TagPagingList repoTags = tagsApi.listTags(skipCount, maxItems, fields, include).getBody().getList(); for (TagEntry repoTagEntry: repoTags.getEntries()) { LOGGER.info(" {} count: {}", repoTagEntry.getEntry().getTag(), repoTagEntry.getEntry().getCount()); } LOGGER.info("Listing tags for node: {}", nodeId); TagPagingList nodeTags = tagsApi.listTagsForNode(nodeId, skipCount, maxItems, fields).getBody().getList(); for (TagEntry nodeTagEntry: nodeTags.getEntries()) { LOGGER.info(" {}", nodeTagEntry.getEntry()); } } private Tag createTag(String nodeId, String text) { TagBody tagBody = new TagBody(); tagBody.setTag(text); Tag tag = tagsApi.createTagForNode(nodeId, tagBody, fields).getBody().getEntry(); LOGGER.info("Created Tag {}", tag); return tag; }}Executing the code gives a log like follows:
% java -jar target/rest-api-0.0.1-SNAPSHOT.jar manage-tags 0492460b-6269-4ca1-9668-0d934d2f33702021-05-04 09:56:25.846 INFO 27655 --- [ main] o.a.tutorial.restapi.RestApiApplication : Started RestApiApplication in 2.884 seconds (JVM running for 3.333)2021-05-04 09:56:25.848 INFO 27655 --- [ main] o.a.tutorial.restapi.RestApiApplication : args[0]: manage-tags2021-05-04 09:56:25.849 INFO 27655 --- [ main] o.a.tutorial.restapi.RestApiApplication : args[1]: 0492460b-6269-4ca1-9668-0d934d2f33702021-05-04 09:56:26.073 INFO 27655 --- [ main] o.a.tutorial.restapi.ManageTagsCmd : Created Tag class Tag { id: a6da6c4d-cb6b-41b5-a010-7188459dd3cb tag: tag-one count: null}2021-05-04 09:56:26.175 INFO 27655 --- [ main] o.a.tutorial.restapi.ManageTagsCmd : Created Tag class Tag { id: 9a9044c9-3787-44ca-bd92-c6797c9a82ae tag: tag-two count: null}2021-05-04 09:56:26.175 INFO 27655 --- [ main] o.a.tutorial.restapi.ManageTagsCmd : Listing tags for the whole repository: 2021-05-04 09:56:26.288 INFO 27655 --- [ main] o.a.tutorial.restapi.ManageTagsCmd : activiti count: 32021-05-04 09:56:26.288 INFO 27655 --- [ main] o.a.tutorial.restapi.ManageTagsCmd : aps count: 12021-05-04 09:56:26.288 INFO 27655 --- [ main] o.a.tutorial.restapi.ManageTagsCmd : tag-one count: null2021-05-04 09:56:26.288 INFO 27655 --- [ main] o.a.tutorial.restapi.ManageTagsCmd : tag-two count: null2021-05-04 09:56:26.288 INFO 27655 --- [ main] o.a.tutorial.restapi.ManageTagsCmd : white-paper count: 22021-05-04 09:56:26.288 INFO 27655 --- [ main] o.a.tutorial.restapi.ManageTagsCmd : Listing tags for node: 0492460b-6269-4ca1-9668-0d934d2f33702021-05-04 09:56:26.310 INFO 27655 --- [ main] o.a.tutorial.restapi.ManageTagsCmd : class Tag { id: a6da6c4d-cb6b-41b5-a010-7188459dd3cb tag: tag-one count: null}2021-05-04 09:56:26.310 INFO 27655 --- [ main] o.a.tutorial.restapi.ManageTagsCmd : class Tag { id: 9a9044c9-3787-44ca-bd92-c6797c9a82ae tag: tag-two count: null}Note that the tag count are not available directly after you have created the tag. It has to be indexed first.
To copy a node, such as a file or folder, use thecopyNode method of theNodesApi.
More info about this ReST API endpoint
For a description of the common parameters, such asinclude, see thissection.
import org.alfresco.core.handler.NodesApi;import org.alfresco.core.model.Node;import org.alfresco.core.model.NodeBodyCopy;import org.slf4j.Logger;import org.slf4j.LoggerFactory;import org.springframework.beans.factory.annotation.Autowired;import org.springframework.stereotype.Component;import java.io.IOException;import java.util.ArrayList;import java.util.List;@Componentpublic class CopyNodeCmd { static final Logger LOGGER = LoggerFactory.getLogger(CopyNodeCmd.class); @Autowired NodesApi nodesApi; public void execute(String nodeId, String parentFolderNodeId) throws IOException { List<String> include = new ArrayList<>(); List<String> fields = null; include.add("path"); // add extra path property in response so we can see location of node Node node = nodesApi.getNode(nodeId, include, null, fields).getBody().getEntry(); LOGGER.info("Got node we want to copy ID: {} Parent: {} Location: {}", node.getId(), node.getParentId(), node.getPath().getName()); NodeBodyCopy nodeBodyCopy = new NodeBodyCopy(); nodeBodyCopy.setTargetParentId(parentFolderNodeId); Node copiedNode = nodesApi.copyNode(nodeId, nodeBodyCopy, include, fields).getBody().getEntry(); LOGGER.info("Copied node ID: {} Parent: {} Location: {}", copiedNode.getId(), copiedNode.getParentId(), copiedNode.getPath().getName()); }}Executing this code would give the following result, passing in node to copy and target folder node:
% java -jar target/rest-api-0.0.1-SNAPSHOT.jar copy-node 0492460b-6269-4ca1-9668-0d934d2f3370 7f041db0-fdb6-4185-b921-2fb9ed3814802021-05-04 10:52:16.741 INFO 28353 --- [ main] o.a.tutorial.restapi.RestApiApplication : Started RestApiApplication in 3.667 seconds (JVM running for 4.218)2021-05-04 10:52:16.743 INFO 28353 --- [ main] o.a.tutorial.restapi.RestApiApplication : args[0]: copy-node2021-05-04 10:52:16.745 INFO 28353 --- [ main] o.a.tutorial.restapi.RestApiApplication : args[1]: 0492460b-6269-4ca1-9668-0d934d2f33702021-05-04 10:52:16.745 INFO 28353 --- [ main] o.a.tutorial.restapi.RestApiApplication : args[2]: 7f041db0-fdb6-4185-b921-2fb9ed3814802021-05-04 10:52:16.974 INFO 28353 --- [ main] o.alfresco.tutorial.restapi.CopyNodeCmd : Got node we want to copy ID: 0492460b-6269-4ca1-9668-0d934d2f3370 Parent: 8fa4e27d-35aa-411d-8bbe-831b6ed0c445 Location: /Company Home/Guest Home2021-05-04 10:52:17.366 INFO 28353 --- [ main] o.alfresco.tutorial.restapi.CopyNodeCmd : Copied node ID: fe955da0-c4e5-42d3-972f-697424b546b1 Parent: 7f041db0-fdb6-4185-b921-2fb9ed381480 Location: /Company Home/Imap AttachmentsNote the new node ID for the copy in the response.
Note that we set theinclude parameter topath so the location of the node is returned.The following extra information is returned:
Location: class PathInfo { elements: [class PathElement { id: e439190c-3fe0-48a1-8a9a-374fbc54b570 name: Company Home nodeType: cm:folder aspectNames: [cm:titled, cm:auditable, app:uifacets] }, class PathElement { id: 7f041db0-fdb6-4185-b921-2fb9ed381480 name: Imap Attachments nodeType: cm:folder aspectNames: [cm:titled, cm:auditable, app:uifacets] }] name: /Company Home/Imap Attachments isComplete: true}To copy a node, such as a file or folder, use themoveNode method of theNodesApi.
More info about this ReST API endpoint
For a description of the common parameters, such asinclude, see thissection.
import org.alfresco.core.handler.NodesApi;import org.alfresco.core.model.Node;import org.alfresco.core.model.NodeBodyMove;import org.slf4j.Logger;import org.slf4j.LoggerFactory;import org.springframework.beans.factory.annotation.Autowired;import org.springframework.stereotype.Component;import java.io.IOException;import java.util.ArrayList;import java.util.List;@Componentpublic class MoveNodeCmd { static final Logger LOGGER = LoggerFactory.getLogger(MoveNodeCmd.class); @Autowired NodesApi nodesApi; public void execute(String nodeId, String parentFolderNodeId) throws IOException { List<String> include = new ArrayList<>(); List<String> fields = null; include.add("path"); // add extra path property in response so we can see location of node Node node = nodesApi.getNode(nodeId, include, null, fields).getBody().getEntry(); LOGGER.info("Got node before move ID: {} Parent: {} Location: {}", node.getId(), node.getParentId(), node.getPath().getName()); NodeBodyMove nodeBodyMove = new NodeBodyMove(); nodeBodyMove.setTargetParentId(parentFolderNodeId); Node movedNode = nodesApi.moveNode(nodeId, nodeBodyMove, include, fields).getBody().getEntry(); LOGGER.info("Moved node ID: {} Parent: {} Location: {}", movedNode.getId(), movedNode.getParentId(), movedNode.getPath().getName()); }}Executing this code would give the following result, passing in node to copy and target folder node:
% java -jar target/rest-api-0.0.1-SNAPSHOT.jar move-node d11d6970-c5c4-4edd-9971-593a23b9344f 7f041db0-fdb6-4185-b921-2fb9ed3814802021-05-04 10:45:47.080 INFO 28288 --- [ main] o.a.tutorial.restapi.RestApiApplication : Started RestApiApplication in 3.103 seconds (JVM running for 3.568)2021-05-04 10:45:47.081 INFO 28288 --- [ main] o.a.tutorial.restapi.RestApiApplication : args[0]: move-node2021-05-04 10:45:47.082 INFO 28288 --- [ main] o.a.tutorial.restapi.RestApiApplication : args[1]: d11d6970-c5c4-4edd-9971-593a23b9344f2021-05-04 10:45:47.082 INFO 28288 --- [ main] o.a.tutorial.restapi.RestApiApplication : args[2]: 7f041db0-fdb6-4185-b921-2fb9ed3814802021-05-04 10:45:47.276 INFO 28288 --- [ main] o.alfresco.tutorial.restapi.MoveNodeCmd : Got node before move ID: d11d6970-c5c4-4edd-9971-593a23b9344f Parent: 8fa4e27d-35aa-411d-8bbe-831b6ed0c445 Location: /Company Home/Guest Home2021-05-04 10:45:47.458 INFO 28288 --- [ main] o.alfresco.tutorial.restapi.MoveNodeCmd : Moved node ID: d11d6970-c5c4-4edd-9971-593a23b9344f Parent: 7f041db0-fdb6-4185-b921-2fb9ed381480 Location: /Company Home/Imap AttachmentsNote that the node ID in the response is the same as passed in node ID, it is just the location of the node thathas changed when moving it.
Note that we set theinclude parameter topath so the location of the node is returned.The following extra information is returned:
Location: class PathInfo { elements: [class PathElement { id: e439190c-3fe0-48a1-8a9a-374fbc54b570 name: Company Home nodeType: cm:folder aspectNames: [cm:titled, cm:auditable, app:uifacets] }, class PathElement { id: 7f041db0-fdb6-4185-b921-2fb9ed381480 name: Imap Attachments nodeType: cm:folder aspectNames: [cm:titled, cm:auditable, app:uifacets] }] name: /Company Home/Imap Attachments isComplete: true}To lock a file for editing, use thelockNode method of theNodesApi.Use theunlockNode method when you are finished editing the node.
More info about this ReST API endpoint
For a description of the common parameters, such asinclude, see thissection.
import org.alfresco.core.handler.NodesApi;import org.alfresco.core.model.Node;import org.alfresco.core.model.NodeBodyLock;import org.slf4j.Logger;import org.slf4j.LoggerFactory;import org.springframework.beans.factory.annotation.Autowired;import org.springframework.stereotype.Component;import java.io.IOException;import java.util.List;@Componentpublic class LockNodeCmd { static final Logger LOGGER = LoggerFactory.getLogger(LockNodeCmd.class); @Autowired NodesApi nodesApi; public void execute(String nodeId) throws IOException { List<String> include = null; List<String> fields = null; Node node = nodesApi.getNode(nodeId, include, null, fields).getBody().getEntry(); LOGGER.info("Got node we want to lock ID: {} Is locked ?: {}", node.getId(), node.isIsLocked()); if (!node.isIsLocked()) { // Lock the file with exclusive lock NodeBodyLock nodeBodyLock = new NodeBodyLock(); Node lockedNode = nodesApi.lockNode(nodeId, nodeBodyLock, include, fields).getBody().getEntry(); LOGGER.info("Locked node: {}", lockedNode); // Do the work on the file // Unlock the file Node unLockedNode = nodesApi.unlockNode(nodeId, include, fields).getBody().getEntry(); LOGGER.info("Unlocked node: {}", unLockedNode); } }}Executing this code would give the following result, passing in node to lock:
% java -jar target/rest-api-0.0.1-SNAPSHOT.jar lock-node 0492460b-6269-4ca1-9668-0d934d2f3370 2021-05-04 11:12:51.070 INFO 28630 --- [ main] o.a.tutorial.restapi.RestApiApplication : Started RestApiApplication in 3.722 seconds (JVM running for 4.523)2021-05-04 11:12:51.072 INFO 28630 --- [ main] o.a.tutorial.restapi.RestApiApplication : args[0]: lock-node2021-05-04 11:12:51.074 INFO 28630 --- [ main] o.a.tutorial.restapi.RestApiApplication : args[1]: 0492460b-6269-4ca1-9668-0d934d2f33702021-05-04 11:12:51.285 INFO 28630 --- [ main] o.alfresco.tutorial.restapi.LockNodeCmd : Got node we want to lock ID: 0492460b-6269-4ca1-9668-0d934d2f3370 Is locked ?: false2021-05-04 11:12:51.671 INFO 28630 --- [ main] o.alfresco.tutorial.restapi.LockNodeCmd : Locked node: class Node { id: 0492460b-6269-4ca1-9668-0d934d2f3370 name: newname.txt nodeType: acme:document isFolder: false isFile: true isLocked: false modifiedAt: 2021-05-04T08:56:26.135Z modifiedByUser: class UserInfo { displayName: Administrator id: admin } createdAt: 2021-04-28T12:02:33.143Z createdByUser: class UserInfo { displayName: Administrator id: admin } parentId: 8fa4e27d-35aa-411d-8bbe-831b6ed0c445 isLink: null isFavorite: null content: class ContentInfo { mimeType: text/plain mimeTypeName: Plain Text sizeInBytes: 30 encoding: ISO-8859-1 } aspectNames: [rn:renditioned, cm:versionable, acme:securityClassified, cm:taggable, cm:thumbnailModification, fm:discussable, cm:titled, cm:lockable, cm:auditable, fm:commentsRollup, cm:author] properties: {cm:lockType=WRITE_LOCK, cm:title=UPDATED title, cm:lockOwner={id=admin, displayName=Administrator}, cm:versionType=MAJOR, acme:documentId=DOC-001, cm:versionLabel=3.0, cm:lockLifetime=PERSISTENT, fm:commentCount=2, acme:securityClassification=Company Confidential, cm:lastThumbnailModification=[doclib:1619613896873, pdf:1619701086215], cm:description=UPDATED description, cm:taggable=[a6da6c4d-cb6b-41b5-a010-7188459dd3cb, 9a9044c9-3787-44ca-bd92-c6797c9a82ae]} allowableOperations: null path: null permissions: null definition: null}2021-05-04 11:12:51.743 INFO 28630 --- [ main] o.alfresco.tutorial.restapi.LockNodeCmd : Unlocked node: class Node { id: 0492460b-6269-4ca1-9668-0d934d2f3370 name: newname.txt nodeType: acme:document isFolder: false isFile: true isLocked: false modifiedAt: 2021-05-04T08:56:26.135Z modifiedByUser: class UserInfo { displayName: Administrator id: admin } createdAt: 2021-04-28T12:02:33.143Z createdByUser: class UserInfo { displayName: Administrator id: admin } parentId: 8fa4e27d-35aa-411d-8bbe-831b6ed0c445 isLink: null isFavorite: null content: class ContentInfo { mimeType: text/plain mimeTypeName: Plain Text sizeInBytes: 30 encoding: ISO-8859-1 } aspectNames: [rn:renditioned, cm:versionable, acme:securityClassified, cm:taggable, cm:thumbnailModification, fm:discussable, cm:titled, cm:auditable, fm:commentsRollup, cm:author] properties: {cm:title=UPDATED title, cm:versionType=MAJOR, acme:documentId=DOC-001, cm:versionLabel=3.0, fm:commentCount=2, acme:securityClassification=Company Confidential, cm:lastThumbnailModification=[doclib:1619613896873, pdf:1619701086215], cm:description=UPDATED description, cm:taggable=[a6da6c4d-cb6b-41b5-a010-7188459dd3cb, 9a9044c9-3787-44ca-bd92-c6797c9a82ae]} allowableOperations: null path: null permissions: null definition: null}Note that thelockNode call response contains some extra parameters with lock information, such ascm:lockType=WRITE_LOCK andcm:lockOwner={id=admin, displayName=Administrator}.
To create a link to a file, use thecreateNode method of theNodesApiand create a node of the typeapp:filelink.
More info about this ReST API endpoint
For a description of the common parameters, such asinclude, see thissection.
import org.alfresco.core.handler.NodesApi;import org.alfresco.core.model.Node;import org.alfresco.core.model.NodeBodyCreate;import org.slf4j.Logger;import org.slf4j.LoggerFactory;import org.springframework.beans.factory.annotation.Autowired;import org.springframework.stereotype.Component;import java.io.IOException;import java.util.*;@Componentpublic class LinkFileCmd { static final Logger LOGGER = LoggerFactory.getLogger(LinkFileCmd.class); @Autowired NodesApi nodesApi; public void execute(String parentFolderNodeId, String linkToNodeId) throws IOException { Map<String, String> linkProps = new HashMap<>(); linkProps.put("cm:destination", linkToNodeId); // Link points to this file node NodeBodyCreate nodeBodyCreate = new NodeBodyCreate(); nodeBodyCreate.setName("Link to a text file"); nodeBodyCreate.setNodeType("app:filelink"); // Out-of-the-box content model type for a file link nodeBodyCreate.setProperties(linkProps); Boolean autoRename = true; List<String> include = new ArrayList<>(); List<String> fields = null; Boolean majorVersion = true; Boolean versioningEnabled = true; // Include the isLink property in the response so we can see if a node is a link include.add("isLink"); Node fileLinkNode = nodesApi.createNode(parentFolderNodeId, nodeBodyCreate, autoRename, majorVersion, versioningEnabled, include, fields).getBody().getEntry(); LOGGER.info("File link: {}", fileLinkNode); }}Executing this code would give the following result, passing in parent folder and node to link:
% java -jar target/rest-api-0.0.1-SNAPSHOT.jar link-file 7f041db0-fdb6-4185-b921-2fb9ed381480 48413f7a-066d-4e38-b2e6-c84ede6354932021-05-04 13:27:43.981 INFO 29404 --- [ main] o.a.tutorial.restapi.RestApiApplication : Started RestApiApplication in 4.237 seconds (JVM running for 4.904)2021-05-04 13:27:43.983 INFO 29404 --- [ main] o.a.tutorial.restapi.RestApiApplication : args[0]: link-file2021-05-04 13:27:43.985 INFO 29404 --- [ main] o.a.tutorial.restapi.RestApiApplication : args[1]: 7f041db0-fdb6-4185-b921-2fb9ed3814802021-05-04 13:27:43.985 INFO 29404 --- [ main] o.a.tutorial.restapi.RestApiApplication : args[2]: 48413f7a-066d-4e38-b2e6-c84ede6354932021-05-04 13:27:44.329 INFO 29404 --- [ main] o.alfresco.tutorial.restapi.LinkFileCmd : File link: class Node { id: c4ab808f-f42b-42a8-b308-d5d82df29830 name: Link to a text file nodeType: app:filelink isFolder: false isFile: true isLocked: false modifiedAt: 2021-05-04T12:27:44.166Z modifiedByUser: class UserInfo { displayName: Administrator id: admin } createdAt: 2021-05-04T12:27:44.166Z createdByUser: class UserInfo { displayName: Administrator id: admin } parentId: 7f041db0-fdb6-4185-b921-2fb9ed381480 isLink: true isFavorite: null content: null aspectNames: [cm:auditable] properties: {cm:destination=48413f7a-066d-4e38-b2e6-c84ede635493} allowableOperations: null path: null permissions: null definition: null}Note that theinclude parameter has been populated with theisLink value, which means the response will containa value for theisLink property.
To delete a folder or a file node, use thedeleteNode method of theNodesApi.
More info about this ReST API endpoint
import org.alfresco.core.handler.NodesApi;import org.slf4j.Logger;import org.slf4j.LoggerFactory;import org.springframework.beans.factory.annotation.Autowired;import org.springframework.http.ResponseEntity;import org.springframework.stereotype.Component;import java.io.IOException;@Componentpublic class DeleteNodeCmd { static final Logger LOGGER = LoggerFactory.getLogger(DeleteNodeCmd.class); @Autowired NodesApi nodesApi; public void execute(String nodeId) throws IOException { // If true, then the node is deleted permanently, without moving to the trashcan. // Only the owner of the node or an admin can permanently delete the node. // default value = false Boolean permanent = false; ResponseEntity<Void> deletedNodeResponse = nodesApi.deleteNode(nodeId, permanent); LOGGER.info("Deleted node response: {}", deletedNodeResponse); }}Executing this code would give the following result, passing in the node to delete:
% java -jar target/rest-api-0.0.1-SNAPSHOT.jar delete-node fe955da0-c4e5-42d3-972f-697424b546b1 2021-05-04 13:47:10.376 INFO 29542 --- [ main] o.a.tutorial.restapi.RestApiApplication : Started RestApiApplication in 3.639 seconds (JVM running for 4.406)2021-05-04 13:47:10.377 INFO 29542 --- [ main] o.a.tutorial.restapi.RestApiApplication : args[0]: delete-node2021-05-04 13:47:10.379 INFO 29542 --- [ main] o.a.tutorial.restapi.RestApiApplication : args[1]: fe955da0-c4e5-42d3-972f-697424b546b12021-05-04 13:47:10.787 INFO 29542 --- [ main] o.a.tutorial.restapi.DeleteNodeCmd : Deleted node response: <204 NO_CONTENT No Content,[cache-control:"no-cache", connection:"keep-alive", content-type:"application/json;charset=UTF-8", date:"Tue, 04 May 2021 12:47:10 GMT", expires:"Thu, 01 Jan 1970 00:00:00 GMT", pragma:"no-cache", server:"nginx/1.18.0", x-frame-options:"SAMEORIGIN"]>To list deleted nodes, use thelistDeletedNodes method of theTrashcanApi.
More info about this ReST API endpoint
For a description of the common parameters, such asinclude, see thissection.
import org.alfresco.core.handler.TrashcanApi;import org.alfresco.core.model.DeletedNodeEntry;import org.alfresco.core.model.DeletedNodesPaging;import org.slf4j.Logger;import org.slf4j.LoggerFactory;import org.springframework.beans.factory.annotation.Autowired;import org.springframework.stereotype.Component;import java.io.IOException;import java.util.ArrayList;import java.util.List;@Componentpublic class ListDeletedNodesCmd { static final Logger LOGGER = LoggerFactory.getLogger(ListDeletedNodesCmd.class); @Autowired TrashcanApi trashcanApi; public void execute() throws IOException { Integer skipCount = 0; Integer maxItems = 100; List<String> include = new ArrayList<>(); include.add("path"); LOGGER.info("Listing soft deleted nodes in the trashcan:"); DeletedNodesPaging deletedNodes = trashcanApi.listDeletedNodes(skipCount, maxItems, include).getBody(); for (DeletedNodeEntry deletedNodeEntry: deletedNodes.getList().getEntries()) { LOGGER.info(" Deleted node: {}", deletedNodeEntry.getEntry()); } }}Executing this code would list the soft deleted nodes that exist in the so called “Trashcan”:
% java -jar target/rest-api-0.0.1-SNAPSHOT.jar list-deleted-nodes 2021-05-05 09:38:54.983 INFO 14986 --- [ main] o.a.tutorial.restapi.RestApiApplication : Started RestApiApplication in 4.404 seconds (JVM running for 4.861)2021-05-05 09:38:54.985 INFO 14986 --- [ main] o.a.tutorial.restapi.RestApiApplication : args[0]: list-deleted-nodes2021-05-05 09:38:54.986 INFO 14986 --- [ main] o.a.t.restapi.ListDeletedNodesCmd : Listing soft deleted nodes in the trashcan:2021-05-05 09:38:55.333 INFO 14986 --- [ main] o.a.t.restapi.ListDeletedNodesCmd : Deleted node: class DeletedNode { id: d32e1b4b-2ae0-48c2-9ee7-6323f8f4e96b name: My Gadgets nodeType: cm:folder isFolder: true isFile: false isLocked: false modifiedAt: 2021-04-30T15:46:17.334Z modifiedByUser: class UserInfo { displayName: Administrator id: admin } createdAt: 2021-04-30T15:46:16.332Z createdByUser: class UserInfo { displayName: Administrator id: admin } parentId: null isLink: null isFavorite: null content: null aspectNames: null properties: null allowableOperations: null path: class PathInfo { elements: [class PathElement { id: e439190c-3fe0-48a1-8a9a-374fbc54b570 name: Company Home nodeType: cm:folder aspectNames: [cm:titled, cm:auditable, app:uifacets] }] name: /Company Home isComplete: true } permissions: null definition: null archivedByUser: class UserInfo { displayName: Administrator id: admin } archivedAt: 2021-05-05T08:36:11.141Z}2021-05-05 09:38:55.333 INFO 14986 --- [ main] o.a.t.restapi.ListDeletedNodesCmd : Deleted node: class DeletedNode { id: fe955da0-c4e5-42d3-972f-697424b546b1 name: newname.txt nodeType: acme:document isFolder: false isFile: true isLocked: false modifiedAt: 2021-05-04T09:52:17.053Z modifiedByUser: class UserInfo { displayName: Administrator id: admin } createdAt: 2021-05-04T09:52:17.053Z createdByUser: class UserInfo { displayName: Administrator id: admin } parentId: null isLink: null isFavorite: null content: class ContentInfo { mimeType: text/plain mimeTypeName: Plain Text sizeInBytes: 30 encoding: ISO-8859-1 } aspectNames: null properties: null allowableOperations: null path: class PathInfo { elements: [class PathElement { id: e439190c-3fe0-48a1-8a9a-374fbc54b570 name: Company Home nodeType: cm:folder aspectNames: [cm:titled, cm:auditable, app:uifacets] }, class PathElement { id: 7f041db0-fdb6-4185-b921-2fb9ed381480 name: Imap Attachments nodeType: cm:folder aspectNames: [cm:titled, cm:auditable, app:uifacets] }] name: /Company Home/Imap Attachments isComplete: true } permissions: null definition: null archivedByUser: class UserInfo { displayName: Administrator id: admin } archivedAt: 2021-05-04T12:47:10.524Z}Note the extra properties at the end that tells you when the node was soft deleted and by who (i.e.archivedAt andarchivedByUser). Also, by setting theinclude parameter topath we get information about where the node was locatedbefore it was deleted (i.e.path.name)
To list deleted nodes, use therestoreDeletedNode method of theTrashcanApi.
More info about this ReST API endpoint
For a description of the common parameters, such asfields, see thissection.
import org.alfresco.core.handler.TrashcanApi;import org.alfresco.core.model.DeletedNodeBodyRestore;import org.alfresco.core.model.NodeEntry;import org.slf4j.Logger;import org.slf4j.LoggerFactory;import org.springframework.beans.factory.annotation.Autowired;import org.springframework.stereotype.Component;import java.io.IOException;import java.util.List;@Componentpublic class RestoreDeletedNodeCmd { static final Logger LOGGER = LoggerFactory.getLogger(RestoreDeletedNodeCmd.class); @Autowired TrashcanApi trashcanApi; public void execute(String nodeId, String restoreFolderId) throws IOException { List<String> fields = null; // POST body need to ne supplied with target folder ID DeletedNodeBodyRestore deletedNodeBodyRestore = new DeletedNodeBodyRestore(); deletedNodeBodyRestore.setTargetParentId(restoreFolderId); deletedNodeBodyRestore.setAssocType("cm:contains"); NodeEntry restoredNode = trashcanApi.restoreDeletedNode(nodeId, fields, deletedNodeBodyRestore).getBody(); LOGGER.info("Restored node: {}", restoredNode.getEntry()); }}Executing this code would restore a node with passed in ID. The location folder ID is also passed in:
% java -jar target/rest-api-0.0.1-SNAPSHOT.jar restore-deleted-node b717304b-1c07-400b-b8a8-3268ea79c49f 7f041db0-fdb6-4185-b921-2fb9ed3814802021-05-05 09:46:19.805 INFO 15098 --- [ main] o.a.tutorial.restapi.RestApiApplication : Started RestApiApplication in 3.033 seconds (JVM running for 3.498)2021-05-05 09:46:19.807 INFO 15098 --- [ main] o.a.tutorial.restapi.RestApiApplication : args[0]: restore-deleted-node2021-05-05 09:46:19.808 INFO 15098 --- [ main] o.a.tutorial.restapi.RestApiApplication : args[1]: b717304b-1c07-400b-b8a8-3268ea79c49f2021-05-05 09:46:19.808 INFO 15098 --- [ main] o.a.tutorial.restapi.RestApiApplication : args[2]: 7f041db0-fdb6-4185-b921-2fb9ed3814802021-05-05 09:46:20.436 INFO 15098 --- [ main] o.a.t.restapi.RestoreDeletedNodeCmd : Restored node: class Node { id: b717304b-1c07-400b-b8a8-3268ea79c49f name: newname.txt nodeType: acme:document isFolder: false isFile: true isLocked: false modifiedAt: 2021-05-04T09:19:49.903Z modifiedByUser: class UserInfo { displayName: Administrator id: admin } createdAt: 2021-05-04T09:19:49.903Z createdByUser: class UserInfo { displayName: Administrator id: admin } parentId: 7f041db0-fdb6-4185-b921-2fb9ed381480 isLink: null isFavorite: null content: class ContentInfo { mimeType: text/plain mimeTypeName: Plain Text sizeInBytes: 30 encoding: ISO-8859-1 } aspectNames: [rn:renditioned, cm:versionable, cm:titled, cm:auditable, acme:securityClassified, cm:taggable, cm:author, cm:thumbnailModification] properties: {cm:title=UPDATED title, cm:versionType=MAJOR, acme:documentId=DOC-001, cm:versionLabel=1.0, acme:securityClassification=Company Confidential, cm:lastThumbnailModification=[doclib:1620120715749], cm:description=UPDATED description, cm:taggable=[a6da6c4d-cb6b-41b5-a010-7188459dd3cb, 9a9044c9-3787-44ca-bd92-c6797c9a82ae]} allowableOperations: null path: null permissions: null definition: null}The following sections walk through how to use the Java ReST API wrapper services when managing Alfresco Share sites.
To create an Alfresco Share site in the repository use thecreateSite method of theSitesApi,which is the main API used to create and manage sites.
More info about this ReST API endpoint
For a description of the common parameters, such asfields, see thissection.
import org.alfresco.core.handler.SitesApi;import org.alfresco.core.model.Site;import org.alfresco.core.model.SiteBodyCreate;import org.slf4j.Logger;import org.slf4j.LoggerFactory;import org.springframework.beans.factory.annotation.Autowired;import org.springframework.stereotype.Component;import java.io.IOException;import java.util.List;@Componentpublic class CreateSite { static final Logger LOGGER = LoggerFactory.getLogger(CreateSite.class); private List<String> fields = null; // Flag to indicate whether the Share-specific (surf) configuration files for the site should not be created // Default = false Boolean skipConfiguration = null; // Flag to indicate whether the site should not be added to the user's site favorites // Default = false Boolean skipAddToFavorites = null; @Autowired SitesApi sitesApi; public void execute(String siteId) throws IOException { SiteBodyCreate siteBodyCreate = new SiteBodyCreate(); siteBodyCreate.setId(siteId); siteBodyCreate.setTitle("title-" + siteId); siteBodyCreate.setDescription("description-" + siteId); siteBodyCreate.setVisibility(SiteBodyCreate.VisibilityEnum.PUBLIC); Site site = sitesApi.createSite(siteBodyCreate, skipConfiguration, skipAddToFavorites, fields).getBody().getEntry(); LOGGER.info("Created site: {}", site); }}For more information about how to list site containers, such as Document Library, for a site seeadd content to site.
Adding content to a site uses the same API calls as are used to create folders and upload files elsewhere in the Repository.Seecreate folder andupload file for more information.
More info about this ReST API endpoint
For a description of the common parameters, such asfields, see thissection.
The tricky bit is to figure out how to add content to the so called “Document Library” of a site. We can figure out theNode ID for the Document Library by using thelistSiteContainers method of theSitesApi:
import org.alfresco.core.handler.NodesApi;import org.alfresco.core.handler.SitesApi;import org.alfresco.core.model.*;import org.slf4j.Logger;import org.slf4j.LoggerFactory;import org.springframework.beans.factory.annotation.Autowired;import org.springframework.stereotype.Component;import java.io.IOException;import java.util.List;@Componentpublic class AddSiteContentCmd { static final Logger LOGGER = LoggerFactory.getLogger(AddSiteContentCmd.class); Integer skipCount = 0; Integer maxItems = 100; private List<String> fields = null; private List<String> include = null; private Boolean autoRename = true; private Boolean majorVersion = true; private Boolean versioningEnabled = true; @Autowired SitesApi sitesApi; @Autowired NodesApi nodesApi; public void execute(String siteId) throws IOException { // First get the Node ID for the Document Library String docLibNodeId = null; SiteContainerPaging siteContainerPaging = sitesApi.listSiteContainers(siteId, skipCount, maxItems, fields).getBody(); LOGGER.info("Listing site containers [{}]: ", siteId); for (SiteContainerEntry siteContainerEntry: siteContainerPaging.getList().getEntries()) { SiteContainer siteContainer = siteContainerEntry.getEntry(); LOGGER.info(" Site container: {}", siteContainer); if (siteContainer.getFolderId().equalsIgnoreCase("DocumentLibrary")) { docLibNodeId = siteContainer.getId(); } } if (docLibNodeId != null) { // Create a folder in the document library createFolder(docLibNodeId, "White papers"); } else { LOGGER.info("Document library not found in site {}", siteId); } } /** * Make the remote call to create a folder in the repository, if it does not exist. * * @param parentFolderId the node ID for the site container * @param folderName the name of the folder * @return a node object for the newly created node, contains the ID, * such as e859588c-ae81-4c5e-a3b6-4c6109b6c905 */ private Node createFolder(String parentFolderId, String folderName) { NodeBodyCreate nodeBodyCreate = new NodeBodyCreate(); nodeBodyCreate.setName(folderName); nodeBodyCreate.setNodeType("cm:folder"); Node folderNode = nodesApi.createNode(parentFolderId, nodeBodyCreate, autoRename, majorVersion, versioningEnabled, include, fields).getBody().getEntry(); LOGGER.info("Created new folder in DocLib: {}", folderNode); return folderNode; }}Executing this code will create a folder in the passed in site’s document library:
% java -jar target/rest-api-0.0.1-SNAPSHOT.jar add-site-content test2021-05-05 10:43:34.208 INFO 16095 --- [ main] o.a.tutorial.restapi.RestApiApplication : Started RestApiApplication in 3.019 seconds (JVM running for 3.46)2021-05-05 10:43:34.210 INFO 16095 --- [ main] o.a.tutorial.restapi.RestApiApplication : args[0]: add-site-content2021-05-05 10:43:34.211 INFO 16095 --- [ main] o.a.tutorial.restapi.RestApiApplication : args[1]: test2021-05-05 10:43:34.390 INFO 16095 --- [ main] o.a.tutorial.restapi.AddSiteContentCmd : Listing site containers [test]: 2021-05-05 10:43:34.391 INFO 16095 --- [ main] o.a.tutorial.restapi.AddSiteContentCmd : Site container: class SiteContainer { id: 605e085c-92ae-4a53-b902-99c7d215f475 folderId: documentLibrary}2021-05-05 10:43:34.833 INFO 16095 --- [ main] o.a.tutorial.restapi.AddSiteContentCmd : Created new folder in DocLib: class Node { id: 6e157336-068a-4384-bc29-e4e1ca09cc6c name: White papers nodeType: cm:folder isFolder: true isFile: false isLocked: false modifiedAt: 2021-05-05T09:43:34.660Z modifiedByUser: class UserInfo { displayName: Administrator id: admin } createdAt: 2021-05-05T09:43:34.660Z createdByUser: class UserInfo { displayName: Administrator id: admin } parentId: 605e085c-92ae-4a53-b902-99c7d215f475 isLink: null isFavorite: null content: null aspectNames: [cm:auditable] properties: null allowableOperations: null path: null permissions: null definition: null}Adding members to a site uses thecreateSiteMembership method of theSitesApi.
More info about this ReST API endpoint
For a description of the common parameters, such asfields, see thissection.
import org.alfresco.core.handler.SitesApi;import org.alfresco.core.model.*;import org.slf4j.Logger;import org.slf4j.LoggerFactory;import org.springframework.beans.factory.annotation.Autowired;import org.springframework.stereotype.Component;import java.io.IOException;import java.util.List;import static org.alfresco.core.model.SiteMembershipBodyCreate.RoleEnum.SITECOLLABORATOR;@Componentpublic class AddSiteMembersCmd { static final Logger LOGGER = LoggerFactory.getLogger(AddSiteMembersCmd.class); private List<String> fields = null; @Autowired SitesApi sitesApi; public void execute(String siteId, String personId) throws IOException { SiteMembershipBodyCreate siteMembershipBodyCreate = new SiteMembershipBodyCreate(); siteMembershipBodyCreate.setId(personId); siteMembershipBodyCreate.setRole(SITECOLLABORATOR); SiteMemberEntry siteMemberEntry = sitesApi.createSiteMembership(siteId, siteMembershipBodyCreate, fields).getBody(); LOGGER.info("Created site membership {}", siteMemberEntry); }}Executing this code will add a user with passed in ID with roleSite Collaborator to site with passed in ID:
% java -jar target/rest-api-0.0.1-SNAPSHOT.jar add-site-member test test2021-05-05 13:21:31.290 INFO 17933 --- [ main] o.a.tutorial.restapi.RestApiApplication : Started RestApiApplication in 2.923 seconds (JVM running for 3.377)2021-05-05 13:21:31.291 INFO 17933 --- [ main] o.a.tutorial.restapi.RestApiApplication : args[0]: add-site-member2021-05-05 13:21:31.292 INFO 17933 --- [ main] o.a.tutorial.restapi.RestApiApplication : args[1]: test2021-05-05 13:21:31.293 INFO 17933 --- [ main] o.a.tutorial.restapi.RestApiApplication : args[2]: test2021-05-05 13:21:31.697 INFO 17933 --- [ main] o.a.tutorial.restapi.AddSiteMembersCmd : Created site membership class SiteMemberEntry { entry: class SiteMember { id: test person: class Person { id: test firstName: Test lastName: User displayName: Test User description: null avatarId: null email: test@example.com skypeId: null googleId: null instantMessageId: null jobTitle: null location: null company: class Company { organization: null address1: null address2: null address3: null postcode: null telephone: null fax: null email: null } mobile: null telephone: null statusUpdatedAt: null userStatus: null enabled: true emailNotificationsEnabled: true aspectNames: null properties: null capabilities: class Capabilities { isAdmin: false isGuest: false isMutable: true } } role: SiteCollaborator isMemberOfGroup: false }}The following sections walk through how to use the Java ReST API wrapper services when managing users and groups. Notethat these are usually managed via a directory server (LDAP/Active Directory).
Listing people uses thelistPeople method of thePeopleApi.
More info about this ReST API endpoint
For a description of the common parameters, such asfields, see thissection.
import org.alfresco.core.handler.PeopleApi;import org.alfresco.core.model.PersonEntry;import org.alfresco.core.model.PersonPaging;import org.slf4j.Logger;import org.slf4j.LoggerFactory;import org.springframework.beans.factory.annotation.Autowired;import org.springframework.stereotype.Component;import java.io.IOException;import java.util.List;@Componentpublic class ListPeopleCmd { static final Logger LOGGER = LoggerFactory.getLogger(ListPeopleCmd.class); @Autowired PeopleApi peopleApi; public void execute() throws IOException { Integer skipCount = 0; Integer maxItems = 100; List<String> orderBy = null; List<String> include = null; List<String> fields = null; LOGGER.info("Listing people in the repository"); PersonPaging people = peopleApi.listPeople(skipCount, maxItems, orderBy, include, fields).getBody(); for (PersonEntry personEntry: people.getList().getEntries()) { LOGGER.info(" {} ({})", personEntry.getEntry().getDisplayName(), personEntry.getEntry().getId()); } }}Executing this code will list all users in the repository (note, if connected to LDAP this could be a lot of users…):
% java -jar target/rest-api-0.0.1-SNAPSHOT.jar list-people2021-05-05 13:42:15.547 INFO 18327 --- [ main] o.a.tutorial.restapi.RestApiApplication : Started RestApiApplication in 3.426 seconds (JVM running for 3.96)2021-05-05 13:42:15.549 INFO 18327 --- [ main] o.a.tutorial.restapi.RestApiApplication : args[0]: list-people2021-05-05 13:42:15.550 INFO 18327 --- [ main] o.a.tutorial.restapi.ListPeopleCmd : Listing people in the repository2021-05-05 13:42:15.879 INFO 18327 --- [ main] o.a.tutorial.restapi.ListPeopleCmd : Alice Beecher (abeecher)2021-05-05 13:42:15.880 INFO 18327 --- [ main] o.a.tutorial.restapi.ListPeopleCmd : Administrator (admin)2021-05-05 13:42:15.880 INFO 18327 --- [ main] o.a.tutorial.restapi.ListPeopleCmd : Guest (guest)2021-05-05 13:42:15.880 INFO 18327 --- [ main] o.a.tutorial.restapi.ListPeopleCmd : Mike Jackson (mjackson)2021-05-05 13:42:15.880 INFO 18327 --- [ main] o.a.tutorial.restapi.ListPeopleCmd : Test User (test)Creating a person uses thecreatePerson method of thePeopleApi.
More info about this ReST API endpoint
For a description of the common parameters, such asfields, see thissection.
import org.alfresco.core.handler.PeopleApi;import org.alfresco.core.model.PersonBodyCreate;import org.alfresco.core.model.PersonEntry;import org.slf4j.Logger;import org.slf4j.LoggerFactory;import org.springframework.beans.factory.annotation.Autowired;import org.springframework.stereotype.Component;import java.io.IOException;import java.util.List;@Componentpublic class CreatePersonCmd { static final Logger LOGGER = LoggerFactory.getLogger(CreatePersonCmd.class); @Autowired PeopleApi peopleApi; public void execute(String username, String pwd, String firstname, String lastname, String email) throws IOException { List<String> fields = null; PersonBodyCreate personBodyCreate = new PersonBodyCreate(); personBodyCreate.setId(username); personBodyCreate.setPassword(pwd); personBodyCreate.setFirstName(firstname); personBodyCreate.setLastName(lastname); personBodyCreate.setEmail(email); PersonEntry person = peopleApi.createPerson(personBodyCreate, fields).getBody(); LOGGER.info("Created person {}", person); }}Executing this code will add a user passed in username, pwd, first name, last name and email:
% java -jar target/rest-api-0.0.1-SNAPSHOT.jar create-person martin 1234 Martin Bergljung martin@example.com2021-05-05 15:49:25.198 INFO 22389 --- [ main] o.a.tutorial.restapi.RestApiApplication : Started RestApiApplication in 3.928 seconds (JVM running for 4.427)2021-05-05 15:49:25.200 INFO 22389 --- [ main] o.a.tutorial.restapi.RestApiApplication : args[0]: create-person2021-05-05 15:49:25.201 INFO 22389 --- [ main] o.a.tutorial.restapi.RestApiApplication : args[1]: martin2021-05-05 15:49:25.201 INFO 22389 --- [ main] o.a.tutorial.restapi.RestApiApplication : args[2]: 12342021-05-05 15:49:25.201 INFO 22389 --- [ main] o.a.tutorial.restapi.RestApiApplication : args[3]: Martin2021-05-05 15:49:25.201 INFO 22389 --- [ main] o.a.tutorial.restapi.RestApiApplication : args[4]: Bergljung2021-05-05 15:49:25.201 INFO 22389 --- [ main] o.a.tutorial.restapi.RestApiApplication : args[5]: martin@example.com2021-05-05 15:49:25.830 INFO 22389 --- [ main] o.a.tutorial.restapi.CreatePersonCmd : Created person class PersonEntry { entry: class Person { id: martin firstName: Martin lastName: Bergljung displayName: Martin Bergljung description: null avatarId: null email: martin@example.com skypeId: null googleId: null instantMessageId: null jobTitle: null location: null company: class Company { organization: null address1: null address2: null address3: null postcode: null telephone: null fax: null email: null } mobile: null telephone: null statusUpdatedAt: null userStatus: null enabled: true emailNotificationsEnabled: true aspectNames: null properties: null capabilities: class Capabilities { isAdmin: false isGuest: false isMutable: true } }}Getting metadata for a person involves a number of API calls:
PeopleApi.getPersonPeopleApi.getAvatarImagePreferencesApi.listPreferencesPreferencesApi.getPreferenceMore info about this ReST API endpoint
For a description of the common parameters, such asfields, see thissection.
import org.alfresco.core.handler.PeopleApi;import org.alfresco.core.handler.PreferencesApi;import org.alfresco.core.model.*;import org.slf4j.Logger;import org.slf4j.LoggerFactory;import org.springframework.beans.factory.annotation.Autowired;import org.springframework.stereotype.Component;import java.io.IOException;import java.util.List;@Componentpublic class GetPersonMetadataCmd { static final Logger LOGGER = LoggerFactory.getLogger(GetPersonMetadataCmd.class); @Autowired PeopleApi peopleApi; @Autowired PreferencesApi preferencesApi; public void execute(String personId) throws IOException { Integer skipCount = 0; Integer maxItems = 100; List<String> fields = null; PersonEntry person = peopleApi.getPerson(personId, fields).getBody(); LOGGER.info("Got person metadata {}", person); PreferencePaging preferencePaging = preferencesApi.listPreferences(personId, skipCount, maxItems, fields).getBody(); LOGGER.info("Got person preferences:"); for (PreferenceEntry preferenceEntry: preferencePaging.getList().getEntries()) { LOGGER.info(" preference: {}", preferenceEntry.getEntry()); } }}Executing this code will list the metadata for the user including any preferences. In the following example we list metadatafor the out-of-the-box userabeecher:
% java -jar target/rest-api-0.0.1-SNAPSHOT.jar get-person-metadata abeecher2021-05-05 16:06:50.550 INFO 22610 --- [ main] o.a.tutorial.restapi.RestApiApplication : Started RestApiApplication in 3.396 seconds (JVM running for 3.893)2021-05-05 16:06:50.552 INFO 22610 --- [ main] o.a.tutorial.restapi.RestApiApplication : args[0]: get-person-metadata2021-05-05 16:06:50.553 INFO 22610 --- [ main] o.a.tutorial.restapi.RestApiApplication : args[1]: abeecher2021-05-05 16:06:50.787 INFO 22610 --- [ main] o.a.t.restapi.GetPersonMetadataCmd : Got person metadata class PersonEntry { entry: class Person { id: abeecher firstName: Alice lastName: Beecher displayName: Alice Beecher description: Alice is a demo user for the sample Alfresco Team site. avatarId: 198500fc-1e99-4f5f-8926-248cea433366 email: abeecher@example.com skypeId: abeecher googleId: null instantMessageId: null jobTitle: Graphic Designer location: Tilbury, UK company: class Company { organization: Moresby, Garland and Wedge address1: 200 Butterwick Street address2: Tilbury address3: UK postcode: ALF1 SAM1 telephone: null fax: null email: null } mobile: 0112211001100 telephone: 0112211001100 statusUpdatedAt: 2011-02-15T20:20:13.432Z userStatus: Helping to design the look and feel of the new web site enabled: false emailNotificationsEnabled: true aspectNames: null properties: null capabilities: class Capabilities { isAdmin: false isGuest: false isMutable: true } }}2021-05-05 16:06:50.849 INFO 22610 --- [ main] o.a.t.restapi.GetPersonMetadataCmd : Got person preferences:2021-05-05 16:06:50.849 INFO 22610 --- [ main] o.a.t.restapi.GetPersonMetadataCmd : preference: class Preference { id: org.alfresco.share.documentList.showFolders value: true}2021-05-05 16:06:50.849 INFO 22610 --- [ main] o.a.t.restapi.GetPersonMetadataCmd : preference: class Preference { id: org.alfresco.share.documentList.simpleView value: false}2021-05-05 16:06:50.849 INFO 22610 --- [ main] o.a.t.restapi.GetPersonMetadataCmd : preference: class Preference { id: org.alfresco.share.documentList.sortField value: cm:name}2021-05-05 16:06:50.849 INFO 22610 --- [ main] o.a.t.restapi.GetPersonMetadataCmd : preference: class Preference { id: org.alfresco.share.documents.favourites value: workspace://SpacesStore/7c7bca1d-b65d-4444-9378-805b459fb74d,workspace://SpacesStore/b2f21ddd-0b0e-449f-bea9-a0be73e7d67b,workspace://SpacesStore/2cf35860-6705-42c3-b123-c4d6b39997b4,workspace://SpacesStore/7d90c94c-fcf7-4f79-9273-bd1352bbb612,workspace://SpacesStore/05dedd34-9d9d-48d9-9af6-c81b555541c9}2021-05-05 16:06:50.850 INFO 22610 --- [ main] o.a.t.restapi.GetPersonMetadataCmd : preference: class Preference { id: org.alfresco.share.sites.favourites.test value: true}2021-05-05 16:06:50.850 INFO 22610 --- [ main] o.a.t.restapi.GetPersonMetadataCmd : preference: class Preference { id: org.alfresco.share.sites.recent._0 value: swsdp}2021-05-05 16:06:50.850 INFO 22610 --- [ main] o.a.t.restapi.GetPersonMetadataCmd : preference: class Preference { id: org.alfresco.share.twisters.collapsed value: DocumentPermissions,DocumentWorkflows,DocumentLinks,DocumentActions}Updating metadata for a person involves these two API calls:
More info about this ReST API endpoint
For a description of the common parameters, such asfields, see thissection.
import org.alfresco.core.handler.PeopleApi;import org.alfresco.core.model.*;import org.slf4j.Logger;import org.slf4j.LoggerFactory;import org.springframework.beans.factory.annotation.Autowired;import org.springframework.stereotype.Component;import java.io.IOException;import java.util.List;@Componentpublic class UpdatePersonMetadataCmd { static final Logger LOGGER = LoggerFactory.getLogger(UpdatePersonMetadataCmd.class); @Autowired PeopleApi peopleApi; public void execute(String personId) throws IOException { List<String> fields = null; PersonBodyUpdate personBodyUpdate = new PersonBodyUpdate(); // Mandatory fields during an update personBodyUpdate.setFirstName("Martin"); personBodyUpdate.setLastName("Bergljung"); personBodyUpdate.setEmail("martin@example.com"); personBodyUpdate.setEmailNotificationsEnabled(true); personBodyUpdate.setOldPassword("1234"); personBodyUpdate.setPassword("1234"); personBodyUpdate.setEnabled(true); // Other fields personBodyUpdate.setJobTitle("Techie"); Company company = new Company(); company.setAddress1("Alfresco way 1"); company.setOrganization("Alfresco Org"); company.setTelephone("12345678"); personBodyUpdate.setCompany(company); PersonEntry person = peopleApi.updatePerson(personId, personBodyUpdate, fields).getBody(); LOGGER.info("Updated person metadata {}", person); }}Executing this code will update the usermartin with some new company information, there are a number of fields thatare mandatory that you need to set, so might be best to read them first and then set them:
% java -jar target/rest-api-0.0.1-SNAPSHOT.jar update-person-metadata martin2021-05-06 09:16:41.833 INFO 24158 --- [ main] o.a.tutorial.restapi.RestApiApplication : Started RestApiApplication in 3.151 seconds (JVM running for 3.596)2021-05-06 09:16:41.835 INFO 24158 --- [ main] o.a.tutorial.restapi.RestApiApplication : args[0]: update-person-metadata2021-05-06 09:16:41.837 INFO 24158 --- [ main] o.a.tutorial.restapi.RestApiApplication : args[1]: martin2021-05-06 09:16:42.111 INFO 24158 --- [ main] o.a.t.restapi.UpdatePersonMetadataCmd : Updated person metadata class PersonEntry { entry: class Person { id: martin firstName: Martin lastName: Bergljung displayName: Martin Bergljung description: null avatarId: null email: martin@example.com skypeId: null googleId: null instantMessageId: null jobTitle: Techie location: null company: class Company { organization: Alfresco Org address1: Alfresco way 1 address2: null address3: null postcode: null telephone: 12345678 fax: null email: null } mobile: null telephone: null statusUpdatedAt: null userStatus: null enabled: true emailNotificationsEnabled: true aspectNames: null properties: null capabilities: class Capabilities { isAdmin: false isGuest: false isMutable: true } }}Requesting a password reset for a person (user) in the repository involves these two API calls:
More info about this ReST API endpoint
import org.alfresco.core.handler.PeopleApi;import org.alfresco.core.model.ClientBody;import org.slf4j.Logger;import org.slf4j.LoggerFactory;import org.springframework.beans.factory.annotation.Autowired;import org.springframework.http.HttpEntity;import org.springframework.stereotype.Component;import java.io.IOException;@Componentpublic class RequestPwdResetCmd { static final Logger LOGGER = LoggerFactory.getLogger(RequestPwdResetCmd.class); @Autowired PeopleApi peopleApi; public void execute(String personId) throws IOException { ClientBody clientBody = new ClientBody(); clientBody.setClient("share"); // Alfresco Share UI client HttpEntity<Void> result = peopleApi.requestPasswordReset(personId, clientBody); LOGGER.info("Password reset request sent for {} result {}", personId, result); }}Executing this code will request a password request for usermartin, an email will be sent to the user assuming thepassword request should be via the Alfresco Share UI:
% java -jar target/rest-api-0.0.1-SNAPSHOT.jar request-pwd-reset martin 2021-05-06 09:30:38.440 INFO 24356 --- [ main] o.a.tutorial.restapi.RestApiApplication : Started RestApiApplication in 3.438 seconds (JVM running for 3.939)2021-05-06 09:30:38.442 INFO 24356 --- [ main] o.a.tutorial.restapi.RestApiApplication : args[0]: request-pwd-reset2021-05-06 09:30:38.443 INFO 24356 --- [ main] o.a.tutorial.restapi.RestApiApplication : args[1]: martin2021-05-06 09:30:39.726 INFO 24356 --- [ main] o.a.tutorial.restapi.RequestPwdResetCmd : Password reset request sent for martin result <202 ACCEPTED Accepted,[cache-control:"no-cache", connection:"keep-alive", content-length:"0", content-type:"application/json;charset=UTF-8", date:"Thu, 06 May 2021 08:30:39 GMT", expires:"Thu, 01 Jan 1970 00:00:00 GMT", pragma:"no-cache", server:"nginx/1.18.0", x-frame-options:"SAMEORIGIN"]>Listing groups that a person is a member of uses thelistGroupMembershipsForPerson method of theGroupsApi.
More info about this ReST API endpoint
For a description of the common parameters, such asfields, see thissection.
import org.alfresco.core.handler.GroupsApi;import org.alfresco.core.model.GroupEntry;import org.alfresco.core.model.GroupPaging;import org.slf4j.Logger;import org.slf4j.LoggerFactory;import org.springframework.beans.factory.annotation.Autowired;import org.springframework.stereotype.Component;import java.io.IOException;import java.util.List;@Componentpublic class ListPersonGroupMembershipsCmd { static final Logger LOGGER = LoggerFactory.getLogger(ListPersonGroupMembershipsCmd.class); @Autowired GroupsApi groupsApi; public void execute(String personId) throws IOException { Integer skipCount = 0; Integer maxItems = 100; String where = null; List<String> orderBy = null; List<String> include = null; List<String> fields = null; LOGGER.info("Listing group memberships for person {}", personId); GroupPaging groups = groupsApi.listGroupMembershipsForPerson( personId, skipCount, maxItems, orderBy, include, where, fields).getBody(); for (GroupEntry groupEntry: groups.getList().getEntries()) { LOGGER.info(" {}", groupEntry.getEntry().getDisplayName()); } }}Executing this code will list the group memberships for passed in username. In this example we list group memberships fortwo of the out-of-the-box usersabeecher andadmin:
% java -jar target/rest-api-0.0.1-SNAPSHOT.jar list-person-group-memberships abeecher2021-05-06 09:42:50.643 INFO 24597 --- [ main] o.a.tutorial.restapi.RestApiApplication : Started RestApiApplication in 3.63 seconds (JVM running for 4.106)2021-05-06 09:42:50.645 INFO 24597 --- [ main] o.a.tutorial.restapi.RestApiApplication : args[0]: list-person-group-memberships2021-05-06 09:42:50.647 INFO 24597 --- [ main] o.a.tutorial.restapi.RestApiApplication : args[1]: abeecher2021-05-06 09:42:50.647 INFO 24597 --- [ main] o.a.t.r.ListPersonGroupMembershipsCmd : Listing group memberships for person abeecher2021-05-06 09:42:50.821 INFO 24597 --- [ main] o.a.t.r.ListPersonGroupMembershipsCmd : null2021-05-06 09:42:50.821 INFO 24597 --- [ main] o.a.t.r.ListPersonGroupMembershipsCmd : site_swsdp2021-05-06 09:42:50.821 INFO 24597 --- [ main] o.a.t.r.ListPersonGroupMembershipsCmd : site_swsdp_SiteCollaborator% java -jar target/rest-api-0.0.1-SNAPSHOT.jar list-person-group-memberships admin 2021-05-06 09:43:06.433 INFO 24599 --- [ main] o.a.tutorial.restapi.RestApiApplication : args[1]: admin2021-05-06 09:43:06.433 INFO 24599 --- [ main] o.a.t.r.ListPersonGroupMembershipsCmd : Listing group memberships for person admin2021-05-06 09:43:06.631 INFO 24599 --- [ main] o.a.t.r.ListPersonGroupMembershipsCmd : ALFRESCO_ADMINISTRATORS2021-05-06 09:43:06.631 INFO 24599 --- [ main] o.a.t.r.ListPersonGroupMembershipsCmd : ALFRESCO_MODEL_ADMINISTRATORS2021-05-06 09:43:06.631 INFO 24599 --- [ main] o.a.t.r.ListPersonGroupMembershipsCmd : ALFRESCO_SEARCH_ADMINISTRATORS2021-05-06 09:43:06.631 INFO 24599 --- [ main] o.a.t.r.ListPersonGroupMembershipsCmd : EMAIL_CONTRIBUTORS2021-05-06 09:43:06.631 INFO 24599 --- [ main] o.a.t.r.ListPersonGroupMembershipsCmd : null2021-05-06 09:43:06.631 INFO 24599 --- [ main] o.a.t.r.ListPersonGroupMembershipsCmd : SITE_ADMINISTRATORS2021-05-06 09:43:06.632 INFO 24599 --- [ main] o.a.t.r.ListPersonGroupMembershipsCmd : site_swsdp2021-05-06 09:43:06.632 INFO 24599 --- [ main] o.a.t.r.ListPersonGroupMembershipsCmd : site_swsdp_SiteManager2021-05-06 09:43:06.632 INFO 24599 --- [ main] o.a.t.r.ListPersonGroupMembershipsCmd : site_test2021-05-06 09:43:06.632 INFO 24599 --- [ main] o.a.t.r.ListPersonGroupMembershipsCmd : site_test_SiteManager```Listing the groups available in the repository uses thelistGroups method of theGroupsApi.
More info about this ReST API endpoint
For a description of the common parameters, such asfields, see thissection.
import org.alfresco.core.handler.GroupsApi;import org.alfresco.core.model.GroupEntry;import org.alfresco.core.model.GroupPaging;import org.slf4j.Logger;import org.slf4j.LoggerFactory;import org.springframework.beans.factory.annotation.Autowired;import org.springframework.stereotype.Component;import java.io.IOException;import java.util.List;@Componentpublic class ListGroupsCmd { static final Logger LOGGER = LoggerFactory.getLogger(ListGroupsCmd.class); @Autowired GroupsApi groupsApi; public void execute() throws IOException { Integer skipCount = 0; Integer maxItems = 100; String where = null; List<String> orderBy = null; List<String> include = null; List<String> fields = null; LOGGER.info("Listing group in the repo:"); GroupPaging groups = groupsApi.listGroups(skipCount, maxItems, orderBy, include, where, fields).getBody(); for (GroupEntry groupEntry: groups.getList().getEntries()) { LOGGER.info(" {}", groupEntry.getEntry().getDisplayName()); } }}Executing this code will list the groups available in the repository, note that this can be a lot of groups if thereare loads of Share sites and the system is connected to a directory server:
% java -jar target/rest-api-0.0.1-SNAPSHOT.jar list-groups 2021-05-06 09:50:39.416 INFO 24665 --- [ main] o.a.tutorial.restapi.RestApiApplication : Started RestApiApplication in 3.637 seconds (JVM running for 4.131)2021-05-06 09:50:39.419 INFO 24665 --- [ main] o.a.tutorial.restapi.RestApiApplication : args[0]: list-groups2021-05-06 09:50:39.420 INFO 24665 --- [ main] o.a.tutorial.restapi.ListGroupsCmd : Listing group in the repo:2021-05-06 09:50:39.807 INFO 24665 --- [ main] o.a.tutorial.restapi.ListGroupsCmd : Engineering2021-05-06 09:50:39.808 INFO 24665 --- [ main] o.a.tutorial.restapi.ListGroupsCmd : ALFRESCO_ADMINISTRATORS2021-05-06 09:50:39.808 INFO 24665 --- [ main] o.a.tutorial.restapi.ListGroupsCmd : ALFRESCO_MODEL_ADMINISTRATORS2021-05-06 09:50:39.808 INFO 24665 --- [ main] o.a.tutorial.restapi.ListGroupsCmd : ALFRESCO_SEARCH_ADMINISTRATORS2021-05-06 09:50:39.808 INFO 24665 --- [ main] o.a.tutorial.restapi.ListGroupsCmd : EMAIL_CONTRIBUTORS2021-05-06 09:50:39.808 INFO 24665 --- [ main] o.a.tutorial.restapi.ListGroupsCmd : SITE_ADMINISTRATORS2021-05-06 09:50:39.808 INFO 24665 --- [ main] o.a.tutorial.restapi.ListGroupsCmd : site_swsdp2021-05-06 09:50:39.808 INFO 24665 --- [ main] o.a.tutorial.restapi.ListGroupsCmd : site_swsdp_SiteCollaborator2021-05-06 09:50:39.808 INFO 24665 --- [ main] o.a.tutorial.restapi.ListGroupsCmd : site_swsdp_SiteConsumer2021-05-06 09:50:39.808 INFO 24665 --- [ main] o.a.tutorial.restapi.ListGroupsCmd : site_swsdp_SiteContributor2021-05-06 09:50:39.808 INFO 24665 --- [ main] o.a.tutorial.restapi.ListGroupsCmd : site_swsdp_SiteManager2021-05-06 09:50:39.808 INFO 24665 --- [ main] o.a.tutorial.restapi.ListGroupsCmd : site_test2021-05-06 09:50:39.808 INFO 24665 --- [ main] o.a.tutorial.restapi.ListGroupsCmd : site_test_SiteCollaborator2021-05-06 09:50:39.808 INFO 24665 --- [ main] o.a.tutorial.restapi.ListGroupsCmd : site_test_SiteConsumer2021-05-06 09:50:39.808 INFO 24665 --- [ main] o.a.tutorial.restapi.ListGroupsCmd : site_test_SiteContributor2021-05-06 09:50:39.809 INFO 24665 --- [ main] o.a.tutorial.restapi.ListGroupsCmd : site_test_SiteManagerCreating a group uses thecreateGroup method of theGroupsApi.
More info about this ReST API endpoint
For a description of the common parameters, such asfields, see thissection.
import org.alfresco.core.handler.GroupsApi;import org.alfresco.core.model.GroupBodyCreate;import org.alfresco.core.model.GroupEntry;import org.slf4j.Logger;import org.slf4j.LoggerFactory;import org.springframework.beans.factory.annotation.Autowired;import org.springframework.stereotype.Component;import java.io.IOException;import java.util.List;@Componentpublic class CreateGroupCmd { static final Logger LOGGER = LoggerFactory.getLogger(CreateGroupCmd.class); @Autowired GroupsApi groupsApi; public void execute(String groupId, String name) throws IOException { List<String> fields = null; List<String> include = null; GroupBodyCreate groupBodyCreate = new GroupBodyCreate(); groupBodyCreate.setId(groupId); groupBodyCreate.setDisplayName(name); GroupEntry groupEntry = groupsApi.createGroup(groupBodyCreate, include, fields).getBody(); LOGGER.info("Created group {}", groupEntry.getEntry()); }}Executing this code will create a group, in this case we are creating an HR group:
% java -jar target/rest-api-0.0.1-SNAPSHOT.jar create-group hr "Human Resources"2021-05-06 10:25:51.906 INFO 25139 --- [ main] o.a.tutorial.restapi.RestApiApplication : Started RestApiApplication in 3.477 seconds (JVM running for 3.956)2021-05-06 10:25:51.908 INFO 25139 --- [ main] o.a.tutorial.restapi.RestApiApplication : args[0]: create-group2021-05-06 10:25:51.909 INFO 25139 --- [ main] o.a.tutorial.restapi.RestApiApplication : args[1]: hr2021-05-06 10:25:51.909 INFO 25139 --- [ main] o.a.tutorial.restapi.RestApiApplication : args[2]: Human Resources2021-05-06 10:25:52.165 INFO 25139 --- [ main] o.a.tutorial.restapi.CreateGroupCmd : Created group class Group { id: GROUP_hr displayName: Human Resources isRoot: true parentIds: null zones: null}Getting metadata for a group uses thegetGroup method of theGroupsApi.
More info about this ReST API endpoint
For a description of the common parameters, such asfields, see thissection.
import org.alfresco.core.handler.GroupsApi;import org.alfresco.core.model.GroupEntry;import org.slf4j.Logger;import org.slf4j.LoggerFactory;import org.springframework.beans.factory.annotation.Autowired;import org.springframework.stereotype.Component;import java.io.IOException;import java.util.List;@Componentpublic class GetGroupCmd { static final Logger LOGGER = LoggerFactory.getLogger(GetGroupCmd.class); @Autowired GroupsApi groupsApi; public void execute(String groupId) throws IOException { List<String> fields = null; List<String> include = null; GroupEntry groupEntry = groupsApi.getGroup(groupId, include, fields).getBody(); LOGGER.info("Got group metadata {}", groupEntry.getEntry()); }}Executing this code will get metadata for a group, in this case we are getting metadata for a group with idhr,note that you have to prefix group ids withGROUP_:
% java -jar target/rest-api-0.0.1-SNAPSHOT.jar get-group GROUP_hr2021-05-06 10:31:37.864 INFO 25363 --- [ main] o.a.tutorial.restapi.RestApiApplication : Started RestApiApplication in 3.763 seconds (JVM running for 4.242)2021-05-06 10:31:37.866 INFO 25363 --- [ main] o.a.tutorial.restapi.RestApiApplication : args[0]: get-group2021-05-06 10:31:37.868 INFO 25363 --- [ main] o.a.tutorial.restapi.RestApiApplication : args[1]: GROUP_hr2021-05-06 10:31:38.025 INFO 25363 --- [ main] o.alfresco.tutorial.restapi.GetGroupCmd : Got group metadata class Group { id: GROUP_hr displayName: Human Resources isRoot: true parentIds: null zones: null}Updating a group name uses theupdateGroup method of theGroupsApi.
More info about this ReST API endpoint
For a description of the common parameters, such asfields, see thissection.
import org.alfresco.core.handler.GroupsApi;import org.alfresco.core.model.GroupBodyUpdate;import org.alfresco.core.model.GroupEntry;import org.slf4j.Logger;import org.slf4j.LoggerFactory;import org.springframework.beans.factory.annotation.Autowired;import org.springframework.stereotype.Component;import java.io.IOException;import java.util.List;@Componentpublic class UpdateGroupCmd { static final Logger LOGGER = LoggerFactory.getLogger(UpdateGroupCmd.class); @Autowired GroupsApi groupsApi; public void execute(String groupId, String newName) throws IOException { List<String> fields = null; List<String> include = null; GroupBodyUpdate groupBodyUpdate = new GroupBodyUpdate(); groupBodyUpdate.setDisplayName(newName); GroupEntry group = groupsApi.updateGroup(groupId, groupBodyUpdate, include, fields).getBody(); LOGGER.info("Updated group {}", group); }}Executing this code will update the name of the group with passed in id, in this case we are updating the name for agroup with idhr, note that you have to prefix group ids withGROUP_:
% java -jar target/rest-api-0.0.1-SNAPSHOT.jar update-group GROUP_hr "Human Resources updated"2021-05-06 12:42:41.475 INFO 26302 --- [ main] o.a.tutorial.restapi.RestApiApplication : Started RestApiApplication in 3.285 seconds (JVM running for 3.742)2021-05-06 12:42:41.477 INFO 26302 --- [ main] o.a.tutorial.restapi.RestApiApplication : args[0]: update-group2021-05-06 12:42:41.478 INFO 26302 --- [ main] o.a.tutorial.restapi.RestApiApplication : args[1]: GROUP_hr2021-05-06 12:42:41.478 INFO 26302 --- [ main] o.a.tutorial.restapi.RestApiApplication : args[2]: Human Resources updated2021-05-06 12:42:41.673 INFO 26302 --- [ main] o.a.tutorial.restapi.UpdateGroupCmd : Updated group class GroupEntry { entry: class Group { id: GROUP_hr displayName: Human Resources updated isRoot: true parentIds: null zones: null }}Listing all the members of a group (i.e. people and groups) uses thelistGroupMemberships method of theGroupsApi.
More info about this ReST API endpoint
For a description of the common parameters, such asfields, see thissection.
import org.alfresco.core.handler.GroupsApi;import org.alfresco.core.model.GroupMemberEntry;import org.alfresco.core.model.GroupMemberPaging;import org.slf4j.Logger;import org.slf4j.LoggerFactory;import org.springframework.beans.factory.annotation.Autowired;import org.springframework.stereotype.Component;import java.io.IOException;import java.util.List;@Componentpublic class ListGroupMembersCmd { static final Logger LOGGER = LoggerFactory.getLogger(ListGroupMembersCmd.class); @Autowired GroupsApi groupsApi; public void execute(String groupId) throws IOException { Integer skipCount = 0; Integer maxItems = 100; String where = null; List<String> orderBy = null; List<String> fields = null; LOGGER.info("Listing members of group {}:", groupId); GroupMemberPaging groupMembers = groupsApi.listGroupMemberships( groupId, skipCount, maxItems, orderBy, where, fields).getBody(); for (GroupMemberEntry groupMemberEntry: groupMembers.getList().getEntries()) { LOGGER.info(" {} ({})", groupMemberEntry.getEntry().getDisplayName(), groupMemberEntry.getEntry().getMemberType()); } }}Executing this code will list the members of passed in group id, note that you have to prefix group ids withGROUP_:
% java -jar target/rest-api-0.0.1-SNAPSHOT.jar list-group-members GROUP_engineering2021-05-06 12:55:43.231 INFO 26500 --- [ main] o.a.tutorial.restapi.RestApiApplication : Started RestApiApplication in 3.59 seconds (JVM running for 4.024)2021-05-06 12:55:43.233 INFO 26500 --- [ main] o.a.tutorial.restapi.RestApiApplication : args[0]: list-group-members2021-05-06 12:55:43.234 INFO 26500 --- [ main] o.a.tutorial.restapi.RestApiApplication : args[1]: GROUP_engineering2021-05-06 12:55:43.234 INFO 26500 --- [ main] o.a.t.restapi.ListGroupMembersCmd : Listing members of group GROUP_engineering:2021-05-06 12:55:43.404 INFO 26500 --- [ main] o.a.t.restapi.ListGroupMembersCmd : martin (PERSON)2021-05-06 12:55:43.404 INFO 26500 --- [ main] o.a.t.restapi.ListGroupMembersCmd : System Architects (GROUP)Adding members to a group uses thecreateGroupMembership method of theGroupsApi.
More info about this ReST API endpoint
For a description of the common parameters, such asfields, see thissection.
import org.alfresco.core.handler.GroupsApi;import org.alfresco.core.model.GroupMemberEntry;import org.alfresco.core.model.GroupMembershipBodyCreate;import org.slf4j.Logger;import org.slf4j.LoggerFactory;import org.springframework.beans.factory.annotation.Autowired;import org.springframework.stereotype.Component;import java.io.IOException;import java.util.List;@Componentpublic class CreateGroupMembershipCmd { static final Logger LOGGER = LoggerFactory.getLogger(CreateGroupMembershipCmd.class); @Autowired GroupsApi groupsApi; public void execute(String groupId, String memberId, String type) throws IOException { List<String> fields = null; GroupMembershipBodyCreate groupMembershipBodyCreate = new GroupMembershipBodyCreate(); groupMembershipBodyCreate.setId(memberId); groupMembershipBodyCreate.setMemberType(GroupMembershipBodyCreate.MemberTypeEnum.fromValue(type)); GroupMemberEntry groupMember = groupsApi.createGroupMembership(groupId, groupMembershipBodyCreate, fields).getBody(); LOGGER.info("Added member to group {} {}", groupId, groupMember.getEntry()); }}Executing this code will add a person, or a group, to passed in group id, note that you have to prefix group ids withGROUP_:
% java -jar target/rest-api-0.0.1-SNAPSHOT.jar create-group-membership GROUP_hr martin PERSON2021-05-06 13:54:39.062 INFO 27295 --- [ main] o.a.tutorial.restapi.RestApiApplication : Started RestApiApplication in 3.83 seconds (JVM running for 4.364)2021-05-06 13:54:39.064 INFO 27295 --- [ main] o.a.tutorial.restapi.RestApiApplication : args[0]: create-group-membership2021-05-06 13:54:39.066 INFO 27295 --- [ main] o.a.tutorial.restapi.RestApiApplication : args[1]: GROUP_hr2021-05-06 13:54:39.066 INFO 27295 --- [ main] o.a.tutorial.restapi.RestApiApplication : args[2]: martin2021-05-06 13:54:39.066 INFO 27295 --- [ main] o.a.tutorial.restapi.RestApiApplication : args[3]: PERSON2021-05-06 13:54:39.311 INFO 27295 --- [ main] o.a.t.restapi.CreateGroupMembershipCmd : Added member to group GROUP_hr class GroupMember { id: martin displayName: martin memberType: PERSON}% java -jar target/rest-api-0.0.1-SNAPSHOT.jar create-group-membership GROUP_hr GROUP_engineering GROUP2021-05-06 13:55:23.094 INFO 27297 --- [ main] o.a.tutorial.restapi.RestApiApplication : Started RestApiApplication in 3.855 seconds (JVM running for 4.351)2021-05-06 13:55:23.096 INFO 27297 --- [ main] o.a.tutorial.restapi.RestApiApplication : args[0]: create-group-membership2021-05-06 13:55:23.097 INFO 27297 --- [ main] o.a.tutorial.restapi.RestApiApplication : args[1]: GROUP_hr2021-05-06 13:55:23.097 INFO 27297 --- [ main] o.a.tutorial.restapi.RestApiApplication : args[2]: GROUP_engineering2021-05-06 13:55:23.097 INFO 27297 --- [ main] o.a.tutorial.restapi.RestApiApplication : args[3]: GROUP2021-05-06 13:55:23.327 INFO 27297 --- [ main] o.a.t.restapi.CreateGroupMembershipCmd : Added member to group GROUP_hr class GroupMember { id: GROUP_engineering displayName: Engineering memberType: GROUP}Deleting members of a group uses thedeleteGroupMembership method of theGroupsApi.
More info about this ReST API endpoint
import org.alfresco.core.handler.GroupsApi;import org.slf4j.Logger;import org.slf4j.LoggerFactory;import org.springframework.beans.factory.annotation.Autowired;import org.springframework.http.HttpEntity;import org.springframework.stereotype.Component;import java.io.IOException;@Componentpublic class DeleteGroupMembershipCmd { static final Logger LOGGER = LoggerFactory.getLogger(DeleteGroupMembershipCmd.class); @Autowired GroupsApi groupsApi; public void execute(String groupId, String groupMemberId) throws IOException { HttpEntity<Void> result = groupsApi.deleteGroupMembership(groupId, groupMemberId); LOGGER.info("Deleted group membership for group {} member {} result {}", groupId, groupMemberId, result); }}Executing this code will delete a person, or a group, from passed in group id, note that you have to prefix group idswithGROUP_:
% java -jar target/rest-api-0.0.1-SNAPSHOT.jar delete-group-membership GROUP_hr martin 2021-05-06 14:09:25.825 INFO 27471 --- [ main] o.a.tutorial.restapi.RestApiApplication : Started RestApiApplication in 3.959 seconds (JVM running for 4.516)2021-05-06 14:09:25.828 INFO 27471 --- [ main] o.a.tutorial.restapi.RestApiApplication : args[0]: delete-group-membership2021-05-06 14:09:25.829 INFO 27471 --- [ main] o.a.tutorial.restapi.RestApiApplication : args[1]: GROUP_hr2021-05-06 14:09:25.829 INFO 27471 --- [ main] o.a.tutorial.restapi.RestApiApplication : args[2]: martin2021-05-06 14:09:26.112 INFO 27471 --- [ main] o.a.t.restapi.DeleteGroupMembershipCmd : Deleted group membership for group GROUP_hr member martin result <204 NO_CONTENT No Content,[cache-control:"no-cache", connection:"keep-alive", content-type:"application/json;charset=UTF-8", date:"Thu, 06 May 2021 13:09:26 GMT", expires:"Thu, 01 Jan 1970 00:00:00 GMT", pragma:"no-cache", server:"nginx/1.18.0", x-frame-options:"SAMEORIGIN"]>% java -jar target/rest-api-0.0.1-SNAPSHOT.jar delete-group-membership GROUP_hr GROUP_engineering2021-05-06 14:09:51.048 INFO 27472 --- [ main] o.a.tutorial.restapi.RestApiApplication : Started RestApiApplication in 3.964 seconds (JVM running for 4.493)2021-05-06 14:09:51.050 INFO 27472 --- [ main] o.a.tutorial.restapi.RestApiApplication : args[0]: delete-group-membership2021-05-06 14:09:51.051 INFO 27472 --- [ main] o.a.tutorial.restapi.RestApiApplication : args[1]: GROUP_hr2021-05-06 14:09:51.051 INFO 27472 --- [ main] o.a.tutorial.restapi.RestApiApplication : args[2]: GROUP_engineering2021-05-06 14:09:51.152 INFO 27472 --- [ main] o.a.t.restapi.DeleteGroupMembershipCmd : Deleted group membership for group GROUP_hr member GROUP_engineering result <204 NO_CONTENT No Content,[cache-control:"no-cache", connection:"keep-alive", content-type:"application/json;charset=UTF-8", date:"Thu, 06 May 2021 13:09:51 GMT", expires:"Thu, 01 Jan 1970 00:00:00 GMT", pragma:"no-cache", server:"nginx/1.18.0", x-frame-options:"SAMEORIGIN"]>Setting permissions for a group uses theupdateNode method of theNodesApi.For more info seeset permissions for a node.
More info about this ReST API endpoint
The following sections walk through how to use the Java ReST API wrapper services when managing audit applications andtheir logs.
Listing all the audit applications uses thelistAuditApps method of theAuditApi.
More info about this ReST API endpoint
For a description of the common parameters, such asfields, see thissection.
import org.alfresco.core.handler.AuditApi;import org.alfresco.core.model.AuditAppEntry;import org.alfresco.core.model.AuditAppPaging;import org.slf4j.Logger;import org.slf4j.LoggerFactory;import org.springframework.beans.factory.annotation.Autowired;import org.springframework.stereotype.Component;import java.io.IOException;import java.util.List;@Componentpublic class ListAuditAppsCmd { static final Logger LOGGER = LoggerFactory.getLogger(ListAuditAppsCmd.class); @Autowired AuditApi auditApi; public void execute() throws IOException { Integer skipCount = 0; Integer maxItems = 100; List<String> fields = null; LOGGER.info("Listing active audit applications in the repository:"); AuditAppPaging auditApps = auditApi.listAuditApps(skipCount, maxItems, fields).getBody(); for (AuditAppEntry auditAppEntry: auditApps.getList().getEntries()) { LOGGER.info(" {}", auditAppEntry); } }}Executing this code will list the audit applications that have been activated, if you have enabled auditing and activatedthealfresco-access audit application, then you will see the following listing of audit apps:
% java -jar target/rest-api-0.0.1-SNAPSHOT.jar list-audit-apps2021-05-07 12:48:12.434 INFO 36995 --- [ main] o.a.tutorial.restapi.RestApiApplication : Started RestApiApplication in 3.525 seconds (JVM running for 4.089)2021-05-07 12:48:12.436 INFO 36995 --- [ main] o.a.tutorial.restapi.RestApiApplication : args[0]: list-audit-apps2021-05-07 12:48:12.437 INFO 36995 --- [ main] o.a.tutorial.restapi.ListAuditAppsCmd : Listing active audit applications in the repository:2021-05-07 12:48:12.912 INFO 36995 --- [ main] o.a.tutorial.restapi.ListAuditAppsCmd : class AuditAppEntry { entry: class AuditApp { id: tagging name: Alfresco Tagging Service isEnabled: true maxEntryId: null minEntryId: null }}2021-05-07 12:48:12.913 INFO 36995 --- [ main] o.a.tutorial.restapi.ListAuditAppsCmd : class AuditAppEntry { entry: class AuditApp { id: alfresco-access name: alfresco-access isEnabled: true maxEntryId: null minEntryId: null }}Getting the audit application metadata uses thegetAuditApp method of theAuditApi.
More info about this ReST API endpoint
For a description of the common parameters, such asfields, see thissection.
import org.alfresco.core.handler.AuditApi;import org.alfresco.core.model.AuditApp;import org.slf4j.Logger;import org.slf4j.LoggerFactory;import org.springframework.beans.factory.annotation.Autowired;import org.springframework.stereotype.Component;import java.io.IOException;import java.util.List;@Componentpublic class GetAuditAppCmd { static final Logger LOGGER = LoggerFactory.getLogger(GetAuditAppCmd.class); @Autowired AuditApi auditApi; public void execute(String auditAppId) throws IOException { List<String> fields = null; List<String> include = null; AuditApp auditApp = auditApi.getAuditApp(auditAppId, fields, include).getBody(); LOGGER.info("Got audit app metadata {}", auditApp); }}Enable and disable an audit application uses theupdateAuditApp method of theAuditApi.
More info about this ReST API endpoint
For a description of the common parameters, such asfields, see thissection.
import org.alfresco.core.handler.AuditApi;import org.alfresco.core.model.AuditApp;import org.alfresco.core.model.AuditBodyUpdate;import org.slf4j.Logger;import org.slf4j.LoggerFactory;import org.springframework.beans.factory.annotation.Autowired;import org.springframework.stereotype.Component;import java.io.IOException;import java.util.List;@Componentpublic class EnableDisableAuditAppCmd { static final Logger LOGGER = LoggerFactory.getLogger(EnableDisableAuditAppCmd.class); @Autowired AuditApi auditApi; public void execute(String auditAppId) throws IOException { List<String> fields = null; AuditBodyUpdate auditBodyUpdate = new AuditBodyUpdate(); auditBodyUpdate.setIsEnabled(true); AuditApp auditApp = auditApi.updateAuditApp(auditAppId, auditBodyUpdate, fields).getBody(); LOGGER.info("Enabled audit app {}", auditApp); }}Listing all the audit logs for an audit application uses thelistAuditEntriesForAuditApp method of theAuditApi.
More info about this ReST API endpoint
For a description of the common parameters, such asfields, see thissection.
import org.alfresco.core.handler.AuditApi;import org.alfresco.core.model.AuditEntryEntry;import org.alfresco.core.model.AuditEntryPaging;import org.slf4j.Logger;import org.slf4j.LoggerFactory;import org.springframework.beans.factory.annotation.Autowired;import org.springframework.stereotype.Component;import java.io.IOException;import java.util.ArrayList;import java.util.List;@Componentpublic class ListAuditLogsCmd { static final Logger LOGGER = LoggerFactory.getLogger(ListAuditLogsCmd.class); @Autowired AuditApi auditApi; public void execute(String auditAppId) throws IOException { Integer skipCount = 0; Integer maxItems = 100; String where = null; List<String> fields = null; List<String> include = new ArrayList<>(); List<String> orderBy = null; // Include the log values include.add("values"); // Controls if the response provides the total numbers of items in the collection. // If not supplied then the default value is false. Boolean omitTotalItems = true; LOGGER.info("Listing logs for audit application {}:", auditAppId); AuditEntryPaging auditLogs = auditApi.listAuditEntriesForAuditApp( auditAppId, skipCount, omitTotalItems, orderBy, maxItems, where, include, fields).getBody(); for (AuditEntryEntry auditAppEntry: auditLogs.getList().getEntries()) { String username = "N/A"; if (auditAppEntry.getEntry().getCreatedByUser() != null) { username = auditAppEntry.getEntry().getCreatedByUser().getId(); } String log = null; if (auditAppEntry.getEntry().getValues().toString().length() > 60) { log = auditAppEntry.getEntry().getValues().toString().substring(0, 60); } else { log = auditAppEntry.getEntry().getValues().toString(); } LOGGER.info(" {} {} {}", auditAppEntry.getEntry().getCreatedAt(), username, log); } }}Note that you have to addvalues to theinclude parameter for the logs to include all the data. Also, the audit logvalue have been truncated for readability.
Executing this code will list the audit logs for passed in audit app id. The audit log values have been trimmed:
% java -jar target/rest-api-0.0.1-SNAPSHOT.jar list-audit-logs alfresco-access2021-05-07 14:46:29.977 INFO 40544 --- [ main] o.a.tutorial.restapi.RestApiApplication : Started RestApiApplication in 3.493 seconds (JVM running for 3.948)2021-05-07 14:46:29.980 INFO 40544 --- [ main] o.a.tutorial.restapi.RestApiApplication : args[0]: list-audit-logs2021-05-07 14:46:29.981 INFO 40544 --- [ main] o.a.tutorial.restapi.RestApiApplication : args[1]: alfresco-access2021-05-07 14:46:29.981 INFO 40544 --- [ main] o.a.tutorial.restapi.ListAuditLogsCmd : Listing logs for audit application alfresco-access:2021-05-07 14:46:30.376 INFO 40544 --- [ main] o.a.tutorial.restapi.ListAuditLogsCmd : 2021-05-07T11:48:12.758Z admin {/alfresco-access/login/user=admin}2021-05-07 14:46:30.376 INFO 40544 --- [ main] o.a.tutorial.restapi.ListAuditLogsCmd : 2021-05-07T13:30:46.256Z N/A {/alfresco-access/loginFailure/user=martin}2021-05-07 14:46:30.377 INFO 40544 --- [ main] o.a.tutorial.restapi.ListAuditLogsCmd : 2021-05-07T13:30:58.768Z N/A {/alfresco-access/loginFailure/user=test}2021-05-07 14:46:30.377 INFO 40544 --- [ main] o.a.tutorial.restapi.ListAuditLogsCmd : 2021-05-07T13:31:07.650Z admin {/alfresco-access/transaction/sub-actions=createNode updateN2021-05-07 14:46:30.379 INFO 40544 --- [ main] o.a.tutorial.restapi.ListAuditLogsCmd : 2021-05-07T13:31:08.087Z admin {/alfresco-access/transaction/sub-actions=createNode updateN2021-05-07 14:46:30.379 INFO 40544 --- [ main] o.a.tutorial.restapi.ListAuditLogsCmd : 2021-05-07T13:31:08.141Z admin {/alfresco-access/transaction/sub-actions=createNode updateN2021-05-07 14:46:30.379 INFO 40544 --- [ main] o.a.tutorial.restapi.ListAuditLogsCmd : 2021-05-07T13:31:08.800Z admin {/alfresco-access/transaction/sub-actions=updateContent upda2021-05-07 14:46:30.379 INFO 40544 --- [ main] o.a.tutorial.restapi.ListAuditLogsCmd : 2021-05-07T13:31:08.853Z admin {/alfresco-access/transaction/sub-actions=updateContent upda2021-05-07 14:46:30.380 INFO 40544 --- [ main] o.a.tutorial.restapi.ListAuditLogsCmd : 2021-05-07T13:31:08.961Z admin {/alfresco-access/transaction/sub-actions=updateContent upda2021-05-07 14:46:30.380 INFO 40544 --- [ main] o.a.tutorial.restapi.ListAuditLogsCmd : 2021-05-07T13:32:04.579Z admin {/alfresco-access/logout/user=admin}2021-05-07 14:46:30.381 INFO 40544 --- [ main] o.a.tutorial.restapi.ListAuditLogsCmd : 2021-05-07T13:32:10.404Z test {/alfresco-access/login/user=test}2021-05-07 14:46:30.381 INFO 40544 --- [ main] o.a.tutorial.restapi.ListAuditLogsCmd : 2021-05-07T13:32:11.261Z test {/alfresco-access/transaction/sub-actions=createNode updateN2021-05-07 14:46:30.381 INFO 40544 --- [ main] o.a.tutorial.restapi.ListAuditLogsCmd : 2021-05-07T13:32:11.316Z test {/alfresco-access/transaction/sub-actions=createNode updateN2021-05-07 14:46:30.381 INFO 40544 --- [ main] o.a.tutorial.restapi.ListAuditLogsCmd : 2021-05-07T13:32:11.371Z test {/alfresco-access/transaction/sub-actions=createNode updateN2021-05-07 14:46:30.381 INFO 40544 --- [ main] o.a.tutorial.restapi.ListAuditLogsCmd : 2021-05-07T13:32:11.436Z test {/alfresco-access/transaction/sub-actions=createNode updateN2021-05-07 14:46:30.382 INFO 40544 --- [ main] o.a.tutorial.restapi.ListAuditLogsCmd : 2021-05-07T13:32:12.075Z test {/alfresco-access/transaction/sub-actions=updateContent upda2021-05-07 14:46:30.382 INFO 40544 --- [ main] o.a.tutorial.restapi.ListAuditLogsCmd : 2021-05-07T13:32:12.101Z test {/alfresco-access/transaction/sub-actions=updateContent upda2021-05-07 14:46:30.382 INFO 40544 --- [ main] o.a.tutorial.restapi.ListAuditLogsCmd : 2021-05-07T13:32:12.124Z test {/alfresco-access/transaction/sub-actions=updateContent upda2021-05-07 14:46:30.383 INFO 40544 --- [ main] o.a.tutorial.restapi.ListAuditLogsCmd : 2021-05-07T13:32:24.764Z test {/alfresco-access/logout/user=test}2021-05-07 14:46:30.383 INFO 40544 --- [ main] o.a.tutorial.restapi.ListAuditLogsCmd : 2021-05-07T13:32:26.423Z admin {/alfresco-access/login/user=admin}2021-05-07 14:46:30.384 INFO 40544 --- [ main] o.a.tutorial.restapi.ListAuditLogsCmd : 2021-05-07T13:32:37.917Z admin {/alfresco-access/transaction/sub-actions=createNode updateN2021-05-07 14:46:30.384 INFO 40544 --- [ main] o.a.tutorial.restapi.ListAuditLogsCmd : 2021-05-07T13:32:47.013Z admin {/alfresco-access/transaction/sub-actions=createNode updateN2021-05-07 14:46:30.385 INFO 40544 --- [ main] o.a.tutorial.restapi.ListAuditLogsCmd : 2021-05-07T13:32:51.284Z admin {/alfresco-access/transaction/sub-actions=addNodeAspect crea2021-05-07 14:46:30.385 INFO 40544 --- [ main] o.a.tutorial.restapi.ListAuditLogsCmd : 2021-05-07T13:32:51.363Z admin {/alfresco-access/transaction/sub-actions=readContent addNod2021-05-07 14:46:30.385 INFO 40544 --- [ main] o.a.tutorial.restapi.ListAuditLogsCmd : 2021-05-07T13:32:51.458Z admin {/alfresco-access/transaction/sub-actions=updateNodeProperti2021-05-07 14:46:30.385 INFO 40544 --- [ main] o.a.tutorial.restapi.ListAuditLogsCmd : 2021-05-07T13:32:51.511Z admin {/alfresco-access/transaction/sub-actions=readContent, /alfr2021-05-07 14:46:30.385 INFO 40544 --- [ main] o.a.tutorial.restapi.ListAuditLogsCmd : 2021-05-07T13:32:54.271Z admin {/alfresco-access/transaction/sub-actions=addNodeAspect crea2021-05-07 14:46:30.385 INFO 40544 --- [ main] o.a.tutorial.restapi.ListAuditLogsCmd : 2021-05-07T13:32:54.343Z admin {/alfresco-access/transaction/sub-actions=updateNodeProperti2021-05-07 14:46:30.385 INFO 40544 --- [ main] o.a.tutorial.restapi.ListAuditLogsCmd : 2021-05-07T13:32:54.443Z admin {/alfresco-access/transaction/sub-actions=updateNodeProperti2021-05-07 14:46:30.385 INFO 40544 --- [ main] o.a.tutorial.restapi.ListAuditLogsCmd : 2021-05-07T13:32:54.468Z admin {/alfresco-access/transaction/sub-actions=readContent, /alfr2021-05-07 14:46:30.385 INFO 40544 --- [ main] o.a.tutorial.restapi.ListAuditLogsCmd : 2021-05-07T13:33:03.656Z admin {/alfresco-access/transaction/sub-actions=createNode updateN2021-05-07 14:46:30.385 INFO 40544 --- [ main] o.a.tutorial.restapi.ListAuditLogsCmd : 2021-05-07T13:33:03.784Z admin {/alfresco-access/transaction/sub-actions=readContent, /alfr2021-05-07 14:46:30.385 INFO 40544 --- [ main] o.a.tutorial.restapi.ListAuditLogsCmd : 2021-05-07T13:33:04.218Z admin {/alfresco-access/transaction/sub-actions=addNodeAspect, /al2021-05-07 14:46:30.386 INFO 40544 --- [ main] o.a.tutorial.restapi.ListAuditLogsCmd : 2021-05-07T13:33:04.264Z admin {/alfresco-access/transaction/sub-actions=readContent, /alfr2021-05-07 14:46:30.386 INFO 40544 --- [ main] o.a.tutorial.restapi.ListAuditLogsCmd : 2021-05-07T13:33:04.347Z admin {/alfresco-access/transaction/sub-actions=readContent, /alfr2021-05-07 14:46:30.386 INFO 40544 --- [ main] o.a.tutorial.restapi.ListAuditLogsCmd : 2021-05-07T13:33:04.754Z admin {/alfresco-access/transaction/sub-actions=addNodeAspect crea2021-05-07 14:46:30.386 INFO 40544 --- [ main] o.a.tutorial.restapi.ListAuditLogsCmd : 2021-05-07T13:33:04.806Z admin {/alfresco-access/transaction/sub-actions=addNodeAspect upda2021-05-07 14:46:30.386 INFO 40544 --- [ main] o.a.tutorial.restapi.ListAuditLogsCmd : 2021-05-07T13:33:04.878Z admin {/alfresco-access/transaction/sub-actions=updateNodeProperti2021-05-07 14:46:30.386 INFO 40544 --- [ main] o.a.tutorial.restapi.ListAuditLogsCmd : 2021-05-07T13:33:04.899Z admin {/alfresco-access/transaction/sub-actions=readContent, /alfrListing all the audit logs for a node uses thelistAuditEntriesForNode method of theAuditApi.
More info about this ReST API endpoint
For a description of the common parameters, such asfields, see thissection.
import org.alfresco.core.handler.AuditApi;import org.alfresco.core.model.AuditEntryEntry;import org.alfresco.core.model.AuditEntryPaging;import org.slf4j.Logger;import org.slf4j.LoggerFactory;import org.springframework.beans.factory.annotation.Autowired;import org.springframework.stereotype.Component;import java.io.IOException;import java.util.ArrayList;import java.util.List;@Componentpublic class ListNodeAuditLogsCmd { static final Logger LOGGER = LoggerFactory.getLogger(ListNodeAuditLogsCmd.class); @Autowired AuditApi auditApi; public void execute(String nodeId) throws IOException { Integer skipCount = 0; Integer maxItems = 100; String where = null; List<String> fields = null; List<String> include = new ArrayList<>(); List<String> orderBy = null; // Include the log values include.add("values"); LOGGER.info("Listing logs for node ID {}:", nodeId); AuditEntryPaging auditLogs = auditApi.listAuditEntriesForNode( nodeId, skipCount, orderBy, maxItems, where, include, fields).getBody(); for (AuditEntryEntry auditAppEntry: auditLogs.getList().getEntries()) { String username = "N/A"; if (auditAppEntry.getEntry().getCreatedByUser() != null) { username = auditAppEntry.getEntry().getCreatedByUser().getId(); } String log = null; if (auditAppEntry.getEntry().getValues().toString().length() > 60) { log = auditAppEntry.getEntry().getValues().toString().substring(0, 60); } else { log = auditAppEntry.getEntry().getValues().toString(); } LOGGER.info(" {} {} {} {}", auditAppEntry.getEntry().getId(), auditAppEntry.getEntry().getCreatedAt(), username, log); } }}Note that you have to addvalues to theinclude parameter for the logs to include all the data. Also, the audit logvalue have been truncated for readability.
Executing this code will list the audit logs for passed in audit app id and audit entry id:
% java -jar target/rest-api-0.0.1-SNAPSHOT.jar list-audit-logs-node 37eedde2-3c78-4d25-bade-5360e22579f42021-05-10 09:27:33.714 INFO 51172 --- [ main] o.a.tutorial.restapi.RestApiApplication : Started RestApiApplication in 4.069 seconds (JVM running for 4.724)2021-05-10 09:27:33.716 INFO 51172 --- [ main] o.a.tutorial.restapi.RestApiApplication : args[0]: list-audit-logs-node2021-05-10 09:27:33.717 INFO 51172 --- [ main] o.a.tutorial.restapi.RestApiApplication : args[1]: 37eedde2-3c78-4d25-bade-5360e22579f42021-05-10 09:27:33.717 INFO 51172 --- [ main] o.a.t.restapi.ListNodeAuditLogsCmd : Listing logs for node ID 37eedde2-3c78-4d25-bade-5360e22579f4:2021-05-10 09:41:55.396 INFO 51505 --- [ main] o.a.t.restapi.ListNodeAuditLogsCmd : 76 2021-05-10T08:26:58.965Z admin {/alfresco-access/transaction/sub-actions=updateNodeProperti2021-05-10 09:41:55.396 INFO 51505 --- [ main] o.a.t.restapi.ListNodeAuditLogsCmd : 77 2021-05-10T08:27:06.541Z admin {/alfresco-access/transaction/sub-actions=readContent, /alfr2021-05-10 09:41:55.396 INFO 51505 --- [ main] o.a.t.restapi.ListNodeAuditLogsCmd : 78 2021-05-10T08:27:11.353Z admin {/alfresco-access/transaction/sub-actions=updateContent upda2021-05-10 09:41:55.396 INFO 51505 --- [ main] o.a.t.restapi.ListNodeAuditLogsCmd : 80 2021-05-10T08:27:12.270Z admin {/alfresco-access/transaction/sub-actions=updateNodeProperti2021-05-10 09:41:55.397 INFO 51505 --- [ main] o.a.t.restapi.ListNodeAuditLogsCmd : 81 2021-05-10T08:27:12.429Z admin {/alfresco-access/transaction/sub-actions=readContent, /alfr2021-05-10 09:41:55.397 INFO 51505 --- [ main] o.a.t.restapi.ListNodeAuditLogsCmd : 83 2021-05-10T08:27:13.524Z admin {/alfresco-access/transaction/sub-actions=updateNodeProperti2021-05-10 09:41:55.397 INFO 51505 --- [ main] o.a.t.restapi.ListNodeAuditLogsCmd : 84 2021-05-10T08:27:13.609Z admin {/alfresco-access/transaction/sub-actions=readContent, /alfrGetting an audit log uses thegetAuditEntry method of theAuditApi.
More info about this ReST API endpoint
For a description of the common parameters, such asfields, see thissection.
import org.alfresco.core.handler.AuditApi;import org.alfresco.core.model.AuditEntryEntry;import org.slf4j.Logger;import org.slf4j.LoggerFactory;import org.springframework.beans.factory.annotation.Autowired;import org.springframework.stereotype.Component;import java.io.IOException;import java.util.List;@Componentpublic class GetAuditLogCmd { static final Logger LOGGER = LoggerFactory.getLogger(GetAuditLogCmd.class); @Autowired AuditApi auditApi; public void execute(String auditAppId, String auditLogId) throws IOException { List<String> fields = null; AuditEntryEntry auditLog = auditApi.getAuditEntry(auditAppId, auditLogId, fields).getBody(); LOGGER.info("Got audit log metadata {}", auditLog); }}Executing this code will list the audit logs for passed in audit app id. The audit log values have been trimmed:
% java -jar target/rest-api-0.0.1-SNAPSHOT.jar get-audit-log alfresco-access 80 2021-05-10 09:49:57.492 INFO 51645 --- [ main] o.a.tutorial.restapi.RestApiApplication : Started RestApiApplication in 3.49 seconds (JVM running for 3.992)2021-05-10 09:49:57.494 INFO 51645 --- [ main] o.a.tutorial.restapi.RestApiApplication : args[0]: get-audit-log2021-05-10 09:49:57.496 INFO 51645 --- [ main] o.a.tutorial.restapi.RestApiApplication : args[1]: alfresco-access2021-05-10 09:49:57.496 INFO 51645 --- [ main] o.a.tutorial.restapi.RestApiApplication : args[2]: 802021-05-10 09:49:57.676 INFO 51645 --- [ main] o.a.tutorial.restapi.GetAuditLogCmd : Got audit log metadata class AuditEntryEntry { entry: class AuditEntry { id: 80 auditApplicationId: alfresco-access createdByUser: class UserInfo { displayName: Administrator id: admin } createdAt: 2021-05-10T08:27:12.270Z values: { /alfresco-access/transaction/sub-actions=updateNodeProperties, /alfresco-access/transaction/properties/from={cm:lastThumbnailModification=[pdf:1620394371183, doclib:1620394374161], {http://www.alfresco.org/model/content/1.0}modified=2021-05-10T08:27:10.986+0000}, /alfresco-access/transaction/properties/to={cm:lastThumbnailModification=[doclib:1620394374161, pdf:1620635231931], {http://www.alfresco.org/model/content/1.0}modified=2021-05-10T08:27:11.935+0000}, /alfresco-access/transaction/path=/app:company_home/app:guest_home/cm:somefileudpated.txt, /alfresco-access/transaction/action=updateNodeProperties, /alfresco-access/transaction/type=cm:content, /alfresco-access/transaction/user=admin} }}Deleting audit logs for an audit app uses thedeleteAuditEntriesForAuditApp method of theAuditApi.
More info about this ReST API endpoint
For a description of the common parameters, such aswhere, see thissection.
import org.alfresco.core.handler.AuditApi;import org.slf4j.Logger;import org.slf4j.LoggerFactory;import org.springframework.beans.factory.annotation.Autowired;import org.springframework.http.HttpEntity;import org.springframework.stereotype.Component;import java.io.IOException;@Componentpublic class DeleteAuditLogsForAppCmd { static final Logger LOGGER = LoggerFactory.getLogger(DeleteAuditLogsForAppCmd.class); @Autowired AuditApi auditApi; public void execute(String auditAppId) throws IOException { // Delete all logs with ids between 1 and 79 String where = "(id BETWEEN ('1', '79'))"; HttpEntity<Void> response = auditApi.deleteAuditEntriesForAuditApp(auditAppId, where); LOGGER.info("Deleted audit logs for app {} where {} response {}", auditAppId, where, response); }}Note that you have to supply awhere clause to be able to delete any audit logs.
Executing this code will delete audit logs for passed in audit app id and where clause:
% java -jar target/rest-api-0.0.1-SNAPSHOT.jar delete-audit-logs-for-app alfresco-access2021-05-10 10:05:22.248 INFO 51942 --- [ main] o.a.tutorial.restapi.RestApiApplication : Started RestApiApplication in 4.116 seconds (JVM running for 4.615)2021-05-10 10:05:22.250 INFO 51942 --- [ main] o.a.tutorial.restapi.RestApiApplication : args[0]: delete-audit-logs-for-app2021-05-10 10:05:22.251 INFO 51942 --- [ main] o.a.tutorial.restapi.RestApiApplication : args[1]: alfresco-access2021-05-10 10:05:22.357 INFO 51942 --- [ main] o.a.t.restapi.DeleteAuditLogsForAppCmd : Deleted audit logs for app alfresco-access where (id BETWEEN ('1', '79')) response <204 NO_CONTENT No Content,[cache-control:"no-cache", connection:"keep-alive", content-type:"application/json;charset=UTF-8", date:"Mon, 10 May 2021 09:05:22 GMT", expires:"Thu, 01 Jan 1970 00:00:00 GMT", pragma:"no-cache", server:"nginx/1.18.0", x-frame-options:"SAMEORIGIN"]Deleting a single audit entry for an audit app uses thedeleteAuditEntry method of theAuditApi.
More info about this ReST API endpoint
import org.alfresco.core.handler.AuditApi;import org.slf4j.Logger;import org.slf4j.LoggerFactory;import org.springframework.beans.factory.annotation.Autowired;import org.springframework.http.HttpEntity;import org.springframework.stereotype.Component;import java.io.IOException;@Componentpublic class DeleteAuditLogCmd { static final Logger LOGGER = LoggerFactory.getLogger(DeleteAuditLogCmd.class); @Autowired AuditApi auditApi; public void execute(String auditAppId, String auditLogId) throws IOException { HttpEntity<Void> response = auditApi.deleteAuditEntry(auditAppId, auditLogId); LOGGER.info("Deleted audit log: app {} log id {} response {}", auditAppId, auditLogId, response); }}Executing this code will delete an audit log with passed in id for audit app with passed in id:
% java -jar target/rest-api-0.0.1-SNAPSHOT.jar delete-audit-log alfresco-access 80 2021-05-10 10:14:54.941 INFO 52102 --- [ main] o.a.tutorial.restapi.RestApiApplication : Started RestApiApplication in 3.736 seconds (JVM running for 4.24)2021-05-10 10:14:54.943 INFO 52102 --- [ main] o.a.tutorial.restapi.RestApiApplication : args[0]: delete-audit-log2021-05-10 10:14:54.944 INFO 52102 --- [ main] o.a.tutorial.restapi.RestApiApplication : args[1]: alfresco-access2021-05-10 10:14:54.944 INFO 52102 --- [ main] o.a.tutorial.restapi.RestApiApplication : args[2]: 802021-05-10 10:14:55.050 INFO 52102 --- [ main] o.a.tutorial.restapi.DeleteAuditLogCmd : Deleted audit log: app alfresco-access log id 80 response <204 NO_CONTENT No Content,[cache-control:"no-cache", connection:"keep-alive", content-type:"application/json;charset=UTF-8", date:"Mon, 10 May 2021 09:14:55 GMT", expires:"Thu, 01 Jan 1970 00:00:00 GMT", pragma:"no-cache", server:"nginx/1.18.0", x-frame-options:"SAMEORIGIN"]>The following sections walk through how to use the Java ReST API wrapper services when managing audit applications andtheir logs.
To find a node, such as a folder or file, by a term use thefindNodes method of theQueriesApi,which is a search API you can use when doing simple search on a term. For more complex search, such as Alfresco Full Text Search (AFTS),use theSearch API;
More info about this ReST API endpoint
For a description of the common parameters, such asinclude, see thissection.
import org.alfresco.core.handler.QueriesApi;import org.alfresco.core.model.NodeEntry;import org.alfresco.core.model.NodePagingList;import org.slf4j.Logger;import org.slf4j.LoggerFactory;import org.springframework.beans.factory.annotation.Autowired;import org.springframework.stereotype.Component;import java.io.IOException;import java.util.List;@Componentpublic class FindNodesCmd { static final Logger LOGGER = LoggerFactory.getLogger(FindNodesCmd.class); @Autowired QueriesApi queriesApi; public void execute() throws IOException { String rootNodeId = "-root-"; // The id of the node to start the search from. Supports the aliases -my-, -root- and -shared-. Integer skipCount = 0; Integer maxItems = 100; // Restrict the returned results to only those of the given node type and its sub-types String nodeType = null; List<String> include = null; List<String> orderBy = null; List<String> fields = null; String term = "Dict*"; LOGGER.info("Searching for nodes by term: {}", term); NodePagingList result = queriesApi.findNodes( term, rootNodeId, skipCount, maxItems, nodeType, include, orderBy, fields).getBody().getList(); for (NodeEntry node: result.getEntries()) { LOGGER.info("Found node [name={}][id={}]", node.getEntry().getName(), node.getEntry().getId()); } }}Executing this code gives the following type of result:
% java -jar target/rest-api-0.0.1-SNAPSHOT.jar find-nodes2021-05-10 13:40:47.999 INFO 54955 --- [ main] o.a.tutorial.restapi.RestApiApplication : Started RestApiApplication in 3.429 seconds (JVM running for 3.909)2021-05-10 13:40:48.001 INFO 54955 --- [ main] o.a.tutorial.restapi.RestApiApplication : args[0]: find-nodes2021-05-10 13:40:48.003 INFO 54955 --- [ main] o.a.tutorial.restapi.FindNodesCmd : Searching for nodes by term: Dict*2021-05-10 13:40:49.143 INFO 54955 --- [ main] o.a.tutorial.restapi.FindNodesCmd : Found node [name=Dictionary][id=b1264564-9b33-4003-bff9-58f2591cea54]2021-05-10 13:40:49.143 INFO 54955 --- [ main] o.a.tutorial.restapi.FindNodesCmd : Found node [name=Dictionary-stuff.txt][id=6f7689af-b31e-493a-ad3a-298abcf03664]2021-05-10 13:40:49.143 INFO 54955 --- [ main] o.a.tutorial.restapi.FindNodesCmd : Found node [name=InviteHelper.txt][id=4875faf1-6366-477a-a97b-b30d15f33808]2021-05-10 13:40:49.143 INFO 54955 --- [ main] o.a.tutorial.restapi.FindNodesCmd : Found node [name=Data Dictionary][id=392f377c-4a0b-4ab1-8327-3034269030a5]2021-05-10 13:40:49.143 INFO 54955 --- [ main] o.a.tutorial.restapi.FindNodesCmd : Found node [name=readme.html][id=d38b8cb0-0973-4bfd-84c5-9db4959d4715]2021-05-10 13:40:49.143 INFO 54955 --- [ main] o.a.tutorial.restapi.FindNodesCmd : Found node [name=Project Contract.pdf][id=1a0b110f-1e09-4ca2-b367-fe25e4964a4e]2021-05-10 13:40:49.143 INFO 54955 --- [ main] o.a.tutorial.restapi.FindNodesCmd : Found node [name=Meeting Notes 2011-02-10.doc][id=a8290263-4178-48f5-a0b0-be155a424828]2021-05-10 13:40:49.144 INFO 54955 --- [ main] o.a.tutorial.restapi.FindNodesCmd : Found node [name=Meeting Notes 2011-02-03.doc][id=150398b3-7f82-4cf6-af63-c450ef6c5eb8]2021-05-10 13:40:49.144 INFO 54955 --- [ main] o.a.tutorial.restapi.FindNodesCmd : Found node [name=Meeting Notes 2011-01-27.doc][id=f3bb5d08-9fd1-46da-a94a-97f20f1ef208]To find sites by term use thefindSites method of theQueriesApi,which is a search API you can use when doing simple search on a term. For more complex search, such as Alfresco Full Text Search (AFTS),use theSearch API;
More info about this ReST API endpoint
For a description of the common parameters, such asfields, see thissection.
import org.alfresco.core.handler.QueriesApi;import org.alfresco.core.model.SiteEntry;import org.alfresco.core.model.SitePagingList;import org.slf4j.Logger;import org.slf4j.LoggerFactory;import org.springframework.beans.factory.annotation.Autowired;import org.springframework.stereotype.Component;import java.io.IOException;import java.util.List;@Componentpublic class FindSitesCmd { static final Logger LOGGER = LoggerFactory.getLogger(FindSitesCmd.class); @Autowired QueriesApi queriesApi; public void execute() throws IOException { Integer skipCount = 0; Integer maxItems = 100; List<String> orderBy = null; List<String> fields = null; String term = "Soft*"; LOGGER.info("Searching for sites by term: {}", term); SitePagingList result = queriesApi.findSites(term, skipCount, maxItems, orderBy, fields).getBody().getList(); for (SiteEntry node: result.getEntries()) { LOGGER.info("Found site [id={}][name={}]", node.getEntry().getId(), node.getEntry().getTitle()); } }}Executing this code gives the following type of result:
% java -jar target/rest-api-0.0.1-SNAPSHOT.jar find-sites2021-05-10 13:52:04.833 INFO 55062 --- [ main] o.a.tutorial.restapi.RestApiApplication : Started RestApiApplication in 4.107 seconds (JVM running for 4.762)2021-05-10 13:52:04.835 INFO 55062 --- [ main] o.a.tutorial.restapi.RestApiApplication : args[0]: find-sites2021-05-10 13:52:04.845 INFO 55062 --- [ main] o.a.tutorial.restapi.FindSitesCmd : Searching for sites by term: Soft*2021-05-10 13:52:05.036 INFO 55062 --- [ main] o.a.tutorial.restapi.FindSitesCmd : Found site [id=downloadable-software][name=Downloadable Software]2021-05-10 13:52:05.036 INFO 55062 --- [ main] o.a.tutorial.restapi.FindSitesCmd : Found site [id=software-design][name=Software Design]To find sites by term use thefindPeople method of theQueriesApi,which is a search API you can use when doing simple search on a term. For more complex search, such as Alfresco Full Text Search (AFTS),use theSearch API;
More info about this ReST API endpoint
For a description of the common parameters, such asfields, see thissection.
import org.alfresco.core.handler.QueriesApi;import org.alfresco.core.model.PersonEntry;import org.alfresco.core.model.PersonPagingList;import org.alfresco.core.model.SiteEntry;import org.alfresco.core.model.SitePagingList;import org.slf4j.Logger;import org.slf4j.LoggerFactory;import org.springframework.beans.factory.annotation.Autowired;import org.springframework.stereotype.Component;import java.io.IOException;import java.util.List;@Componentpublic class FindPeopleCmd { static final Logger LOGGER = LoggerFactory.getLogger(FindPeopleCmd.class); @Autowired QueriesApi queriesApi; public void execute() throws IOException { Integer skipCount = 0; Integer maxItems = 100; List<String> orderBy = null; List<String> fields = null; String term = "*mi*"; LOGGER.info("Searching for people by term: {}", term); PersonPagingList result = queriesApi.findPeople(term, skipCount, maxItems, fields, orderBy).getBody().getList(); for (PersonEntry person: result.getEntries()) { LOGGER.info("Found person [id={}][name={}]", person.getEntry().getId(), person.getEntry().getDisplayName()); } }}Executing this code gives the following type of result:
% java -jar target/rest-api-0.0.1-SNAPSHOT.jar find-people2021-05-10 14:00:38.019 INFO 55327 --- [ main] o.a.tutorial.restapi.RestApiApplication : Started RestApiApplication in 3.568 seconds (JVM running for 4.045)2021-05-10 14:00:38.021 INFO 55327 --- [ main] o.a.tutorial.restapi.RestApiApplication : args[0]: find-people2021-05-10 14:00:38.022 INFO 55327 --- [ main] o.a.tutorial.restapi.FindPeopleCmd : Searching for people by term: *mi*2021-05-10 14:00:38.839 INFO 55327 --- [ main] o.a.tutorial.restapi.FindPeopleCmd : Found person [id=admin][name=Administrator]2021-05-10 14:00:38.839 INFO 55327 --- [ main] o.a.tutorial.restapi.FindPeopleCmd : Found person [id=mjackson][name=Mike Jackson]To find content based on more complex search queries, such as using Alfresco Full Text Search (AFTS), use theSearchApi,;
More info about this ReST API endpoint
For a description of the common parameters, such asinclude, see thissection.
import org.alfresco.search.handler.SearchApi;import org.alfresco.search.model.RequestQuery;import org.alfresco.search.model.ResultSetPaging;import org.alfresco.search.model.ResultSetRowEntry;import org.alfresco.search.model.SearchRequest;import org.slf4j.Logger;import org.slf4j.LoggerFactory;import org.springframework.beans.factory.annotation.Autowired;import org.springframework.http.ResponseEntity;import org.springframework.stereotype.Component;import java.io.IOException;import java.util.List;@Componentpublic class SearchCmd { static final Logger LOGGER = LoggerFactory.getLogger(SearchCmd.class); @Autowired SearchApi searchApi; /** * Search in a site * * @param siteId the site id * @param term the term to search for in the site */ public void execute(String siteId, String term) throws IOException { List<ResultSetRowEntry> result = search("(SITE:\"" + siteId + "\" AND TEXT:\"" + term + "\" )"); LOGGER.info("Search result: {}", result); } /** * Search the repository for content using an Alfresco Full Text Search (AFTS) query * * @param aftsQuery the query statement * @return a list of search results */ List<ResultSetRowEntry> search(String aftsQuery) { ResponseEntity<ResultSetPaging> result = searchApi.search(new SearchRequest() .query(new RequestQuery() .language(RequestQuery.LanguageEnum.AFTS) .query(aftsQuery))); return result.getBody().getList().getEntries(); }}