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 3ee93c5d2d..0ff8314839 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 @@ -3,7 +3,11 @@ Remote service mirroring the Store interface - to an AVM store /remotestore/{method} /remotestore/{method}/{path} - none + /remotestore/{method}/s/{store} + /remotestore/{method}/s/{store}/{path} + /remotestore/{method}/s/{store}/w/{webapp} + /remotestore/{method}/s/{store}/w/{webapp}/{path} + guest required argument \ No newline at end of file diff --git a/config/alfresco/templates/webscripts/org/alfresco/repository/wcm2/sandbox-list.get.desc.xml b/config/alfresco/templates/webscripts/org/alfresco/repository/wcm2/sandbox-list.get.desc.xml new file mode 100644 index 0000000000..eab533fae5 --- /dev/null +++ b/config/alfresco/templates/webscripts/org/alfresco/repository/wcm2/sandbox-list.get.desc.xml @@ -0,0 +1,8 @@ + + Web Content Management - List Sandboxes + Web Content Management - List Sandboxes + /api/wcm/sandbox/list + argument + user + required + \ No newline at end of file diff --git a/config/alfresco/templates/webscripts/org/alfresco/repository/wcm2/sandbox-list.get.html.ftl b/config/alfresco/templates/webscripts/org/alfresco/repository/wcm2/sandbox-list.get.html.ftl new file mode 100644 index 0000000000..fd10c0fc0c --- /dev/null +++ b/config/alfresco/templates/webscripts/org/alfresco/repository/wcm2/sandbox-list.get.html.ftl @@ -0,0 +1,16 @@ +{ + "results" : [ + +<#assign first = true> +<#list results as result> + <#if first == false>, + + { + "name" : "${result.name}" + } + + <#assign first = false> + + + ] +} diff --git a/config/alfresco/templates/webscripts/org/alfresco/repository/wcm2/sandbox-list.get.js b/config/alfresco/templates/webscripts/org/alfresco/repository/wcm2/sandbox-list.get.js new file mode 100644 index 0000000000..f058412a92 --- /dev/null +++ b/config/alfresco/templates/webscripts/org/alfresco/repository/wcm2/sandbox-list.get.js @@ -0,0 +1,29 @@ +var webproject = args["webproject"]; + +var dmType = "{http://www.alfresco.org/model/wcmappmodel/1.0}webfolder"; +var query = "TYPE:\"" + dmType + "\""; + +var webprojects = search.luceneSearch(query); + +var results = null; +var avmStoreId = null; + +// walk through the projects, get the avm store id (for staging) +for(var i = 0; i < webprojects.length; i++) +{ + var projName = webprojects[i].name; + if(projName == webproject) + { + avmStoreId = webprojects[i].properties["{http://www.alfresco.org/model/wcmappmodel/1.0}avmstore"]; + } +} + +if(avmStoreId != null) +{ + results = new Array(); + results[results.length] = avm.lookupStore(avmStoreId); + results[results.length] = avm.lookupStore(avmStoreId + "--admin"); +} + +model.results = results; + diff --git a/config/alfresco/templates/webscripts/org/alfresco/repository/wcm2/sandbox.get.desc.xml b/config/alfresco/templates/webscripts/org/alfresco/repository/wcm2/sandbox.get.desc.xml new file mode 100644 index 0000000000..e5d2f9f56a --- /dev/null +++ b/config/alfresco/templates/webscripts/org/alfresco/repository/wcm2/sandbox.get.desc.xml @@ -0,0 +1,8 @@ + + Web Content Management - Sandbox GET + Web Content Management - Sandbox GET + /api/wcm/sandbox/{id} + + user + required + \ No newline at end of file diff --git a/config/alfresco/templates/webscripts/org/alfresco/repository/wcm2/sandbox.get.js b/config/alfresco/templates/webscripts/org/alfresco/repository/wcm2/sandbox.get.js new file mode 100644 index 0000000000..3aed5b70e0 --- /dev/null +++ b/config/alfresco/templates/webscripts/org/alfresco/repository/wcm2/sandbox.get.js @@ -0,0 +1,19 @@ +function main() +{ + // Get the node from the URL + var pathSegments = url.match.split("/"); + var reference = [ url.templateArgs.store_type, url.templateArgs.store_id ].concat(url.templateArgs.id.split("/")); + var node = search.findNode(pathSegments[2], reference); + + // 404 if the node is not found + if (node == null) + { + status.setCode(status.STATUS_NOT_FOUND, "The node could not be found"); + return; + } + + // Get the tags of the node + model.tags = node.tags; +} + +main(); \ No newline at end of file diff --git a/config/alfresco/templates/webscripts/org/alfresco/repository/wcm2/sandbox.get.json.ftl b/config/alfresco/templates/webscripts/org/alfresco/repository/wcm2/sandbox.get.json.ftl new file mode 100644 index 0000000000..2e4aa788ce --- /dev/null +++ b/config/alfresco/templates/webscripts/org/alfresco/repository/wcm2/sandbox.get.json.ftl @@ -0,0 +1,5 @@ +[ + <#list tags as tag> + ${jsonUtils.encodeJSONString(tag)}<#if tag_has_next>, + +] \ No newline at end of file diff --git a/config/alfresco/templates/webscripts/org/alfresco/repository/wcm2/sandbox.put.desc.xml b/config/alfresco/templates/webscripts/org/alfresco/repository/wcm2/sandbox.put.desc.xml new file mode 100644 index 0000000000..fc59f7a1fd --- /dev/null +++ b/config/alfresco/templates/webscripts/org/alfresco/repository/wcm2/sandbox.put.desc.xml @@ -0,0 +1,8 @@ + + Web Content Management - Sandbox POST + Web Content Management - Sandbox POST + /api/wcm/sandbox + + user + required + \ No newline at end of file diff --git a/config/alfresco/templates/webscripts/org/alfresco/repository/wcm2/sandbox.put.js b/config/alfresco/templates/webscripts/org/alfresco/repository/wcm2/sandbox.put.js new file mode 100644 index 0000000000..3aed5b70e0 --- /dev/null +++ b/config/alfresco/templates/webscripts/org/alfresco/repository/wcm2/sandbox.put.js @@ -0,0 +1,19 @@ +function main() +{ + // Get the node from the URL + var pathSegments = url.match.split("/"); + var reference = [ url.templateArgs.store_type, url.templateArgs.store_id ].concat(url.templateArgs.id.split("/")); + var node = search.findNode(pathSegments[2], reference); + + // 404 if the node is not found + if (node == null) + { + status.setCode(status.STATUS_NOT_FOUND, "The node could not be found"); + return; + } + + // Get the tags of the node + model.tags = node.tags; +} + +main(); \ No newline at end of file diff --git a/config/alfresco/templates/webscripts/org/alfresco/repository/wcm2/sandbox.put.json.ftl b/config/alfresco/templates/webscripts/org/alfresco/repository/wcm2/sandbox.put.json.ftl new file mode 100644 index 0000000000..2e4aa788ce --- /dev/null +++ b/config/alfresco/templates/webscripts/org/alfresco/repository/wcm2/sandbox.put.json.ftl @@ -0,0 +1,5 @@ +[ + <#list tags as tag> + ${jsonUtils.encodeJSONString(tag)}<#if tag_has_next>, + +] \ No newline at end of file diff --git a/config/alfresco/templates/webscripts/org/alfresco/repository/wcm2/webproject-list.get.desc.xml b/config/alfresco/templates/webscripts/org/alfresco/repository/wcm2/webproject-list.get.desc.xml new file mode 100644 index 0000000000..2352e1a217 --- /dev/null +++ b/config/alfresco/templates/webscripts/org/alfresco/repository/wcm2/webproject-list.get.desc.xml @@ -0,0 +1,8 @@ + + Web Content Management - List Web Projects + Web Content Management - List Web Projects + /api/wcm/webproject/list + argument + user + required + \ No newline at end of file diff --git a/config/alfresco/templates/webscripts/org/alfresco/repository/wcm2/webproject-list.get.html.ftl b/config/alfresco/templates/webscripts/org/alfresco/repository/wcm2/webproject-list.get.html.ftl new file mode 100644 index 0000000000..1b0c9e1b2e --- /dev/null +++ b/config/alfresco/templates/webscripts/org/alfresco/repository/wcm2/webproject-list.get.html.ftl @@ -0,0 +1,18 @@ +{ + "results" : [ + +<#assign first = true> +<#list results as result> + <#if first == false>, + + { + "name" : "${result.name}" + , + "nodeRef" : "${result.nodeRef}" + } + + <#assign first = false> + + + ] +} diff --git a/config/alfresco/templates/webscripts/org/alfresco/repository/wcm2/webproject-list.get.js b/config/alfresco/templates/webscripts/org/alfresco/repository/wcm2/webproject-list.get.js new file mode 100644 index 0000000000..5b2f330b50 --- /dev/null +++ b/config/alfresco/templates/webscripts/org/alfresco/repository/wcm2/webproject-list.get.js @@ -0,0 +1,5 @@ +var dmType = "{http://www.alfresco.org/model/wcmappmodel/1.0}webfolder"; +var query = "TYPE:\"" + dmType + "\""; +var results = search.luceneSearch(query); + +model.results = results; diff --git a/config/alfresco/templates/webscripts/org/alfresco/repository/wcm2/webproject.get.desc.xml b/config/alfresco/templates/webscripts/org/alfresco/repository/wcm2/webproject.get.desc.xml new file mode 100644 index 0000000000..9d0221dfd1 --- /dev/null +++ b/config/alfresco/templates/webscripts/org/alfresco/repository/wcm2/webproject.get.desc.xml @@ -0,0 +1,8 @@ + + Web Content Management - Web Project GET + Web Content Management - Web Project GET + /api/wcm/webproject + + user + required + \ No newline at end of file diff --git a/config/alfresco/templates/webscripts/org/alfresco/repository/wcm2/webproject.get.html.ftl b/config/alfresco/templates/webscripts/org/alfresco/repository/wcm2/webproject.get.html.ftl new file mode 100644 index 0000000000..ba73aaa366 --- /dev/null +++ b/config/alfresco/templates/webscripts/org/alfresco/repository/wcm2/webproject.get.html.ftl @@ -0,0 +1,11 @@ +<#if result?exists> +{ + "name" : "${result.name}" + , + "id" : "${result.webProjectId}" + , + "stagingSandboxId" : "${result.sandboxId}" + , + "stagingStoreId" : "${result.storeId}" +} + diff --git a/config/alfresco/templates/webscripts/org/alfresco/repository/wcm2/webproject.get.js b/config/alfresco/templates/webscripts/org/alfresco/repository/wcm2/webproject.get.js new file mode 100644 index 0000000000..3d5267b54a --- /dev/null +++ b/config/alfresco/templates/webscripts/org/alfresco/repository/wcm2/webproject.get.js @@ -0,0 +1,23 @@ +var id = args["id"]; + +var dmType = "{http://www.alfresco.org/model/wcmappmodel/1.0}webfolder"; +var query = "TYPE:\"" + dmType + "\""; + +var webprojects = search.luceneSearch(query); + +var result = { }; + +// walk through the projects, get the avm store id (for staging) +for(var i = 0; i < webprojects.length; i++) +{ + var projName = webprojects[i].name; + if(projName == id) + { + result["name"] = projName; + result["webProjectId"] = id; + result["storeId"] = webprojects[i].properties["{http://www.alfresco.org/model/wcmappmodel/1.0}avmstore"]; + result["sandboxId"] = webprojects[i].properties["{http://www.alfresco.org/model/wcmappmodel/1.0}avmstore"]; + } +} + +model.result = result; \ No newline at end of file diff --git a/config/alfresco/templates/webscripts/org/alfresco/repository/wcm2/webproject.put.desc.xml b/config/alfresco/templates/webscripts/org/alfresco/repository/wcm2/webproject.put.desc.xml new file mode 100644 index 0000000000..46198fd8fa --- /dev/null +++ b/config/alfresco/templates/webscripts/org/alfresco/repository/wcm2/webproject.put.desc.xml @@ -0,0 +1,8 @@ + + Web Content Management - Web Project POST + Web Content Management - Web Project POST + /api/wcm/webproject + + user + required + \ No newline at end of file diff --git a/config/alfresco/templates/webscripts/org/alfresco/repository/wcm2/webproject.put.js b/config/alfresco/templates/webscripts/org/alfresco/repository/wcm2/webproject.put.js new file mode 100644 index 0000000000..b3d178c45c --- /dev/null +++ b/config/alfresco/templates/webscripts/org/alfresco/repository/wcm2/webproject.put.js @@ -0,0 +1,30 @@ +// arguments +var jsonString = args["json"]; + +model.status = null; + +if(jsonString != null) +{ + // load arguments into object + var json = eval('(' + jsonString + ')'); + + // attributes + var id = json.id; + var title = json.title; + var description = json.description; + + // TODO: create the web project + + // set back onto return + model.webProjectId = id; + model.storeId = id; + model.sandboxId = id; + + model.status = 'ok'; +} + +if(model.status == null) +{ + model.status = 'error'; +} + \ No newline at end of file diff --git a/config/alfresco/templates/webscripts/org/alfresco/repository/wcm2/webproject.put.json.ftl b/config/alfresco/templates/webscripts/org/alfresco/repository/wcm2/webproject.put.json.ftl new file mode 100644 index 0000000000..d65690a64c --- /dev/null +++ b/config/alfresco/templates/webscripts/org/alfresco/repository/wcm2/webproject.put.json.ftl @@ -0,0 +1,13 @@ +{ + "status" : "${status}" + +<#if status == 'ok'> + , + "webProjectId" : "${webProjectId}" + , + "sandboxId" : "${sandboxId}" + , + "storeId" : "${storeId}" + + +} \ No newline at end of file diff --git a/config/alfresco/templates/webscripts/org/alfresco/webframework/avm-metadata.get.desc.xml b/config/alfresco/templates/webscripts/org/alfresco/webframework/avm-metadata.get.desc.xml new file mode 100644 index 0000000000..10382ace81 --- /dev/null +++ b/config/alfresco/templates/webscripts/org/alfresco/webframework/avm-metadata.get.desc.xml @@ -0,0 +1,8 @@ + + AVM Metadata Retrieval Service + AVM Metadata Retrieval Service + /webframework/avm/metadata/{storeId}/{webappId}/{path} + argument + user + required + \ No newline at end of file diff --git a/config/alfresco/templates/webscripts/org/alfresco/webframework/avm-metadata.get.html.ftl b/config/alfresco/templates/webscripts/org/alfresco/webframework/avm-metadata.get.html.ftl new file mode 100644 index 0000000000..6f4425fa85 --- /dev/null +++ b/config/alfresco/templates/webscripts/org/alfresco/webframework/avm-metadata.get.html.ftl @@ -0,0 +1,87 @@ +{ + <@serialize object=object includeChildren=includeChildren includeContent=includeContent/> +} + +<#macro serialize object includeChildren includeContent> + "isContainer" : ${object.isContainer?string} + , + "isDocument" : ${object.isDocument?string} + , + "url" : "${object.url}" + , + "downloadUrl" : "${object.downloadUrl}" + +<#if object.mimetype?exists> + , + "mimetype" : "${object.mimetype}" + + , + "size" : "${object.size}" + , + "displayPath" : "${object.displayPath}" + , + "qnamePath" : "${object.qnamePath}" + , + "icon16" : "${object.icon16}" + , + "icon32" : "${object.icon32}" + , + "isLocked" : ${object.isLocked?string} + , + "id" : "${object.id}" + , + "nodeRef" : "${object.nodeRef}" + , + "name" : "${object.name}" + , + "type" : "${object.type}" + , + "isCategory" : ${object.isCategory?string} + +<#if object.properties?exists> + , + "properties" : + { + <#assign first = true> + <#list object.properties?keys as key> + <#if object.properties[key]?exists> + <#assign val = object.properties[key]> + <#if val?is_string == true> + <#if first == false>, + "${key}" : "${val?js_string}" + <#assign first = false> + <#elseif val?is_date == true> + <#if first == false>, + "${key}" : "${val?datetime}" + <#assign first = false> + <#elseif val?is_boolean == true> + <#if first == false>, + "${key}" : "${val?string}" + <#assign first = false> + + + + } + + +<#if includeChildren && object.children?exists> + , + "children" : + [ + <#assign first = true> + <#list object.children as child> + <#if first == false> + , + + { + <@serialize object=child includeChildren=false includeContent=includeContent/> + } + <#assign first = false> + + ] +<#else> + , + "children" : [] + + + \ No newline at end of file diff --git a/config/alfresco/templates/webscripts/org/alfresco/webframework/avm-metadata.get.js b/config/alfresco/templates/webscripts/org/alfresco/webframework/avm-metadata.get.js new file mode 100644 index 0000000000..de4d996381 --- /dev/null +++ b/config/alfresco/templates/webscripts/org/alfresco/webframework/avm-metadata.get.js @@ -0,0 +1,17 @@ +model.includeChildren = true; +model.includeContent = false; + +var object = null; + +var storeId = url.templateArgs["storeId"]; +var webappId = url.templateArgs["webappId"]; +var path = url.templateArgs["path"]; + +var storeRootNode = avm.lookupStoreRoot(storeId); +if (storeRootNode != null) +{ + var path = storeRootNode.path + "/" + webappId + "/" + path; + object = avm.lookupNode(path); +} + +model.object = object; diff --git a/config/alfresco/templates/webscripts/org/alfresco/webframework/jsf-client-redirect.get.desc.xml b/config/alfresco/templates/webscripts/org/alfresco/webframework/jsf-client-redirect.get.desc.xml new file mode 100644 index 0000000000..8c2e4e5fb3 --- /dev/null +++ b/config/alfresco/templates/webscripts/org/alfresco/webframework/jsf-client-redirect.get.desc.xml @@ -0,0 +1,9 @@ + + JSF Redirection Handler + JSF Redirection Handler + /webframework/redirect/jsf-client/{command}/{objectType}/{storeType}/{storeId}/{nodeId} + /webframework/redirect/jsf-client/{command}/{objectType}/{webProjectId} + argument + user + required + \ No newline at end of file diff --git a/config/alfresco/templates/webscripts/org/alfresco/webframework/jsf-client-redirect.get.html.ftl b/config/alfresco/templates/webscripts/org/alfresco/webframework/jsf-client-redirect.get.html.ftl new file mode 100644 index 0000000000..32aa4bb32a --- /dev/null +++ b/config/alfresco/templates/webscripts/org/alfresco/webframework/jsf-client-redirect.get.html.ftl @@ -0,0 +1,5 @@ +<#if redirectUrl?exists> + + \ No newline at end of file diff --git a/config/alfresco/templates/webscripts/org/alfresco/webframework/jsf-client-redirect.get.js b/config/alfresco/templates/webscripts/org/alfresco/webframework/jsf-client-redirect.get.js new file mode 100644 index 0000000000..081c849d52 --- /dev/null +++ b/config/alfresco/templates/webscripts/org/alfresco/webframework/jsf-client-redirect.get.js @@ -0,0 +1,40 @@ +model.command = url.templateArgs["command"]; +model.objectType = url.templateArgs["objectType"]; + +if("browse" == model.command) +{ + if("node" == model.objectType) + { + var storeType = url.templateArgs["storeType"]; + var storeId = url.templateArgs["storeId"]; + var nodeId = url.templateArgs["nodeId"]; + + model.redirectUrl = "/alfresco/n/browse/"+storeType+"/"+storeId+"/"+nodeId; + } + + if("webproject" == model.objectType) + { + model.webProjectId = url.templateArgs["webProjectId"]; + + // look up the web project + var dmType = "{http://www.alfresco.org/model/wcmappmodel/1.0}webfolder"; + var query = "TYPE:\"" + dmType + "\""; + + var webprojects = search.luceneSearch(query); + + // walk through the projects, get the avm store id (for staging) + for(var i = 0; i < webprojects.length; i++) + { + var projId = webprojects[i].name; + if(projId == model.webProjectId) + { + var storeType = webprojects[i].properties["{http://www.alfresco.org/model/system/1.0}store-protocol"]; + var storeId = webprojects[i].properties["{http://www.alfresco.org/model/system/1.0}store-identifier"]; + var nodeId = webprojects[i].properties["{http://www.alfresco.org/model/system/1.0}node-uuid"]; + + model.redirectUrl = "/alfresco/n/browse/"+storeType+"/"+storeId+"/"+nodeId; + } + } + } +} + diff --git a/config/alfresco/templates/webscripts/org/alfresco/webframework/metadata.get.html.ftl b/config/alfresco/templates/webscripts/org/alfresco/webframework/metadata.get.html.ftl index de2b6b403b..0cb0a2c06b 100644 --- a/config/alfresco/templates/webscripts/org/alfresco/webframework/metadata.get.html.ftl +++ b/config/alfresco/templates/webscripts/org/alfresco/webframework/metadata.get.html.ftl @@ -10,8 +10,11 @@ "url" : "${object.url}" , "downloadUrl" : "${object.downloadUrl}" + +<#if object.mimetype?exists> , - "mimetype" : "${mimetype}" + "mimetype" : "${object.mimetype}" + , "size" : "${object.size}" , @@ -57,7 +60,7 @@ <#assign first = false> <#elseif val?is_boolean == true> <#if first == false>, - "${key}" : "${val}" + "${key}" : "${val?string}" <#assign first = false> diff --git a/config/alfresco/templates/webscripts/org/alfresco/webframework/metadata.get.js b/config/alfresco/templates/webscripts/org/alfresco/webframework/metadata.get.js index 0dd8e4a2a9..0356ca715f 100644 --- a/config/alfresco/templates/webscripts/org/alfresco/webframework/metadata.get.js +++ b/config/alfresco/templates/webscripts/org/alfresco/webframework/metadata.get.js @@ -32,7 +32,7 @@ else } else { - path = "/Company Home" + path; + //path = "/Company Home" + path; } // look up the content by path @@ -40,4 +40,3 @@ else } model.object = object; -model.mimetype = object.mimetype; \ No newline at end of file diff --git a/config/alfresco/web-scripts-application-context.xml b/config/alfresco/web-scripts-application-context.xml index b2f5b722aa..0e77c03779 100644 --- a/config/alfresco/web-scripts-application-context.xml +++ b/config/alfresco/web-scripts-application-context.xml @@ -246,22 +246,28 @@ + + + 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 9f670f818f..115f90615f 100644 --- a/source/java/org/alfresco/repo/web/scripts/bean/AVMRemoteStore.java +++ b/source/java/org/alfresco/repo/web/scripts/bean/AVMRemoteStore.java @@ -28,6 +28,7 @@ import java.io.IOException; import java.io.InputStream; import java.io.Writer; import java.net.SocketException; +import java.util.List; import java.util.SortedMap; import java.util.regex.Pattern; @@ -36,6 +37,7 @@ import org.alfresco.repo.content.MimetypeMap; import org.alfresco.repo.security.authentication.AuthenticationUtil; import org.alfresco.repo.security.authentication.AuthenticationUtil.RunAsWork; import org.alfresco.repo.security.permissions.AccessDeniedException; +import org.alfresco.repo.web.scripts.RepoStore; import org.alfresco.service.cmr.avm.AVMExistsException; import org.alfresco.service.cmr.avm.AVMNodeDescriptor; import org.alfresco.service.cmr.avm.AVMNotFoundException; @@ -43,6 +45,9 @@ import org.alfresco.service.cmr.avm.AVMService; import org.alfresco.service.cmr.repository.ContentIOException; import org.alfresco.service.cmr.repository.ContentReader; import org.alfresco.service.cmr.repository.ContentWriter; +import org.alfresco.service.cmr.repository.NodeRef; +import org.alfresco.service.cmr.repository.StoreRef; +import org.alfresco.service.cmr.search.ResultSet; import org.alfresco.service.cmr.search.SearchService; import org.alfresco.web.scripts.Status; import org.alfresco.web.scripts.WebScriptException; @@ -62,7 +67,7 @@ public class AVMRemoteStore extends BaseRemoteStore { private static final Log logger = LogFactory.getLog(AVMRemoteStore.class); - private String rootPath; + private String rootPath = "/"; private AVMService avmService; private SearchService searchService; @@ -72,6 +77,11 @@ public class AVMRemoteStore extends BaseRemoteStore */ public void setRootPath(String rootPath) { + if(rootPath != null && rootPath.length() == 0) + { + rootPath = "/"; + } + this.rootPath = rootPath; } @@ -94,13 +104,14 @@ public class AVMRemoteStore extends BaseRemoteStore /** * Gets the last modified timestamp for the document. * + * @param store the store id * @param path document path to an existing document */ @Override - protected void lastModified(WebScriptResponse res, String path) + protected void lastModified(WebScriptResponse res, String store, String path) throws IOException { - String avmPath = buildAVMPath(path); + String avmPath = buildAVMPath(store, path); AVMNodeDescriptor desc = this.avmService.lookup(-1, avmPath); if (desc == null) { @@ -116,9 +127,9 @@ public class AVMRemoteStore extends BaseRemoteStore * @see org.alfresco.repo.web.scripts.bean.BaseRemoteStore#getDocument(org.alfresco.web.scripts.WebScriptResponse, java.lang.String) */ @Override - protected void getDocument(final WebScriptResponse res, final String path) throws IOException + protected void getDocument(final WebScriptResponse res, final String store, final String path) throws IOException { - final String avmPath = buildAVMPath(path); + final String avmPath = buildAVMPath(store, path); final AVMNodeDescriptor desc = this.avmService.lookup(-1, avmPath); if (desc == null) { @@ -201,9 +212,9 @@ public class AVMRemoteStore extends BaseRemoteStore * @see org.alfresco.repo.web.scripts.bean.BaseRemoteStore#hasDocument(org.alfresco.web.scripts.WebScriptResponse, java.lang.String) */ @Override - protected void hasDocument(WebScriptResponse res, String path) throws IOException + protected void hasDocument(WebScriptResponse res, String store, String path) throws IOException { - String avmPath = buildAVMPath(path); + String avmPath = buildAVMPath(store, path); AVMNodeDescriptor desc = this.avmService.lookup(-1, avmPath); Writer out = res.getWriter(); @@ -215,14 +226,14 @@ public class AVMRemoteStore extends BaseRemoteStore * @see org.alfresco.repo.web.scripts.bean.BaseRemoteStore#createDocument(org.alfresco.web.scripts.WebScriptResponse, java.lang.String, java.io.InputStream) */ @Override - protected void createDocument(final WebScriptResponse res, final String path, final InputStream content) + protected void createDocument(final WebScriptResponse res, final String store, final String path, final InputStream content) { AuthenticationUtil.runAs(new RunAsWork() { @SuppressWarnings("synthetic-access") public Object doWork() throws Exception { - String avmPath = buildAVMPath(path); + String avmPath = buildAVMPath(store, path); try { String[] parts = AVMNodeConverter.SplitBase(avmPath); @@ -241,6 +252,7 @@ public class AVMRemoteStore extends BaseRemoteStore } avmService.createFile(parts[0], parts[1], content); + avmService.createSnapshot(store, "AVMRemoteStore.createDocument()", path); } catch (AccessDeniedException ae) { @@ -259,9 +271,9 @@ public class AVMRemoteStore extends BaseRemoteStore * @see org.alfresco.repo.web.scripts.bean.BaseRemoteStore#updateDocument(org.alfresco.web.scripts.WebScriptResponse, java.lang.String, java.io.InputStream) */ @Override - protected void updateDocument(final WebScriptResponse res, final String path, final InputStream content) + protected void updateDocument(final WebScriptResponse res, final String store, final String path, final InputStream content) { - final String avmPath = buildAVMPath(path); + final String avmPath = buildAVMPath(store, path); AVMNodeDescriptor desc = this.avmService.lookup(-1, avmPath); if (desc == null) { @@ -292,9 +304,9 @@ public class AVMRemoteStore extends BaseRemoteStore * @see org.alfresco.repo.web.scripts.bean.BaseRemoteStore#deleteDocument(org.alfresco.web.scripts.WebScriptResponse, java.lang.String) */ @Override - protected void deleteDocument(final WebScriptResponse res, final String path) + protected void deleteDocument(final WebScriptResponse res, final String store, final String path) { - final String avmPath = buildAVMPath(path); + final String avmPath = buildAVMPath(store, path); AVMNodeDescriptor desc = this.avmService.lookup(-1, avmPath); if (desc == null) { @@ -310,6 +322,7 @@ public class AVMRemoteStore extends BaseRemoteStore try { avmService.removeNode(avmPath); + avmService.createSnapshot(store, "AVMRemoteStore.deleteDocument()", path); } catch (AccessDeniedException ae) { @@ -324,9 +337,9 @@ public class AVMRemoteStore extends BaseRemoteStore * @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 + protected void listDocuments(WebScriptResponse res, String store, String path, boolean recurse) throws IOException { - String avmPath = buildAVMPath(path); + String avmPath = buildAVMPath(store, path); AVMNodeDescriptor node = this.avmService.lookup(-1, avmPath); if (node == null) { @@ -336,7 +349,7 @@ public class AVMRemoteStore extends BaseRemoteStore try { - traverseNode(res.getWriter(), node, null, recurse); + traverseNode(res.getWriter(), store, node, recurse); } catch (AccessDeniedException ae) { @@ -348,13 +361,45 @@ public class AVMRemoteStore extends BaseRemoteStore } } + private void traverseNode(Writer out, String store, AVMNodeDescriptor node, boolean recurse) + throws IOException + { + /** + * The node path appears as such: + * project1:/www/avm_webapps/ROOT/WEB-INF/classes/alfresco/site-data/template-instances/file.xml + */ + int cropPoint = store.length() + this.rootPath.length() + 1; + SortedMap listing = this.avmService.getDirectoryListing(node); + for (AVMNodeDescriptor n : listing.values()) + { + if (n.isFile()) + { + /* + String myPath = n.getPath(); + String origPath = node.getPath(); + + String toWrite = myPath.substring(origPath.length()); + out.write(toWrite); + out.write("\n"); + */ + + out.write(n.getPath().substring(cropPoint)); + out.write("\n"); + } + else if (recurse && n.isDirectory()) + { + traverseNode(out, store, n, recurse); + } + } + } + /* (non-Javadoc) * @see org.alfresco.repo.web.scripts.bean.BaseRemoteStore#listDocuments(org.alfresco.web.scripts.WebScriptResponse, java.lang.String, java.lang.String) */ @Override - protected void listDocuments(WebScriptResponse res, String path, String pattern) throws IOException + protected void listDocuments(WebScriptResponse res, final String store, String path, String pattern) throws IOException { - String avmPath = buildAVMPath(path); + String avmPath = buildAVMPath(store, path); AVMNodeDescriptor node = this.avmService.lookup(-1, avmPath); if (node == null) { @@ -368,70 +413,68 @@ public class AVMRemoteStore extends BaseRemoteStore } String matcher = pattern.replace(".","\\.").replace("*",".*"); + final Pattern pat = Pattern.compile(matcher); - try + String encPath = RepoStore.encodePathISO9075(path); + final StringBuilder query = new StringBuilder(128); + + query.append("+PATH:\"").append(this.rootPath) + .append(encPath.length() != 0 ? ('/' + encPath) : "") + .append("//*\" +QNAME:") + .append(pattern); + + /* + query.append("+PATH:\"/").append(this.rootPath) + .append(encPath.length() != 0 ? ('/' + encPath) : "") + .append("//*\" +QNAME:") + .append(pattern); +*/ + + final Writer out = res.getWriter(); + final StoreRef avmStore = new StoreRef(StoreRef.PROTOCOL_AVM + StoreRef.URI_FILLER + store); + AuthenticationUtil.runAs(new RunAsWork() { - traverseNode(res.getWriter(), node, Pattern.compile(matcher), true); - } - catch (AccessDeniedException ae) - { - res.setStatus(Status.STATUS_UNAUTHORIZED); - } - finally - { - res.getWriter().close(); - } + @SuppressWarnings("synthetic-access") + public Object doWork() throws Exception + { + int cropPoint = store.length() + rootPath.length() + 1; + ResultSet resultSet = searchService.query(avmStore, SearchService.LANGUAGE_LUCENE, query.toString()); + try + { + List nodes = resultSet.getNodeRefs(); + for (NodeRef nodeRef : nodes) + { + String path = AVMNodeConverter.ToAVMVersionPath(nodeRef).getSecond(); + String name = path.substring(path.lastIndexOf('/') + 1); + if (pat.matcher(name).matches()) + { + out.write(path.substring(cropPoint)); + out.write("\n"); + } + } + } + finally + { + resultSet.close(); + } + return null; + } + }, AuthenticationUtil.getSystemUserName()); } /** + * @param store the store id * @param path root path relative * * @return full AVM path to document including store and root path components */ - private String buildAVMPath(String path) + private String buildAVMPath(String store, String path) { - return this.store + ":/" + this.rootPath + (path != null ? ("/" + path) : ""); - } - - /** - * Traverse a Node and recursively output the file paths it contains. - * - * @param out Writer for output - relative paths separated by newline characters - * @param node The AVM Node to traverse - * @param pattern Optional Pattern to match filenames against - * @param recurse True to recurse sub-directories - * - * @throws IOException - */ - private void traverseNode(Writer out, AVMNodeDescriptor node, Pattern pattern, 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()) - { - String path = n.getPath(); - if (pattern != null) - { - String name = path.substring(path.lastIndexOf('/') + 1); - if (pattern.matcher(name).matches()) - { - out.write(path.substring(cropPoint)); - out.write("\n"); - } - } - else - { - out.write(path.substring(cropPoint)); - out.write("\n"); - } - } - else if (recurse && n.isDirectory()) - { - traverseNode(out, n, pattern, recurse); - } - } + //return store + ":/" + this.rootPath + (path != null ? ("/" + path) : ""); + if(path.startsWith("/")) + { + path = path.substring(1); + } + return 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 538b59245a..47ea18ddca 100644 --- a/source/java/org/alfresco/repo/web/scripts/bean/BaseRemoteStore.java +++ b/source/java/org/alfresco/repo/web/scripts/bean/BaseRemoteStore.java @@ -28,6 +28,7 @@ import java.io.IOException; import java.io.InputStream; import java.util.ArrayList; import java.util.List; +import java.util.StringTokenizer; import javax.servlet.http.HttpServletRequest; @@ -49,6 +50,8 @@ import org.apache.commons.logging.LogFactory; * * Request format: * //[?] + * //s//[?] + * //s//w//[?] * * Example: * /service/remotestore/lastmodified/sites/xyz/pages/page.xml @@ -57,6 +60,11 @@ import org.apache.commons.logging.LogFactory; * /service/remotestore -> service path * /lastmodified -> method name * /sites/../page.xml -> document path + * + * optional request parameters: + * + * s -> the avm store id + * w -> the wcm web application id * * Note: path is relative to the root path as configured for this webscript bean * @@ -81,19 +89,25 @@ import org.apache.commons.logging.LogFactory; */ public abstract class BaseRemoteStore extends AbstractWebScript { - private static final Log logger = LogFactory.getLog(BaseRemoteStore.class); + public static final String TOKEN_STORE = "s"; + public static final String TOKEN_WEBAPP = "w"; + + public static final String REQUEST_PARAM_STORE = "s"; + public static final String REQUEST_PARAM_WEBAPP = "w"; + + private static final Log logger = LogFactory.getLog(BaseRemoteStore.class); - protected String store; + protected String defaultStore; protected ContentService contentService; protected MimetypeService mimetypeService; /** - * @param store the store name of the store to process document requests against + * @param defaultStore the default store name of the store to process document requests against */ - public void setStore(String store) + public void setStore(String defaultStore) { - this.store = store; + this.defaultStore = defaultStore; } /** @@ -124,79 +138,156 @@ public abstract class BaseRemoteStore extends AbstractWebScript } HttpServletRequest httpReq = ((WebScriptServletRequest)req).getHttpServletRequest(); - - // break down and validate the request - expecting method name and document path + + // the request path for the remote store String extPath = req.getExtensionPath(); - String[] extParts = extPath == null ? new String[0] : extPath.split("/"); - if (extParts.length < 1) + + // values that we need to determine + String methodName = null; + String store = null; + String webapp = null; + StringBuilder pathBuilder = null; + + // tokenize the path and figure out tokenized values + StringTokenizer tokenizer = new StringTokenizer(extPath, "/"); + if (tokenizer.hasMoreTokens()) { - throw new WebScriptException("Remote Store expecting method name."); + methodName = tokenizer.nextToken(); + + if (tokenizer.hasMoreTokens()) + { + String el = tokenizer.nextToken(); + + if (TOKEN_STORE.equals(el)) + { + // if the token is "s", then the next token is the id of the store + store = tokenizer.nextToken(); + + // reset el + el = (tokenizer.hasMoreTokens() ? tokenizer.nextToken() : null); + } + + if (TOKEN_WEBAPP.equals(el)) + { + // if the token is "w", then the next token is a WCM webapp id + webapp = tokenizer.nextToken(); + + // reset el + el = (tokenizer.hasMoreTokens() ? tokenizer.nextToken() : null); + + } + + while(el != null) + { + if(pathBuilder == null) + { + pathBuilder = new StringBuilder(128); + } + pathBuilder.append("/"); + pathBuilder.append(el); + + el = (tokenizer.hasMoreTokens() ? tokenizer.nextToken() : null); + } + } + } + else + { + throw new WebScriptException("Unable to tokenize web path: " + extPath); } - // extract path from url extension - String path = null; - if (extParts.length >= 2) + // if we don't have a store, check whether it came in on a request parameter + if (store == null) { - path = req.getExtensionPath().substring(extParts[0].length() + 1); + store = req.getParameter(REQUEST_PARAM_STORE); + if (store == null) + { + store = this.defaultStore; + } + if (store == null) + { + // not good, we should have a store by this point + + // this means that a store was not passed in and that we + // also didn't have a configured store + throw new WebScriptException("Unable to determine which store to operate against. A store was not specified and a default was not provided."); + } } + // if we don't have a webapp, check whether it may have been passed in on a request parameter + if (webapp == null) + { + webapp = req.getParameter(REQUEST_PARAM_WEBAPP); + } + + // if we do have a webapp, allow for path prepending + if (webapp != null) + { + pathBuilder.insert(0, "/www/avm_webapps/" + webapp); + } + + // convert down to the path + String path = pathBuilder.toString(); + + // debugger information if (logger.isDebugEnabled()) - logger.debug("Remote store method: " + extParts[0] + " path: " + path); - - // TODO: support storeref name override as argument? (i.e. for AVM virtualisation) + { + logger.debug("Remote method: " + methodName); + logger.debug("Remote store id: " + store); + logger.debug("Remote path: " + path); + } try { // generate enum from string method name - so we can use a fast switch table lookup - APIMethod method = APIMethod.valueOf(extParts[0].toUpperCase()); + APIMethod method = APIMethod.valueOf(methodName.toUpperCase()); switch (method) { case LASTMODIFIED: validatePath(path); - lastModified(res, path); + lastModified(res, store, path); break; case HAS: validatePath(path); - hasDocument(res, path); + hasDocument(res, store, path); break; case GET: validatePath(path); - getDocument(res, path); + getDocument(res, store, path); break; case LIST: - listDocuments(res, path, false); + listDocuments(res, store, path, false); break; case LISTALL: - listDocuments(res, path, true); + listDocuments(res, store, path, true); break; case LISTPATTERN: - listDocuments(res, path, req.getParameter("m")); + listDocuments(res, store, path, req.getParameter("m")); break; case CREATE: validatePath(path); - createDocument(res, path, httpReq.getInputStream()); + createDocument(res, store, path, httpReq.getInputStream()); break; case UPDATE: validatePath(path); - updateDocument(res, path, httpReq.getInputStream()); + updateDocument(res, store, path, httpReq.getInputStream()); break; case DELETE: validatePath(path); - deleteDocument(res, path); + deleteDocument(res, store, path); break; } } catch (IllegalArgumentException enumErr) { - throw new WebScriptException("Unknown method specified to remote store API: " + extParts[0]); + throw new WebScriptException("Unknown method specified to remote store API: " + methodName); } catch (IOException ioErr) { @@ -233,9 +324,10 @@ public abstract class BaseRemoteStore extends AbstractWebScript * * The output will be the last modified date as a long toString(). * + * @param store the store id * @param path document path to an existing document */ - protected abstract void lastModified(WebScriptResponse res, String path) + protected abstract void lastModified(WebScriptResponse res, String store, String path) throws IOException; /** @@ -243,9 +335,10 @@ public abstract class BaseRemoteStore extends AbstractWebScript * * The output will be either the string "true" or the string "false". * + * @param store the store id * @param path document path */ - protected abstract void hasDocument(WebScriptResponse res, String path) + protected abstract void hasDocument(WebScriptResponse res, String store, String path) throws IOException; /** @@ -253,12 +346,13 @@ public abstract class BaseRemoteStore extends AbstractWebScript * * The output will be the document content stream. * + * @param store the store id * @param path document path * @return * * @throws IOException if an error occurs retrieving the document */ - protected abstract void getDocument(WebScriptResponse res, String path) + protected abstract void getDocument(WebScriptResponse res, String store, String path) throws IOException; /** @@ -267,12 +361,13 @@ public abstract class BaseRemoteStore extends AbstractWebScript * The output will be the list of relative document paths found under the path. * Separated by newline characters. * + * @param store the store id * @param path document path * @param recurse true to peform a recursive list, false for direct children only. * * @throws IOException if an error occurs listing the documents */ - protected abstract void listDocuments(WebScriptResponse res, String path, boolean recurse) + protected abstract void listDocuments(WebScriptResponse res, String store, String path, boolean recurse) throws IOException; /** @@ -281,42 +376,46 @@ public abstract class BaseRemoteStore extends AbstractWebScript * The output will be the list of relative document paths found under the path that * match the given file pattern. Separated by newline characters. * + * @param store the store id * @param path document path * @param pattern file pattern to match - allows wildcards e.g. *.xml or site*.xml * * @throws IOException if an error occurs listing the documents */ - protected abstract void listDocuments(WebScriptResponse res, String path, String pattern) + protected abstract void listDocuments(WebScriptResponse res, String store, String path, String pattern) throws IOException; /** * Creates a document. * - * @param path document path + * @param store the store id + * @param path document path * @param content content of the document to write * * @throws IOException if the create fails */ - protected abstract void createDocument(WebScriptResponse res, String path, InputStream content); + protected abstract void createDocument(WebScriptResponse res, String store, String path, InputStream content); /** * Updates an existing document. * + * @param store the store id * @param path document path * @param content content to update the document with * * @throws IOException if the update fails */ - protected abstract void updateDocument(WebScriptResponse res, String path, InputStream content); + protected abstract void updateDocument(WebScriptResponse res, String store, String path, InputStream content); /** * Deletes an existing document. * + * @param store the store id * @param path document path * * @throws IOException if the delete fails */ - protected abstract void deleteDocument(WebScriptResponse res, String path); + protected abstract void deleteDocument(WebScriptResponse res, String store, String path); /**