diff --git a/config/alfresco/templates/webscripts/org/alfresco/repository/tenant/tenant.lib.ftl b/config/alfresco/templates/webscripts/org/alfresco/repository/tenant/tenant.lib.ftl new file mode 100644 index 0000000000..3b18ffb51e --- /dev/null +++ b/config/alfresco/templates/webscripts/org/alfresco/repository/tenant/tenant.lib.ftl @@ -0,0 +1,7 @@ +<#macro tenantJSON tenant> + { + "tenantDomain": "${tenant.tenantDomain}", + "enabled": "${tenant.enabled?string}", + "contentRoot": "${tenant.rootContentStoreDir!""}" + } + diff --git a/config/alfresco/templates/webscripts/org/alfresco/repository/tenant/tenants.delete.desc.xml b/config/alfresco/templates/webscripts/org/alfresco/repository/tenant/tenants.delete.desc.xml new file mode 100644 index 0000000000..15e348deb5 --- /dev/null +++ b/config/alfresco/templates/webscripts/org/alfresco/repository/tenant/tenants.delete.desc.xml @@ -0,0 +1,18 @@ + + Delete Tenant + The repository must be configured such that Multi-Tenancy is enabled. +
You must have "administrator" privileges to delete a tenant. + +
WARNING: This operation cannot be recovered !!! + ]]> +
+ /api/tenants/{tenantDomain} + argument + admin + required + draft_public_api + MultiTenantAdmin +
\ No newline at end of file diff --git a/config/alfresco/templates/webscripts/org/alfresco/repository/tenant/tenants.delete.json.ftl b/config/alfresco/templates/webscripts/org/alfresco/repository/tenant/tenants.delete.json.ftl new file mode 100644 index 0000000000..124ee87b86 --- /dev/null +++ b/config/alfresco/templates/webscripts/org/alfresco/repository/tenant/tenants.delete.json.ftl @@ -0,0 +1 @@ +<#import "tenant.lib.ftl" as tenantLib/> \ No newline at end of file diff --git a/config/alfresco/templates/webscripts/org/alfresco/repository/tenant/tenants.get.desc.xml b/config/alfresco/templates/webscripts/org/alfresco/repository/tenant/tenants.get.desc.xml new file mode 100644 index 0000000000..f79d0a6207 --- /dev/null +++ b/config/alfresco/templates/webscripts/org/alfresco/repository/tenant/tenants.get.desc.xml @@ -0,0 +1,16 @@ + + Get Tenants + The repository must be in Multi-Tenant mode (1st tenant created). +
You must have "administrator" privileges to get list of tenants. + ]]> +
+ /api/tenants + argument + admin + required + draft_public_api + MultiTenantAdmin +
\ No newline at end of file diff --git a/config/alfresco/templates/webscripts/org/alfresco/repository/tenant/tenants.get.json.ftl b/config/alfresco/templates/webscripts/org/alfresco/repository/tenant/tenants.get.json.ftl new file mode 100644 index 0000000000..d753794629 --- /dev/null +++ b/config/alfresco/templates/webscripts/org/alfresco/repository/tenant/tenants.get.json.ftl @@ -0,0 +1,10 @@ +<#import "tenant.lib.ftl" as tenantLib/> +{ + "tenants" : + [ + <#list tenants as tenant> + <@tenantLib.tenantJSON tenant=tenant/> + <#if tenant_has_next>, + + ] +} \ No newline at end of file diff --git a/config/alfresco/templates/webscripts/org/alfresco/repository/tenant/tenants.post.desc.xml b/config/alfresco/templates/webscripts/org/alfresco/repository/tenant/tenants.post.desc.xml new file mode 100644 index 0000000000..91fcaf1af1 --- /dev/null +++ b/config/alfresco/templates/webscripts/org/alfresco/repository/tenant/tenants.post.desc.xml @@ -0,0 +1,22 @@ + + Create Tenant + The repository must be in Multi-Tenant mode (1st tenant created). +
You must have "administrator" privileges to create a tenant. + +
+
tenantDomain
mandatory
+
tenantAdminPassword
mandatory
+
tenantContentStoreRoot
optional
+
+ ]]> +
+ /api/tenants + argument + admin + required + draft_public_api + MultiTenantAdmin +
\ No newline at end of file diff --git a/config/alfresco/templates/webscripts/org/alfresco/repository/tenant/tenants.post.json.ftl b/config/alfresco/templates/webscripts/org/alfresco/repository/tenant/tenants.post.json.ftl new file mode 100644 index 0000000000..124ee87b86 --- /dev/null +++ b/config/alfresco/templates/webscripts/org/alfresco/repository/tenant/tenants.post.json.ftl @@ -0,0 +1 @@ +<#import "tenant.lib.ftl" as tenantLib/> \ No newline at end of file diff --git a/config/alfresco/templates/webscripts/org/alfresco/repository/upload/upload.post.js b/config/alfresco/templates/webscripts/org/alfresco/repository/upload/upload.post.js index d72633b475..cc99b0e219 100644 --- a/config/alfresco/templates/webscripts/org/alfresco/repository/upload/upload.post.js +++ b/config/alfresco/templates/webscripts/org/alfresco/repository/upload/upload.post.js @@ -345,6 +345,11 @@ function main() // Also perform the encoding guess step in the write() method to save an additional Writer operation. newFile.properties.content.write(content, false, true); newFile.save(); + + + // TODO (THOR-175) - review + // Ensure the file is versionable (autoVersion = true, autoVersionProps = false) + newFile.ensureVersioningEnabled(true, false); // NOTE: Removal of first request for thumbnails to improve upload performance // Thumbnails are still requested by Share on first render of the doclist image. diff --git a/config/alfresco/web-scripts-application-context.xml b/config/alfresco/web-scripts-application-context.xml index f952cc4806..8c5743e058 100644 --- a/config/alfresco/web-scripts-application-context.xml +++ b/config/alfresco/web-scripts-application-context.xml @@ -137,7 +137,7 @@ js - + Repository @@ -1873,8 +1873,7 @@ - - + @@ -1950,4 +1949,32 @@ + + + + + + + + + + + + + + + + + + + + diff --git a/source/java/org/alfresco/repo/web/scripts/BaseWebScriptTest.java b/source/java/org/alfresco/repo/web/scripts/BaseWebScriptTest.java index 767ac4d218..e010607ee7 100644 --- a/source/java/org/alfresco/repo/web/scripts/BaseWebScriptTest.java +++ b/source/java/org/alfresco/repo/web/scripts/BaseWebScriptTest.java @@ -151,7 +151,7 @@ public abstract class BaseWebScriptTest extends TestCase * Sets custom context for Test Web Script Server (in-process only) * @param customContext */ - protected void setCustomContext(String customContext) + public void setCustomContext(String customContext) { this.customContext = customContext; } @@ -254,7 +254,7 @@ public abstract class BaseWebScriptTest extends TestCase /** * Get the server for the previously-supplied {@link #setCustomContext(String) custom context} */ - protected TestWebScriptServer getServer() + public TestWebScriptServer getServer() { TestWebScriptServer server; if (customContext == null) diff --git a/source/java/org/alfresco/repo/web/scripts/RepositoryContainer.java b/source/java/org/alfresco/repo/web/scripts/RepositoryContainer.java index 3b45b42a73..6479067bba 100644 --- a/source/java/org/alfresco/repo/web/scripts/RepositoryContainer.java +++ b/source/java/org/alfresco/repo/web/scripts/RepositoryContainer.java @@ -1,5 +1,5 @@ /* - * Copyright (C) 2005-2012 Alfresco Software Limited. + * Copyright (C) 2005-2013 Alfresco Software Limited. * * This file is part of Alfresco * @@ -30,20 +30,15 @@ import java.io.OutputStream; import java.io.Writer; import java.util.HashMap; import java.util.Map; -import java.util.concurrent.locks.ReadWriteLock; -import java.util.concurrent.locks.ReentrantReadWriteLock; import javax.servlet.http.HttpServletResponse; import javax.transaction.Status; import javax.transaction.UserTransaction; import org.alfresco.error.AlfrescoRuntimeException; -import org.alfresco.repo.cache.SimpleCache; import org.alfresco.repo.model.Repository; import org.alfresco.repo.security.authentication.AuthenticationUtil; import org.alfresco.repo.security.authentication.AuthenticationUtil.RunAsWork; -import org.alfresco.repo.tenant.TenantAdminService; -import org.alfresco.repo.tenant.TenantDeployer; import org.alfresco.repo.transaction.AlfrescoTransactionSupport; import org.alfresco.repo.transaction.AlfrescoTransactionSupport.TxnReadState; import org.alfresco.repo.transaction.RetryingTransactionHelper; @@ -57,7 +52,6 @@ import org.alfresco.service.transaction.TransactionService; import org.alfresco.util.TempFileProvider; import org.apache.commons.logging.Log; import org.apache.commons.logging.LogFactory; -import org.springframework.beans.factory.ObjectFactory; import org.springframework.context.ApplicationContext; import org.springframework.context.ApplicationEvent; import org.springframework.context.event.ContextRefreshedEvent; @@ -73,7 +67,6 @@ import org.springframework.extensions.webscripts.Description.RequiredTransaction import org.springframework.extensions.webscripts.Description.RequiredTransactionParameters; import org.springframework.extensions.webscripts.Description.TransactionCapability; import org.springframework.extensions.webscripts.Match; -import org.springframework.extensions.webscripts.Registry; import org.springframework.extensions.webscripts.Runtime; import org.springframework.extensions.webscripts.ServerModel; import org.springframework.extensions.webscripts.WebScript; @@ -90,7 +83,7 @@ import org.springframework.util.FileCopyUtils; * * @author davidc */ -public class RepositoryContainer extends AbstractRuntimeContainer implements TenantDeployer +public class RepositoryContainer extends AbstractRuntimeContainer { // Logger protected static final Log logger = LogFactory.getLog(RepositoryContainer.class); @@ -102,28 +95,7 @@ public class RepositoryContainer extends AbstractRuntimeContainer implements Ten private RetryingTransactionHelper fallbackTransactionHelper; private AuthorityService authorityService; private DescriptorService descriptorService; - private TenantAdminService tenantAdminService; - private ObjectFactory registryFactory; - private SimpleCache webScriptsRegistryCache; - private ReadWriteLock webScriptsRegistryLock = new ReentrantReadWriteLock(); - private boolean initialized; - /** - * @param webScriptsRegistryCache - */ - public void setWebScriptsRegistryCache(SimpleCache webScriptsRegistryCache) - { - this.webScriptsRegistryCache = webScriptsRegistryCache; - } - - /** - * @param registryFactory - */ - public void setRegistryFactory(ObjectFactory registryFactory) - { - this.registryFactory = registryFactory; - } - /** * @param repository */ @@ -172,14 +144,6 @@ public class RepositoryContainer extends AbstractRuntimeContainer implements Ten this.authorityService = authorityService; } - /** - * @param tenantAdminService - */ - public void setTenantAdminService(TenantAdminService tenantAdminService) - { - this.tenantAdminService = tenantAdminService; - } - /* (non-Javadoc) * @see org.alfresco.web.scripts.Container#getDescription() */ @@ -546,51 +510,6 @@ public class RepositoryContainer extends AbstractRuntimeContainer implements Ten } } - /* (non-Javadoc) - * @see org.alfresco.web.scripts.AbstractRuntimeContainer#getRegistry() - */ - @Override - public Registry getRegistry() - { - String tenantDomain = tenantAdminService.getCurrentUserDomain(); - Registry registry; - webScriptsRegistryLock.readLock().lock(); - try - { - registry = webScriptsRegistryCache.get(tenantDomain); - } - finally - { - webScriptsRegistryLock.readLock().unlock(); - } - if (registry == null) - { - webScriptsRegistryLock.writeLock().lock(); - try - { - // Double check now we have write lock - registry = webScriptsRegistryCache.get(tenantDomain); - - // Initialize / reinitialize the registry in this thread only - if (registry == null) - { - registry = (Registry) registryFactory.getObject(); - // We only need to reset the registry if the superclass thinks its already initialized - if (initialized) - { - registry.reset(); - } - webScriptsRegistryCache.put(tenantDomain, registry); - } - } - finally - { - webScriptsRegistryLock.writeLock().unlock(); - } - } - return registry; - } - /* (non-Javadoc) * @see org.alfresco.web.scripts.AbstractRuntimeContainer#onApplicationEvent(org.springframework.context.ApplicationEvent) */ @@ -656,68 +575,17 @@ public class RepositoryContainer extends AbstractRuntimeContainer implements Ten { public Object execute() throws Exception { - destroy(); - init(); - + internalReset(); return null; } }, true, false); } - /* (non-Javadoc) - * @see org.alfresco.repo.tenant.TenantDeployer#onEnableTenant() - */ - public void onEnableTenant() + private void internalReset() { - init(); - } - - /* (non-Javadoc) - * @see org.alfresco.repo.tenant.TenantDeployer#onDisableTenant() - */ - public void onDisableTenant() - { - destroy(); - } - - /* (non-Javadoc) - * @see org.alfresco.repo.tenant.TenantDeployer#init() - */ - public void init() - { - tenantAdminService.register(this); - super.reset(); - - initialized = true; } - /* (non-Javadoc) - * @see org.alfresco.repo.tenant.TenantDeployer#destroy() - */ - public void destroy() - { - try - { - webScriptsRegistryLock.writeLock().lock(); - webScriptsRegistryCache.remove(tenantAdminService.getCurrentUserDomain()); - - if (logger.isTraceEnabled()) - { - Exception e = new Exception("RepositoryContainer destroy called."); - e.fillInStackTrace(); - logger.trace("", e); - } - } - finally - { - webScriptsRegistryLock.writeLock().unlock(); - } - - initialized = false; - } - - /** * Transactional Buffered Response */ diff --git a/source/java/org/alfresco/repo/web/scripts/TenantRepositoryContainer.java b/source/java/org/alfresco/repo/web/scripts/TenantRepositoryContainer.java new file mode 100644 index 0000000000..c416f1e0c0 --- /dev/null +++ b/source/java/org/alfresco/repo/web/scripts/TenantRepositoryContainer.java @@ -0,0 +1,131 @@ +/* + * Copyright (C) 2005-2010 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; + +import org.alfresco.repo.cache.SimpleCache; +import org.alfresco.repo.security.authentication.AuthenticationUtil; +import org.alfresco.repo.tenant.TenantAdminService; +import org.alfresco.repo.tenant.TenantDeployer; +import org.apache.commons.logging.Log; +import org.apache.commons.logging.LogFactory; +import org.springframework.beans.factory.ObjectFactory; +import org.springframework.extensions.webscripts.Description.RequiredAuthentication; +import org.springframework.extensions.webscripts.Registry; + + +/** + * Tenant-aware Repository (server-tier) container for Web Scripts + * + * @author davidc + */ +public class TenantRepositoryContainer extends RepositoryContainer implements TenantDeployer +{ + // Logger + protected static final Log logger = LogFactory.getLog(TenantRepositoryContainer.class); + + /** Component Dependencies */ + private TenantAdminService tenantAdminService; + private ObjectFactory registryFactory; + private SimpleCache webScriptsRegistryCache; + private boolean initialized; + + /** + * @param webScriptsRegistryCache + */ + public void setWebScriptsRegistryCache(SimpleCache webScriptsRegistryCache) + { + this.webScriptsRegistryCache = webScriptsRegistryCache; + } + + /** + * @param registryFactory + */ + public void setRegistryFactory(ObjectFactory registryFactory) + { + this.registryFactory = registryFactory; + } + + /** + * @param tenantAdminService + */ + public void setTenantAdminService(TenantAdminService tenantAdminService) + { + this.tenantAdminService = tenantAdminService; + } + + /* (non-Javadoc) + * @see org.alfresco.web.scripts.AbstractRuntimeContainer#getRegistry() + */ + @Override + public Registry getRegistry() + { + String tenantDomain = tenantAdminService.getCurrentUserDomain(); + Registry registry = webScriptsRegistryCache.get(tenantDomain); + if (registry == null) + { + registry = (Registry)registryFactory.getObject(); + // We only need to reset the registry if the superclass thinks its already initialized + if (initialized) + { + registry.reset(); + } + webScriptsRegistryCache.put(tenantDomain, registry); + } + return registry; + } + + /* (non-Javadoc) + * @see org.alfresco.repo.tenant.TenantDeployer#onEnableTenant() + */ + public void onEnableTenant() + { + init(); + } + + /* (non-Javadoc) + * @see org.alfresco.repo.tenant.TenantDeployer#onDisableTenant() + */ + public void onDisableTenant() + { + destroy(); + } + + /* (non-Javadoc) + * @see org.alfresco.repo.tenant.TenantDeployer#init() + */ + public void init() + { + tenantAdminService.register(this); + + super.reset(); + + initialized = true; + } + + /* (non-Javadoc) + * @see org.alfresco.repo.tenant.TenantDeployer#destroy() + */ + public void destroy() + { + webScriptsRegistryCache.remove(tenantAdminService.getCurrentUserDomain()); + + initialized = false; + } + +} diff --git a/source/java/org/alfresco/repo/web/scripts/TenantWebScriptServlet.java b/source/java/org/alfresco/repo/web/scripts/TenantWebScriptServlet.java new file mode 100644 index 0000000000..5dce253113 --- /dev/null +++ b/source/java/org/alfresco/repo/web/scripts/TenantWebScriptServlet.java @@ -0,0 +1,74 @@ +/** + * Copyright (C) 2005-2009 Alfresco Software Limited. + * + * This file is part of the Spring Surf Extension project. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.alfresco.repo.web.scripts; + +import java.io.IOException; + +import javax.servlet.ServletException; +import javax.servlet.http.HttpServletRequest; +import javax.servlet.http.HttpServletResponse; + +import org.apache.commons.logging.Log; +import org.apache.commons.logging.LogFactory; +import org.springframework.extensions.surf.util.I18NUtil; +import org.springframework.extensions.webscripts.servlet.WebScriptServlet; +import org.springframework.extensions.webscripts.servlet.WebScriptServletRuntime; + + +/** + * Entry point for web scripts which can accept a tenant id in their servlet path + * + * @author davidc + */ +public class TenantWebScriptServlet extends WebScriptServlet +{ + public static final String DEFAULT_TENANT = "-default-"; + + private static final long serialVersionUID = 2954663814419046489L; + + // Logger + private static final Log logger = LogFactory.getLog(TenantWebScriptServlet.class); + + /* (non-Javadoc) + * @see javax.servlet.http.HttpServlet#service(javax.servlet.http.HttpServletRequest, javax.servlet.http.HttpServletResponse) + */ + protected void service(HttpServletRequest req, HttpServletResponse res) throws ServletException, IOException + { + if (logger.isDebugEnabled()) + logger.debug("Processing tenant request (" + req.getMethod() + ") " + req.getRequestURL() + (req.getQueryString() != null ? "?" + req.getQueryString() : "")); + + if (req.getCharacterEncoding() == null) + { + req.setCharacterEncoding("UTF-8"); + } + + setLanguageFromRequestHeader(req); + + try + { + WebScriptServletRuntime runtime = new TenantWebScriptServletRuntime(container, authenticatorFactory, req, res, serverProperties); + runtime.executeScript(); + } + finally + { + // clear threadlocal + I18NUtil.setLocale(null); + } + } +} diff --git a/source/java/org/alfresco/repo/web/scripts/TenantWebScriptServletRequest.java b/source/java/org/alfresco/repo/web/scripts/TenantWebScriptServletRequest.java new file mode 100644 index 0000000000..16c7ec9082 --- /dev/null +++ b/source/java/org/alfresco/repo/web/scripts/TenantWebScriptServletRequest.java @@ -0,0 +1,104 @@ +/** + * Copyright (C) 2005-2009 Alfresco Software Limited. + * + * This file is part of the Spring Surf Extension project. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.alfresco.repo.web.scripts; + +import javax.servlet.http.HttpServletRequest; + +import org.springframework.extensions.config.ServerProperties; +import org.springframework.extensions.surf.util.URLDecoder; +import org.springframework.extensions.webscripts.Match; +import org.springframework.extensions.webscripts.Runtime; +import org.springframework.extensions.webscripts.servlet.WebScriptServletRequest; + + +/** + * Web Script Request which can handle a tenant id in their servlet path + * + * @author davidc + */ +public class TenantWebScriptServletRequest extends WebScriptServletRequest +{ + private String tenant; + private String pathInfo; + + /** + * Construction + * + * @param container request generator + * @param req + * @param serviceMatch + */ + public TenantWebScriptServletRequest(Runtime container, HttpServletRequest req, Match serviceMatch, ServerProperties serverProperties) + { + super(container, req, serviceMatch, serverProperties); + + String realPathInfo = getRealPathInfo(); + + // remove tenant + int idx = realPathInfo.indexOf('/', 1); + tenant = realPathInfo.substring(1, idx == -1 ? realPathInfo.length() : idx); + pathInfo = realPathInfo.substring(tenant.length() + 1); + } + + /* (non-Javadoc) + * @see org.alfresco.web.scripts.WebScriptRequest#getServiceContextPath() + */ + public String getServiceContextPath() + { + return getHttpServletRequest().getContextPath() + getHttpServletRequest().getServletPath() + "/" + tenant; + } + + /* (non-Javadoc) + * @see org.alfresco.web.scripts.WebScriptRequest#getPathInfo() + */ + public String getPathInfo() + { + return pathInfo; + } + + public String getTenant() + { + return tenant; + } + + /* (non-Javadoc) + * @see org.alfresco.web.scripts.WebScriptRequest#getPathInfo() + */ + private String getRealPathInfo() + { + // NOTE: Don't use req.getPathInfo() - it truncates the path at first semi-colon in Tomcat + final String requestURI = getHttpServletRequest().getRequestURI(); + final String serviceContextPath = getHttpServletRequest().getContextPath() + getHttpServletRequest().getServletPath(); + String pathInfo; + + if (serviceContextPath.length() > requestURI.length()) + { + // NOTE: assume a redirect has taken place e.g. tomcat welcome-page + // NOTE: this is unlikely, and we'll take the hit if the path contains a semi-colon + pathInfo = getHttpServletRequest().getPathInfo(); + } + else + { + pathInfo = URLDecoder.decode(requestURI.substring(serviceContextPath.length())); + } + + return pathInfo; + } + +} diff --git a/source/java/org/alfresco/repo/web/scripts/TenantWebScriptServletRuntime.java b/source/java/org/alfresco/repo/web/scripts/TenantWebScriptServletRuntime.java new file mode 100644 index 0000000000..f5be0ecf00 --- /dev/null +++ b/source/java/org/alfresco/repo/web/scripts/TenantWebScriptServletRuntime.java @@ -0,0 +1,100 @@ +/** + * Copyright (C) 2005-2009 Alfresco Software Limited. + * + * This file is part of the Spring Surf Extension project. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.alfresco.repo.web.scripts; + +import javax.servlet.http.HttpServletRequest; +import javax.servlet.http.HttpServletResponse; + +import org.springframework.extensions.config.ServerProperties; +import org.springframework.extensions.surf.util.URLDecoder; +import org.springframework.extensions.webscripts.Match; +import org.springframework.extensions.webscripts.RuntimeContainer; +import org.springframework.extensions.webscripts.WebScriptException; +import org.springframework.extensions.webscripts.WebScriptRequest; +import org.springframework.extensions.webscripts.servlet.ServletAuthenticatorFactory; +import org.springframework.extensions.webscripts.servlet.WebScriptServletRuntime; + + +/** + * HTTP Servlet Web Script Runtime which can handle a tenant id in a web script path + * + * @author davidc + */ +public class TenantWebScriptServletRuntime extends WebScriptServletRuntime +{ + public TenantWebScriptServletRuntime(RuntimeContainer container, ServletAuthenticatorFactory authFactory, HttpServletRequest req, HttpServletResponse res, ServerProperties serverProperties) + { + super(container, authFactory, req, res, serverProperties); + } + + /* (non-Javadoc) + * @see org.alfresco.web.scripts.WebScriptRuntime#getScriptUrl() + */ + @Override + protected String getScriptUrl() + { + // NOTE: Don't use req.getPathInfo() - it truncates the path at first semi-colon in Tomcat + final String requestURI = req.getRequestURI(); + final String serviceContextPath = req.getContextPath() + req.getServletPath(); + String pathInfo; + + if (serviceContextPath.length() > requestURI.length()) + { + // NOTE: assume a redirect has taken place e.g. tomcat welcome-page + // NOTE: this is unlikely, and we'll take the hit if the path contains a semi-colon + pathInfo = req.getPathInfo(); + } + else + { + pathInfo = URLDecoder.decode(requestURI.substring(serviceContextPath.length())); + } + + // ensure tenant is specified at beginning of path + // NOTE: must contain at least root / and single character for tenant name + if (pathInfo.length() < 2) + { + throw new WebScriptException("Missing tenant name in path: " + pathInfo); + } + // remove tenant + int idx = pathInfo.indexOf('/', 1); + pathInfo = pathInfo.substring(idx == -1 ? pathInfo.length() : idx); + return pathInfo; + } + + /* (non-Javadoc) + * @see org.alfresco.web.scripts.WebScriptRuntime#createRequest(org.alfresco.web.scripts.WebScriptMatch) + */ + @Override + protected WebScriptRequest createRequest(Match match) + { + // TODO: construct org.springframework.extensions.webscripts.servlet.WebScriptServletResponse when + // org.alfresco.web.scripts.WebScriptServletResponse (deprecated) is removed + servletReq = new TenantWebScriptServletRequest(this, req, match, serverProperties); + return servletReq; + } + + /* (non-Javadoc) + * @see org.alfresco.web.scripts.WebScriptContainer#getName() + */ + public String getName() + { + return "TenantServletRuntime"; + } + +} diff --git a/source/java/org/alfresco/repo/web/scripts/invite/InviteByTicket.java b/source/java/org/alfresco/repo/web/scripts/invite/InviteByTicket.java index b0c91d179f..5d73fb1c30 100644 --- a/source/java/org/alfresco/repo/web/scripts/invite/InviteByTicket.java +++ b/source/java/org/alfresco/repo/web/scripts/invite/InviteByTicket.java @@ -1,5 +1,5 @@ /* - * Copyright (C) 2005-2011 Alfresco Software Limited. + * Copyright (C) 2005-2013 Alfresco Software Limited. * * This file is part of Alfresco * @@ -25,6 +25,8 @@ import org.alfresco.repo.invitation.site.InviteInfo; import org.alfresco.repo.security.authentication.AuthenticationUtil; import org.alfresco.repo.template.TemplateNode; import org.alfresco.repo.tenant.TenantService; +import org.alfresco.repo.tenant.TenantUtil; +import org.alfresco.repo.tenant.TenantUtil.TenantRunAsWork; import org.alfresco.service.ServiceRegistry; import org.alfresco.service.cmr.invitation.Invitation; import org.alfresco.service.cmr.invitation.InvitationExceptionNotFound; @@ -102,14 +104,14 @@ public class InviteByTicket extends DeclarativeWebScript // run as system user String mtAwareSystemUser = tenantService.getDomainUser(AuthenticationUtil.getSystemUserName(), tenantDomain); - - Map ret = AuthenticationUtil.runAs(new AuthenticationUtil.RunAsWork>() + + Map ret = TenantUtil.runAsSystemTenant(new TenantRunAsWork>() { public Map doWork() throws Exception { return execute(req, status); } - }, mtAwareSystemUser); + }, tenantDomain); // authenticate as system for the rest of the webscript AuthenticationUtil.setRunAsUser(mtAwareSystemUser); diff --git a/source/java/org/alfresco/repo/web/scripts/invite/InviteResponse.java b/source/java/org/alfresco/repo/web/scripts/invite/InviteResponse.java index 3f5cdad445..864223b446 100644 --- a/source/java/org/alfresco/repo/web/scripts/invite/InviteResponse.java +++ b/source/java/org/alfresco/repo/web/scripts/invite/InviteResponse.java @@ -1,5 +1,5 @@ /* - * Copyright (C) 2005-2011 Alfresco Software Limited. + * Copyright (C) 2005-2013 Alfresco Software Limited. * * This file is part of Alfresco * @@ -23,6 +23,8 @@ import java.util.Map; import org.alfresco.repo.security.authentication.AuthenticationUtil; import org.alfresco.repo.tenant.TenantService; +import org.alfresco.repo.tenant.TenantUtil; +import org.alfresco.repo.tenant.TenantUtil.TenantRunAsWork; import org.alfresco.service.cmr.invitation.Invitation; import org.alfresco.service.cmr.invitation.InvitationExceptionForbidden; import org.alfresco.service.cmr.invitation.InvitationExceptionUserError; @@ -88,13 +90,13 @@ public class InviteResponse extends DeclarativeWebScript } // run as system user - return AuthenticationUtil.runAs(new AuthenticationUtil.RunAsWork>() + return TenantUtil.runAsSystemTenant(new TenantRunAsWork>() { public Map doWork() throws Exception { return execute(req, status); } - }, tenantService.getDomainUser(AuthenticationUtil.getSystemUserName(), tenantDomain)); + }, tenantDomain); } private Map execute(WebScriptRequest req, Status status) diff --git a/source/java/org/alfresco/repo/web/scripts/tenant/AbstractTenantAdminWebScript.java b/source/java/org/alfresco/repo/web/scripts/tenant/AbstractTenantAdminWebScript.java new file mode 100644 index 0000000000..25c33d54c2 --- /dev/null +++ b/source/java/org/alfresco/repo/web/scripts/tenant/AbstractTenantAdminWebScript.java @@ -0,0 +1,40 @@ +/* + * Copyright (C) 2005-2013 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.tenant; + +import org.alfresco.repo.tenant.TenantAdminService; +import org.springframework.extensions.webscripts.DeclarativeWebScript; + +/** + * @author janv + * @since 4.2 + */ +public abstract class AbstractTenantAdminWebScript extends DeclarativeWebScript +{ + protected static final String TENANT_DOMAIN = "tenantDomain"; + protected static final String TENANT_ADMIN_PASSWORD = "tenantAdminPassword"; + protected static final String TENANT_CONTENT_STORE_ROOT = "tenantContentStoreRoot"; + + protected TenantAdminService tenantAdminService; + + public void setTenantAdminService(TenantAdminService tenantAdminService) + { + this.tenantAdminService = tenantAdminService; + } +} diff --git a/source/java/org/alfresco/repo/web/scripts/tenant/TenantAdminSystemTest.java b/source/java/org/alfresco/repo/web/scripts/tenant/TenantAdminSystemTest.java new file mode 100644 index 0000000000..ffc1a40413 --- /dev/null +++ b/source/java/org/alfresco/repo/web/scripts/tenant/TenantAdminSystemTest.java @@ -0,0 +1,405 @@ +/* + * Copyright (C) 2005-2013 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.tenant; + +import java.io.BufferedReader; +import java.io.DataOutputStream; +import java.io.IOException; +import java.io.InputStream; +import java.io.InputStreamReader; +import java.io.OutputStream; +import java.io.PrintWriter; +import java.io.StringWriter; +import java.net.HttpURLConnection; +import java.net.MalformedURLException; +import java.net.URISyntaxException; +import java.net.URL; + +import junit.framework.TestCase; + +import org.apache.commons.logging.Log; +import org.apache.commons.logging.LogFactory; +import org.json.JSONObject; +import org.springframework.extensions.surf.util.Base64; + +/** + * Simple test of Tenant REST API - eg. create tenant + * + * @author janv + * @since 4.2 + */ +public class TenantAdminSystemTest extends TestCase +{ + private static Log logger = LogFactory.getLog(TenantAdminSystemTest.class); + + // TODO - use test property file + private static final String REPO = "http://localhost:8080/alfresco"; + + // web script (REST) + private static final String WEBSCRIPT_ENDPOINT = REPO + "/service"; + + // Tenant Admin Service part-URLs + private static final String URL_TENANTS = "/api/tenants"; + + // Test users & passwords + private static final String ADMIN_USER = "admin"; + private static final String ADMIN_PW = "admin"; + + private static final String TENANT_PREFIX = "t"+System.currentTimeMillis()+"-"; + + private static final int T_CNT = 5; + + public enum Op {CREATE_TENANT}; + + public TenantAdminSystemTest() + { + } + + @Override + protected void setUp() throws Exception + { + super.setUp(); + } + + @Override + protected void tearDown() throws Exception + { + super.tearDown(); + } + + public void testLogin() throws Exception + { + String ticket = callLoginWebScript(WEBSCRIPT_ENDPOINT, ADMIN_USER, ADMIN_PW); + assertNotNull(ticket); + } + + public void testCreateTenants() throws Exception + { + runWorkers(1, T_CNT, Op.CREATE_TENANT); + } + + protected static void createTenant(String tenantDomain, String ticket) throws Exception + { + JSONObject tenant = new JSONObject(); + tenant.put("tenantDomain", tenantDomain); + tenant.put("tenantAdminPassword", tenantDomain); + + String url = WEBSCRIPT_ENDPOINT + URL_TENANTS; + String response = callPostWebScript(url, ticket, tenant.toString()); + + if (logger.isDebugEnabled()) + { + logger.debug("createTenant: " + tenantDomain); + logger.debug("----------"); + logger.debug(url); + logger.debug(response); + } + } + + public void testGetTenants() throws Exception + { + String ticket = callLoginWebScript(WEBSCRIPT_ENDPOINT, ADMIN_USER, ADMIN_PW); + + getTenants(ticket); + } + + protected void getTenants(String ticket) throws Exception + { + String url = WEBSCRIPT_ENDPOINT + URL_TENANTS; + String response = callGetWebScript(url, ticket); + + if (logger.isDebugEnabled()) + { + logger.debug("getTenants:"); + logger.debug("-------"); + logger.debug(url); + logger.debug(response); + } + } + + protected static String callGetWebScript(String urlString, String ticket) throws MalformedURLException, URISyntaxException, IOException + { + return callOutWebScript(urlString, "GET", ticket); + } + + protected static String callDeleteWebScript(String urlString, String ticket) throws MalformedURLException, URISyntaxException, IOException + { + return callOutWebScript(urlString, "DELETE", ticket); + } + + protected static String callPostWebScript(String urlString, String ticket, String data) throws MalformedURLException, URISyntaxException, IOException + { + return callInOutWebScript(urlString, "POST", ticket, data); + } + + protected static String callPutWebScript(String urlString, String ticket, String data) throws MalformedURLException, URISyntaxException, IOException + { + return callInOutWebScript(urlString, "PUT", ticket, data); + } + + private static String callOutWebScript(String urlString, String method, String ticket) throws MalformedURLException, URISyntaxException, IOException + { + URL url = new URL(urlString); + + HttpURLConnection conn = (HttpURLConnection)url.openConnection(); + conn.setRequestMethod(method); + + if (ticket != null) + { + // add Base64 encoded authorization header + // refer to: http://wiki.alfresco.com/wiki/Web_Scripts_Framework#HTTP_Basic_Authentication + conn.addRequestProperty("Authorization", "Basic " + Base64.encodeBytes(ticket.getBytes())); + } + + String result = null; + InputStream is = null; + BufferedReader br = null; + + try + { + is = conn.getInputStream(); + br = new BufferedReader(new InputStreamReader(is)); + + String line = null; + StringBuffer sb = new StringBuffer(); + while(((line = br.readLine()) !=null)) { + sb.append(line); + } + + result = sb.toString(); + } + finally + { + if (br != null) { br.close(); }; + if (is != null) { is.close(); }; + } + + return result; + } + + private static String callInOutWebScript(String urlString, String method, String ticket, String data) throws MalformedURLException, URISyntaxException, IOException + { + return callInOutWeb(urlString, method, ticket, data, "application/json", null); + } + + private static String callInOutWeb(String urlString, String method, String ticket, String data, String contentType, String soapAction) throws MalformedURLException, URISyntaxException, IOException + { + URL url = new URL(urlString); + + HttpURLConnection conn = (HttpURLConnection)url.openConnection(); + conn.setRequestMethod(method); + + conn.setRequestProperty("Content-type", contentType); + + conn.setDoOutput(true); + conn.setDoInput(true); + conn.setUseCaches (false); + + if (soapAction != null) + { + conn.setRequestProperty("SOAPAction", soapAction); + } + + if (ticket != null) + { + // add Base64 encoded authorization header + // refer to: http://wiki.alfresco.com/wiki/Web_Scripts_Framework#HTTP_Basic_Authentication + conn.addRequestProperty("Authorization", "Basic " + Base64.encodeBytes(ticket.getBytes())); + } + + String result = null; + BufferedReader br = null; + DataOutputStream wr = null; + OutputStream os = null; + InputStream is = null; + + try + { + os = conn.getOutputStream(); + wr = new DataOutputStream(os); + wr.write(data.getBytes()); + wr.flush(); + } + finally + { + if (wr != null) { wr.close(); }; + if (os != null) { os.close(); }; + } + + try + { + is = conn.getInputStream(); + br = new BufferedReader(new InputStreamReader(is)); + + String line = null; + StringBuffer sb = new StringBuffer(); + while(((line = br.readLine()) !=null)) + { + sb.append(line); + } + + result = sb.toString(); + } + finally + { + if (br != null) { br.close(); }; + if (is != null) { is.close(); }; + } + + return result; + } + + protected static String callLoginWebScript(String serviceUrl, String username, String password) throws MalformedURLException, URISyntaxException, IOException + { + // Refer to: http://wiki.alfresco.com/wiki/Web_Scripts_Framework#HTTP_Basic_Authentication + String ticketResult = callGetWebScript(serviceUrl+"/api/login?u="+username+"&pw="+password, null); + + if (ticketResult != null) + { + int startTag = ticketResult.indexOf(""); + int endTag = ticketResult.indexOf(""); + if ((startTag != -1) && (endTag != -1)) + { + ticketResult = ticketResult.substring(startTag+("".length()), endTag); + } + } + + return ticketResult; + } + + private static void runWorkers(int threadCount, int threadBatch, Op mode) + { + logger.info("Start: Mode "+mode+" ["+threadCount+"]"); + + long start = System.currentTimeMillis(); + + Thread[] threads = new Thread[threadCount]; + + Worker[] nesters = new Worker[threadCount]; + + for (int i = 0; i < threadCount; i++) + { + int startId = (i*threadBatch)+1; + int endId = (i+1)*threadBatch; + + Worker nester = new Worker(mode, startId, endId); + nesters[i] = nester; + + threads[i] = new Thread(nester); + threads[i].start(); + } + + int totalCnt = 0; + long totalTime = 0; + + // join each thread so that we wait for them all to finish + for (int i = 0; i < threadCount; i++) + { + try + { + threads[i].join(); + + if (nesters[i].getErrorStackTrace() != null) + { + throw new RuntimeException(nesters[i].getErrorStackTrace()); + } + + if (nesters[i].getOpTime() != null) + { + totalTime = totalTime + nesters[i].getOpTime(); + totalCnt++; + } + } + catch (InterruptedException e) + { + // ignore + } + } + + logger.info("Finish: Mode "+mode+" [threadCount="+threadCount+", threadBatch="+threadBatch+"] in "+(System.currentTimeMillis()-start)+" ms (avg per thread = "+totalTime/totalCnt+" ms)"); + } + + private static class Worker implements Runnable + { + private Op op; + private int startId; + private int endId; + + private String errorStackTrace = null; + + private Long opTime; + + Worker(Op mode, int startId, int endId) + { + this.op = mode; + this.startId = startId; + this.endId = endId; + } + + public String getErrorStackTrace() + { + return errorStackTrace; + } + + public Long getOpTime() + { + return opTime; + } + + public void run() + { + String tenantDomain = null; + + try + { + long start = System.currentTimeMillis(); + + logger.info("Start: Mode "+op+" ("+startId+" to "+endId+") [ThreadId="+Thread.currentThread().getId()+"]"); + + for (int i = startId; i <= endId; i++) + { + tenantDomain = TENANT_PREFIX+String.format("%05d", i); + + switch(op) + { + case CREATE_TENANT: + String ticket = callLoginWebScript(WEBSCRIPT_ENDPOINT, ADMIN_USER, ADMIN_PW); + createTenant(TENANT_PREFIX+"--"+String.format("%05d", i), ticket); + break; + default: + throw new UnsupportedOperationException("Unsupported op type: "+op); + } + } + + opTime = (System.currentTimeMillis()-start); + + logger.info("Finish: Mode "+op+" ("+startId+" to "+endId+") [ThreadId="+Thread.currentThread().getId()+"] in "+opTime+" ms"); + } + catch (Throwable t) + { + logger.error("End " + tenantDomain + " with error " + t.getMessage()); + + StringWriter sw = new StringWriter(); + t.printStackTrace(new PrintWriter(sw)); + + errorStackTrace = sw.toString(); + } + } + } +} diff --git a/source/java/org/alfresco/repo/web/scripts/tenant/TenantDelete.java b/source/java/org/alfresco/repo/web/scripts/tenant/TenantDelete.java new file mode 100644 index 0000000000..3f3484446c --- /dev/null +++ b/source/java/org/alfresco/repo/web/scripts/tenant/TenantDelete.java @@ -0,0 +1,52 @@ +/* + * Copyright (C) 2005-2013 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.tenant; + +import java.util.HashMap; +import java.util.Map; + +import org.apache.commons.logging.Log; +import org.apache.commons.logging.LogFactory; +import org.springframework.extensions.webscripts.Cache; +import org.springframework.extensions.webscripts.Status; +import org.springframework.extensions.webscripts.WebScriptRequest; + +/** + * REST API - delete tenant + * + * @author janv + * @since 4.2 + */ +public class TenantDelete extends AbstractTenantAdminWebScript +{ + protected static final Log logger = LogFactory.getLog(TenantPost.class); + + @Override + protected Map executeImpl(WebScriptRequest req, Status status, Cache cache) + { + // get request parameters + Map templateVars = req.getServiceMatch().getTemplateVars(); + String tenantDomain = templateVars.get("tenantDomain"); + + tenantAdminService.deleteTenant(tenantDomain); + + Map model = new HashMap(0); + return model; + } +} diff --git a/source/java/org/alfresco/repo/web/scripts/tenant/TenantPost.java b/source/java/org/alfresco/repo/web/scripts/tenant/TenantPost.java new file mode 100644 index 0000000000..0c6fff64dc --- /dev/null +++ b/source/java/org/alfresco/repo/web/scripts/tenant/TenantPost.java @@ -0,0 +1,87 @@ +/* + * Copyright (C) 2005-2013 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.tenant; + +import java.io.IOException; +import java.util.HashMap; +import java.util.Map; + +import org.apache.commons.logging.Log; +import org.apache.commons.logging.LogFactory; +import org.json.JSONException; +import org.json.JSONObject; +import org.json.JSONTokener; +import org.springframework.extensions.webscripts.Cache; +import org.springframework.extensions.webscripts.Status; +import org.springframework.extensions.webscripts.WebScriptException; +import org.springframework.extensions.webscripts.WebScriptRequest; + +/** + * REST API - create tenant + * + * @author janv + * @since 4.2 + */ +public class TenantPost extends AbstractTenantAdminWebScript +{ + protected static final Log logger = LogFactory.getLog(TenantPost.class); + + @Override + protected Map executeImpl(WebScriptRequest req, Status status, Cache cache) + { + String tenantDomain = null; + String tenantAdminPassword = null; + String contentStoreRoot = null; + + try + { + JSONObject json = new JSONObject(new JSONTokener(req.getContent().getContent())); + + if (! json.has(TENANT_DOMAIN)) + { + throw new WebScriptException(Status.STATUS_BAD_REQUEST, "Could not find required 'tenantDomain' parameter"); + } + tenantDomain = json.getString(TENANT_DOMAIN); + + if (! json.has(TENANT_ADMIN_PASSWORD)) + { + throw new WebScriptException(Status.STATUS_BAD_REQUEST, "Could not find required 'tenantAdminPassword' parameter"); + } + tenantAdminPassword = json.getString(TENANT_ADMIN_PASSWORD); + + if (json.has(TENANT_CONTENT_STORE_ROOT)) + { + contentStoreRoot = json.getString(TENANT_CONTENT_STORE_ROOT); + } + } + catch (IOException iox) + { + throw new WebScriptException(Status.STATUS_BAD_REQUEST, "Could not read content from req.", iox); + } + catch (JSONException je) + { + throw new WebScriptException(Status.STATUS_BAD_REQUEST, "Could not parse JSON from req.", je); + } + + tenantAdminService.createTenant(tenantDomain, tenantAdminPassword.toCharArray(), contentStoreRoot); + + Map model = new HashMap(0); + return model; + } +} diff --git a/source/java/org/alfresco/repo/web/scripts/tenant/TenantsGet.java b/source/java/org/alfresco/repo/web/scripts/tenant/TenantsGet.java new file mode 100644 index 0000000000..34376916b6 --- /dev/null +++ b/source/java/org/alfresco/repo/web/scripts/tenant/TenantsGet.java @@ -0,0 +1,59 @@ +/* + * Copyright (C) 2005-2013 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.tenant; + +import java.util.HashMap; +import java.util.List; +import java.util.Map; + +import org.alfresco.repo.tenant.Tenant; +import org.apache.commons.logging.Log; +import org.apache.commons.logging.LogFactory; +import org.springframework.extensions.webscripts.Cache; +import org.springframework.extensions.webscripts.Status; +import org.springframework.extensions.webscripts.WebScriptRequest; + +/** + * REST API - get tenants + * + * TODO filter params - eg. enabled/ disabled and name startsWith + * + * @author janv + * @since 4.2 + */ +public class TenantsGet extends AbstractTenantAdminWebScript +{ + protected static final Log logger = LogFactory.getLog(TenantsGet.class); + + @Override + protected Map executeImpl(WebScriptRequest req, Status status, Cache cache) + { + List tenants = tenantAdminService.getAllTenants(); + + Map model = new HashMap(1); + model.put("tenants", tenants); + + if (logger.isDebugEnabled()) + { + logger.debug("Result: \n\tRequest: " + req + "\n\tModel: " + model); + } + + return model; + } +} diff --git a/source/java/org/alfresco/slingshot/web/scripts/NodeBrowserScript.java b/source/java/org/alfresco/slingshot/web/scripts/NodeBrowserScript.java index 96eef9b48d..5b631ed188 100644 --- a/source/java/org/alfresco/slingshot/web/scripts/NodeBrowserScript.java +++ b/source/java/org/alfresco/slingshot/web/scripts/NodeBrowserScript.java @@ -1,3 +1,21 @@ +/* + * 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.slingshot.web.scripts; import java.io.IOException; @@ -54,6 +72,7 @@ public class NodeBrowserScript extends DeclarativeWebScript private static List queryLanguages = new ArrayList(); static { + queryLanguages.add("storeroot"); queryLanguages.add("noderef"); queryLanguages.add(SearchService.LANGUAGE_XPATH); queryLanguages.add(SearchService.LANGUAGE_LUCENE); @@ -459,8 +478,16 @@ public class NodeBrowserScript extends DeclarativeWebScript { public List execute() throws Throwable { - List searchResults = null; - if (queryLanguage.equals("noderef")) + List searchResults = null; + + if (queryLanguage.equals("storeroot")) + { + NodeRef rootNodeRef = getNodeService().getRootNode(storeRef); + searchResults = new ArrayList(1); + searchResults.add(new Node(rootNodeRef)); + return searchResults; + } + else if (queryLanguage.equals("noderef")) { // ensure node exists NodeRef nodeRef = new NodeRef(query);