ACE-2682: MT: Failure occurs when creating tenant with specified contentstore directory

This is not a nice solution, nicer would be if we could allow Spring's ProxyFactoryBean to discover all the interfaces implemented by the underlying bean.

git-svn-id: https://svn.alfresco.com/repos/alfresco-enterprise/alfresco/HEAD/root@85696 c4b6b30b-aa2e-2d43-bbcb-ca4b014f7261
This commit is contained in:
Matt Ward
2014-09-25 09:56:02 +00:00
parent e507f9ea55
commit 0758dc4431
5 changed files with 318 additions and 10 deletions

View File

@@ -45,7 +45,7 @@
</bean> </bean>
<!-- Import the selected ContentStore subsystem's fileContentStore bean for use in the main repository context --> <!-- Import the selected ContentStore subsystem's fileContentStore bean for use in the main repository context -->
<bean id="fileContentStore" class="org.alfresco.repo.management.subsystems.SubsystemProxyFactory"> <bean id="fileContentStore" class="org.alfresco.repo.management.subsystems.CryptodocSubsystemProxyFactory">
<property name="sourceApplicationContextFactory"> <property name="sourceApplicationContextFactory">
<ref bean="ContentStore" /> <ref bean="ContentStore" />
</property> </property>
@@ -55,6 +55,7 @@
<property name="interfaces"> <property name="interfaces">
<list> <list>
<value>org.alfresco.repo.content.ContentStore</value> <value>org.alfresco.repo.content.ContentStore</value>
<value>org.alfresco.repo.content.ContentStoreCaps</value>
</list> </list>
</property> </property>
</bean> </bean>

View File

@@ -0,0 +1,83 @@
/*
* Copyright (C) 2005-2012 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 <http://www.gnu.org/licenses/>.
*/
package org.alfresco.repo.management.subsystems;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import org.alfresco.repo.tenant.TenantDeployer;
import org.alfresco.repo.tenant.TenantRoutingContentStore;
import org.aopalliance.intercept.MethodInterceptor;
import org.aopalliance.intercept.MethodInvocation;
import org.springframework.aop.support.DefaultPointcutAdvisor;
public class CryptodocSubsystemProxyFactory extends SubsystemProxyFactory
{
private static final long serialVersionUID = 1L;
public CryptodocSubsystemProxyFactory()
{
super();
addAdvisor(0, new DefaultPointcutAdvisor(new MethodInterceptor()
{
public Object invoke(MethodInvocation mi) throws Throwable
{
Method method = mi.getMethod();
try
{
switch (method.getName())
{
case "getTenantRoutingContentStore":
return getTenantRoutingContentStore(mi);
case "getTenantDeployer":
return getTenantDeployer(mi);
default:
return mi.proceed();
}
}
catch (InvocationTargetException e)
{
// Unwrap invocation target exceptions
throw e.getTargetException();
}
}
private TenantDeployer getTenantDeployer(MethodInvocation mi)
{
Object bean = locateBean(mi);
if (bean instanceof TenantDeployer)
{
return (TenantDeployer) bean;
}
return null;
}
private TenantRoutingContentStore getTenantRoutingContentStore(MethodInvocation mi)
{
Object bean = locateBean(mi);
if (bean instanceof TenantRoutingContentStore)
{
return (TenantRoutingContentStore) bean;
}
return null;
}
}));
}
}

View File

