diff --git a/config/alfresco/templates/webscripts/org/alfresco/repository/nodelocator/node-location.get.desc.xml b/config/alfresco/templates/webscripts/org/alfresco/repository/nodelocator/node-location.get.desc.xml new file mode 100644 index 0000000000..1d8be103fc --- /dev/null +++ b/config/alfresco/templates/webscripts/org/alfresco/repository/nodelocator/node-location.get.desc.xml @@ -0,0 +1,11 @@ + + Locate Node + + Locates a Node in the repository using the specified Node Location strategy. + + /api/{store_type}/{store_id}/{node_id}/nodelocator/{node_locator_name} + /api/nodelocator/{node_locator_name} + + user + required + diff --git a/config/alfresco/templates/webscripts/org/alfresco/repository/nodelocator/node-location.get.json.ftl b/config/alfresco/templates/webscripts/org/alfresco/repository/nodelocator/node-location.get.json.ftl new file mode 100644 index 0000000000..e556473201 --- /dev/null +++ b/config/alfresco/templates/webscripts/org/alfresco/repository/nodelocator/node-location.get.json.ftl @@ -0,0 +1,11 @@ +{ + data: + { + <#if nodeRef?? > + nodeRef: "${nodeRef}" + <#else > + nodeRef: null + + } +} + diff --git a/config/alfresco/web-scripts-application-context.xml b/config/alfresco/web-scripts-application-context.xml index 8a5b5458fd..9fd59b4059 100644 --- a/config/alfresco/web-scripts-application-context.xml +++ b/config/alfresco/web-scripts-application-context.xml @@ -1254,4 +1254,11 @@ - + + + + + + \ No newline at end of file diff --git a/source/java/org/alfresco/repo/web/scripts/nodelocator/NodeLocationGet.java b/source/java/org/alfresco/repo/web/scripts/nodelocator/NodeLocationGet.java new file mode 100644 index 0000000000..4a59f93acc --- /dev/null +++ b/source/java/org/alfresco/repo/web/scripts/nodelocator/NodeLocationGet.java @@ -0,0 +1,107 @@ +/* + * Copyright (C) 2005-2011 Alfresco Software Limited. + * + * This file is part of Alfresco + * + * Alfresco is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * Alfresco is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with Alfresco. If not, see . + */ + +package org.alfresco.repo.web.scripts.nodelocator; + +import java.io.Serializable; +import java.util.HashMap; +import java.util.Map; + +import javax.servlet.http.HttpServletResponse; + +import org.alfresco.service.cmr.repository.NodeLocatorService; +import org.alfresco.service.cmr.repository.NodeRef; +import org.springframework.extensions.surf.util.URLDecoder; +import org.springframework.extensions.webscripts.DeclarativeWebScript; +import org.springframework.extensions.webscripts.Status; +import org.springframework.extensions.webscripts.WebScriptException; +import org.springframework.extensions.webscripts.WebScriptRequest; + +/** + * @author Nick Smith + * @since 4.0 + * + */ +public class NodeLocationGet extends DeclarativeWebScript +{ + private static final String NODE_ID = "node_id"; + private static final String STORE_ID = "store_id"; + private static final String STORE_TYPE = "store_type"; + private static final String NODE_LOCATOR_NAME = "node_locator_name"; + private NodeLocatorService locatorService; + + /** + * {@inheritDoc} + */ + @Override + protected Map executeImpl(WebScriptRequest req, Status status) + { + Map vars = req.getServiceMatch().getTemplateVars(); + // getting task id from request parameters + String locatorName = vars.get(NODE_LOCATOR_NAME); + + // No locatorname specified -> return 404 + if (locatorName == null) + { + throw new WebScriptException(HttpServletResponse.SC_NOT_FOUND, "No NodeLocator strategy was specified!"); + } + + NodeRef source = null; + String storeType = vars.get(STORE_TYPE); + String storeId= vars.get(STORE_ID); + String nodeId= vars.get(NODE_ID); + if(storeType!=null && storeId != null && nodeId != null) + { + source = new NodeRef(storeType, storeId, nodeId); + } + + Map params = mapParams(req); + + NodeRef node = locatorService.getNode(locatorName, source, params); + + Map model = new HashMap(); + model.put("nodeRef", node==null ? null : node.toString()); + return model; + } + + private Map mapParams(WebScriptRequest req) + { + Map params = new HashMap(); + for(String key: req.getParameterNames()) + { + String value = req.getParameter(key); + if (value != null) + { + String decodedValue = URLDecoder.decode(value); + // TODO Handle type conversions here. + params.put(key, decodedValue); + } + } + return params; + } + + /** + * @param locatorService the locatorService to set + */ + public void setNodeLocatorService(NodeLocatorService locatorService) + { + this.locatorService = locatorService; + } + +} diff --git a/source/java/org/alfresco/repo/web/scripts/nodelocator/NodeLocationWebScriptTest.java b/source/java/org/alfresco/repo/web/scripts/nodelocator/NodeLocationWebScriptTest.java new file mode 100644 index 0000000000..a4bdaec29b --- /dev/null +++ b/source/java/org/alfresco/repo/web/scripts/nodelocator/NodeLocationWebScriptTest.java @@ -0,0 +1,281 @@ +/* + * Copyright (C) 2005-2011 Alfresco Software Limited. + * + * This file is part of Alfresco + * + * Alfresco is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * Alfresco is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with Alfresco. If not, see . + */ + +package org.alfresco.repo.web.scripts.nodelocator; + +import org.alfresco.model.ContentModel; +import org.alfresco.repo.model.Repository; +import org.alfresco.repo.node.locator.AncestorNodeLocator; +import org.alfresco.repo.node.locator.CompanyHomeNodeLocator; +import org.alfresco.repo.node.locator.DocLibNodeLocator; +import org.alfresco.repo.node.locator.SitesHomeNodeLocator; +import org.alfresco.repo.node.locator.UserHomeNodeLocator; +import org.alfresco.repo.node.locator.XPathNodeLocator; +import org.alfresco.repo.security.authentication.AuthenticationUtil; +import org.alfresco.repo.site.SiteServiceInternal; +import org.alfresco.repo.web.scripts.BaseWebScriptTest; +import org.alfresco.service.cmr.repository.ChildAssociationRef; +import org.alfresco.service.cmr.repository.NodeRef; +import org.alfresco.service.cmr.repository.NodeService; +import org.alfresco.service.cmr.repository.StoreRef; +import org.alfresco.service.cmr.site.SiteInfo; +import org.alfresco.service.cmr.site.SiteService; +import org.alfresco.service.cmr.site.SiteVisibility; +import org.alfresco.service.namespace.NamespaceService; +import org.alfresco.service.namespace.QName; +import org.alfresco.util.GUID; +import org.json.JSONObject; +import org.springframework.context.ApplicationContext; +import org.springframework.extensions.surf.util.URLEncoder; +import org.springframework.extensions.webscripts.TestWebScriptServer.GetRequest; +import org.springframework.extensions.webscripts.TestWebScriptServer.Response; + +/** + * @author Nick Smith + * @since 4.0 + * + */ +public class NodeLocationWebScriptTest extends BaseWebScriptTest +{ + private static final String baseURL = "api/nodelocator/"; + private SiteServiceInternal siteService; + private NodeService nodeService; + private Repository repositoryHelper; + private NodeRef companyHome; + private NamespaceService namespaceService; + + public void testCompanyHomeNodeLocator() throws Exception + { + String url = baseURL + CompanyHomeNodeLocator.NAME; + checkNodeLocator(url, companyHome); + } + + public void testSitesHomeNodeLocator() throws Exception + { + String url = baseURL + SitesHomeNodeLocator.NAME; + NodeRef sitesHome = siteService.getSiteRoot(); + checkNodeLocator(url, sitesHome); + } + + public void testDocLibNodeLocator() throws Exception + { + AuthenticationUtil.setFullyAuthenticatedUser(AuthenticationUtil.getAdminUserName()); + SiteInfo site = null; + + NodeRef companyChild = makeChildContentNode(companyHome); + try + { + // Set up site + String siteName = "TestSite" + GUID.generate(); + site = siteService.createSite("", siteName, "Title", "Description", SiteVisibility.PUBLIC); + NodeRef fooFolder = makeContainer(siteName, "Foo"); + NodeRef docLib = makeContainer(siteName, SiteService.DOCUMENT_LIBRARY); + NodeRef fooChild = makeChildContentNode(fooFolder); + NodeRef docLibChild = makeChildContentNode(docLib); + + // Check returns company home if no source node specified. + String noNodeUrl = baseURL + DocLibNodeLocator.NAME; + checkNodeLocator(noNodeUrl, companyHome); + + // Check returns company home if source is not in a site. + String noSiteUrl = makeUrl(companyChild, DocLibNodeLocator.NAME); + checkNodeLocator(noSiteUrl, companyHome); + + // Check returns site doc lib if source is in site doc lib. + String docLibUrl = makeUrl(docLibChild, DocLibNodeLocator.NAME); + checkNodeLocator(docLibUrl, docLib); + + // Check returns site doc lib if source is in other site container. + String fooUrl = makeUrl(fooChild, DocLibNodeLocator.NAME); + checkNodeLocator(fooUrl, docLib); + } + finally + { + nodeService.deleteNode(companyChild); + if(site != null) + { + siteService.deleteSite(site.getShortName()); + } + } + } + + public void testUserHomeNodeLocator() throws Exception + { + String url = baseURL + UserHomeNodeLocator.NAME; + // Run as System User, no User Home. + AuthenticationUtil.setRunAsUser(AuthenticationUtil.getSystemUserName()); + checkNodeLocator(url, null); + + //Run as Admin User + AuthenticationUtil.setFullyAuthenticatedUser(AuthenticationUtil.getAdminUserName()); + + NodeRef admin = repositoryHelper.getPerson(); + NodeRef userHome = repositoryHelper.getUserHome(admin); + + checkNodeLocator(url, userHome); + } + + public void testAncestorOfTypeNodeLocator() throws Exception + { + AuthenticationUtil.setFullyAuthenticatedUser(AuthenticationUtil.getAdminUserName()); + NodeRef folder= makeChildFolderNode(companyHome); + try + { + NodeRef sysFolder = makeChildSystemFolderNode(folder); + NodeRef subFolder = makeChildFolderNode(sysFolder); + NodeRef source = makeChildContentNode(subFolder); + + // No params so should find first parent. + String ancestorUrl = makeUrl(source, AncestorNodeLocator.NAME); + checkNodeLocator(ancestorUrl, subFolder); + + // Set type to cm:content. Should not match any node. + String encodedContentType = URLEncoder.encode(ContentModel.TYPE_CONTENT.toPrefixString(namespaceService)); + String contentAncestorUrl = ancestorUrl + "?type=" + encodedContentType; + checkNodeLocator(contentAncestorUrl, null); + + // Set type to cm:systemfolder. Should find the sysFolder node. + String encodedSysFolderType = URLEncoder.encode(ContentModel.TYPE_SYSTEM_FOLDER.toPrefixString(namespaceService)); + String sysFolderAncestorUrl = ancestorUrl + "?type=" + encodedSysFolderType; + checkNodeLocator(sysFolderAncestorUrl, sysFolder); + + // Set aspect to cm:ownable. Should not match any node. + String encodedOwnableAspect= URLEncoder.encode(ContentModel.ASPECT_OWNABLE.toPrefixString(namespaceService)); + String ownableAncestorUrl = ancestorUrl + "?aspect=" + encodedOwnableAspect; + checkNodeLocator(ownableAncestorUrl, null); + + // Add ownable aspect to folder node. Now that node should be found. + nodeService.addAspect(folder, ContentModel.ASPECT_OWNABLE, null); + checkNodeLocator(ownableAncestorUrl, folder); + + // Set aspect to cm:ownable and type to cm:systemfolder. Should not match any node. + String ownableSysFolderAncestorUrl = sysFolderAncestorUrl + "&aspect=" + encodedOwnableAspect; + checkNodeLocator(ownableSysFolderAncestorUrl, null); + + // Set aspect to cm:ownable and type to cm:folder. Should find folder node. + String encodedFOlderType = URLEncoder.encode(ContentModel.TYPE_FOLDER.toPrefixString(namespaceService)); + String ownableFolderAncestorUrl = ownableAncestorUrl + "&type=" + encodedFOlderType; + checkNodeLocator(ownableFolderAncestorUrl, folder); + } + finally + { + nodeService.deleteNode(folder); + } + } + + public void testXPathNodeLocator() throws Exception + { + AuthenticationUtil.setFullyAuthenticatedUser(AuthenticationUtil.getAdminUserName()); + NodeRef first = makeChildFolderNode(companyHome); + try + { + NodeRef second = makeChildFolderNode(first); + NodeRef content = makeChildContentNode(second); + + // Check bad path returns null + String badPath = URLEncoder.encode("cm:foo/cm:bar/cm:foobar"); + String badPathUrl = baseURL + XPathNodeLocator.NAME + "?query=" + badPath; + checkNodeLocator(badPathUrl, null); + + String path = nodeService.getPath(content).toPrefixString(namespaceService); + String encodedPath = URLEncoder.encode(path); + + // Check default store ref works. + String defaultStoreUrl = baseURL + XPathNodeLocator.NAME + "?query=" +encodedPath; + checkNodeLocator(defaultStoreUrl, content); + + // Check specified store ref works. + String storeIdUrl = defaultStoreUrl + "&store_type=workspace&store_id=SpacesStore"; + checkNodeLocator(storeIdUrl, content); + + // Check node store ref works. + String nodePathUrl = makeUrl(companyHome, XPathNodeLocator.NAME) + "?query=" + encodedPath; + checkNodeLocator(nodePathUrl, content); + } + finally + { + nodeService.deleteNode(first); + } + } + + private String makeUrl(NodeRef node, String locatorName) + { + StoreRef storeRef = node.getStoreRef(); + StringBuilder url = new StringBuilder("/api/"); + url.append(storeRef.getProtocol()).append("/") + .append(storeRef.getIdentifier()).append("/") + .append(node.getId()).append("/") + .append("nodelocator").append("/") + .append(locatorName); + return url.toString(); + } + + private void checkNodeLocator(String url, NodeRef expNode) throws Exception + { + Response response = sendRequest(new GetRequest(url), 200); + String jsonStr = response.getContentAsString(); + JSONObject json = new JSONObject(jsonStr); + JSONObject result = json.getJSONObject("data"); + assertNotNull(result); + String nodeRef = result.getString("nodeRef"); + String expResult = expNode == null ? "null" : expNode.toString(); + assertEquals(expResult, nodeRef); + } + + private NodeRef makeChildContentNode(NodeRef parent) + { + return makeChildNode(parent, ContentModel.TYPE_CONTENT); + } + + private NodeRef makeChildSystemFolderNode(NodeRef parent) + { + return makeChildNode(parent, ContentModel.TYPE_SYSTEM_FOLDER); + } + + private NodeRef makeChildFolderNode(NodeRef parent) + { + return makeChildNode(parent, ContentModel.TYPE_FOLDER); + } + + private NodeRef makeChildNode(NodeRef parent, QName type) + { + QName qName = QName.createQName("", GUID.generate()); + QName contains = ContentModel.ASSOC_CONTAINS; + ChildAssociationRef result = nodeService.createNode(parent, contains, qName, type); + return result.getChildRef(); + } + + private NodeRef makeContainer(String siteName, String containerId) + { + QName type = ContentModel.TYPE_FOLDER; + return siteService.createContainer(siteName, containerId, type, null); + } + + @Override + protected void setUp() throws Exception + { + super.setUp(); + ApplicationContext appContext = getServer().getApplicationContext(); + this.siteService = (SiteServiceInternal) appContext.getBean("SiteService"); + this.nodeService = (NodeService) appContext.getBean("NodeService"); + this.namespaceService= (NamespaceService) appContext.getBean("NamespaceService"); + this.repositoryHelper = (Repository) appContext.getBean("repositoryHelper"); + this.companyHome = repositoryHelper.getCompanyHome(); + } +}