Upload documents to alfresco using REST Api:
Prerequisites:-----
Following jar files are required (httpcomponents-client-4.3.4):
commons-codec-1.6.jarcommons-logging-1.1.3.jarcommons-httpclient-3.1.jarhttpcore-4.1.3.jar
junit-4.12.0.jar
**************************************************************************
Alfresco's Login (POST) REST Api '/alfresco/service/api/login' return authentication ticket in response.
This is how authTicket will look like: <ticket>TICKET_4b36ecaxxxxx5cdc5d782xxxxxxxxxxxx</ticket>
In the response you will get the authentication ticket, this authentication ticket will be used in all subsequent requests in order to get authenticated with alfresco.
In the subsequent request (as example given below in Test class) i am trying to upload a file to alfresco using REST URI::
'/alfresco/service/api/upload?alf_ticket=TICKET_4b36ecaxxxxx5cdc5d782xxxxxxxxxxxx'
Here i am passing alf_ticket as a parameter with the 'authentication ticket' value which i got from '/alfresco/service/api/login' REST call.
For more details visit: http://docs.alfresco.com/5.0/references/RESTful-intro.html
**************************************************************************
1- HttpUtils
/* * Created By: Abhinav Kumar Mishra * Copyright © 2014. Abhinav Kumar Mishra. * All rights reserved. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ import java.io.File; import java.io.IOException; import java.nio.file.Files; import java.nio.file.Path; import java.nio.file.Paths; import java.util.Map; import java.util.concurrent.ConcurrentHashMap; import org.apache.commons.httpclient.HttpClient; import org.apache.commons.httpclient.methods.GetMethod; import org.apache.commons.httpclient.methods.PostMethod; import org.apache.commons.httpclient.methods.multipart.FilePart; import org.apache.commons.httpclient.methods.multipart.MultipartRequestEntity; import org.apache.commons.httpclient.methods.multipart.Part; import org.apache.commons.httpclient.methods.multipart.StringPart; import org.apache.commons.logging.Log; import org.apache.commons.logging.LogFactory; import org.apache.http.ParseException; /** * The Class HttpUtils. * * @author Abhinav Kumar Mishra * @since 2014 */ public final class HttpUtils { /** The Constant logger. */ private static final Log LOG = LogFactory.getLog(HttpUtils.class); /** * Gets the login response. * * @param authURI the path * @param username the username * @param password the password * @return the login response * @throws ParseException the parse exception * @throws IOException Signals that an I/O exception has occurred. */ public Map<String, String> getAuthResponse(final String authURI, final String username, final String password) throws ParseException, IOException { LOG.info("Authenticating request.."); final Map<String, String> responseMap = new ConcurrentHashMap<String, String>(); GetMethod getRequest = null; try { final HttpClient httpclient = new HttpClient(); getRequest = new GetMethod(getAuthURL(authURI, username, password)); final int statusCode = httpclient.executeMethod(getRequest); LOG.info("Auth Response Status: "+ statusCode+"|"+ getRequest.getStatusText()); responseMap.put(Constants.RESP_BODY, getRequest.getResponseBodyAsString()); responseMap.put(Constants.CONTENT_TYPE, getRequest.getResponseHeader(Constants.CONTENT_TYPE_HDR).getValue()); responseMap.put(Constants.STATUS_CODE, String.valueOf(statusCode)); } finally { if(getRequest!=null){ getRequest.releaseConnection(); } } return responseMap; } /** * Gets the auth ticket. * * @param authURI the auth uri * @param username the username * @param password the password * @return the auth ticket * @throws IOException Signals that an I/O exception has occurred. */ public String getAuthTicket(final String authURI, final String username, final String password) throws IOException { final Map<String, String> responseMap = getAuthResponse(authURI, username, password); final String ticketFrmResponse = responseMap.get(Constants.RESP_BODY); final int startindex = ticketFrmResponse.indexOf("TICKET"); final int endindex = ticketFrmResponse.indexOf("</"); return ticketFrmResponse.substring(startindex, endindex); } /** * Document upload. * * @param docFileObj the doc file obj * @param authTicket the auth ticket * @param uploadURI the upload uri * @param siteID the site id * @param uploadDir the upload dir * @return the string * @throws IOException Signals that an I/O exception has occurred. */ public String documentUpload(final File docFileObj, final String authTicket, final String uploadURI, final String siteID, final String uploadDir) throws IOException { String uploadResponse = Constants.EMPTY; PostMethod postRequest = null; try { final String uploadURL = getFileUploadURL(uploadURI,authTicket); LOG.info("documentUpload() | Upload URL: " + uploadURL); final HttpClient httpClient = new HttpClient(); postRequest = new PostMethod(uploadURL); final String mimeType = getMimeType(docFileObj); final String docName = docFileObj.getName(); LOG.info("documentUpload() | Uploading document: "+docName+" , content-type: "+mimeType); //To always replace the file then end following parameters in parts array //uploaddirectory can accept a folder name or a folder path. Do not include documentLibrary in the path final Part[] parts = { new FilePart("filedata", docName, docFileObj, mimeType,null), new StringPart("filename", docName), new StringPart("overwrite", "true"), new StringPart("siteid",siteID), new StringPart("containerid","documentLibrary"), new StringPart("uploaddirectory",uploadDir) }; postRequest.setRequestEntity(new MultipartRequestEntity(parts, postRequest.getParams())); final int statusCode = httpClient.executeMethod(postRequest); uploadResponse = postRequest.getResponseBodyAsString(); LOG.info("documentUpload() | Upload status: "+statusCode+" \nUpload response: "+uploadResponse); } finally{ if(postRequest!=null){ //releaseConnection http connection postRequest.releaseConnection(); } } return uploadResponse; } /** * Gets the auth url. * * @param path the path * @param username the username * @param password the password * @return the url */ private String getAuthURL(final String path, final String username, final String password) { final StringBuffer urlStrb = new StringBuffer(path); urlStrb.append(Constants.QUES); urlStrb.append(Constants.U); urlStrb.append(Constants.EQL); urlStrb.append(username); urlStrb.append(Constants.AMPERSND); urlStrb.append(Constants.PW); urlStrb.append(Constants.EQL); urlStrb.append(password); return urlStrb.toString(); } /** * Url file upload. * * @param path the path * @param ticket the ticket * @return the string */ private String getFileUploadURL(final String path, final String ticket) { final StringBuffer urlStrb = new StringBuffer(path); urlStrb.append(Constants.QUES); urlStrb.append(Constants.TICKET_QRY); urlStrb.append(Constants.EQL); urlStrb.append(ticket); return urlStrb.toString(); } /** * Gets the mime type. * * @param fileObj the file obj * @return the mime type * @throws IOException Signals that an I/O exception has occurred. */ public String getMimeType(final File fileObj) throws IOException { final Path source = Paths.get(fileObj.getPath()); return Files.probeContentType(source); } }
2- Constants:
/* * Created By: Abhinav Kumar Mishra * Copyright © 2014. Abhinav Kumar Mishra. * All rights reserved. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ /** * The Class Constants. */ public final class Constants{ /** The Constant EMPTY. */ public static final String EMPTY = ""; /** The Constant BR. */ public static final String BR = "\n"; /** The Constant SERVER. */ public static final String SERVER = "server"; /** The Constant BASEPATH. */ public static final String BASEPATH = "baseurl"; /** The Constant LOGIN_PATH. */ public static final String LOGIN_PATH = "authURI"; /** The Constant UPLOAD_PATH. */ public static final String UPLOAD_PATH = "uploadURI"; /** The Constant INPUT_PATH. */ public static final String INPUT_PATH = "inputPath"; /** The Constant DESC. */ public static final String DESC = "description"; /** The Constant U. */ public static final String U = "u"; /** The Constant PW. */ public static final String PW = "pw"; /** The Constant USERNAME. */ public static final String USERNAME = "username"; /** The Constant PASSWORD. */ public static final String PASSWORD = "password"; /** The Constant ENCODING. */ public static final String ENCODING = "UTF-8"; /** The Constant SERVER_ERR. */ public static final String SERVER_ERR = "500"; /** The Constant EQL. */ public static final String EQL = "="; /** The Constant QUES. */ public static final String QUES = "?"; /** The Constant AMPERSND. */ public static final String AMPERSND = "&"; /** The Constant RESP_BODY. */ public static final String RESP_BODY = "responsebody"; /** The Constant CONTENT_TYPE. */ public static final String CONTENT_TYPE = "content-type"; /** The Constant STATUS_CODE. */ public static final String STATUS_CODE = "statuscode"; /** The Constant CONTENT_TYPE_HDR. */ public static final String CONTENT_TYPE_HDR = "Content-Type"; /** The Constant MIME_TYPE. */ public static final String MIME_TYPE = "application/json"; /** The Constant GLOBAL_PROPERTIESFILE. */ public static final String GLOBAL_PROPERTIESFILE = "config.properties"; /** The Constant TICKET_QRY. */ public static final String TICKET_QRY = "alf_ticket"; /** The Constant SITE_ID. */ public static final String SITE_ID = "siteid"; /** The Constant CONTAINER_ID. */ public static final String CONTAINER_ID = "containerid"; /** The Constant UPLOAD_DIR. */ public static final String UPLOAD_DIR = "uploaddirectory"; }
3- Directory utility class
/* * Created By: Abhinav Kumar Mishra * Copyright © 2014. Abhinav Kumar Mishra. * All rights reserved. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * http://www.apache.org/licenses/LICENSE-2.0 * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License */ import java.io.File; import java.io.FileNotFoundException; import java.util.Arrays; import java.util.HashSet; import java.util.Iterator; import java.util.List; import java.util.Set; /** * This class DirectoryTraverser.<br/> * It returns set of files by traversing directories recursively. * * @author Abhinav Kumar Mishra * @since 2014 */ public final class DirectoryTraverser { /** * Gets the file uris. * * @param startDir the start dir * @return the file uris * @throws FileNotFoundException the file not found exception */ public static Set<File> getFileUris(final File startDir) throws FileNotFoundException { checkDirectories(startDir); // throw exception if not valid. return getUrisRecursive(startDir); } /** * Gets the uris recursive.<br/> * Recursively traverse each directory and uris of files. * * @param startDir the a starting dir * @return the uris recursive * @throws FileNotFoundException the file not found exception */ private static Set<File> getUrisRecursive(final File startDir) throws FileNotFoundException { final Set<File> sortedSetOfFiles = new HashSet<File>(); final File[] filesAndDirs = startDir.listFiles(); final List<File> filesDirs = Arrays.asList(filesAndDirs); final Iterator<File> filesDirsItr = filesDirs.iterator(); while (filesDirsItr.hasNext()) { final File file = filesDirsItr.next(); sortedSetOfFiles.add(file); // Add files and directory URIs both // If uri is a directory the revisit it recursively. if (!file.isFile()) { // Call 'getUrisRecursive' to extract uris from directory final Set<File> innerSet = getUrisRecursive(file); sortedSetOfFiles.addAll(innerSet); } } return sortedSetOfFiles; } /** * Checks if is valid directory.<br/> * If directory exists then it is valid. If directory is valid then it can * be read. * * @param directoryUri the a directory * @throws FileNotFoundException the file not found exception */ private static void checkDirectories(final File directoryUri) throws FileNotFoundException { if (directoryUri == null) { throw new IllegalArgumentException("Directory should not be null."); }if (!directoryUri.exists()) { throw new FileNotFoundException("Directory does not exist: "+ directoryUri); }if (!directoryUri.isDirectory()) { throw new IllegalArgumentException("Is not a directory: "+ directoryUri); }if (!directoryUri.canRead()) { throw new IllegalArgumentException("Directory cannot be read: "+ directoryUri); } } private DirectoryTraverser() { super(); } }
4- Test
/* * Created By: Abhinav Kumar Mishra * Copyright © 2014. Abhinav Kumar Mishra. * All rights reserved. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ import java.io.File; import java.io.IOException; import java.util.Iterator; import java.util.Set; import junit.framework.TestCase; /** * The Class UploadDocumentHttpTest. * * @author Abhinav Kumar Mishra * @since 2014 */ public class UploadDocumentHttpTest extends TestCase{ /** * Test document upload. * * @throws IOException Signals that an I/O exception has occurred. */ @Test public void testDocumentUpload() throws IOException { final String uploadURI = "http://127.0.0.1:8080/alfresco/service/api/upload"; final String authURI = "http://127.0.0.1:8080/alfresco/service/api/login"; final String username = "admin"; final String password = "admin"; final String inputUri = "C:/Users/Abhi/Desktop/data"; // files to be uploaded from this directory final String siteID = "testpoc"; //id of the site for e.g if site name is TestPoc the id will be testpoc final String uploadDir = "testUpload"; //directory created under document library final HttpUtils httpUtils = new HttpUtils(); String authTicket = Constants.EMPTY; try { // Get the authentication ticket from alfresco. //This authTicket will be used in all subsequent requests in order to get authenticated with alfresco. // e.g TICKET_4b36ecaxxxxx5cdc5d782xxxxxxxxxxxx authTicket = httpUtils.getAuthTicket(authURI, username, password); } catch (IOException e) { e.printStackTrace(); } final StringBuffer responseBody= new StringBuffer(); final File fileObject = new File (inputUri); //if uri is a directory the upload all files.. if(fileObject.isDirectory()){ final Set<File> setOfFiles = DirectoryTraverser.getFileUris(fileObject); for (Iterator<File> iterator = setOfFiles.iterator(); iterator.hasNext();) { final File fileObj = iterator.next(); //call document upload if(fileObj.isFile()){ responseBody.append(httpUtils.documentUpload( fileObj, authTicket, uploadURI, siteID, uploadDir)); responseBody.append(Constants.BR); } } }else{ responseBody.append(httpUtils.documentUpload( fileObject, authTicket, uploadURI, siteID, uploadDir)); } System.out.println("Response of upload operation >>>: "+responseBody); assertEquals(true, responseBody.toString().contains("File uploaded successfully")); } }
Further implementations:
If you want to upload a new version of already existing file, you just have to get the nodeRef of existing file and pass below given parts parameter to same Upload REST API call. See documentUpload method above, I have highlighted the parts parameter. You have to replace the parts parameter and upload the file.// To upload the file as a new version once the file was uploaded, then send following parameters in
// parts array. Note that we have to remove the "override" parameter from the parts array and add
// "updateNodeRef" parameter.
//uploaddirectory can accept a folder name or a folder path. Do not include documentLibrary in the path
final Part[] partsUploadAsVersion = { new FilePart("filedata", docName, docFileObj, mimeType,null), new StringPart("filename", docName), new StringPart("siteid",siteID), new StringPart("containerid","documentLibrary"), new StringPart("uploaddirectory",uploadDir), //Optional Parameter new StringPart("updateNodeRef ", nodeRefOfExistingFile) };
Note:- You will still need the old parts array to upload the file for the first time. Once file is uploaded then to upload new version of that file (node) you have to use above given option.
If you want to upload file to a target destination for example: 'Shared' folder in the alfresco repository, then you can use the destination parameter to pass the nodeRef and additionally pass the folder name inside the destination node.
Here is the sample:
Here is the sample:
final Part[] partsUploadAsVersion = { new FilePart("filedata", docName, docFileObj, mimeType,null), new StringPart("filename", docName), new StringPart("destination", destinationNodeRef), // nodeRef of 'Shared' folder i.e. workspace://SpacesStore/85d2a84d-271b-41b1-9449-02f5942893a0 new StringPart("uploaddirectory",uploadDir), //Optional Parameter new StringPart("overwrite ", "true") };
Here is the detailed description for upload api:
Upload file content and meta-data into repository.
POST /alfresco/service/api/upload
HTML form data
- filedata, (mandatory) HTML type file
- You must specify one of:
- destination (the folder NodeRef where the node will be created)
- updateNodeRef (the NodeRef of an existing node that will be updated)
- siteid and containerid (the Site name and the container in that site where the document will be created)
- uploaddirectory - name of the folder (either in the site container or the destination) where the document will be uploaded. This folder must already exist
- description - Description for a version update (versionDescription)
- contenttype - The content type that this document should be specialised to
- majorversion
- overwrite
- thumbnails
Return content
- nodeRef
Return status: STATUS_OK (200)
The web script description document specifies the following options:
Value | Description |
---|---|
json | The default response format |
user | The authentication access |
required | The transaction level |
any | The format style |
----------------------------------------------------------------------------------------------------------------------
If you want to download or delete a node/file then you can write a piece of code taking the reference of above code to download/delete the node/file.
REST API for download file/node is: (It should be HTTP Get request)
http://127.0.0.1:8080/alfresco/service/api/node/content/workspace/SpacesStore/85d2a84d-271b-41b1-9449-02f5942893a0?a=false&alf_ticket=TICKET_5550fa5e9b87bead8f008e906185e023b7ce21ed
Where:
a: means attach. if true, force download of content as attachment. Possible values are true/false
store_type: workspace
store_id: SpacesStore
id: nodeRefId (UUID of the node)
A StoreRef is comprised of:
Store Protocol - that is, the type of store
Store Identifier - the id of the store
Example storeRefs are:
workspace://SpacesStore (store_type://store_id)
version://versionStore (store_type://store_id)
archive://SpacesStore (store_type://store_id)
Store Protocol - that is, the type of store
Store Identifier - the id of the store
Example storeRefs are:
workspace://SpacesStore (store_type://store_id)
version://versionStore (store_type://store_id)
archive://SpacesStore (store_type://store_id)
For more on Download Services visit my another post here: Downloading Content From Alfresco
--------------------------------------------------------------------------------------------------------------------------------
Example:
http://127.0.0.1:8080/alfresco/service/api/node/workspace/SpacesStore/0a1b9c30-39a6-4249-8f2b-78c4e8b29b2c?alf_ticket=TICKET_5550fa5e9b87bead8f008e906185e023b7ce21ed
Note: You need to pass alf_ticket as a parameter for very REST call. You can see, i am adding alf_ticket parameter for upload, download and delete examples above.
Refer to Repository REST API references:
https://docs.alfresco.com/5.0/references/RESTful-Repository.html