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
This commit is contained in:
Kevin Roast
2008-06-20 13:27:43 +00:00
parent 9674ca28c7
commit 84891a3f01
3 changed files with 140 additions and 22 deletions

View File

@@ -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>admin</authentication> <authentication>admin</authentication>
<format default="">argument</format> <format default="">argument</format>

View File

@@ -28,11 +28,14 @@ import java.io.IOException;
import java.io.InputStream; import java.io.InputStream;
import java.io.Writer; import java.io.Writer;
import java.net.SocketException; import java.net.SocketException;
import java.util.SortedMap;
import org.alfresco.repo.avm.AVMNodeConverter; import org.alfresco.repo.avm.AVMNodeConverter;
import org.alfresco.repo.content.MimetypeMap; import org.alfresco.repo.content.MimetypeMap;
import org.alfresco.repo.security.permissions.AccessDeniedException; 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.AVMNodeDescriptor;
import org.alfresco.service.cmr.avm.AVMNotFoundException;
import org.alfresco.service.cmr.avm.AVMService; import org.alfresco.service.cmr.avm.AVMService;
import org.alfresco.service.cmr.repository.ContentIOException; import org.alfresco.service.cmr.repository.ContentIOException;
import org.alfresco.service.cmr.repository.ContentReader; import org.alfresco.service.cmr.repository.ContentReader;
@@ -47,7 +50,7 @@ import org.apache.commons.logging.LogFactory;
/** /**
* AVM Remote Store service. * AVM Remote Store service.
* *
* @see BaseRemoteStore for API methods. * @see BaseRemoteStore for the available API methods.
* *
* @author Kevin Roast * @author Kevin Roast
*/ */
@@ -107,7 +110,8 @@ public class AVMRemoteStore extends BaseRemoteStore
AVMNodeDescriptor desc = this.avmService.lookup(-1, avmPath); AVMNodeDescriptor desc = this.avmService.lookup(-1, avmPath);
if (desc == null) if (desc == null)
{ {
throw new WebScriptException("Unable to locate file: " + avmPath); res.setStatus(Status.STATUS_NOT_FOUND);
return;
} }
ContentReader reader; ContentReader reader;
@@ -167,6 +171,10 @@ public class AVMRemoteStore extends BaseRemoteStore
{ {
res.setStatus(Status.STATUS_UNAUTHORIZED); res.setStatus(Status.STATUS_UNAUTHORIZED);
} }
catch (AVMNotFoundException avmErr)
{
res.setStatus(Status.STATUS_NOT_FOUND);
}
} }
/* (non-Javadoc) /* (non-Javadoc)
@@ -190,21 +198,33 @@ public class AVMRemoteStore extends BaseRemoteStore
protected void createDocument(WebScriptResponse res, String path, InputStream content) protected void createDocument(WebScriptResponse res, String path, InputStream content)
{ {
String avmPath = buildAVMPath(path); 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 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); this.avmService.createFile(parts[0], parts[1], content);
} }
catch (AccessDeniedException ae) catch (AccessDeniedException ae)
{ {
res.setStatus(Status.STATUS_UNAUTHORIZED); res.setStatus(Status.STATUS_UNAUTHORIZED);
} }
catch (AVMExistsException avmErr)
{
res.setStatus(Status.STATUS_CONFLICT);
}
} }
/* (non-Javadoc) /* (non-Javadoc)
@@ -217,7 +237,8 @@ public class AVMRemoteStore extends BaseRemoteStore
AVMNodeDescriptor desc = this.avmService.lookup(-1, avmPath); AVMNodeDescriptor desc = this.avmService.lookup(-1, avmPath);
if (desc == null) if (desc == null)
{ {
throw new WebScriptException("Unable to locate file for update: " + avmPath); res.setStatus(Status.STATUS_NOT_FOUND);
return;
} }
try 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<String, AVMNodeDescriptor> 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 * @param path root path relative
* *
@@ -238,6 +306,6 @@ public class AVMRemoteStore extends BaseRemoteStore
*/ */
private String buildAVMPath(String path) private String buildAVMPath(String path)
{ {
return this.store + ":/" + this.rootPath + "/" + path; return this.store + ":/" + this.rootPath + (path != null ? ("/" + path) : "");
} }
} }

