mirror of
https://github.com/Alfresco/alfresco-community-repo.git
synced 2025-08-14 17:58:59 +00:00
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
This commit is contained in:
@@ -1,6 +1,7 @@
|
|||||||
<webscript>
|
<webscript>
|
||||||
<shortname>Remote ADM Store</shortname>
|
<shortname>Remote ADM Store</shortname>
|
||||||
<description>Remote service mirroring the Store interface - to an ADM store</description>
|
<description>Remote service mirroring the Store interface - to an ADM store</description>
|
||||||
|
<url>/remoteadm/{method}</url>
|
||||||
<url>/remoteadm/{method}/{path}</url>
|
<url>/remoteadm/{method}/{path}</url>
|
||||||
<authentication>user</authentication>
|
<authentication>user</authentication>
|
||||||
<transaction buffersize="0">required</transaction>
|
<transaction buffersize="0">required</transaction>
|
||||||
|
@@ -1,6 +1,7 @@
|
|||||||
<webscript>
|
<webscript>
|
||||||
<shortname>Remote AVM Store</shortname>
|
<shortname>Remote AVM Store</shortname>
|
||||||
<description>Remote service mirroring the Store interface - to an AVM store</description>
|
<description>Remote service mirroring the Store interface - to an AVM store</description>
|
||||||
|
<url>/remotestore/{method}</url>
|
||||||
<url>/remotestore/{method}/{path}</url>
|
<url>/remotestore/{method}/{path}</url>
|
||||||
<authentication>user</authentication>
|
<authentication>user</authentication>
|
||||||
<transaction>required</transaction>
|
<transaction>required</transaction>
|
||||||
|
@@ -18,6 +18,7 @@
|
|||||||
*/
|
*/
|
||||||
package org.alfresco.repo.web.scripts.bean;
|
package org.alfresco.repo.web.scripts.bean;
|
||||||
|
|
||||||
|
import java.io.ByteArrayInputStream;
|
||||||
import java.io.IOException;
|
import java.io.IOException;
|
||||||
import java.io.InputStream;
|
import java.io.InputStream;
|
||||||
import java.io.Serializable;
|
import java.io.Serializable;
|
||||||
@@ -31,6 +32,12 @@ import java.util.StringTokenizer;
|
|||||||
import java.util.regex.Matcher;
|
import java.util.regex.Matcher;
|
||||||
import java.util.regex.Pattern;
|
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.model.ContentModel;
|
||||||
import org.alfresco.query.CannedQueryPageDetails;
|
import org.alfresco.query.CannedQueryPageDetails;
|
||||||
import org.alfresco.query.PagingRequest;
|
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.cmr.site.SiteService;
|
||||||
import org.alfresco.service.namespace.NamespaceService;
|
import org.alfresco.service.namespace.NamespaceService;
|
||||||
import org.alfresco.service.namespace.QName;
|
import org.alfresco.service.namespace.QName;
|
||||||
|
import org.apache.axis.utils.ByteArrayOutputStream;
|
||||||
import org.apache.commons.logging.Log;
|
import org.apache.commons.logging.Log;
|
||||||
import org.apache.commons.logging.LogFactory;
|
import org.apache.commons.logging.LogFactory;
|
||||||
import org.springframework.extensions.surf.util.URLDecoder;
|
import org.springframework.extensions.surf.util.URLDecoder;
|
||||||
import org.springframework.extensions.webscripts.Status;
|
import org.springframework.extensions.webscripts.Status;
|
||||||
import org.springframework.extensions.webscripts.WebScriptException;
|
import org.springframework.extensions.webscripts.WebScriptException;
|
||||||
import org.springframework.extensions.webscripts.WebScriptResponse;
|
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.
|
* ADM Remote Store service.
|
||||||
@@ -328,50 +339,7 @@ public class ADMRemoteStore extends BaseRemoteStore
|
|||||||
{
|
{
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
// do not support filenames directly at the root - all objectypes must exist in a named child folder
|
writeDocument(path, 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<Void>()
|
|
||||||
{
|
|
||||||
@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);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
catch (AccessDeniedException ae)
|
catch (AccessDeniedException ae)
|
||||||
{
|
{
|
||||||
@@ -389,9 +357,103 @@ public class ADMRemoteStore extends BaseRemoteStore
|
|||||||
* @param content XML document containing multiple document contents to write
|
* @param content XML document containing multiple document contents to write
|
||||||
*/
|
*/
|
||||||
@Override
|
@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<Void>()
|
||||||
|
{
|
||||||
|
@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);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@@ -31,8 +31,6 @@ import java.util.StringTokenizer;
|
|||||||
import javax.xml.parsers.DocumentBuilder;
|
import javax.xml.parsers.DocumentBuilder;
|
||||||
import javax.xml.parsers.DocumentBuilderFactory;
|
import javax.xml.parsers.DocumentBuilderFactory;
|
||||||
import javax.xml.transform.Transformer;
|
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.dom.DOMSource;
|
||||||
import javax.xml.transform.stream.StreamResult;
|
import javax.xml.transform.stream.StreamResult;
|
||||||
|
|
||||||
@@ -70,22 +68,6 @@ import org.w3c.dom.Node;
|
|||||||
public class AVMRemoteStore extends BaseRemoteStore
|
public class AVMRemoteStore extends BaseRemoteStore
|
||||||
{
|
{
|
||||||
private static final Log logger = LogFactory.getLog(AVMRemoteStore.class);
|
private static final Log logger = LogFactory.getLog(AVMRemoteStore.class);
|
||||||
private static final TransformerFactory TRANSFORMER_FACTORY = TransformerFactory.newInstance();
|
|
||||||
private static ThreadLocal<Transformer> transformer = new ThreadLocal<Transformer>()
|
|
||||||
{
|
|
||||||
@Override
|
|
||||||
protected Transformer initialValue()
|
|
||||||
{
|
|
||||||
try
|
|
||||||
{
|
|
||||||
return TRANSFORMER_FACTORY.newTransformer();
|
|
||||||
}
|
|
||||||
catch (TransformerConfigurationException e)
|
|
||||||
{
|
|
||||||
throw new RuntimeException(e);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
};
|
|
||||||
private String rootPath = "/";
|
private String rootPath = "/";
|
||||||
private AVMService avmService;
|
private AVMService avmService;
|
||||||
private SearchService searchService;
|
private SearchService searchService;
|
||||||
@@ -305,7 +287,7 @@ public class AVMRemoteStore extends BaseRemoteStore
|
|||||||
{
|
{
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
Set<String> checkedPaths = new HashSet<String>(19);
|
Set<String> checkedPaths = new HashSet<String>(16);
|
||||||
DocumentBuilder documentBuilder = DocumentBuilderFactory.newInstance().newDocumentBuilder();
|
DocumentBuilder documentBuilder = DocumentBuilderFactory.newInstance().newDocumentBuilder();
|
||||||
Document document = documentBuilder.parse(in);
|
Document document = documentBuilder.parse(in);
|
||||||
Element docEl = document.getDocumentElement();
|
Element docEl = document.getDocumentElement();
|
||||||
|
@@ -25,17 +25,19 @@ import java.util.List;
|
|||||||
import java.util.StringTokenizer;
|
import java.util.StringTokenizer;
|
||||||
|
|
||||||
import javax.servlet.http.HttpServletRequest;
|
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.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.AbstractWebScript;
|
||||||
import org.springframework.extensions.webscripts.WebScriptException;
|
import org.springframework.extensions.webscripts.WebScriptException;
|
||||||
import org.springframework.extensions.webscripts.WebScriptRequest;
|
import org.springframework.extensions.webscripts.WebScriptRequest;
|
||||||
import org.springframework.extensions.webscripts.WebScriptResponse;
|
import org.springframework.extensions.webscripts.WebScriptResponse;
|
||||||
import org.springframework.extensions.webscripts.WrappingWebScriptRequest;
|
import org.springframework.extensions.webscripts.WrappingWebScriptRequest;
|
||||||
import org.springframework.extensions.webscripts.servlet.WebScriptServletRequest;
|
import org.springframework.extensions.webscripts.servlet.WebScriptServletRequest;
|
||||||
import org.apache.commons.logging.Log;
|
|
||||||
import org.apache.commons.logging.LogFactory;
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Remote Store service.
|
* Remote Store service.
|
||||||
@@ -102,6 +104,23 @@ public abstract class BaseRemoteStore extends AbstractWebScript
|
|||||||
protected String defaultStore;
|
protected String defaultStore;
|
||||||
protected MimetypeService mimetypeService;
|
protected MimetypeService mimetypeService;
|
||||||
|
|
||||||
|
protected static final TransformerFactory TRANSFORMER_FACTORY = TransformerFactory.newInstance();
|
||||||
|
protected static ThreadLocal<Transformer> transformer = new ThreadLocal<Transformer>()
|
||||||
|
{
|
||||||
|
@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
|
* @param defaultStore the default store name of the store to process document requests against
|
||||||
|
Reference in New Issue
Block a user