From 9ce92f240476a25e7da89739766e7e3242ae7d36 Mon Sep 17 00:00:00 2001 From: Kevin Roast Date: Thu, 12 Jul 2012 15:08:54 +0000 Subject: [PATCH] Merged BRANCHES/DEV/V4.1-BUG-FIX to HEAD 39084: Merged BRANCHES/DEV/V3.4-BUG-FIX to BRANCHES/DEV/V4.1-BUG-FIX 39081: Fix for ALF-6139 and ALF-13959 - Incomplete site creation issues - latest Surf libs and related changes to allow atomic creation of multiple Surf objects in a single REST call. Originally authored by Dave Ward for 3.2 - now migrated to SpringSurf. Implemented ADMRemoteStore changes for above change to apply to 4.0. git-svn-id: https://svn.alfresco.com/repos/alfresco-enterprise/alfresco/HEAD/root@39205 c4b6b30b-aa2e-2d43-bbcb-ca4b014f7261 --- .../repository/store/remoteadm.post.desc.xml | 1 + .../repository/store/remoteavm.post.desc.xml | 1 + .../repo/web/scripts/bean/ADMRemoteStore.java | 154 ++++++++++++------ .../repo/web/scripts/bean/AVMRemoteStore.java | 20 +-- .../web/scripts/bean/BaseRemoteStore.java | 25 ++- 5 files changed, 133 insertions(+), 68 deletions(-) diff --git a/config/alfresco/templates/webscripts/org/alfresco/repository/store/remoteadm.post.desc.xml b/config/alfresco/templates/webscripts/org/alfresco/repository/store/remoteadm.post.desc.xml index 4c9bafe981..794d2cb959 100644 --- a/config/alfresco/templates/webscripts/org/alfresco/repository/store/remoteadm.post.desc.xml +++ b/config/alfresco/templates/webscripts/org/alfresco/repository/store/remoteadm.post.desc.xml @@ -1,6 +1,7 @@ Remote ADM Store Remote service mirroring the Store interface - to an ADM store + /remoteadm/{method} /remoteadm/{method}/{path} user required diff --git a/config/alfresco/templates/webscripts/org/alfresco/repository/store/remoteavm.post.desc.xml b/config/alfresco/templates/webscripts/org/alfresco/repository/store/remoteavm.post.desc.xml index 122595e97c..d99d1cea04 100644 --- a/config/alfresco/templates/webscripts/org/alfresco/repository/store/remoteavm.post.desc.xml +++ b/config/alfresco/templates/webscripts/org/alfresco/repository/store/remoteavm.post.desc.xml @@ -1,6 +1,7 @@ Remote AVM Store Remote service mirroring the Store interface - to an AVM store + /remotestore/{method} /remotestore/{method}/{path} user required diff --git a/source/java/org/alfresco/repo/web/scripts/bean/ADMRemoteStore.java b/source/java/org/alfresco/repo/web/scripts/bean/ADMRemoteStore.java index 999402ea5e..0efbe525cb 100644 --- a/source/java/org/alfresco/repo/web/scripts/bean/ADMRemoteStore.java +++ b/source/java/org/alfresco/repo/web/scripts/bean/ADMRemoteStore.java @@ -18,6 +18,7 @@ */ package org.alfresco.repo.web.scripts.bean; +import java.io.ByteArrayInputStream; import java.io.IOException; import java.io.InputStream; import java.io.Serializable; @@ -31,6 +32,12 @@ import java.util.StringTokenizer; import java.util.regex.Matcher; import java.util.regex.Pattern; +import javax.xml.parsers.DocumentBuilder; +import javax.xml.parsers.DocumentBuilderFactory; +import javax.xml.transform.Transformer; +import javax.xml.transform.dom.DOMSource; +import javax.xml.transform.stream.StreamResult; + import org.alfresco.model.ContentModel; import org.alfresco.query.CannedQueryPageDetails; import org.alfresco.query.PagingRequest; @@ -56,12 +63,16 @@ import org.alfresco.service.cmr.site.SiteInfo; import org.alfresco.service.cmr.site.SiteService; import org.alfresco.service.namespace.NamespaceService; import org.alfresco.service.namespace.QName; +import org.apache.axis.utils.ByteArrayOutputStream; import org.apache.commons.logging.Log; import org.apache.commons.logging.LogFactory; import org.springframework.extensions.surf.util.URLDecoder; import org.springframework.extensions.webscripts.Status; import org.springframework.extensions.webscripts.WebScriptException; import org.springframework.extensions.webscripts.WebScriptResponse; +import org.w3c.dom.Document; +import org.w3c.dom.Element; +import org.w3c.dom.Node; /** * ADM Remote Store service. @@ -328,50 +339,7 @@ public class ADMRemoteStore extends BaseRemoteStore { try { - // do not support filenames directly at the root - all objectypes must exist in a named child folder - final String encpath = encodePath(path); - final int off = encpath.lastIndexOf('/'); - if (off != -1) - { - // check we actually are the user we are creating a user specific path for - String runAsUser = AuthenticationUtil.getFullyAuthenticatedUser(); - String userId = null; - Matcher matcher; - if ((matcher = USER_PATTERN_1.matcher(path)).matches()) - { - userId = matcher.group(1); - } - else if ((matcher = USER_PATTERN_2.matcher(path)).matches()) - { - userId = matcher.group(1); - } - if (userId != null && userId.equals(runAsUser)) - { - runAsUser = AuthenticationUtil.getSystemUserName(); - } - AuthenticationUtil.runAs(new RunAsWork() - { - @SuppressWarnings("synthetic-access") - public Void doWork() throws Exception - { - final FileInfo parentFolder = resolveNodePath(encpath, true, false); - if (parentFolder == null) - { - throw new IllegalStateException("Unable to aquire parent folder reference for path: " + path); - } - FileInfo fileInfo = fileFolderService.create( - parentFolder.getNodeRef(), encpath.substring(off + 1), ContentModel.TYPE_CONTENT); - - ContentWriter writer = contentService.getWriter( - fileInfo.getNodeRef(), ContentModel.PROP_CONTENT, true); - writer.guessMimetype(fileInfo.getName()); - writer.putContent(content); - if (logger.isDebugEnabled()) - logger.debug("createDocument: " + fileInfo.toString()); - return null; - } - }, runAsUser); - } + writeDocument(path, content); } catch (AccessDeniedException ae) { @@ -389,9 +357,103 @@ public class ADMRemoteStore extends BaseRemoteStore * @param content XML document containing multiple document contents to write */ @Override - protected void createDocuments(WebScriptResponse res, String store, InputStream content) + protected void createDocuments(WebScriptResponse res, String store, InputStream in) { - // no implementation currently + try + { + DocumentBuilder documentBuilder = DocumentBuilderFactory.newInstance().newDocumentBuilder(); + Document document; + document = documentBuilder.parse(in); + Element docEl = document.getDocumentElement(); + Transformer transformer = ADMRemoteStore.this.transformer.get(); + for (Node n = docEl.getFirstChild(); n != null; n = n.getNextSibling()) + { + if (!(n instanceof Element)) + { + continue; + } + final String path = ((Element) n).getAttribute("path"); + + // Turn the first element child into a document + Document doc = documentBuilder.newDocument(); + Node child; + for (child = n.getFirstChild(); child != null ; child=child.getNextSibling()) + { + if (child instanceof Element) + { + doc.appendChild(doc.importNode(child, true)); + break; + } + } + ByteArrayOutputStream out = new ByteArrayOutputStream(512); + transformer.transform(new DOMSource(doc), new StreamResult(out)); + out.close(); + + writeDocument(path, new ByteArrayInputStream(out.toByteArray())); + } + } + catch (AccessDeniedException ae) + { + res.setStatus(Status.STATUS_UNAUTHORIZED); + } + catch (FileExistsException feeErr) + { + res.setStatus(Status.STATUS_CONFLICT); + } + catch (Exception e) + { + // various annoying checked SAX/IO exceptions related to XML processing can be thrown + // none of them should occur if the XML document is well formed + logger.error(e); + res.setStatus(Status.STATUS_INTERNAL_SERVER_ERROR); + } + } + + private void writeDocument(final String path, final InputStream content) + { + final String encpath = encodePath(path); + final int off = encpath.lastIndexOf('/'); + if (off != -1) + { + // check we actually are the user we are creating a user specific path for + String runAsUser = AuthenticationUtil.getFullyAuthenticatedUser(); + String userId = null; + Matcher matcher; + if ((matcher = USER_PATTERN_1.matcher(path)).matches()) + { + userId = matcher.group(1); + } + else if ((matcher = USER_PATTERN_2.matcher(path)).matches()) + { + userId = matcher.group(1); + } + if (userId != null && userId.equals(runAsUser)) + { + runAsUser = AuthenticationUtil.getSystemUserName(); + } + AuthenticationUtil.runAs(new RunAsWork() + { + @SuppressWarnings("synthetic-access") + public Void doWork() throws Exception + { + final FileInfo parentFolder = resolveNodePath(encpath, true, false); + if (parentFolder == null) + { + throw new IllegalStateException("Unable to aquire parent folder reference for path: " + path); + } + FileInfo fileInfo = fileFolderService.create( + parentFolder.getNodeRef(), encpath.substring(off + 1), ContentModel.TYPE_CONTENT); + + ContentWriter writer = contentService.getWriter( + fileInfo.getNodeRef(), ContentModel.PROP_CONTENT, true); + writer.guessMimetype(fileInfo.getName()); + writer.putContent(content); + if (logger.isDebugEnabled()) + logger.debug("createDocument: " + fileInfo.toString()); + return null; + } + }, runAsUser); + } } /** diff --git a/source/java/org/alfresco/repo/web/scripts/bean/AVMRemoteStore.java b/source/java/org/alfresco/repo/web/scripts/bean/AVMRemoteStore.java index e12e04e32c..015857704b 100644 --- a/source/java/org/alfresco/repo/web/scripts/bean/AVMRemoteStore.java +++ b/source/java/org/alfresco/repo/web/scripts/bean/AVMRemoteStore.java @@ -31,8 +31,6 @@ import java.util.StringTokenizer; import javax.xml.parsers.DocumentBuilder; import javax.xml.parsers.DocumentBuilderFactory; import javax.xml.transform.Transformer; -import javax.xml.transform.TransformerConfigurationException; -import javax.xml.transform.TransformerFactory; import javax.xml.transform.dom.DOMSource; import javax.xml.transform.stream.StreamResult; @@ -70,22 +68,6 @@ import org.w3c.dom.Node; public class AVMRemoteStore extends BaseRemoteStore { private static final Log logger = LogFactory.getLog(AVMRemoteStore.class); - private static final TransformerFactory TRANSFORMER_FACTORY = TransformerFactory.newInstance(); - private static ThreadLocal transformer = new ThreadLocal() - { - @Override - protected Transformer initialValue() - { - try - { - return TRANSFORMER_FACTORY.newTransformer(); - } - catch (TransformerConfigurationException e) - { - throw new RuntimeException(e); - } - } - }; private String rootPath = "/"; private AVMService avmService; private SearchService searchService; @@ -305,7 +287,7 @@ public class AVMRemoteStore extends BaseRemoteStore { try { - Set checkedPaths = new HashSet(19); + Set checkedPaths = new HashSet(16); DocumentBuilder documentBuilder = DocumentBuilderFactory.newInstance().newDocumentBuilder(); Document document = documentBuilder.parse(in); Element docEl = document.getDocumentElement(); diff --git a/source/java/org/alfresco/repo/web/scripts/bean/BaseRemoteStore.java b/source/java/org/alfresco/repo/web/scripts/bean/BaseRemoteStore.java index bfc04fc57d..27b2416acc 100644 --- a/source/java/org/alfresco/repo/web/scripts/bean/BaseRemoteStore.java +++ b/source/java/org/alfresco/repo/web/scripts/bean/BaseRemoteStore.java @@ -25,17 +25,19 @@ import java.util.List; import java.util.StringTokenizer; import javax.servlet.http.HttpServletRequest; +import javax.xml.transform.Transformer; +import javax.xml.transform.TransformerConfigurationException; +import javax.xml.transform.TransformerFactory; -import org.alfresco.service.cmr.repository.ContentService; import org.alfresco.service.cmr.repository.MimetypeService; +import org.apache.commons.logging.Log; +import org.apache.commons.logging.LogFactory; import org.springframework.extensions.webscripts.AbstractWebScript; import org.springframework.extensions.webscripts.WebScriptException; import org.springframework.extensions.webscripts.WebScriptRequest; import org.springframework.extensions.webscripts.WebScriptResponse; import org.springframework.extensions.webscripts.WrappingWebScriptRequest; import org.springframework.extensions.webscripts.servlet.WebScriptServletRequest; -import org.apache.commons.logging.Log; -import org.apache.commons.logging.LogFactory; /** * Remote Store service. @@ -102,6 +104,23 @@ public abstract class BaseRemoteStore extends AbstractWebScript protected String defaultStore; protected MimetypeService mimetypeService; + protected static final TransformerFactory TRANSFORMER_FACTORY = TransformerFactory.newInstance(); + protected static ThreadLocal transformer = new ThreadLocal() + { + @Override + protected Transformer initialValue() + { + try + { + return TRANSFORMER_FACTORY.newTransformer(); + } + catch (TransformerConfigurationException e) + { + throw new RuntimeException(e); + } + } + }; + /** * @param defaultStore the default store name of the store to process document requests against