@@ -162,7 +162,7 @@ public class SubsystemProxyFactory extends ProxyFactoryBean implements Applicati
// Bring our cached copies of the source beans in line with the application context factory, using a RW lock to // Bring our cached copies of the source beans in line with the application context factory, using a RW lock to
// ensure consistency // ensure consistency
private Object locateBean(MethodInvocation mi) protected Object locateBean(MethodInvocation mi)
{ {
boolean haveWriteLock = false; boolean haveWriteLock = false;
this.lock.readLock().lock(); this.lock.readLock().lock();

View File

@@ -34,6 +34,7 @@ import net.sf.acegisecurity.providers.encoding.PasswordEncoder;
import org.alfresco.error.AlfrescoRuntimeException; import org.alfresco.error.AlfrescoRuntimeException;
import org.alfresco.repo.admin.RepoModelDefinition; import org.alfresco.repo.admin.RepoModelDefinition;
import org.alfresco.repo.content.ContentStore; import org.alfresco.repo.content.ContentStore;
import org.alfresco.repo.content.ContentStoreCaps;
import org.alfresco.repo.dictionary.DictionaryComponent; import org.alfresco.repo.dictionary.DictionaryComponent;
import org.alfresco.repo.domain.tenant.TenantAdminDAO; import org.alfresco.repo.domain.tenant.TenantAdminDAO;
import org.alfresco.repo.domain.tenant.TenantEntity; import org.alfresco.repo.domain.tenant.TenantEntity;
@@ -282,11 +283,11 @@ public class MultiTAdminServiceImpl implements TenantAdminService, ApplicationCo
// register dictionary - to allow enable/disable tenant callbacks // register dictionary - to allow enable/disable tenant callbacks
register(dictionaryComponent); register(dictionaryComponent);
if (tenantFileContentStore instanceof TenantDeployer) if (isTenantDeployer(tenantFileContentStore))
{ {
// register file store - to allow enable/disable tenant callbacks // register file store - to allow enable/disable tenant callbacks
// note: tenantFileContentStore must be registed before dictionaryRepositoryBootstrap // note: tenantFileContentStore must be registed before dictionaryRepositoryBootstrap
register((TenantDeployer)tenantFileContentStore, 0); register(tenantDeployer(tenantFileContentStore), 0);
} }
UserTransaction userTransaction = transactionService.getUserTransaction(); UserTransaction userTransaction = transactionService.getUserTransaction();
@@ -304,7 +305,7 @@ public class MultiTAdminServiceImpl implements TenantAdminService, ApplicationCo
for (Tenant tenant : tenants) for (Tenant tenant : tenants)
{ {
if ((! (tenantFileContentStore instanceof TenantRoutingContentStore)) && (! tenantFileContentStore.getRootLocation().equals(tenant.getRootContentStoreDir()))) if ((! (isTenantRoutingContentStore(tenantFileContentStore))) && (! tenantFileContentStore.getRootLocation().equals(tenant.getRootContentStoreDir())))
{ {
// eg. ALF-14121 - MT will not work with replicating-content-services-context.sample if tenants are not co-mingled // eg. ALF-14121 - MT will not work with replicating-content-services-context.sample if tenants are not co-mingled
throw new AlfrescoRuntimeException("MT: cannot start tenants - TenantRoutingContentStore is not configured AND not all tenants use co-mingled content store"); throw new AlfrescoRuntimeException("MT: cannot start tenants - TenantRoutingContentStore is not configured AND not all tenants use co-mingled content store");
@@ -438,9 +439,10 @@ public class MultiTAdminServiceImpl implements TenantAdminService, ApplicationCo
{ {
dictionaryComponent.init(); dictionaryComponent.init();
if (tenantFileContentStore instanceof TenantDeployer) if (isTenantDeployer(tenantFileContentStore))
{ {
((TenantDeployer)tenantFileContentStore).init(); TenantDeployer deployer = tenantDeployer(tenantFileContentStore);
deployer.init();
} }
// callback // callback
@@ -553,9 +555,10 @@ public class MultiTAdminServiceImpl implements TenantAdminService, ApplicationCo
dictionaryComponent.init(); dictionaryComponent.init();
if (tenantFileContentStore instanceof TenantDeployer) if (isTenantDeployer(tenantFileContentStore))
{ {
((TenantDeployer)tenantFileContentStore).init(); TenantDeployer deployer = tenantDeployer(tenantFileContentStore);
deployer.init();
} }
// import tenant-specific stores // import tenant-specific stores
@@ -1262,6 +1265,47 @@ public class MultiTAdminServiceImpl implements TenantAdminService, ApplicationCo
} }
} }
protected TenantRoutingContentStore tenantRoutingContentStore(ContentStore contentStore)
{
if (contentStore instanceof TenantRoutingContentStore)
{
return (TenantRoutingContentStore) contentStore;
}
else if (contentStore instanceof ContentStoreCaps)
{
ContentStoreCaps capabilities = (ContentStoreCaps) contentStore;
return (TenantRoutingContentStore) capabilities.getTenantRoutingContentStore();
}
return null;
}
protected boolean isTenantRoutingContentStore(ContentStore contentStore)
{
boolean router = tenantRoutingContentStore(contentStore) != null;
return router;
}
protected TenantDeployer tenantDeployer(ContentStore contentStore)
{
if (contentStore instanceof TenantDeployer)
{
return (TenantDeployer) contentStore;
}
else if (contentStore instanceof ContentStoreCaps)
{
ContentStoreCaps capabilities = (ContentStoreCaps) contentStore;
return (TenantDeployer) capabilities.getTenantDeployer();
}
return null;
}
protected boolean isTenantDeployer(ContentStore contentStore)
{
boolean deployer = tenantDeployer(contentStore) != null;
return deployer;
}
private void initTenant(String tenantDomain, String contentRoot, String dbUrl) private void initTenant(String tenantDomain, String contentRoot, String dbUrl)
{ {
validateTenantName(tenantDomain); validateTenantName(tenantDomain);
@@ -1277,7 +1321,7 @@ public class MultiTAdminServiceImpl implements TenantAdminService, ApplicationCo
} }
else else
{ {
if (! (tenantFileContentStore instanceof TenantRoutingContentStore)) if (! isTenantRoutingContentStore(tenantFileContentStore))
{ {
// eg. ALF-14121 - MT will not work with replicating-content-services-context.sample // eg. ALF-14121 - MT will not work with replicating-content-services-context.sample
throw new AlfrescoRuntimeException("MT: cannot initialse tenant - TenantRoutingContentStore is not configured AND tenant is not using co-mingled content store (ie. default root location)"); throw new AlfrescoRuntimeException("MT: cannot initialse tenant - TenantRoutingContentStore is not configured AND tenant is not using co-mingled content store (ie. default root location)");

View File

@@ -0,0 +1,180 @@
package org.alfresco.repo.tenant;
import static org.junit.Assert.*;
import org.alfresco.repo.content.AbstractContentStore;
import org.alfresco.repo.content.ContentStore;
import org.alfresco.repo.content.ContentStoreCaps;
import org.alfresco.service.cmr.repository.ContentReader;
import org.junit.Before;
import org.junit.Test;
public class MultiTAdminServiceImplTest
{
private MultiTAdminServiceImpl tenantAdmin;
@Before
public void setUp() throws Exception
{
tenantAdmin = new MultiTAdminServiceImpl();
}
@Test
public void testTenantDeployer()
{
ContentStore contentStore = new ConcreteTenantDeployer();
TenantDeployer tenantDeployer = tenantAdmin.tenantDeployer(contentStore);
assertNotNull(tenantDeployer);
}
@Test
public void testTenantDeployerRetrievedByContentStoreCaps()
{
ContentStore contentStore = new FakeSubsystemProxy(false);
TenantDeployer tenantDeployer = tenantAdmin.tenantDeployer(contentStore);
assertNotNull(tenantDeployer);
}
@Test
public void testTenantDeployerMayBeNullWhenInterfaceNotImplemented()
{
ContentStore contentStore = new BaseStore();
TenantDeployer tenantDeployer = tenantAdmin.tenantDeployer(contentStore);
assertNull(tenantDeployer);
}
@Test
public void testTenantDeployerMayBeNullWhenProxyingAndInterfaceNotImplemented()
{
// Represents proxy in front of non-TenantDeployer ContentStore
ContentStore contentStore = new FakeSubsystemProxy(true);
TenantDeployer tenantDeployer = tenantAdmin.tenantDeployer(contentStore);
assertNull(tenantDeployer);
}
@Test
public void testTenantRoutingContentStore()
{
ContentStore contentStore = new ConcreteTenantRoutingContentStore();
TenantRoutingContentStore router = tenantAdmin.tenantRoutingContentStore(contentStore);
assertNotNull(router);
}
@Test
public void testTenantRoutingContentStoreRetrievedByContentStoreCaps()
{
ContentStore contentStore = new FakeSubsystemProxy(false);
TenantRoutingContentStore router = tenantAdmin.tenantRoutingContentStore(contentStore);
assertNotNull(router);
}
@Test
public void testTenantRoutingContentStoreMayBeNullWhenInterfaceNotImplemented()
{
ContentStore contentStore = new BaseStore();
TenantRoutingContentStore router = tenantAdmin.tenantRoutingContentStore(contentStore);
assertNull(router);
}
@Test
public void testTenantRoutingContentStoreMayBeNullWhenProxyingAndInterfaceNotImplemented()
{
// Represents proxy in front of non-TenantRoutingContentStore ContentStore
ContentStore contentStore = new FakeSubsystemProxy(true);
TenantRoutingContentStore router = tenantAdmin.tenantRoutingContentStore(contentStore);
assertNull(router);
}
// This is implemented by the CryptodocSubsystemProxyFactory in real life.
private static class FakeSubsystemProxy extends BaseStore implements ContentStoreCaps
{
private boolean returnNull;
FakeSubsystemProxy(boolean returnNull)
{
this.returnNull = returnNull;
}
@Override
public TenantDeployer getTenantRoutingContentStore()
{
// would return the underlying ContentStore bean in real life (or null).
return returnNull ? null : new ConcreteTenantRoutingContentStore();
}
@Override
public TenantDeployer getTenantDeployer()
{
// would return the underlying ContentStore bean in real life (or null).
return returnNull ? null : new ConcreteTenantDeployer();
}
}
private static class ConcreteTenantDeployer extends BaseStore implements TenantDeployer
{
@Override
public void onEnableTenant()
{
}
@Override
public void onDisableTenant()
{
}
@Override
public void init()
{
}
@Override
public void destroy()
{
}
}
private static class ConcreteTenantRoutingContentStore extends BaseStore implements TenantRoutingContentStore
{
@Override
public void onEnableTenant()
{
}
@Override
public void onDisableTenant()
{
}
@Override
public void init()
{
}
@Override
public void destroy()
{
}
}
private static class BaseStore extends AbstractContentStore
{
@Override
public boolean isWriteSupported()
{
return false;
}
@Override
public ContentReader getReader(String contentUrl)
{
return null;
}
}
}