From 84891a3f01d248f9e20ab2b17d63c8110b86368d Mon Sep 17 00:00:00 2001 From: Kevin Roast Date: Fri, 20 Jun 2008 13:27:43 +0000 Subject: [PATCH] Remote AVM Store REST API now supports "list" and "listall" to retrieve lists and recursive lists of document paths. Much improved JUnit test for RemoteStore - on web-tier end. - various issues fixed in existing API as highlighted by JUnit tests Separated out RemoteStore test from the RemoteClient JUnit test into own file. git-svn-id: https://svn.alfresco.com/repos/alfresco-enterprise/alfresco/HEAD/root@9530 c4b6b30b-aa2e-2d43-bbcb-ca4b014f7261 --- .../repository/store/remoteavm.get.desc.xml | 1 + .../repo/web/scripts/bean/AVMRemoteStore.java | 90 ++++++++++++++++--- .../web/scripts/bean/BaseRemoteStore.java | 71 ++++++++++++--- 3 files changed, 140 insertions(+), 22 deletions(-) diff --git a/config/alfresco/templates/webscripts/org/alfresco/repository/store/remoteavm.get.desc.xml b/config/alfresco/templates/webscripts/org/alfresco/repository/store/remoteavm.get.desc.xml index 0c4b8bc9f6..a59d22a59d 100644 --- a/config/alfresco/templates/webscripts/org/alfresco/repository/store/remoteavm.get.desc.xml +++ b/config/alfresco/templates/webscripts/org/alfresco/repository/store/remoteavm.get.desc.xml @@ -1,6 +1,7 @@ Remote AVM Store Remote service mirroring the Store interface - to an AVM store + /remotestore/{method} /remotestore/{method}/{path} admin argument 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 ba2583301b..2a7d2e5679 100644 --- a/source/java/org/alfresco/repo/web/scripts/bean/AVMRemoteStore.java +++ b/source/java/org/alfresco/repo/web/scripts/bean/AVMRemoteStore.java @@ -28,11 +28,14 @@ import java.io.IOException; import java.io.InputStream; import java.io.Writer; import java.net.SocketException; +import java.util.SortedMap; import org.alfresco.repo.avm.AVMNodeConverter; import org.alfresco.repo.content.MimetypeMap; import org.alfresco.repo.security.permissions.AccessDeniedException; +import org.alfresco.service.cmr.avm.AVMExistsException; import org.alfresco.service.cmr.avm.AVMNodeDescriptor; +import org.alfresco.service.cmr.avm.AVMNotFoundException; import org.alfresco.service.cmr.avm.AVMService; import org.alfresco.service.cmr.repository.ContentIOException; import org.alfresco.service.cmr.repository.ContentReader; @@ -47,7 +50,7 @@ import org.apache.commons.logging.LogFactory; /** * AVM Remote Store service. * - * @see BaseRemoteStore for API methods. + * @see BaseRemoteStore for the available API methods. * * @author Kevin Roast */ @@ -107,7 +110,8 @@ public class AVMRemoteStore extends BaseRemoteStore AVMNodeDescriptor desc = this.avmService.lookup(-1, avmPath); if (desc == null) { - throw new WebScriptException("Unable to locate file: " + avmPath); + res.setStatus(Status.STATUS_NOT_FOUND); + return; } ContentReader reader; @@ -167,6 +171,10 @@ public class AVMRemoteStore extends BaseRemoteStore { res.setStatus(Status.STATUS_UNAUTHORIZED); } + catch (AVMNotFoundException avmErr) + { + res.setStatus(Status.STATUS_NOT_FOUND); + } } /* (non-Javadoc) @@ -190,21 +198,33 @@ public class AVMRemoteStore extends BaseRemoteStore protected void createDocument(WebScriptResponse res, String path, InputStream content) { String avmPath = buildAVMPath(path); - AVMNodeDescriptor desc = this.avmService.lookup(-1, avmPath); - if (desc != null) - { - throw new WebScriptException("Unable to create, file already exists: " + avmPath); - } - - String[] parts = AVMNodeConverter.SplitBase(avmPath); try { + String[] parts = AVMNodeConverter.SplitBase(avmPath); + String[] dirs = parts[0].split("/"); + String parentPath = dirs[0] + "/" + dirs[1]; + int index = 2; + while (index < dirs.length) + { + String dirPath = parentPath + "/" + dirs[index]; + if (this.avmService.lookup(-1, dirPath) == null) + { + this.avmService.createDirectory(parentPath, dirs[index]); + } + parentPath = dirPath; + index++; + } + this.avmService.createFile(parts[0], parts[1], content); } catch (AccessDeniedException ae) { res.setStatus(Status.STATUS_UNAUTHORIZED); } + catch (AVMExistsException avmErr) + { + res.setStatus(Status.STATUS_CONFLICT); + } } /* (non-Javadoc) @@ -217,7 +237,8 @@ public class AVMRemoteStore extends BaseRemoteStore AVMNodeDescriptor desc = this.avmService.lookup(-1, avmPath); if (desc == null) { - throw new WebScriptException("Unable to locate file for update: " + avmPath); + res.setStatus(Status.STATUS_NOT_FOUND); + return; } try @@ -231,6 +252,53 @@ public class AVMRemoteStore extends BaseRemoteStore } } + /* (non-Javadoc) + * @see org.alfresco.repo.web.scripts.bean.BaseRemoteStore#listDocuments(org.alfresco.web.scripts.WebScriptResponse, java.lang.String, boolean) + */ + @Override + protected void listDocuments(WebScriptResponse res, String path, boolean recurse) throws IOException + { + String avmPath = buildAVMPath(path); + AVMNodeDescriptor node = this.avmService.lookup(-1, avmPath); + if (node == null) + { + res.setStatus(Status.STATUS_NOT_FOUND); + return; + } + + try + { + traverseNode(res.getWriter(), node, recurse); + } + catch (AccessDeniedException ae) + { + res.setStatus(Status.STATUS_UNAUTHORIZED); + } + finally + { + res.getWriter().close(); + } + } + + private void traverseNode(Writer out, AVMNodeDescriptor node, boolean recurse) + throws IOException + { + int cropPoint = this.store.length() + this.rootPath.length() + 3; + SortedMap listing = this.avmService.getDirectoryListing(node); + for (AVMNodeDescriptor n : listing.values()) + { + if (n.isFile()) + { + out.write(n.getPath().substring(cropPoint)); + out.write("\n"); + } + else if (recurse && n.isDirectory()) + { + traverseNode(out, n, recurse); + } + } + } + /** * @param path root path relative * @@ -238,6 +306,6 @@ public class AVMRemoteStore extends BaseRemoteStore */ private String buildAVMPath(String path) { - return this.store + ":/" + this.rootPath + "/" + path; + return this.store + ":/" + this.rootPath + (path != null ? ("/" + path) : ""); } } 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 5730d11009..575821f30a 100644 --- a/source/java/org/alfresco/repo/web/scripts/bean/BaseRemoteStore.java +++ b/source/java/org/alfresco/repo/web/scripts/bean/BaseRemoteStore.java @@ -33,7 +33,6 @@ import javax.servlet.http.HttpServletRequest; import org.alfresco.service.cmr.repository.ContentService; import org.alfresco.service.cmr.repository.MimetypeService; -import org.alfresco.service.cmr.repository.StoreRef; import org.alfresco.web.scripts.AbstractWebScript; import org.alfresco.web.scripts.WebScriptException; import org.alfresco.web.scripts.WebScriptRequest; @@ -69,6 +68,8 @@ import org.apache.commons.logging.LogFactory; * GET has -> return true/false of existence for a document * GET get -> return document content - in addition the usual HTTP headers for the * character encoding, content type, length and modified date will be supplied + * GET list -> return the list of available document paths under a path + * GET listall -> return the list of available document paths (recursively) under a given path * POST create -> create a new document with request content payload * POST update -> update an existing document with request content payload * @@ -127,13 +128,13 @@ public abstract class BaseRemoteStore extends AbstractWebScript { throw new WebScriptException("Remote Store expecting method name."); } - if (extParts.length < 2) - { - throw new WebScriptException("Remote Store expecting document path."); - } - // build path as a string and as a list of path elements - String path = req.getExtensionPath().substring(extParts[0].length() + 1); + // extract path from url extension + String path = null; + if (extParts.length >= 2) + { + path = req.getExtensionPath().substring(extParts[0].length() + 1); + } if (logger.isDebugEnabled()) logger.debug("Remote store method: " + extParts[0] + " path: " + path); @@ -147,22 +148,49 @@ public abstract class BaseRemoteStore extends AbstractWebScript switch (method) { case LASTMODIFIED: + if (path == null) + { + throw new WebScriptException("Remote Store expecting document path."); + } lastModified(res, path); break; case HAS: + if (path == null) + { + throw new WebScriptException("Remote Store expecting document path."); + } hasDocument(res, path); break; case GET: + if (path == null) + { + throw new WebScriptException("Remote Store expecting document path."); + } getDocument(res, path); break; + case LIST: + listDocuments(res, path, false); + break; + + case LISTALL: + listDocuments(res, path, true); + case CREATE: + if (path == null) + { + throw new WebScriptException("Remote Store expecting document path."); + } createDocument(res, path, httpReq.getInputStream()); break; case UPDATE: + if (path == null) + { + throw new WebScriptException("Remote Store expecting document path."); + } updateDocument(res, path, httpReq.getInputStream()); break; } @@ -193,31 +221,50 @@ public abstract class BaseRemoteStore extends AbstractWebScript /** * Gets the last modified timestamp for the document. * + * The output will be the last modified date as a long toString(). + * * @param path document path to an existing document */ protected abstract void lastModified(WebScriptResponse res, String path) throws IOException; /** - * Determines if the document exists + * Determines if the document exists. + * + * The output will be either the string "true" or the string "false". * * @param path document path - * @return true => exists, false => does not exist */ protected abstract void hasDocument(WebScriptResponse res, String path) throws IOException; /** - * Gets a document + * Gets a document. + * + * The output will be the document content stream. * * @param path document path - * @return input stream onto document + * @return * * @throws IOException if the document does not exist in the store */ protected abstract void getDocument(WebScriptResponse res, String path) throws IOException; + /** + * Lists the document paths under a given path. + * + * The output will be the list of relative document paths found under the path. + * Separated by newline characters. + * + * @param path document path + * @param recurse true to peform a recursive list, false for direct children only. + * + * @throws IOException if the path does not exist in the store + */ + protected abstract void listDocuments(WebScriptResponse res, String path, boolean recurse) + throws IOException; + /** * Creates a document. * @@ -247,6 +294,8 @@ public abstract class BaseRemoteStore extends AbstractWebScript LASTMODIFIED, HAS, GET, + LIST, + LISTALL, CREATE, UPDATE };