From ee3eb7d5d49ef5cd5a52f243eebd5a5d516d581d Mon Sep 17 00:00:00 2001 From: David Caruana Date: Tue, 7 Apr 2009 09:30:10 +0000 Subject: [PATCH] CMIS setContentStream() - implemented as a web script - complements the "get content" web script; just use put against same resource - added testContentStream() to CMISTest git-svn-id: https://svn.alfresco.com/repos/alfresco-enterprise/alfresco/HEAD/root@13870 c4b6b30b-aa2e-2d43-bbcb-ca4b014f7261 --- .../repository/store/content.put.desc.xml | 13 ++ .../repository/store/content.put.text.ftl | 0 .../web-scripts-application-context.xml | 8 + .../repo/cmis/rest/test/CMISTest.java | 28 +++ .../repo/web/scripts/content/ContentGet.java | 23 -- .../repo/web/scripts/content/ContentSet.java | 204 ++++++++++++++++++ 6 files changed, 253 insertions(+), 23 deletions(-) create mode 100644 config/alfresco/templates/webscripts/org/alfresco/repository/store/content.put.desc.xml create mode 100644 config/alfresco/templates/webscripts/org/alfresco/repository/store/content.put.text.ftl create mode 100644 source/java/org/alfresco/repo/web/scripts/content/ContentSet.java diff --git a/config/alfresco/templates/webscripts/org/alfresco/repository/store/content.put.desc.xml b/config/alfresco/templates/webscripts/org/alfresco/repository/store/content.put.desc.xml new file mode 100644 index 0000000000..d56ee9042b --- /dev/null +++ b/config/alfresco/templates/webscripts/org/alfresco/repository/store/content.put.desc.xml @@ -0,0 +1,13 @@ + + Content Write (setContent) + TODO + /api/node/content{property}/{store_type}/{store_id}/{id}?overwriteFlag={overwriteFlag?} + /api/path/content{property}/{store_type}/{store_id}/{id}?overwriteFlag={overwriteFlag?} + /api/avmpath/content{property}/{store_id}/{id}?overwriteFlag={overwriteFlag?} + /api/node/{store_type}/{store_id}/{id}/content{property}?overwriteFlag={overwriteFlag?} + /api/path/{store_type}/{store_id}/{id}/content{property}?overwriteFlag={overwriteFlag?} + guest + argument + CMIS + draft_public_api + \ No newline at end of file diff --git a/config/alfresco/templates/webscripts/org/alfresco/repository/store/content.put.text.ftl b/config/alfresco/templates/webscripts/org/alfresco/repository/store/content.put.text.ftl new file mode 100644 index 0000000000..e69de29bb2 diff --git a/config/alfresco/web-scripts-application-context.xml b/config/alfresco/web-scripts-application-context.xml index 7422f586f5..b8919f647b 100644 --- a/config/alfresco/web-scripts-application-context.xml +++ b/config/alfresco/web-scripts-application-context.xml @@ -246,6 +246,14 @@ + + + + + + + + diff --git a/source/java/org/alfresco/repo/cmis/rest/test/CMISTest.java b/source/java/org/alfresco/repo/cmis/rest/test/CMISTest.java index 832d95bc13..6f42636407 100644 --- a/source/java/org/alfresco/repo/cmis/rest/test/CMISTest.java +++ b/source/java/org/alfresco/repo/cmis/rest/test/CMISTest.java @@ -554,6 +554,34 @@ public class CMISTest extends BaseCMISWebScriptTest assertEquals("updated content " + guid, contentRes.getContentAsString()); } + public void testContentStream() + throws Exception + { + // retrieve test folder for content stream tests + Entry testFolder = createTestFolder("testContentStream"); + Link childrenLink = testFolder.getLink(CMISConstants.REL_CHILDREN); + + // create document for setting / getting content + Entry document = createDocument(childrenLink.getHref(), "testContent"); + + // retrieve content + Response documentContentRes = sendRequest(new GetRequest(document.getContentSrc().toString()), 200); + String resContent = documentContentRes.getContentAsString(); + assertEquals(document.getTitle(), resContent); + + // set content + String UPDATED_CONTENT = "Updated via SetContentStream()"; + Link editMediaLink = document.getEditMediaLink(); + assertNotNull(editMediaLink); + Response res = sendRequest(new PutRequest(editMediaLink.getHref().toString(), UPDATED_CONTENT, Format.TEXT.mimetype()), 200); + assertNotNull(res); + + // retrieve updated content + Response documentUpdatedContentRes = sendRequest(new GetRequest(document.getContentSrc().toString()), 200); + String resUpdatedContent = documentUpdatedContentRes.getContentAsString(); + assertEquals(UPDATED_CONTENT, resUpdatedContent); + } + public void testAllowableActions() throws Exception { diff --git a/source/java/org/alfresco/repo/web/scripts/content/ContentGet.java b/source/java/org/alfresco/repo/web/scripts/content/ContentGet.java index 5330c8ad6c..6bc14b72bb 100644 --- a/source/java/org/alfresco/repo/web/scripts/content/ContentGet.java +++ b/source/java/org/alfresco/repo/web/scripts/content/ContentGet.java @@ -25,7 +25,6 @@ package org.alfresco.repo.web.scripts.content; import java.io.IOException; -import java.text.MessageFormat; import java.util.Arrays; import java.util.Map; @@ -36,7 +35,6 @@ import org.alfresco.repo.model.Repository; import org.alfresco.service.cmr.repository.NodeRef; import org.alfresco.service.namespace.NamespaceService; import org.alfresco.service.namespace.QName; -import org.alfresco.util.URLEncoder; import org.alfresco.web.scripts.WebScriptException; import org.alfresco.web.scripts.WebScriptRequest; import org.alfresco.web.scripts.WebScriptResponse; @@ -57,8 +55,6 @@ public class ContentGet extends StreamContent @SuppressWarnings("unused") private static final Log logger = LogFactory.getLog(ContentGet.class); - private static final String NODE_URL = "/api/node/content/{0}/{1}/{2}/{3}"; - // Component dependencies private Repository repository; private NamespaceService namespaceService; @@ -122,23 +118,4 @@ public class ContentGet extends StreamContent // Stream the content streamContent(req, res, nodeRef, propertyQName, attach); } - - /** - * Helper to generate a URL to a content node for downloading content from the server. - * The content is supplied directly in the reponse. This generally means a browser will - * attempt to open the content directly if possible, else it will prompt to save the file. - * - * @param ref NodeRef of the content node to generate URL for (cannot be null) - * @param name File name end element to return on the url (used by the browser on Save) - * - * @return URL to download the content from the specified node - */ - public final static String generateNodeURL(NodeRef ref, String name) - { - return MessageFormat.format(NODE_URL, new Object[] { - ref.getStoreRef().getProtocol(), - ref.getStoreRef().getIdentifier(), - ref.getId(), - URLEncoder.encode(name) } ); - } } \ No newline at end of file diff --git a/source/java/org/alfresco/repo/web/scripts/content/ContentSet.java b/source/java/org/alfresco/repo/web/scripts/content/ContentSet.java new file mode 100644 index 0000000000..bb3209cd9b --- /dev/null +++ b/source/java/org/alfresco/repo/web/scripts/content/ContentSet.java @@ -0,0 +1,204 @@ +/* + * Copyright (C) 2005-2007 Alfresco Software Limited. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + + * As a special exception to the terms and conditions of version 2.0 of + * the GPL, you may redistribute this Program in connection with Free/Libre + * and Open Source Software ("FLOSS") applications as described in Alfresco's + * FLOSS exception. You should have recieved a copy of the text describing + * the FLOSS exception, and it is also available here: + * http://www.alfresco.com/legal/licensing" + */ +package org.alfresco.repo.web.scripts.content; + +import java.io.BufferedInputStream; +import java.io.IOException; +import java.io.InputStream; +import java.nio.charset.Charset; +import java.util.Arrays; +import java.util.Map; + +import javax.servlet.http.HttpServletResponse; + +import org.alfresco.model.ContentModel; +import org.alfresco.repo.content.encoding.ContentCharsetFinder; +import org.alfresco.repo.model.Repository; +import org.alfresco.service.cmr.dictionary.DataTypeDefinition; +import org.alfresco.service.cmr.dictionary.DictionaryService; +import org.alfresco.service.cmr.dictionary.PropertyDefinition; +import org.alfresco.service.cmr.repository.ContentReader; +import org.alfresco.service.cmr.repository.ContentService; +import org.alfresco.service.cmr.repository.ContentWriter; +import org.alfresco.service.cmr.repository.MimetypeService; +import org.alfresco.service.cmr.repository.NodeRef; +import org.alfresco.service.namespace.NamespaceService; +import org.alfresco.service.namespace.QName; +import org.alfresco.web.scripts.AbstractWebScript; +import org.alfresco.web.scripts.WebScriptException; +import org.alfresco.web.scripts.WebScriptRequest; +import org.alfresco.web.scripts.WebScriptResponse; +import org.apache.commons.logging.Log; +import org.apache.commons.logging.LogFactory; + + +/** + * Content Write Service + * + * Stream content to the Repository. + * + * @author davidc + */ +public class ContentSet extends AbstractWebScript +{ + // Logger + @SuppressWarnings("unused") + private static final Log logger = LogFactory.getLog(ContentSet.class); + + // Component dependencies + private Repository repository; + private DictionaryService dictionaryService; + private NamespaceService namespaceService; + private ContentService contentService; + private MimetypeService mimetypeService; + + /** + * @param repository + */ + public void setRepository(Repository repository) + { + this.repository = repository; + } + + /** + * @param dictionaryService + */ + public void setDictionaryService(DictionaryService dictionaryService) + { + this.dictionaryService = dictionaryService; + } + + /** + * @param namespaceService + */ + public void setNamespaceService(NamespaceService namespaceService) + { + this.namespaceService = namespaceService; + } + + /** + * @param contentService + */ + public void setContentService(ContentService contentService) + { + this.contentService = contentService; + } + + /** + * @param mimetypeService + */ + public void setMimetypeService(MimetypeService mimetypeService) + { + this.mimetypeService = mimetypeService; + } + + /** + * @see org.alfresco.web.scripts.WebScript#execute(org.alfresco.web.scripts.WebScriptRequest, org.alfresco.web.scripts.WebScriptResponse) + */ + public void execute(WebScriptRequest req, WebScriptResponse res) + throws IOException + { + // convert web script URL to node reference in Repository + String match = req.getServiceMatch().getPath(); + String[] matchParts = match.split("/"); + Map templateVars = req.getServiceMatch().getTemplateVars(); + String[] id = templateVars.get("id").split("/"); + String[] path = new String[id.length + 2]; + path[0] = templateVars.get("store_type"); + path[1] = templateVars.get("store_id"); + System.arraycopy(id, 0, path, 2, id.length); + NodeRef nodeRef = repository.findNodeRef(matchParts[2], path); + if (nodeRef == null) + { + throw new WebScriptException(HttpServletResponse.SC_NOT_FOUND, "Unable to find " + matchParts[2] + " reference " + Arrays.toString(path)); + } + + // determine content property + QName propertyQName = ContentModel.PROP_CONTENT; + String contentPart = templateVars.get("property"); + if (contentPart.length() > 0 && contentPart.charAt(0) == ';') + { + if (contentPart.length() < 2) + { + throw new WebScriptException(HttpServletResponse.SC_BAD_REQUEST, "Content property malformed"); + } + String propertyName = contentPart.substring(1); + if (propertyName.length() > 0) + { + propertyQName = QName.createQName(propertyName, namespaceService); + } + } + PropertyDefinition propertyDef = dictionaryService.getProperty(propertyQName); + if (propertyDef == null) + { + throw new WebScriptException(HttpServletResponse.SC_NOT_FOUND, "Unable to find " + matchParts[2] + " reference " + Arrays.toString(path) + " content property " + propertyQName); + } + if (!propertyDef.getDataType().getName().equals(DataTypeDefinition.CONTENT)) + { + throw new WebScriptException(HttpServletResponse.SC_NOT_FOUND, "Content stream not found"); + } + + // ensure content can be overwritten + // TODO: check parameter name + String overwrite = req.getParameter("overwriteFlag"); + if (overwrite != null && overwrite.equalsIgnoreCase("false")) + { + ContentReader reader = contentService.getReader(nodeRef, propertyQName); + if (reader != null) + { + throw new WebScriptException(HttpServletResponse.SC_INTERNAL_SERVER_ERROR, "Content already exists."); + } + } + + // setup content writer + ContentWriter writer = contentService.getWriter(nodeRef, propertyQName, true); + + // establish mimetype + String mimetype = req.getContentType(); + if (mimetype == null) + { + if (matchParts[2].equals("path") || matchParts[2].equals("avmpath")) + { + mimetype = mimetypeService.guessMimetype(templateVars.get("id")); + } + } + if (mimetype != null) + { + writer.setMimetype(mimetype); + } + + // get the input stream from the request data + InputStream is = req.getContent().getInputStream(); + is = is.markSupported() ? is : new BufferedInputStream(is); + + // establish content encoding + ContentCharsetFinder charsetFinder = mimetypeService.getContentCharsetFinder(); + Charset encoding = charsetFinder.getCharset(is, mimetype); + writer.setEncoding(encoding.name()); + + // write the new data + writer.putContent(is); + } +} \ No newline at end of file