View File

@@ -33,7 +33,6 @@ import javax.servlet.http.HttpServletRequest;
import org.alfresco.service.cmr.repository.ContentService; import org.alfresco.service.cmr.repository.ContentService;
import org.alfresco.service.cmr.repository.MimetypeService; 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.AbstractWebScript;
import org.alfresco.web.scripts.WebScriptException; import org.alfresco.web.scripts.WebScriptException;
import org.alfresco.web.scripts.WebScriptRequest; 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 has -> return true/false of existence for a document
* GET get -> return document content - in addition the usual HTTP headers for the * GET get -> return document content - in addition the usual HTTP headers for the
* character encoding, content type, length and modified date will be supplied * 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 create -> create a new document with request content payload
* POST update -> update an existing 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."); 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 // extract path from url extension
String path = req.getExtensionPath().substring(extParts[0].length() + 1); String path = null;
if (extParts.length >= 2)
{
path = req.getExtensionPath().substring(extParts[0].length() + 1);
}
if (logger.isDebugEnabled()) if (logger.isDebugEnabled())
logger.debug("Remote store method: " + extParts[0] + " path: " + path); logger.debug("Remote store method: " + extParts[0] + " path: " + path);
@@ -147,22 +148,49 @@ public abstract class BaseRemoteStore extends AbstractWebScript
switch (method) switch (method)
{ {
case LASTMODIFIED: case LASTMODIFIED:
if (path == null)
{
throw new WebScriptException("Remote Store expecting document path.");
}
lastModified(res, path); lastModified(res, path);
break; break;
case HAS: case HAS:
if (path == null)
{
throw new WebScriptException("Remote Store expecting document path.");
}
hasDocument(res, path); hasDocument(res, path);
break; break;
case GET: case GET:
if (path == null)
{
throw new WebScriptException("Remote Store expecting document path.");
}
getDocument(res, path); getDocument(res, path);
break; break;
case LIST:
listDocuments(res, path, false);
break;
case LISTALL:
listDocuments(res, path, true);
case CREATE: case CREATE:
if (path == null)
{
throw new WebScriptException("Remote Store expecting document path.");
}
createDocument(res, path, httpReq.getInputStream()); createDocument(res, path, httpReq.getInputStream());
break; break;
case UPDATE: case UPDATE:
if (path == null)
{
throw new WebScriptException("Remote Store expecting document path.");
}
updateDocument(res, path, httpReq.getInputStream()); updateDocument(res, path, httpReq.getInputStream());
break; break;
} }
@@ -193,31 +221,50 @@ public abstract class BaseRemoteStore extends AbstractWebScript
/** /**
* Gets the last modified timestamp for the document. * 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 * @param path document path to an existing document
*/ */
protected abstract void lastModified(WebScriptResponse res, String path) protected abstract void lastModified(WebScriptResponse res, String path)
throws IOException; 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 * @param path document path
* @return true => exists, false => does not exist
*/ */
protected abstract void hasDocument(WebScriptResponse res, String path) protected abstract void hasDocument(WebScriptResponse res, String path)
throws IOException; throws IOException;
/** /**
* Gets a document * Gets a document.
*
* The output will be the document content stream.
* *
* @param path document path * @param path document path
* @return input stream onto document * @return
* *
* @throws IOException if the document does not exist in the store * @throws IOException if the document does not exist in the store
*/ */
protected abstract void getDocument(WebScriptResponse res, String path) protected abstract void getDocument(WebScriptResponse res, String path)
throws IOException; 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. * Creates a document.
* *
@@ -247,6 +294,8 @@ public abstract class BaseRemoteStore extends AbstractWebScript
LASTMODIFIED, LASTMODIFIED,
HAS, HAS,
GET, GET,
LIST,
LISTALL,
CREATE, CREATE,
UPDATE UPDATE
}; };