MOB-659 (part 2 of 2) - improve dictionary cache reset (should work even with null / cache)

git-svn-id: https://svn.alfresco.com/repos/alfresco-enterprise/alfresco/HEAD/root@14059 c4b6b30b-aa2e-2d43-bbcb-ca4b014f7261
This commit is contained in:
Jan Vonka
2009-04-23 10:29:32 +00:00
parent 9c91679af7
commit f28579cc8e
24 changed files with 777 additions and 532 deletions

View File

@@ -148,11 +148,6 @@
<property name="transactionService" ref="transactionService"/> <property name="transactionService" ref="transactionService"/>
</bean> </bean>
<!-- Bootstrap MT (multi-tenancy) if applicable -->
<bean id="multiTenantBootstrap" class="org.alfresco.repo.tenant.MultiTenantBootstrap" >
<property name="tenantAdminService" ref="tenantAdminService" />
</bean>
<!-- Load models --> <!-- Load models -->
<bean id="dictionaryRepositoryBootstrap" class="org.alfresco.repo.dictionary.DictionaryRepositoryBootstrap"> <bean id="dictionaryRepositoryBootstrap" class="org.alfresco.repo.dictionary.DictionaryRepositoryBootstrap">
@@ -278,6 +273,11 @@
<property name="repositoryWorkflowDefsLocations" ref="customWorkflowDefsRepositoryLocation"/> <property name="repositoryWorkflowDefsLocations" ref="customWorkflowDefsRepositoryLocation"/>
</bean> </bean>
<!-- Bootstrap MT (multi-tenancy) if applicable -->
<bean id="multiTenantBootstrap" class="org.alfresco.repo.tenant.MultiTenantBootstrap" >
<property name="tenantAdminService" ref="tenantAdminService" />
</bean>
<bean id="personDaoBootstrap" class="org.alfresco.repo.security.person.PersonDaoBootstrap" > <bean id="personDaoBootstrap" class="org.alfresco.repo.security.person.PersonDaoBootstrap" >
<property name="personDaoImpl"> <property name="personDaoImpl">
<ref bean="personDaoImpl"/> <ref bean="personDaoImpl"/>

View File

@@ -636,39 +636,7 @@
<!-- Dictionary / Namespace Caches --> <!-- Dictionary / Namespace Caches -->
<!-- ===================================== --> <!-- ===================================== -->
<!-- The cross-transaction shared cache for In-Memory UriToModels --> <!-- The cross-transaction shared cache for Dictionary Models -->
<bean name="uriToModelsSharedCache" class="org.alfresco.repo.cache.EhCacheAdapter">
<property name="cache">
<bean class="org.springframework.cache.ehcache.EhCacheFactoryBean" >
<property name="cacheManager">
<ref bean="internalEHCacheManager" />
</property>
<property name="cacheName">
<value>org.alfresco.cache.uriToModelsCache</value>
</property>
</bean>
</property>
</bean>
<!-- The transactional cache for In-Memory UriToModels -->
<bean name="uriToModelsCache" class="org.alfresco.repo.cache.TransactionalCache">
<property name="sharedCache">
<ref bean="uriToModelsSharedCache" />
</property>
<property name="cacheManager" >
<ref bean="transactionalEHCacheManager" />
</property>
<property name="name">
<value>org.alfresco.uriToModelsTransactionalCache</value>
</property>
<property name="maxCacheSize">
<value>100</value>
</property>
</bean>
<!-- The cross-transaction shared cache for In-Memory CompiledModels -->
<bean name="compiledModelsSharedCache" class="org.alfresco.repo.cache.EhCacheAdapter"> <bean name="compiledModelsSharedCache" class="org.alfresco.repo.cache.EhCacheAdapter">
<property name="cache"> <property name="cache">
@@ -683,7 +651,7 @@
</property> </property>
</bean> </bean>
<!-- The transactional cache for In-Memory CompiledModels --> <!-- The transactional cache for Dictionary Models -->
<bean name="compiledModelsCache" class="org.alfresco.repo.cache.TransactionalCache"> <bean name="compiledModelsCache" class="org.alfresco.repo.cache.TransactionalCache">
<property name="sharedCache"> <property name="sharedCache">
@@ -700,39 +668,7 @@
</property> </property>
</bean> </bean>
<!-- The cross-transaction shared cache for In-Memory Namespace Uris --> <!-- The cross-transaction shared cache for Dictionary Namespaces -->
<bean name="urisSharedCache" class="org.alfresco.repo.cache.EhCacheAdapter">
<property name="cache">
<bean class="org.springframework.cache.ehcache.EhCacheFactoryBean" >
<property name="cacheManager">
<ref bean="internalEHCacheManager" />
</property>
<property name="cacheName">
<value>org.alfresco.cache.urisCache</value>
</property>
</bean>
</property>
</bean>
<!-- The transactional cache for In-Memory Namespace Uris -->
<bean name="urisCache" class="org.alfresco.repo.cache.TransactionalCache">
<property name="sharedCache">
<ref bean="urisSharedCache" />
</property>
<property name="cacheManager" >
<ref bean="transactionalEHCacheManager" />
</property>
<property name="name">
<value>org.alfresco.urisTransactionalCache</value>
</property>
<property name="maxCacheSize">
<value>100</value>
</property>
</bean>
<!-- The cross-transaction shared cache for In-Memory Namespace Prefixes -->
<bean name="prefixesSharedCache" class="org.alfresco.repo.cache.EhCacheAdapter"> <bean name="prefixesSharedCache" class="org.alfresco.repo.cache.EhCacheAdapter">
<property name="cache"> <property name="cache">
@@ -747,7 +683,7 @@
</property> </property>
</bean> </bean>
<!-- The transactional cache for In-Memory Namespace Prefixes --> <!-- The transactional cache for Dictionary Namespaces -->
<bean name="prefixesCache" class="org.alfresco.repo.cache.TransactionalCache"> <bean name="prefixesCache" class="org.alfresco.repo.cache.TransactionalCache">
<property name="sharedCache"> <property name="sharedCache">

View File

@@ -863,7 +863,7 @@
<property name="tenantService"> <property name="tenantService">
<ref bean="tenantService"/> <ref bean="tenantService"/>
</property> </property>
<property name="namespaceDataCache"> <property name="namespaceRegistryCache">
<ref bean="prefixesCache"/> <ref bean="prefixesCache"/>
</property> </property>
</bean> </bean>
@@ -890,10 +890,7 @@
<property name="tenantService"> <property name="tenantService">
<ref bean="tenantService"/> <ref bean="tenantService"/>
</property> </property>
<property name="uriToModelsCache"> <property name="dictionaryRegistryCache">
<ref bean="uriToModelsCache"/>
</property>
<property name="compiledModelsCache">
<ref bean="compiledModelsCache"/> <ref bean="compiledModelsCache"/>
</property> </property>
</bean> </bean>

View File

@@ -380,13 +380,6 @@
<!-- Dictionary / Namespace (tenant-based) --> <!-- Dictionary / Namespace (tenant-based) -->
<!-- dictionary models --> <!-- dictionary models -->
<cache
name="org.alfresco.cache.uriToModelsCache"
maxElementsInMemory="100"
eternal="true"
overflowToDisk="false"
/>
<cache <cache
name="org.alfresco.cache.compiledModelsCache" name="org.alfresco.cache.compiledModelsCache"
maxElementsInMemory="100" maxElementsInMemory="100"

View File

@@ -876,22 +876,6 @@
<!-- Dictionary / Namespace (tenant-based) --> <!-- Dictionary / Namespace (tenant-based) -->
<cache
name="org.alfresco.cache.uriToModelsCache"
maxElementsInMemory="100"
eternal="true"
overflowToDisk="false">
<cacheEventListenerFactory
class="net.sf.ehcache.distribution.RMICacheReplicatorFactory"
properties="replicatePuts = false,
replicateUpdates = true,
replicateRemovals = true,
replicateUpdatesViaCopy = false,
replicateAsynchronously = false"/>
</cache>
<cache <cache
name="org.alfresco.cache.compiledModelsCache" name="org.alfresco.cache.compiledModelsCache"
maxElementsInMemory="100" maxElementsInMemory="100"

View File

@@ -1,5 +1,5 @@
/* /*
* Copyright (C) 2005-2007 Alfresco Software Limited. * Copyright (C) 2005-2009 Alfresco Software Limited.
* *
* This program is free software; you can redistribute it and/or * This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License * modify it under the terms of the GNU General Public License
@@ -275,8 +275,10 @@ import org.apache.commons.logging.LogFactory;
} }
classes.add(def); classes.add(def);
if (logger.isDebugEnabled()) if (logger.isTraceEnabled())
logger.debug("Resolving inheritance: class " + def.getName() + " found at depth " + depth); {
logger.trace("Resolving inheritance: class " + def.getName() + " found at depth " + depth);
}
} }
// Resolve inheritance of each class // Resolve inheritance of each class

View File

@@ -137,8 +137,10 @@ public class DictionaryBootstrap implements DictionaryListener
} }
try try
{ {
if (logger.isInfoEnabled()) if (logger.isDebugEnabled())
logger.info("Loading model from " + bootstrapModel); {
logger.debug("Loading model from " + bootstrapModel);
}
M2Model model = M2Model.createModel(modelStream); M2Model model = M2Model.createModel(modelStream);
dictionaryDAO.putModel(model); dictionaryDAO.putModel(model);

View File

@@ -1,5 +1,5 @@
/* /*
* Copyright (C) 2005-2007 Alfresco Software Limited. * Copyright (C) 2005-2009 Alfresco Software Limited.
* *
* This program is free software; you can redistribute it and/or * This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License * modify it under the terms of the GNU General Public License
@@ -64,13 +64,6 @@ import org.apache.commons.logging.LogFactory;
*/ */
public class DictionaryDAOImpl implements DictionaryDAO public class DictionaryDAOImpl implements DictionaryDAO
{ {
// TODO: Allow for the dynamic creation of models. Supporting
// this requires the ability to persistently store the
// registration of models, the ability to load models
// from a persistent store, the refresh of the cache
// and concurrent read/write of the models.
// (in progress)
/** /**
* Lock objects * Lock objects
*/ */
@@ -84,11 +77,12 @@ public class DictionaryDAOImpl implements DictionaryDAO
// Tenant Service // Tenant Service
private TenantService tenantService; private TenantService tenantService;
// Map of Namespace URI usages to Models // Internal cache (clusterable)
private SimpleCache<String, Map<String, List<CompiledModel>>> uriToModelsCache; private SimpleCache<String, DictionaryRegistry> dictionaryRegistryCache;
// Map of model name to compiled model // used to reset the cache
private SimpleCache<String, Map<QName,CompiledModel>> compiledModelsCache; private ThreadLocal<DictionaryRegistry> dictionaryRegistryThreadLocal = new ThreadLocal<DictionaryRegistry>();
private ThreadLocal<DictionaryRegistry> defaultDictionaryRegistryThreadLocal = new ThreadLocal<DictionaryRegistry>();
// Static list of registered dictionary listeners // Static list of registered dictionary listeners
private List<DictionaryListener> dictionaryListeners = new ArrayList<DictionaryListener>(); private List<DictionaryListener> dictionaryListeners = new ArrayList<DictionaryListener>();
@@ -104,14 +98,9 @@ public class DictionaryDAOImpl implements DictionaryDAO
this.tenantService = tenantService; this.tenantService = tenantService;
} }
public void setUriToModelsCache(SimpleCache<String, Map<String, List<CompiledModel>>> uriToModelsCache) public void setDictionaryRegistryCache(SimpleCache<String, DictionaryRegistry> dictionaryRegistryCache)
{ {
this.uriToModelsCache = uriToModelsCache; this.dictionaryRegistryCache = dictionaryRegistryCache;
}
public void setCompiledModelsCache(SimpleCache<String, Map<QName,CompiledModel>> compiledModelsCache)
{
this.compiledModelsCache = compiledModelsCache;
} }
/** /**
@@ -133,6 +122,7 @@ public class DictionaryDAOImpl implements DictionaryDAO
{ {
if (! dictionaryListeners.contains(dictionaryDeployer)) if (! dictionaryListeners.contains(dictionaryDeployer))
{ {
destroy(); // force reload on next get
dictionaryListeners.add(dictionaryDeployer); dictionaryListeners.add(dictionaryDeployer);
} }
} }
@@ -142,27 +132,7 @@ public class DictionaryDAOImpl implements DictionaryDAO
*/ */
public void init() public void init()
{ {
String tenantDomain = tenantService.getCurrentUserDomain(); initDictionary(tenantService.getCurrentUserDomain());
// initialise empty dictionary & namespaces
putCompiledModels(tenantDomain, new HashMap<QName,CompiledModel>());
putUriToModels(tenantDomain, new HashMap<String, List<CompiledModel>>());
namespaceDAO.init();
// populate the dictionary
for (DictionaryListener dictionaryListener : dictionaryListeners)
{
dictionaryListener.onDictionaryInit();
}
// notify registered listeners that dictionary has been initialised
for (DictionaryListener dictionaryListener : dictionaryListeners)
{
dictionaryListener.afterDictionaryInit();
}
logger.info("Dictionary initialised");
} }
/** /**
@@ -172,8 +142,7 @@ public class DictionaryDAOImpl implements DictionaryDAO
{ {
String tenantDomain = tenantService.getCurrentUserDomain(); String tenantDomain = tenantService.getCurrentUserDomain();
removeCompiledModels(tenantDomain); removeDictionaryRegistry(tenantDomain);
removeUriToModels(tenantDomain);
namespaceDAO.destroy(); namespaceDAO.destroy();
@@ -183,41 +152,117 @@ public class DictionaryDAOImpl implements DictionaryDAO
dictionaryDeployer.afterDictionaryDestroy(); dictionaryDeployer.afterDictionaryDestroy();
} }
logger.info("Dictionary destroyed"); if (logger.isDebugEnabled())
{
logger.debug("Dictionary destroyed");
}
} }
/** /**
* Reset the Dictionary & Namespaces * Reset the Dictionary & Namespaces
*/ */
public void reset() public void reset()
{
reset(tenantService.getCurrentUserDomain());
}
private void reset(String tenantDomain)
{ {
if (logger.isDebugEnabled()) if (logger.isDebugEnabled())
{ {
logger.debug("Resetting dictionary ..."); logger.debug("Resetting dictionary ...");
} }
AuthenticationUtil.runAs(new RunAsWork<Object>()
{
public Object doWork()
{
destroy(); destroy();
init(); init();
return null;
}
}, tenantService.getDomainUser(AuthenticationUtil.getSystemUserName(), tenantDomain));
if (logger.isDebugEnabled()) if (logger.isDebugEnabled())
{ {
logger.debug("... resetting dictionary completed"); logger.debug("... resetting dictionary completed");
} }
} }
// load dictionary (models and namespaces)
private DictionaryRegistry initDictionary(final String tenantDomain)
{
long startTime = System.currentTimeMillis();
try
{
return AuthenticationUtil.runAs(new RunAsWork<DictionaryRegistry>()
{
public DictionaryRegistry doWork()
{
try
{
// create threadlocal, if needed
createDataDictionaryLocal(tenantDomain);
DictionaryRegistry dictionaryRegistry = initDictionaryRegistry(tenantDomain);
if (dictionaryRegistry == null)
{
// unexpected
throw new AlfrescoRuntimeException("Failed to init dictionaryRegistry " + tenantDomain);
}
try
{
writeLock.lock();
dictionaryRegistryCache.put(tenantDomain, dictionaryRegistry);
}
finally
{
writeLock.unlock();
}
return dictionaryRegistry;
}
finally
{
try
{
readLock.lock();
if (dictionaryRegistryCache.get(tenantDomain) != null)
{
removeDataDictionaryLocal(tenantDomain);
}
}
finally
{
readLock.unlock();
}
}
}
}, tenantService.getDomainUser(AuthenticationUtil.getSystemUserName(), tenantDomain));
}
finally
{
if (logger.isInfoEnabled())
{
logger.info("Init Dictionary: model count = "+(getModels() != null ? getModels().size() : 0) +" in "+(System.currentTimeMillis()-startTime)+" msecs "+(tenantDomain.equals(TenantService.DEFAULT_DOMAIN) ? "" : " (Tenant: "+tenantDomain+")"));
}
}
}
private DictionaryRegistry initDictionaryRegistry(String tenantDomain)
{
getDictionaryRegistry(tenantDomain).setCompiledModels(new HashMap<QName,CompiledModel>());
getDictionaryRegistry(tenantDomain).setUriToModels(new HashMap<String, List<CompiledModel>>());
// initialise empty dictionary & namespaces
namespaceDAO.init();
// populate the dictionary based on registered sources
for (DictionaryListener dictionaryDeployer : dictionaryListeners)
{
dictionaryDeployer.onDictionaryInit();
}
// notify registered listeners that dictionary has been initialised (population is complete)
for (DictionaryListener dictionaryListener : dictionaryListeners)
{
dictionaryListener.afterDictionaryInit();
}
return getDictionaryRegistryLocal(tenantDomain);
}
/* (non-Javadoc) /* (non-Javadoc)
* @see org.alfresco.repo.dictionary.impl.DictionaryDAO#putModel(org.alfresco.repo.dictionary.impl.M2Model) * @see org.alfresco.repo.dictionary.impl.DictionaryDAO#putModel(org.alfresco.repo.dictionary.impl.M2Model)
*/ */
@@ -260,19 +305,18 @@ public class DictionaryDAOImpl implements DictionaryDAO
// Publish new Model Definition // Publish new Model Definition
getCompiledModels(tenantDomain).put(modelName, compiledModel); getCompiledModels(tenantDomain).put(modelName, compiledModel);
if (logger.isInfoEnabled()) if (logger.isDebugEnabled())
{ {
logger.info("Registered model " + modelName.toPrefixString(namespaceDAO)); logger.debug("Registered model " + modelName.toPrefixString(namespaceDAO));
for (M2Namespace namespace : model.getNamespaces()) for (M2Namespace namespace : model.getNamespaces())
{ {
logger.info("Registered namespace '" + namespace.getUri() + "' (prefix '" + namespace.getPrefix() + "')"); logger.debug("Registered namespace '" + namespace.getUri() + "' (prefix '" + namespace.getPrefix() + "')");
} }
} }
return modelName; return modelName;
} }
/** /**
* @see org.alfresco.repo.dictionary.DictionaryDAO#removeModel(org.alfresco.service.namespace.QName) * @see org.alfresco.repo.dictionary.DictionaryDAO#removeModel(org.alfresco.service.namespace.QName)
*/ */
@@ -297,7 +341,6 @@ public class DictionaryDAOImpl implements DictionaryDAO
} }
} }
/** /**
* Map Namespace URI to Model * Map Namespace URI to Model
* *
@@ -319,7 +362,6 @@ public class DictionaryDAOImpl implements DictionaryDAO
} }
} }
/** /**
* Unmap Namespace URI from Model * Unmap Namespace URI from Model
* *
@@ -394,7 +436,6 @@ public class DictionaryDAOImpl implements DictionaryDAO
return models; return models;
} }
/** /**
* @param modelName the model name * @param modelName the model name
* @return the compiled model of the given name * @return the compiled model of the given name
@@ -440,7 +481,6 @@ public class DictionaryDAOImpl implements DictionaryDAO
return null; return null;
} }
/* (non-Javadoc) /* (non-Javadoc)
* @see org.alfresco.repo.dictionary.ModelQuery#getDataType(java.lang.Class) * @see org.alfresco.repo.dictionary.ModelQuery#getDataType(java.lang.Class)
*/ */
@@ -892,6 +932,120 @@ public class DictionaryDAOImpl implements DictionaryDAO
return namespaces; return namespaces;
} }
// re-entrant (eg. via reset)
private DictionaryRegistry getDictionaryRegistry(String tenantDomain)
{
DictionaryRegistry dictionaryRegistry = null;
try
{
// check cache first - return if set
readLock.lock();
dictionaryRegistry = dictionaryRegistryCache.get(tenantDomain);
if (dictionaryRegistry != null)
{
return dictionaryRegistry; // return cached config
}
}
finally
{
readLock.unlock();
}
// check threadlocal second - return if set
dictionaryRegistry = getDictionaryRegistryLocal(tenantDomain);
if (dictionaryRegistry != null)
{
return dictionaryRegistry; // return local dictionaryRegistry
}
// reset caches - may have been invalidated (e.g. in a cluster)
dictionaryRegistry = initDictionary(tenantDomain);
if (dictionaryRegistry == null)
{
// unexpected
throw new AlfrescoRuntimeException("Failed to get dictionaryRegistry " + tenantDomain);
}
return dictionaryRegistry;
}
// create threadlocal
private void createDataDictionaryLocal(String tenantDomain)
{
// create threadlocal, if needed
DictionaryRegistry dictionaryRegistry = getDictionaryRegistryLocal(tenantDomain);
if (dictionaryRegistry == null)
{
dictionaryRegistry = new DictionaryRegistry(tenantDomain);
if (tenantDomain.equals(TenantService.DEFAULT_DOMAIN))
{
defaultDictionaryRegistryThreadLocal.set(dictionaryRegistry);
}
else
{
dictionaryRegistryThreadLocal.set(dictionaryRegistry);
}
}
}
// get threadlocal
private DictionaryRegistry getDictionaryRegistryLocal(String tenantDomain)
{
DictionaryRegistry dictionaryRegistry = null;
if (tenantDomain.equals(TenantService.DEFAULT_DOMAIN))
{
dictionaryRegistry = this.defaultDictionaryRegistryThreadLocal.get();
}
else
{
dictionaryRegistry = this.dictionaryRegistryThreadLocal.get();
}
// check to see if domain switched
if ((dictionaryRegistry != null) && (tenantDomain.equals(dictionaryRegistry.getTenantDomain())))
{
return dictionaryRegistry; // return threadlocal, if set
}
return null;
}
// remove threadlocal
private void removeDataDictionaryLocal(String tenantDomain)
{
if (tenantDomain.equals(TenantService.DEFAULT_DOMAIN))
{
defaultDictionaryRegistryThreadLocal.set(null); // it's in the cache, clear the threadlocal
}
else
{
dictionaryRegistryThreadLocal.set(null); // it's in the cache, clear the threadlocal
}
}
private void removeDictionaryRegistry(String tenantDomain)
{
try
{
writeLock.lock();
if (dictionaryRegistryCache.get(tenantDomain) != null)
{
dictionaryRegistryCache.remove(tenantDomain);
}
removeDataDictionaryLocal(tenantDomain);
}
finally
{
writeLock.unlock();
}
}
/** /**
* Get compiledModels from the cache (in the context of the given tenant domain) * Get compiledModels from the cache (in the context of the given tenant domain)
* *
@@ -899,80 +1053,7 @@ public class DictionaryDAOImpl implements DictionaryDAO
*/ */
private Map<QName,CompiledModel> getCompiledModels(String tenantDomain) private Map<QName,CompiledModel> getCompiledModels(String tenantDomain)
{ {
Map<QName,CompiledModel> compiledModels = null; return getDictionaryRegistry(tenantDomain).getCompiledModels();
try
{
readLock.lock();
compiledModels = compiledModelsCache.get(tenantDomain);
}
finally
{
readLock.unlock();
}
if (compiledModels == null)
{
reset(tenantDomain); // reset caches - may have been invalidated (e.g. in a cluster)
try
{
readLock.lock();
compiledModels = compiledModelsCache.get(tenantDomain);
}
finally
{
readLock.unlock();
}
if (compiledModels == null)
{
// unexpected
throw new AlfrescoRuntimeException("Failed to re-initialise compiledModelsCache " + tenantDomain);
}
}
return compiledModels;
}
/**
* Put compiledModels into the cache (in the context of the given tenant domain)
*
* @param tenantDomain
*/
private void putCompiledModels(String tenantDomain, Map<QName, CompiledModel> compiledModels)
{
try
{
writeLock.lock();
compiledModelsCache.put(tenantDomain, compiledModels);
}
finally
{
writeLock.unlock();
}
}
/**
* Remove compiledModels from the cache (in the context of the given tenant domain)
*
* @param tenantDomain
*/
private void removeCompiledModels(String tenantDomain)
{
try
{
writeLock.lock();
if (compiledModelsCache.get(tenantDomain) != null)
{
compiledModelsCache.get(tenantDomain).clear();
compiledModelsCache.remove(tenantDomain);
}
}
finally
{
writeLock.unlock();
}
} }
/** /**
@@ -982,79 +1063,7 @@ public class DictionaryDAOImpl implements DictionaryDAO
*/ */
private Map<String, List<CompiledModel>> getUriToModels(String tenantDomain) private Map<String, List<CompiledModel>> getUriToModels(String tenantDomain)
{ {
Map<String, List<CompiledModel>> uriToModels = null; return getDictionaryRegistry(tenantDomain).getUriToModels();
try
{
readLock.lock();
uriToModels = uriToModelsCache.get(tenantDomain);
}
finally
{
readLock.unlock();
}
if (uriToModels == null)
{
reset(tenantDomain); // reset caches - may have been invalidated (e.g. in a cluster)
try
{
readLock.lock();
uriToModels = uriToModelsCache.get(tenantDomain);
}
finally
{
readLock.unlock();
}
if (uriToModels == null)
{
// unexpected
throw new AlfrescoRuntimeException("Failed to re-initialise uriToModelsCache " + tenantDomain);
}
}
return uriToModels;
}
/**
* Put uriToModels into the cache (in the context of the given tenant domain)
*
* @param tenantDomain
*/
private void putUriToModels(String tenantDomain, Map<String, List<CompiledModel>> uriToModels)
{
try
{
writeLock.lock();
uriToModelsCache.put(tenantDomain, uriToModels);
}
finally
{
writeLock.unlock();
}
}
/**
* Remove uriToModels from the cache (in the context of the given tenant domain)
*
* @param tenantDomain
*/
private void removeUriToModels(String tenantDomain)
{
try
{
writeLock.lock();
if (uriToModelsCache.get(tenantDomain) != null)
{
uriToModelsCache.get(tenantDomain).clear();
uriToModelsCache.remove(tenantDomain);
}
}
finally
{
writeLock.unlock();
}
} }
/** /**
@@ -1205,4 +1214,39 @@ public class DictionaryDAOImpl implements DictionaryDAO
} }
} }
} }
/* package */ class DictionaryRegistry
{
private Map<String, List<CompiledModel>> uriToModels = new HashMap<String, List<CompiledModel>>(0);
private Map<QName,CompiledModel> compiledModels = new HashMap<QName,CompiledModel>(0);
private String tenantDomain;
public DictionaryRegistry(String tenantDomain)
{
this.tenantDomain = tenantDomain;
}
public String getTenantDomain()
{
return tenantDomain;
}
public Map<String, List<CompiledModel>> getUriToModels()
{
return uriToModels;
}
public void setUriToModels(Map<String, List<CompiledModel>> uriToModels)
{
this.uriToModels = uriToModels;
}
public Map<QName, CompiledModel> getCompiledModels()
{
return compiledModels;
}
public void setCompiledModels(Map<QName, CompiledModel> compiledModels)
{
this.compiledModels = compiledModels;
}
}
} }

View File

@@ -39,7 +39,8 @@ import net.sf.ehcache.CacheManager;
import org.alfresco.i18n.I18NUtil; import org.alfresco.i18n.I18NUtil;
import org.alfresco.model.ContentModel; import org.alfresco.model.ContentModel;
import org.alfresco.repo.cache.EhCacheAdapter; import org.alfresco.repo.cache.EhCacheAdapter;
import org.alfresco.repo.dictionary.NamespaceDAOImpl.NamespaceData; import org.alfresco.repo.dictionary.DictionaryDAOImpl.DictionaryRegistry;
import org.alfresco.repo.dictionary.NamespaceDAOImpl.NamespaceRegistry;
import org.alfresco.repo.dictionary.constraint.RegexConstraint; import org.alfresco.repo.dictionary.constraint.RegexConstraint;
import org.alfresco.repo.dictionary.constraint.StringLengthConstraint; import org.alfresco.repo.dictionary.constraint.StringLengthConstraint;
import org.alfresco.repo.tenant.SingleTServiceImpl; import org.alfresco.repo.tenant.SingleTServiceImpl;
@@ -107,19 +108,12 @@ public class DictionaryDAOTest extends TestCase
{ {
CacheManager cacheManager = new CacheManager(); CacheManager cacheManager = new CacheManager();
Cache uriToModelsEhCache = new Cache("uriToModelsCache", 50, false, true, 0L, 0L); Cache dictionaryEhCache = new Cache("dictionaryCache", 50, false, true, 0L, 0L);
cacheManager.addCache(uriToModelsEhCache); cacheManager.addCache(dictionaryEhCache);
EhCacheAdapter<String, Map<String, List<CompiledModel>>> uriToModelsCache = new EhCacheAdapter<String, Map<String, List<CompiledModel>>>(); EhCacheAdapter<String, DictionaryRegistry> dictionaryCache = new EhCacheAdapter<String, DictionaryRegistry>();
uriToModelsCache.setCache(uriToModelsEhCache); dictionaryCache.setCache(dictionaryEhCache);
dictionaryDAO.setUriToModelsCache(uriToModelsCache); dictionaryDAO.setDictionaryRegistryCache(dictionaryCache);
Cache compileModelsEhCache = new Cache("compiledModelsCache", 50, false, true, 0L, 0L);
cacheManager.addCache(compileModelsEhCache);
EhCacheAdapter<String, Map<QName,CompiledModel>> compileModelCache = new EhCacheAdapter<String, Map<QName,CompiledModel>>();
compileModelCache.setCache(compileModelsEhCache);
dictionaryDAO.setCompiledModelsCache(compileModelCache);
} }
private void initNamespaceCaches(NamespaceDAOImpl namespaceDAO) private void initNamespaceCaches(NamespaceDAOImpl namespaceDAO)
@@ -128,10 +122,10 @@ public class DictionaryDAOTest extends TestCase
Cache namespaceEhCache = new Cache("namespaceCache", 50, false, true, 0L, 0L); Cache namespaceEhCache = new Cache("namespaceCache", 50, false, true, 0L, 0L);
cacheManager.addCache(namespaceEhCache); cacheManager.addCache(namespaceEhCache);
EhCacheAdapter<String, NamespaceData> namespaceCache = new EhCacheAdapter<String, NamespaceData>(); EhCacheAdapter<String, NamespaceRegistry> namespaceCache = new EhCacheAdapter<String, NamespaceRegistry>();
namespaceCache.setCache(namespaceEhCache); namespaceCache.setCache(namespaceEhCache);
namespaceDAO.setNamespaceDataCache(namespaceCache); namespaceDAO.setNamespaceRegistryCache(namespaceCache);
} }

View File

@@ -71,11 +71,12 @@ import org.apache.commons.logging.LogFactory;
/** /**
* Dictionary model type behaviour. * Dictionary model type behaviour.
* *
* @author Roy Wetherall * @author Roy Wetherall, janv
*/ */
public class DictionaryModelType implements ContentServicePolicies.OnContentUpdatePolicy, public class DictionaryModelType implements ContentServicePolicies.OnContentUpdatePolicy,
NodeServicePolicies.OnUpdatePropertiesPolicy, NodeServicePolicies.OnUpdatePropertiesPolicy,
NodeServicePolicies.BeforeDeleteNodePolicy, NodeServicePolicies.BeforeDeleteNodePolicy,
NodeServicePolicies.OnDeleteNodePolicy,
NodeServicePolicies.OnCreateNodePolicy, NodeServicePolicies.OnCreateNodePolicy,
NodeServicePolicies.OnRemoveAspectPolicy NodeServicePolicies.OnRemoveAspectPolicy
{ {
@@ -85,6 +86,9 @@ public class DictionaryModelType implements ContentServicePolicies.OnContentUpda
/** Key to the pending models */ /** Key to the pending models */
private static final String KEY_PENDING_MODELS = "dictionaryModelType.pendingModels"; private static final String KEY_PENDING_MODELS = "dictionaryModelType.pendingModels";
/** Key to the pending deleted models */
private static final String KEY_PENDING_DELETE_MODELS = "dictionaryModelType.pendingDeleteModels";
/** Key to the removed "workingcopy" aspect */ /** Key to the removed "workingcopy" aspect */
private static final String KEY_WORKING_COPY = "dictionaryModelType.workingCopy"; private static final String KEY_WORKING_COPY = "dictionaryModelType.workingCopy";
@@ -224,25 +228,31 @@ public class DictionaryModelType implements ContentServicePolicies.OnContentUpda
ContentModel.TYPE_DICTIONARY_MODEL, ContentModel.TYPE_DICTIONARY_MODEL,
new JavaBehaviour(this, "onContentUpdate")); new JavaBehaviour(this, "onContentUpdate"));
// Register interest in the onPropertyUpdate policy for the dictionary model type // Register interest in the onUpdateProperties policy for the dictionary model type
policyComponent.bindClassBehaviour( policyComponent.bindClassBehaviour(
QName.createQName(NamespaceService.ALFRESCO_URI, "onUpdateProperties"), QName.createQName(NamespaceService.ALFRESCO_URI, "onUpdateProperties"),
ContentModel.TYPE_DICTIONARY_MODEL, ContentModel.TYPE_DICTIONARY_MODEL,
new JavaBehaviour(this, "onUpdateProperties")); new JavaBehaviour(this, "onUpdateProperties"));
// Register interest in the node delete policy // Register interest in the beforeDeleteNode policy for the dictionary model type
policyComponent.bindClassBehaviour( policyComponent.bindClassBehaviour(
QName.createQName(NamespaceService.ALFRESCO_URI, "beforeDeleteNode"), QName.createQName(NamespaceService.ALFRESCO_URI, "beforeDeleteNode"),
ContentModel.TYPE_DICTIONARY_MODEL, ContentModel.TYPE_DICTIONARY_MODEL,
new JavaBehaviour(this, "beforeDeleteNode")); new JavaBehaviour(this, "beforeDeleteNode"));
// Register interest in the remove aspect policy // Register interest in the onDeleteNode policy for the dictionary model type
policyComponent.bindClassBehaviour(
QName.createQName(NamespaceService.ALFRESCO_URI, "onDeleteNode"),
ContentModel.TYPE_DICTIONARY_MODEL,
new JavaBehaviour(this, "onDeleteNode"));
// Register interest in the onRemoveAspect policy
policyComponent.bindClassBehaviour( policyComponent.bindClassBehaviour(
QName.createQName(NamespaceService.ALFRESCO_URI, "onRemoveAspect"), QName.createQName(NamespaceService.ALFRESCO_URI, "onRemoveAspect"),
this, this,
new JavaBehaviour(this, "onRemoveAspect")); new JavaBehaviour(this, "onRemoveAspect"));
// Register interest in the onCreateNode policy for the dictionary model type // Register interest in the onCreateNode policy
policyComponent.bindClassBehaviour( policyComponent.bindClassBehaviour(
QName.createQName(NamespaceService.ALFRESCO_URI, "onCreateNode"), QName.createQName(NamespaceService.ALFRESCO_URI, "onCreateNode"),
this, this,
@@ -321,6 +331,7 @@ public class DictionaryModelType implements ContentServicePolicies.OnContentUpda
} }
} }
@SuppressWarnings("unchecked")
public void beforeDeleteNode(NodeRef nodeRef) public void beforeDeleteNode(NodeRef nodeRef)
{ {
boolean workingCopy = nodeService.hasAspect(nodeRef, ContentModel.ASPECT_WORKING_COPY); boolean workingCopy = nodeService.hasAspect(nodeRef, ContentModel.ASPECT_WORKING_COPY);
@@ -346,8 +357,48 @@ public class DictionaryModelType implements ContentServicePolicies.OnContentUpda
// Validate model delete against usages - content and/or workflows // Validate model delete against usages - content and/or workflows
validateModelDelete(modelName); validateModelDelete(modelName);
// Remove the model from the dictionary if (logger.isDebugEnabled())
dictionaryDAO.removeModel(modelName); {
logger.debug("beforeDeleteNode: modelName="+modelName+" ("+nodeRef+")");
}
Set<NodeRef> pendingModelDeletes = (Set<NodeRef>)AlfrescoTransactionSupport.getResource(KEY_PENDING_DELETE_MODELS);
if (pendingModelDeletes == null)
{
pendingModelDeletes = new HashSet<NodeRef>();
AlfrescoTransactionSupport.bindResource(KEY_PENDING_DELETE_MODELS, pendingModelDeletes);
}
pendingModelDeletes.add(tenantService.getName(nodeRef));
AlfrescoTransactionSupport.bindListener(this.transactionListener);
}
}
}
@SuppressWarnings("unchecked")
public void onDeleteNode(ChildAssociationRef childAssocRef, boolean isNodeArchived)
{
NodeRef nodeRef = childAssocRef.getChildRef();
Set<NodeRef> pendingDeleteModels = (Set<NodeRef>)AlfrescoTransactionSupport.getResource(KEY_PENDING_DELETE_MODELS);
if (pendingDeleteModels != null)
{
if (pendingDeleteModels.contains(nodeRef))
{
String tenantDomain = tenantService.getDomain(nodeRef.getStoreRef().getIdentifier());
String tenantSystemUserName = tenantService.getDomainUser(AuthenticationUtil.getSystemUserName(), tenantDomain);
AuthenticationUtil.runAs(new RunAsWork<Object>()
{
public Object doWork()
{
// invalidate - to force lazy re-init
dictionaryDAO.destroy();
return null;
}
}, tenantSystemUserName);
} }
} }
} }
@@ -395,6 +446,11 @@ public class DictionaryModelType implements ContentServicePolicies.OnContentUpda
if (pendingModels != null) if (pendingModels != null)
{ {
if (logger.isDebugEnabled())
{
logger.debug("beforeCommit: pendingModelsCnt="+pendingModels.size());
}
for (NodeRef pendingNodeRef : pendingModels) for (NodeRef pendingNodeRef : pendingModels)
{ {
String tenantDomain = tenantService.getDomain(pendingNodeRef.getStoreRef().getIdentifier()); String tenantDomain = tenantService.getDomain(pendingNodeRef.getStoreRef().getIdentifier());
@@ -464,8 +520,8 @@ public class DictionaryModelType implements ContentServicePolicies.OnContentUpda
// Validate model against dictionary - could be new, unchanged or updated // Validate model against dictionary - could be new, unchanged or updated
dictionaryDAO.validateModel(m2Model); dictionaryDAO.validateModel(m2Model);
// Put the model // invalidate - to force lazy re-init
dictionaryDAO.putModel(m2Model); dictionaryDAO.destroy();
} }
} }
else else
@@ -476,8 +532,8 @@ public class DictionaryModelType implements ContentServicePolicies.OnContentUpda
// Validate model delete against usages - content and/or workflows // Validate model delete against usages - content and/or workflows
validateModelDelete(modelName); validateModelDelete(modelName);
// Remove the model from the dictionary // invalidate - to force lazy re-init
dictionaryDAO.removeModel(modelName); dictionaryDAO.destroy();
} }
} }
} }

View File

@@ -1,5 +1,5 @@
/* /*
* Copyright (C) 2005-2007 Alfresco Software Limited. * Copyright (C) 2005-2009 Alfresco Software Limited.
* *
* This program is free software; you can redistribute it and/or * This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License * modify it under the terms of the GNU General Public License
@@ -24,8 +24,13 @@
*/ */
package org.alfresco.repo.dictionary; package org.alfresco.repo.dictionary;
import java.util.ArrayList;
import java.util.List;
import org.alfresco.model.ContentModel; import org.alfresco.model.ContentModel;
import org.alfresco.repo.content.MimetypeMap; import org.alfresco.repo.content.MimetypeMap;
import org.alfresco.repo.i18n.MessageService;
import org.alfresco.repo.tenant.TenantAdminService;
import org.alfresco.repo.transaction.RetryingTransactionHelper.RetryingTransactionCallback; import org.alfresco.repo.transaction.RetryingTransactionHelper.RetryingTransactionCallback;
import org.alfresco.service.cmr.coci.CheckOutCheckInService; import org.alfresco.service.cmr.coci.CheckOutCheckInService;
import org.alfresco.service.cmr.dictionary.DictionaryException; import org.alfresco.service.cmr.dictionary.DictionaryException;
@@ -33,6 +38,8 @@ import org.alfresco.service.cmr.dictionary.DictionaryService;
import org.alfresco.service.cmr.dictionary.ModelDefinition; import org.alfresco.service.cmr.dictionary.ModelDefinition;
import org.alfresco.service.cmr.repository.ContentWriter; import org.alfresco.service.cmr.repository.ContentWriter;
import org.alfresco.service.cmr.repository.NodeRef; import org.alfresco.service.cmr.repository.NodeRef;
import org.alfresco.service.cmr.repository.NodeService;
import org.alfresco.service.cmr.search.SearchService;
import org.alfresco.service.namespace.NamespaceService; import org.alfresco.service.namespace.NamespaceService;
import org.alfresco.service.namespace.QName; import org.alfresco.service.namespace.QName;
import org.alfresco.util.BaseAlfrescoSpringTest; import org.alfresco.util.BaseAlfrescoSpringTest;
@@ -136,7 +143,35 @@ public class DictionaryModelTypeTest extends BaseAlfrescoSpringTest
this.namespaceService = (NamespaceService)this.applicationContext.getBean("namespaceService"); this.namespaceService = (NamespaceService)this.applicationContext.getBean("namespaceService");
this.cociService = (CheckOutCheckInService)this.applicationContext.getBean("checkOutCheckInService"); this.cociService = (CheckOutCheckInService)this.applicationContext.getBean("checkOutCheckInService");
this.dictionaryDAO = (DictionaryDAO)this.applicationContext.getBean("dictionaryDAO"); this.dictionaryDAO = (DictionaryDAO)this.applicationContext.getBean("dictionaryDAO");
this.nodeService = (NodeService)this.applicationContext.getBean("NodeService");
SearchService searchService = (SearchService)this.applicationContext.getBean("searchService");
TenantAdminService tenantAdminService = (TenantAdminService)this.applicationContext.getBean("tenantAdminService");
MessageService messageService = (MessageService)this.applicationContext.getBean("messageService");
DictionaryRepositoryBootstrap bootstrap = new DictionaryRepositoryBootstrap();
bootstrap.setContentService(this.contentService);
bootstrap.setSearchService(searchService);
bootstrap.setDictionaryDAO(this.dictionaryDAO);
bootstrap.setTransactionService(this.transactionService);
bootstrap.setTenantAdminService(tenantAdminService);
bootstrap.setNodeService(this.nodeService);
bootstrap.setNamespaceService(this.namespaceService);
bootstrap.setMessageService(messageService);
RepositoryLocation location = new RepositoryLocation();
location.setStoreProtocol(this.storeRef.getProtocol());
location.setStoreId(this.storeRef.getIdentifier());
location.setQueryLanguage(SearchService.LANGUAGE_XPATH);
// NOTE: we are not setting the path for now .. in doing so we are searching the whole store
List<RepositoryLocation> locations = new ArrayList<RepositoryLocation>();
locations.add(location);
bootstrap.setRepositoryModelsLocations(locations);
// register with dictionary service
bootstrap.register();
} }
/** /**
@@ -233,12 +268,19 @@ public class DictionaryModelTypeTest extends BaseAlfrescoSpringTest
} }
}); });
transactionService.getRetryingTransactionHelper().doInTransaction(new RetryingTransactionCallback<Object>()
{
public Object execute() throws Exception
{
DictionaryModelTypeTest.this.nodeService.deleteNode(modelNode);
return null;
}
});
} }
public void testIsActiveFlagAndDelete() public void testIsActiveFlagAndDelete()
{ {
this.dictionaryDAO.removeModel(TEST_MODEL_ONE);
try try
{ {
// Check that the model has not yet been loaded into the dictionary // Check that the model has not yet been loaded into the dictionary

View File

@@ -251,8 +251,8 @@ public class DictionaryRepositoryBootstrap extends AbstractLifecycleBean impleme
for (NodeRef dictionaryModel : nodeRefs) for (NodeRef dictionaryModel : nodeRefs)
{ {
// Ignore if the node is a working copy or if its inactive // Ignore if the node is a working copy or archived, or if its inactive
if (nodeService.hasAspect(dictionaryModel, ContentModel.ASPECT_WORKING_COPY) == false) if (! (nodeService.hasAspect(dictionaryModel, ContentModel.ASPECT_WORKING_COPY) || nodeService.hasAspect(dictionaryModel, ContentModel.ASPECT_ARCHIVED)))
{ {
Boolean isActive = (Boolean)nodeService.getProperty(dictionaryModel, ContentModel.PROP_MODEL_ACTIVE); Boolean isActive = (Boolean)nodeService.getProperty(dictionaryModel, ContentModel.PROP_MODEL_ACTIVE);
@@ -261,6 +261,11 @@ public class DictionaryRepositoryBootstrap extends AbstractLifecycleBean impleme
M2Model model = createM2Model(dictionaryModel); M2Model model = createM2Model(dictionaryModel);
if (model != null) if (model != null)
{ {
if (logger.isTraceEnabled())
{
logger.trace("onDictionaryInit: "+model.getName()+" ("+dictionaryModel+")");
}
for (M2Namespace namespace : model.getNamespaces()) for (M2Namespace namespace : model.getNamespaces())
{ {
modelMap.put(namespace.getUri(), model); modelMap.put(namespace.getUri(), model);
@@ -407,21 +412,6 @@ public class DictionaryRepositoryBootstrap extends AbstractLifecycleBean impleme
@Override @Override
protected void onBootstrap(ApplicationEvent event) protected void onBootstrap(ApplicationEvent event)
{ {
// run as System on bootstrap
AuthenticationUtil.runAs(new RunAsWork<Object>()
{
public Object doWork()
{
init();
return null;
}
}, AuthenticationUtil.getSystemUserName());
if (tenantAdminService.isEnabled())
{
tenantAdminService.deployTenants(this, logger);
}
register(); register();
} }

View File

@@ -27,7 +27,6 @@ package org.alfresco.repo.dictionary;
import java.io.ByteArrayInputStream; import java.io.ByteArrayInputStream;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.List; import java.util.List;
import java.util.Map;
import junit.framework.TestCase; import junit.framework.TestCase;
import net.sf.ehcache.Cache; import net.sf.ehcache.Cache;
@@ -35,7 +34,8 @@ import net.sf.ehcache.CacheManager;
import org.alfresco.error.AlfrescoRuntimeException; import org.alfresco.error.AlfrescoRuntimeException;
import org.alfresco.repo.cache.EhCacheAdapter; import org.alfresco.repo.cache.EhCacheAdapter;
import org.alfresco.repo.dictionary.NamespaceDAOImpl.NamespaceData; import org.alfresco.repo.dictionary.DictionaryDAOImpl.DictionaryRegistry;
import org.alfresco.repo.dictionary.NamespaceDAOImpl.NamespaceRegistry;
import org.alfresco.repo.tenant.SingleTServiceImpl; import org.alfresco.repo.tenant.SingleTServiceImpl;
import org.alfresco.repo.tenant.TenantService; import org.alfresco.repo.tenant.TenantService;
import org.alfresco.service.namespace.QName; import org.alfresco.service.namespace.QName;
@@ -789,19 +789,12 @@ public class DiffModelTest extends TestCase
{ {
CacheManager cacheManager = new CacheManager(); CacheManager cacheManager = new CacheManager();
Cache uriToModelsEhCache = new Cache("uriToModelsCache", 50, false, true, 0L, 0L); Cache dictionaryEhCache = new Cache("dictionaryCache", 50, false, true, 0L, 0L);
cacheManager.addCache(uriToModelsEhCache); cacheManager.addCache(dictionaryEhCache);
EhCacheAdapter<String, Map<String, List<CompiledModel>>> uriToModelsCache = new EhCacheAdapter<String, Map<String, List<CompiledModel>>>(); EhCacheAdapter<String, DictionaryRegistry> dictionaryCache = new EhCacheAdapter<String, DictionaryRegistry>();
uriToModelsCache.setCache(uriToModelsEhCache); dictionaryCache.setCache(dictionaryEhCache);
dictionaryDAO.setUriToModelsCache(uriToModelsCache); dictionaryDAO.setDictionaryRegistryCache(dictionaryCache);
Cache compileModelsEhCache = new Cache("compiledModelsCache", 50, false, true, 0L, 0L);
cacheManager.addCache(compileModelsEhCache);
EhCacheAdapter<String, Map<QName,CompiledModel>> compileModelCache = new EhCacheAdapter<String, Map<QName,CompiledModel>>();
compileModelCache.setCache(compileModelsEhCache);
dictionaryDAO.setCompiledModelsCache(compileModelCache);
} }
private void initNamespaceCaches(NamespaceDAOImpl namespaceDAO) private void initNamespaceCaches(NamespaceDAOImpl namespaceDAO)
@@ -810,10 +803,10 @@ public class DiffModelTest extends TestCase
Cache namespaceEhCache = new Cache("namespaceCache", 50, false, true, 0L, 0L); Cache namespaceEhCache = new Cache("namespaceCache", 50, false, true, 0L, 0L);
cacheManager.addCache(namespaceEhCache); cacheManager.addCache(namespaceEhCache);
EhCacheAdapter<String, NamespaceData> namespaceCache = new EhCacheAdapter<String, NamespaceData>(); EhCacheAdapter<String, NamespaceRegistry> namespaceCache = new EhCacheAdapter<String, NamespaceRegistry>();
namespaceCache.setCache(namespaceEhCache); namespaceCache.setCache(namespaceEhCache);
namespaceDAO.setNamespaceDataCache(namespaceCache); namespaceDAO.setNamespaceRegistryCache(namespaceCache);
} }
public void testDeleteModel() public void testDeleteModel()

View File

@@ -56,11 +56,11 @@ public class NamespaceDAOImpl implements NamespaceDAO
private Lock writeLock = lock.writeLock(); private Lock writeLock = lock.writeLock();
// Internal cache (clusterable) // Internal cache (clusterable)
private SimpleCache<String, NamespaceData> namespaceDataCache; private SimpleCache<String, NamespaceRegistry> namespaceRegistryCache;
// used to reset the cache // used to reset the cache
private ThreadLocal<NamespaceData> namespaceDataThreadLocal = new ThreadLocal<NamespaceData>(); private ThreadLocal<NamespaceRegistry> namespaceRegistryThreadLocal = new ThreadLocal<NamespaceRegistry>();
private ThreadLocal<NamespaceData> defaultNamespaceDataThreadLocal = new ThreadLocal<NamespaceData>(); private ThreadLocal<NamespaceRegistry> defaultNamespaceRegistryThreadLocal = new ThreadLocal<NamespaceRegistry>();
// Dependencies // Dependencies
private TenantService tenantService; private TenantService tenantService;
@@ -72,9 +72,9 @@ public class NamespaceDAOImpl implements NamespaceDAO
this.tenantService = tenantService; this.tenantService = tenantService;
} }
public void setNamespaceDataCache(SimpleCache<String, NamespaceData> namespaceDataCache) public void setNamespaceRegistryCache(SimpleCache<String, NamespaceRegistry> namespaceRegistryCache)
{ {
this.namespaceDataCache = namespaceDataCache; this.namespaceRegistryCache = namespaceRegistryCache;
} }
public void registerDictionary(DictionaryDAO dictionaryDAO) public void registerDictionary(DictionaryDAO dictionaryDAO)
@@ -98,7 +98,7 @@ public class NamespaceDAOImpl implements NamespaceDAO
{ {
String tenantDomain = getTenantDomain(); String tenantDomain = getTenantDomain();
removeNamespaceData(tenantDomain); removeNamespaceRegistry(tenantDomain);
if (logger.isDebugEnabled()) if (logger.isDebugEnabled())
{ {
@@ -109,7 +109,7 @@ public class NamespaceDAOImpl implements NamespaceDAO
/** /**
* Resets the namespaces (by re-initialising the dictionary) * Resets the namespaces (by re-initialising the dictionary)
*/ */
private NamespaceData reset(String tenantDomain) private NamespaceRegistry reset(String tenantDomain)
{ {
if (dictionaryDAO == null) if (dictionaryDAO == null)
{ {
@@ -124,48 +124,48 @@ public class NamespaceDAOImpl implements NamespaceDAO
dictionaryDAO.init(); dictionaryDAO.init();
NamespaceData namespaceData = getNamespaceData(tenantDomain); NamespaceRegistry namespaceRegistry = getNamespaceRegistry(tenantDomain);
if (logger.isDebugEnabled()) if (logger.isDebugEnabled())
{ {
logger.debug("... resetting namespaces completed"); logger.debug("... resetting namespaces completed");
} }
return namespaceData; return namespaceRegistry;
} }
private NamespaceData initNamespace(String tenantDomain) private NamespaceRegistry initNamespace(String tenantDomain)
{ {
try try
{ {
createNamespaceLocal(tenantDomain); createNamespaceLocal(tenantDomain);
NamespaceData namespaceData = initNamespaceData(tenantDomain); NamespaceRegistry namespaceRegistry = initNamespaceRegistry(tenantDomain);
if (namespaceData == null) if (namespaceRegistry == null)
{ {
// unexpected // unexpected
throw new AlfrescoRuntimeException("Failed to init namespaceData " + tenantDomain); throw new AlfrescoRuntimeException("Failed to init namespaceRegistry " + tenantDomain);
} }
try try
{ {
writeLock.lock(); writeLock.lock();
namespaceDataCache.put(tenantDomain, namespaceData); namespaceRegistryCache.put(tenantDomain, namespaceRegistry);
} }
finally finally
{ {
writeLock.unlock(); writeLock.unlock();
} }
return namespaceData; return namespaceRegistry;
} }
finally finally
{ {
try try
{ {
readLock.lock(); readLock.lock();
if (namespaceDataCache.get(tenantDomain) != null) if (namespaceRegistryCache.get(tenantDomain) != null)
{ {
removeNamespaceLocal(tenantDomain); removeNamespaceLocal(tenantDomain);
} }
@@ -177,17 +177,17 @@ public class NamespaceDAOImpl implements NamespaceDAO
} }
} }
private NamespaceData initNamespaceData(String tenantDomain) private NamespaceRegistry initNamespaceRegistry(String tenantDomain)
{ {
getNamespaceData(tenantDomain).setUrisCache(new ArrayList<String>()); getNamespaceRegistry(tenantDomain).setUrisCache(new ArrayList<String>());
getNamespaceData(tenantDomain).setPrefixesCache(new HashMap<String, String>()); getNamespaceRegistry(tenantDomain).setPrefixesCache(new HashMap<String, String>());
if (logger.isDebugEnabled()) if (logger.isDebugEnabled())
{ {
logger.debug("Empty namespaces initialised"); logger.debug("Empty namespaces initialised");
} }
return getNamespaceDataLocal(tenantDomain); return getNamespaceRegistryLocal(tenantDomain);
} }
@@ -393,18 +393,18 @@ public class NamespaceDAOImpl implements NamespaceDAO
// re-entrant (eg. via reset) // re-entrant (eg. via reset)
private NamespaceData getNamespaceData(String tenantDomain) private NamespaceRegistry getNamespaceRegistry(String tenantDomain)
{ {
NamespaceData namespaceData = null; NamespaceRegistry namespaceRegistry = null;
try try
{ {
// check cache first - return if set // check cache first - return if set
readLock.lock(); readLock.lock();
namespaceData = namespaceDataCache.get(tenantDomain); namespaceRegistry = namespaceRegistryCache.get(tenantDomain);
if (namespaceData != null) if (namespaceRegistry != null)
{ {
return namespaceData; // return cached config return namespaceRegistry; // return cached config
} }
} }
finally finally
@@ -413,62 +413,65 @@ public class NamespaceDAOImpl implements NamespaceDAO
} }
// check threadlocal second - return if set // check threadlocal second - return if set
namespaceData = getNamespaceDataLocal(tenantDomain); namespaceRegistry = getNamespaceRegistryLocal(tenantDomain);
if (namespaceData != null) if (namespaceRegistry != null)
{ {
return namespaceData; // return local namespaceData return namespaceRegistry; // return local namespaceRegistry
} }
// reset caches - may have been invalidated (e.g. in a cluster) // reset caches - may have been invalidated (e.g. in a cluster)
namespaceData = reset(tenantDomain); namespaceRegistry = reset(tenantDomain);
if (namespaceData == null) if (namespaceRegistry == null)
{ {
// unexpected // unexpected
throw new AlfrescoRuntimeException("Failed to get namespaceData " + tenantDomain); throw new AlfrescoRuntimeException("Failed to get namespaceRegistry " + tenantDomain);
} }
return namespaceData; return namespaceRegistry;
} }
// create threadlocal // create threadlocal
private void createNamespaceLocal(String tenantDomain) private void createNamespaceLocal(String tenantDomain)
{ {
// create threadlocal, if needed // create threadlocal, if needed
NamespaceData namespaceData = getNamespaceDataLocal(tenantDomain); NamespaceRegistry namespaceRegistry = getNamespaceRegistryLocal(tenantDomain);
if (namespaceData == null) if (namespaceRegistry == null)
{ {
namespaceData = new NamespaceData(tenantDomain); namespaceRegistry = new NamespaceRegistry(tenantDomain);
if (tenantDomain.equals(TenantService.DEFAULT_DOMAIN)) if (! tenantDomain.equals(TenantService.DEFAULT_DOMAIN))
{ {
defaultNamespaceDataThreadLocal.set(namespaceData); namespaceRegistryThreadLocal.set(namespaceRegistry);
} }
else
if (defaultNamespaceRegistryThreadLocal.get() == null)
{ {
namespaceDataThreadLocal.set(namespaceData); namespaceRegistry = new NamespaceRegistry(TenantService.DEFAULT_DOMAIN);
defaultNamespaceRegistryThreadLocal.set(namespaceRegistry);
} }
} }
} }
// get threadlocal // get threadlocal
private NamespaceData getNamespaceDataLocal(String tenantDomain) private NamespaceRegistry getNamespaceRegistryLocal(String tenantDomain)
{ {
NamespaceData namespaceData = null; NamespaceRegistry namespaceRegistry = null;
if (tenantDomain.equals(TenantService.DEFAULT_DOMAIN)) if (tenantDomain.equals(TenantService.DEFAULT_DOMAIN))
{ {
namespaceData = this.defaultNamespaceDataThreadLocal.get(); namespaceRegistry = this.defaultNamespaceRegistryThreadLocal.get();
} }
else else
{ {
namespaceData = this.namespaceDataThreadLocal.get(); namespaceRegistry = this.namespaceRegistryThreadLocal.get();
} }
// check to see if domain switched (eg. during login) // check to see if domain switched (eg. during login)
if ((namespaceData != null) && (tenantDomain.equals(namespaceData.getTenantDomain()))) if ((namespaceRegistry != null) && (tenantDomain.equals(namespaceRegistry.getTenantDomain())))
{ {
return namespaceData; // return threadlocal, if set return namespaceRegistry; // return threadlocal, if set
} }
return null; return null;
@@ -479,22 +482,22 @@ public class NamespaceDAOImpl implements NamespaceDAO
{ {
if (tenantDomain.equals(TenantService.DEFAULT_DOMAIN)) if (tenantDomain.equals(TenantService.DEFAULT_DOMAIN))
{ {
defaultNamespaceDataThreadLocal.set(null); // it's in the cache, clear the threadlocal defaultNamespaceRegistryThreadLocal.set(null); // it's in the cache, clear the threadlocal
} }
else else
{ {
namespaceDataThreadLocal.set(null); // it's in the cache, clear the threadlocal namespaceRegistryThreadLocal.set(null); // it's in the cache, clear the threadlocal
} }
} }
private void removeNamespaceData(String tenantDomain) private void removeNamespaceRegistry(String tenantDomain)
{ {
try try
{ {
writeLock.lock(); writeLock.lock();
if (namespaceDataCache.get(tenantDomain) != null) if (namespaceRegistryCache.get(tenantDomain) != null)
{ {
namespaceDataCache.remove(tenantDomain); namespaceRegistryCache.remove(tenantDomain);
} }
removeNamespaceLocal(tenantDomain); removeNamespaceLocal(tenantDomain);
@@ -523,7 +526,7 @@ public class NamespaceDAOImpl implements NamespaceDAO
*/ */
private List<String> getUrisCtx(String tenantDomain) private List<String> getUrisCtx(String tenantDomain)
{ {
return getNamespaceData(tenantDomain).getUrisCache(); return getNamespaceRegistry(tenantDomain).getUrisCache();
} }
/** /**
@@ -544,7 +547,7 @@ public class NamespaceDAOImpl implements NamespaceDAO
*/ */
private Map<String, String> getPrefixesCtx(String tenantDomain) private Map<String, String> getPrefixesCtx(String tenantDomain)
{ {
return getNamespaceData(tenantDomain).getPrefixesCache(); return getNamespaceRegistry(tenantDomain).getPrefixesCache();
} }
/** /**
@@ -555,14 +558,14 @@ public class NamespaceDAOImpl implements NamespaceDAO
return tenantService.getCurrentUserDomain(); return tenantService.getCurrentUserDomain();
} }
/* package */ class NamespaceData /* package */ class NamespaceRegistry
{ {
private List<String> urisCache; private List<String> urisCache = new ArrayList<String>(0);
private Map<String, String> prefixesCache; private Map<String, String> prefixesCache = new HashMap<String, String>(0);
private String tenantDomain; private String tenantDomain;
public NamespaceData(String tenantDomain) public NamespaceRegistry(String tenantDomain)
{ {
this.tenantDomain = tenantDomain; this.tenantDomain = tenantDomain;
} }

View File

@@ -26,16 +26,15 @@ package org.alfresco.repo.dictionary;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.List; import java.util.List;
import java.util.Map;
import net.sf.ehcache.Cache; import net.sf.ehcache.Cache;
import net.sf.ehcache.CacheManager; import net.sf.ehcache.CacheManager;
import org.alfresco.repo.cache.EhCacheAdapter; import org.alfresco.repo.cache.EhCacheAdapter;
import org.alfresco.repo.dictionary.NamespaceDAOImpl.NamespaceData; import org.alfresco.repo.dictionary.DictionaryDAOImpl.DictionaryRegistry;
import org.alfresco.repo.dictionary.NamespaceDAOImpl.NamespaceRegistry;
import org.alfresco.repo.tenant.SingleTServiceImpl; import org.alfresco.repo.tenant.SingleTServiceImpl;
import org.alfresco.repo.tenant.TenantService; import org.alfresco.repo.tenant.TenantService;
import org.alfresco.service.namespace.QName;
/** /**
@@ -114,19 +113,12 @@ public class TestModel
{ {
CacheManager cacheManager = new CacheManager(); CacheManager cacheManager = new CacheManager();
Cache uriToModelsEhCache = new Cache("uriToModelsCache", 50, false, true, 0L, 0L); Cache dictionaryEhCache = new Cache("dictionaryCache", 50, false, true, 0L, 0L);
cacheManager.addCache(uriToModelsEhCache); cacheManager.addCache(dictionaryEhCache);
EhCacheAdapter<String, Map<String, List<CompiledModel>>> uriToModelsCache = new EhCacheAdapter<String, Map<String, List<CompiledModel>>>(); EhCacheAdapter<String, DictionaryRegistry> dictionaryCache = new EhCacheAdapter<String, DictionaryRegistry>();
uriToModelsCache.setCache(uriToModelsEhCache); dictionaryCache.setCache(dictionaryEhCache);
dictionaryDAO.setUriToModelsCache(uriToModelsCache); dictionaryDAO.setDictionaryRegistryCache(dictionaryCache);
Cache compileModelsEhCache = new Cache("compiledModelsCache", 50, false, true, 0L, 0L);
cacheManager.addCache(compileModelsEhCache);
EhCacheAdapter<String, Map<QName,CompiledModel>> compileModelCache = new EhCacheAdapter<String, Map<QName,CompiledModel>>();
compileModelCache.setCache(compileModelsEhCache);
dictionaryDAO.setCompiledModelsCache(compileModelCache);
} }
private static void initNamespaceCaches(NamespaceDAOImpl namespaceDAO) private static void initNamespaceCaches(NamespaceDAOImpl namespaceDAO)
@@ -135,9 +127,9 @@ public class TestModel
Cache namespaceEhCache = new Cache("namespaceCache", 50, false, true, 0L, 0L); Cache namespaceEhCache = new Cache("namespaceCache", 50, false, true, 0L, 0L);
cacheManager.addCache(namespaceEhCache); cacheManager.addCache(namespaceEhCache);
EhCacheAdapter<String, NamespaceData> namespaceCache = new EhCacheAdapter<String, NamespaceData>(); EhCacheAdapter<String, NamespaceRegistry> namespaceCache = new EhCacheAdapter<String, NamespaceRegistry>();
namespaceCache.setCache(namespaceEhCache); namespaceCache.setCache(namespaceEhCache);
namespaceDAO.setNamespaceDataCache(namespaceCache); namespaceDAO.setNamespaceRegistryCache(namespaceCache);
} }
} }

View File

@@ -29,10 +29,7 @@ import java.util.Collection;
import java.util.List; import java.util.List;
import junit.framework.TestCase; import junit.framework.TestCase;
import net.sf.ehcache.Cache;
import net.sf.ehcache.CacheManager;
import org.alfresco.repo.cache.EhCacheAdapter;
import org.alfresco.repo.cache.NullCache; import org.alfresco.repo.cache.NullCache;
import org.alfresco.repo.dictionary.DictionaryBootstrap; import org.alfresco.repo.dictionary.DictionaryBootstrap;
import org.alfresco.repo.dictionary.DictionaryComponent; import org.alfresco.repo.dictionary.DictionaryComponent;
@@ -93,30 +90,15 @@ public class PolicyComponentTest extends TestCase
@SuppressWarnings("unchecked") @SuppressWarnings("unchecked")
private void initDictionaryCaches(DictionaryDAOImpl dictionaryDAO) private void initDictionaryCaches(DictionaryDAOImpl dictionaryDAO)
{ {
CacheManager cacheManager = new CacheManager(); // note: unit tested here with null cache
dictionaryDAO.setDictionaryRegistryCache(new NullCache());
Cache uriToModelsEhCache = new Cache("uriToModelsCache", 50, false, true, 0L, 0L);
cacheManager.addCache(uriToModelsEhCache);
//EhCacheAdapter<String, Map<String, List<CompiledModel>>> uriToModelsCache = new EhCacheAdapter<String, Map<String, List<CompiledModel>>>();
EhCacheAdapter uriToModelsCache = new EhCacheAdapter();
uriToModelsCache.setCache(uriToModelsEhCache);
dictionaryDAO.setUriToModelsCache(uriToModelsCache);
Cache compileModelsEhCache = new Cache("compiledModelsCache", 50, false, true, 0L, 0L);
cacheManager.addCache(compileModelsEhCache);
//EhCacheAdapter<String, Map<QName,CompiledModel>> compileModelCache = new EhCacheAdapter<String, Map<QName,CompiledModel>>();
EhCacheAdapter compileModelCache = new EhCacheAdapter();
compileModelCache.setCache(compileModelsEhCache);
dictionaryDAO.setCompiledModelsCache(compileModelCache);
} }
@SuppressWarnings("unchecked") @SuppressWarnings("unchecked")
private void initNamespaceCaches(NamespaceDAOImpl namespaceDAO) private void initNamespaceCaches(NamespaceDAOImpl namespaceDAO)
{ {
// note: unit tested here with null cache // note: unit tested here with null cache
namespaceDAO.setNamespaceDataCache(new NullCache()); namespaceDAO.setNamespaceRegistryCache(new NullCache());
} }
public void testJavaBehaviour() public void testJavaBehaviour()

View File

@@ -1,5 +1,5 @@
/* /*
* Copyright (C) 2005-2007 Alfresco Software Limited. * Copyright (C) 2005-2009 Alfresco Software Limited.
* *
* This program is free software; you can redistribute it and/or * This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License * modify it under the terms of the GNU General Public License
@@ -34,6 +34,7 @@ import org.alfresco.service.cmr.dictionary.DictionaryService;
import org.alfresco.service.cmr.repository.ContentService; import org.alfresco.service.cmr.repository.ContentService;
import org.alfresco.service.cmr.repository.NodeService; import org.alfresco.service.cmr.repository.NodeService;
import org.alfresco.service.cmr.repository.StoreRef; import org.alfresco.service.cmr.repository.StoreRef;
import org.alfresco.service.cmr.search.SearchService;
import org.alfresco.service.namespace.NamespaceService; import org.alfresco.service.namespace.NamespaceService;
/** /**
@@ -135,6 +136,19 @@ public class ADMLuceneIndexerAndSearcherFactory extends AbstractLuceneIndexerAnd
return searcher; return searcher;
} }
protected SearchService getNodeSearcher() throws SearcherException
{
ADMLuceneSearcherImpl searcher = ADMLuceneSearcherImpl.getNodeSearcher();
searcher.setNamespacePrefixResolver(nameSpaceService);
searcher.setNodeService(nodeService);
searcher.setTenantService(tenantService);
searcher.setDictionaryService(dictionaryService);
searcher.setQueryRegister(getQueryRegister());
searcher.setQueryEngine(queryEngine);
searcher.setDictionaryService(dictionaryService);
return searcher;
}
protected List<StoreRef> getAllStores() protected List<StoreRef> getAllStores()
{ {

View File

@@ -1,5 +1,5 @@
/* /*
* Copyright (C) 2005-2007 Alfresco Software Limited. * Copyright (C) 2005-2009 Alfresco Software Limited.
* *
* This program is free software; you can redistribute it and/or * This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License * modify it under the terms of the GNU General Public License
@@ -37,7 +37,6 @@ import java.util.Locale;
import java.util.Map; import java.util.Map;
import java.util.Set; import java.util.Set;
import org.alfresco.cmis.CMISQueryException;
import org.alfresco.i18n.I18NUtil; import org.alfresco.i18n.I18NUtil;
import org.alfresco.repo.search.CannedQueryDef; import org.alfresco.repo.search.CannedQueryDef;
import org.alfresco.repo.search.EmptyResultSet; import org.alfresco.repo.search.EmptyResultSet;
@@ -53,11 +52,9 @@ import org.alfresco.repo.search.impl.querymodel.QueryEngine;
import org.alfresco.repo.search.impl.querymodel.QueryEngineResults; import org.alfresco.repo.search.impl.querymodel.QueryEngineResults;
import org.alfresco.repo.search.impl.querymodel.QueryModelFactory; import org.alfresco.repo.search.impl.querymodel.QueryModelFactory;
import org.alfresco.repo.search.impl.querymodel.QueryOptions; import org.alfresco.repo.search.impl.querymodel.QueryOptions;
import org.alfresco.repo.search.impl.querymodel.Selector;
import org.alfresco.repo.search.results.SortedResultSet; import org.alfresco.repo.search.results.SortedResultSet;
import org.alfresco.repo.tenant.TenantService; import org.alfresco.repo.tenant.TenantService;
import org.alfresco.service.cmr.dictionary.DataTypeDefinition; import org.alfresco.service.cmr.dictionary.DataTypeDefinition;
import org.alfresco.service.cmr.dictionary.DictionaryService;
import org.alfresco.service.cmr.dictionary.PropertyDefinition; import org.alfresco.service.cmr.dictionary.PropertyDefinition;
import org.alfresco.service.cmr.repository.InvalidNodeRefException; import org.alfresco.service.cmr.repository.InvalidNodeRefException;
import org.alfresco.service.cmr.repository.NodeRef; import org.alfresco.service.cmr.repository.NodeRef;
@@ -162,6 +159,15 @@ public class ADMLuceneSearcherImpl extends AbstractLuceneBase implements LuceneS
return getSearcher(storeRef, null, config); return getSearcher(storeRef, null, config);
} }
/**
* Get a select-node-based searcher
* @return
*/
public static ADMLuceneSearcherImpl getNodeSearcher()
{
return new ADMLuceneSearcherImpl();
}
public void setNamespacePrefixResolver(NamespacePrefixResolver namespacePrefixResolver) public void setNamespacePrefixResolver(NamespacePrefixResolver namespacePrefixResolver)
{ {
this.namespacePrefixResolver = namespacePrefixResolver; this.namespacePrefixResolver = namespacePrefixResolver;

View File

@@ -1,5 +1,5 @@
/* /*
* Copyright (C) 2005-2007 Alfresco Software Limited. * Copyright (C) 2005-2009 Alfresco Software Limited.
* *
* This program is free software; you can redistribute it and/or * This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License * modify it under the terms of the GNU General Public License
@@ -40,9 +40,8 @@ import org.alfresco.service.cmr.dictionary.DictionaryService;
import org.alfresco.service.cmr.repository.ContentService; import org.alfresco.service.cmr.repository.ContentService;
import org.alfresco.service.cmr.repository.NodeService; import org.alfresco.service.cmr.repository.NodeService;
import org.alfresco.service.cmr.repository.StoreRef; import org.alfresco.service.cmr.repository.StoreRef;
import org.alfresco.service.cmr.search.SearchService;
import org.alfresco.service.namespace.NamespaceService; import org.alfresco.service.namespace.NamespaceService;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
/** /**
* Factory for AVM indexers and searchers * Factory for AVM indexers and searchers
@@ -52,7 +51,7 @@ import org.apache.commons.logging.LogFactory;
*/ */
public class AVMLuceneIndexerAndSearcherFactory extends AbstractLuceneIndexerAndSearcherFactory implements SupportsBackgroundIndexing public class AVMLuceneIndexerAndSearcherFactory extends AbstractLuceneIndexerAndSearcherFactory implements SupportsBackgroundIndexing
{ {
private static Log s_logger = LogFactory.getLog(AVMLuceneIndexerAndSearcherFactory.class); //private static Log s_logger = LogFactory.getLog(AVMLuceneIndexerAndSearcherFactory.class);
private DictionaryService dictionaryService; private DictionaryService dictionaryService;
@@ -191,6 +190,12 @@ public class AVMLuceneIndexerAndSearcherFactory extends AbstractLuceneIndexerAnd
return searcher; return searcher;
} }
@Override
protected SearchService getNodeSearcher() throws SearcherException
{
throw new UnsupportedOperationException();
}
/** /**
* Register the full text searcher (done by the seracher bean to break cyclic bean defs) * Register the full text searcher (done by the seracher bean to break cyclic bean defs)
* *

View File

@@ -1,5 +1,5 @@
/* /*
* Copyright (C) 2005-2007 Alfresco Software Limited. * Copyright (C) 2005-2009 Alfresco Software Limited.
* *
* This program is free software; you can redistribute it and/or * This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License * modify it under the terms of the GNU General Public License
@@ -60,6 +60,7 @@ import org.alfresco.repo.transaction.AlfrescoTransactionSupport;
import org.alfresco.repo.transaction.RetryingTransactionHelper.RetryingTransactionCallback; import org.alfresco.repo.transaction.RetryingTransactionHelper.RetryingTransactionCallback;
import org.alfresco.service.cmr.repository.NodeService; import org.alfresco.service.cmr.repository.NodeService;
import org.alfresco.service.cmr.repository.StoreRef; import org.alfresco.service.cmr.repository.StoreRef;
import org.alfresco.service.cmr.search.SearchService;
import org.alfresco.service.transaction.TransactionService; import org.alfresco.service.transaction.TransactionService;
import org.alfresco.util.GUID; import org.alfresco.util.GUID;
import org.apache.commons.logging.Log; import org.apache.commons.logging.Log;
@@ -465,6 +466,11 @@ public abstract class AbstractLuceneIndexerAndSearcherFactory implements LuceneI
return searcher; return searcher;
} }
/**
* Get node-based searcher (for "selectNodes / selectProperties")
*/
protected abstract SearchService getNodeSearcher() throws SearcherException;
/** /**
* Get a searcher over the index and the current delta * Get a searcher over the index and the current delta
* *

View File

@@ -493,12 +493,13 @@ public class MultiTDemoTest extends TestCase
{ {
NodeRef homeSpaceRef = getHomeSpaceFolderNode(tenantUserName); NodeRef homeSpaceRef = getHomeSpaceFolderNode(tenantUserName);
NodeRef contentRef = addTextContent(homeSpaceRef, tenantUserName+" quick brown fox.txt", "The quick brown fox jumps over the lazy dog (tenant " + tenantDomain + ")"); NodeRef contentRef = addContent(homeSpaceRef, tenantUserName+" quick brown fox.txt", "The quick brown fox jumps over the lazy dog (tenant " + tenantDomain + ")", MimetypeMap.MIMETYPE_TEXT_PLAIN);
nodeService.addAspect(contentRef, ContentModel.ASPECT_VERSIONABLE, null); nodeService.addAspect(contentRef, ContentModel.ASPECT_VERSIONABLE, null);
if (tenantDomain.equals(TEST_TENANT_DOMAIN2)) if (tenantDomain.equals(TEST_TENANT_DOMAIN2))
{ {
contentRef = addTextContent(homeSpaceRef, tenantUserName+" quick brown fox ANO.txt", "The quick brown fox jumps over the lazy dog ANO (tenant " + tenantDomain + ")"); contentRef = addContent(homeSpaceRef, tenantUserName+" quick brown fox ANO.txt", "The quick brown fox jumps over the lazy dog ANO (tenant " + tenantDomain + ")", MimetypeMap.MIMETYPE_TEXT_PLAIN);
nodeService.addAspect(contentRef, ContentModel.ASPECT_VERSIONABLE, null); nodeService.addAspect(contentRef, ContentModel.ASPECT_VERSIONABLE, null);
} }
@@ -519,7 +520,12 @@ public class MultiTDemoTest extends TestCase
{ {
public Object doWork() throws Exception public Object doWork() throws Exception
{ {
assertTrue("System: ", (nodeService.getStores().size() >= (DEFAULT_STORE_COUNT * (tenants.size()+1)))); for (StoreRef storeRef : nodeService.getStores())
{
System.out.println("StoreRef: "+storeRef);
}
assertTrue("System: "+nodeService.getStores().size()+", "+(tenants.size()+1), (nodeService.getStores().size() >= (DEFAULT_STORE_COUNT * (tenants.size()+1))));
return null; return null;
} }
}, AuthenticationUtil.getSystemUserName()); }, AuthenticationUtil.getSystemUserName());
@@ -529,7 +535,7 @@ public class MultiTDemoTest extends TestCase
{ {
public Object doWork() throws Exception public Object doWork() throws Exception
{ {
assertTrue("Super admin: ", (nodeService.getStores().size() >= DEFAULT_STORE_COUNT)); assertTrue("Super admin: "+nodeService.getStores().size(), (nodeService.getStores().size() >= DEFAULT_STORE_COUNT));
return null; return null;
} }
}, AuthenticationUtil.getAdminUserName()); }, AuthenticationUtil.getAdminUserName());
@@ -644,7 +650,7 @@ public class MultiTDemoTest extends TestCase
public Object doWork() throws Exception public Object doWork() throws Exception
{ {
NodeRef homeSpaceRef = getHomeSpaceFolderNode(tenantUserName); NodeRef homeSpaceRef = getHomeSpaceFolderNode(tenantUserName);
NodeRef contentRef = addTextContent(homeSpaceRef, tenantUserName+" tqbfjotld.txt", "The quick brown fox jumps over the lazy dog (tenant " + tenantDomain + ")"); NodeRef contentRef = addContent(homeSpaceRef, tenantUserName+" tqbfjotld.txt", "The quick brown fox jumps over the lazy dog (tenant " + tenantDomain + ")", MimetypeMap.MIMETYPE_TEXT_PLAIN);
NodeRef storeArchiveNode = nodeService.getStoreArchiveNode(contentRef.getStoreRef()); NodeRef storeArchiveNode = nodeService.getStoreArchiveNode(contentRef.getStoreRef());
@@ -662,9 +668,9 @@ public class MultiTDemoTest extends TestCase
} }
} }
public void testCustomDynamicModels() public void testCustomModels()
{ {
logger.info("test custom/dynamic models"); logger.info("test custom models");
final int defaultModelCnt = dictionaryService.getAllModels().size(); final int defaultModelCnt = dictionaryService.getAllModels().size();
@@ -715,6 +721,33 @@ public class MultiTDemoTest extends TestCase
} }
} }
public void testAddCustomWebClient()
{
// note: add as demo files - need to re-start Alfresco to see custom web client config / messages
logger.info("test add custom web client config");
for (final String tenantDomain : tenants)
{
final String tenantAdminName = tenantService.getDomainUser(AuthenticationUtil.getAdminUserName(), tenantDomain);
AuthenticationUtil.runAs(new RunAsWork<Object>()
{
public Object doWork() throws Exception
{
NodeRef webClientExtFolder = getWebClientExtensionNodeRef(SPACES_STORE);
InputStream is = getClass().getClassLoader().getResourceAsStream("tenant/webclient.properties");
addContent(webClientExtFolder, "webclient.properties", is, MimetypeMap.MIMETYPE_TEXT_PLAIN);
is = getClass().getClassLoader().getResourceAsStream("tenant/web-client-config-custom.xml");
addContent(webClientExtFolder, "web-client-config-custom.xml", is, MimetypeMap.MIMETYPE_XML);
return null;
}
}, tenantAdminName);
}
}
private void createGroup(String shortName, String parentShortName) private void createGroup(String shortName, String parentShortName)
{ {
// create new Group using authority Service // create new Group using authority Service
@@ -816,6 +849,12 @@ public class MultiTDemoTest extends TestCase
return findFolderNodeRef(storeRef, "/app:company_home/app:user_homes"); return findFolderNodeRef(storeRef, "/app:company_home/app:user_homes");
} }
private NodeRef getWebClientExtensionNodeRef(StoreRef storeRef)
{
// get the "Web Client Extensions" location
return findFolderNodeRef(storeRef, "/app:company_home/app:dictionary/app:webclient_extension");
}
private NodeRef findFolderNodeRef(StoreRef storeRef, String folderXPath) private NodeRef findFolderNodeRef(StoreRef storeRef, String folderXPath)
{ {
ResultSet rs = this.searchService.query(storeRef, SearchService.LANGUAGE_XPATH, folderXPath); ResultSet rs = this.searchService.query(storeRef, SearchService.LANGUAGE_XPATH, folderXPath);
@@ -926,7 +965,7 @@ public class MultiTDemoTest extends TestCase
return (NodeRef)this.nodeService.getProperty(personService.getPerson(userName), ContentModel.PROP_HOMEFOLDER); return (NodeRef)this.nodeService.getProperty(personService.getPerson(userName), ContentModel.PROP_HOMEFOLDER);
} }
private NodeRef addTextContent(NodeRef spaceRef, String name, String textData) private NodeRef addContent(NodeRef spaceRef, String name, String textData, String mimeType)
{ {
Map<QName, Serializable> contentProps = new HashMap<QName, Serializable>(); Map<QName, Serializable> contentProps = new HashMap<QName, Serializable>();
contentProps.put(ContentModel.PROP_NAME, name); contentProps.put(ContentModel.PROP_NAME, name);
@@ -947,7 +986,7 @@ public class MultiTDemoTest extends TestCase
ContentWriter writer = contentService.getWriter(content, ContentModel.PROP_CONTENT, true); ContentWriter writer = contentService.getWriter(content, ContentModel.PROP_CONTENT, true);
writer.setMimetype(MimetypeMap.MIMETYPE_TEXT_PLAIN); writer.setMimetype(mimeType);
writer.setEncoding("UTF-8"); writer.setEncoding("UTF-8");
writer.putContent(textData); writer.putContent(textData);
@@ -955,6 +994,35 @@ public class MultiTDemoTest extends TestCase
return content; return content;
} }
private NodeRef addContent(NodeRef spaceRef, String name, InputStream is, String mimeType)
{
Map<QName, Serializable> contentProps = new HashMap<QName, Serializable>();
contentProps.put(ContentModel.PROP_NAME, name);
ChildAssociationRef association = nodeService.createNode(spaceRef,
ContentModel.ASSOC_CONTAINS,
QName.createQName(NamespaceService.CONTENT_MODEL_1_0_URI, name),
ContentModel.TYPE_CONTENT,
contentProps);
NodeRef content = association.getChildRef();
// add titled aspect (for Web Client display)
Map<QName, Serializable> titledProps = new HashMap<QName, Serializable>();
titledProps.put(ContentModel.PROP_TITLE, name);
titledProps.put(ContentModel.PROP_DESCRIPTION, name);
this.nodeService.addAspect(content, ContentModel.ASPECT_TITLED, titledProps);
ContentWriter writer = contentService.getWriter(content, ContentModel.PROP_CONTENT, true);
writer.setMimetype(mimeType);
writer.setEncoding("UTF-8");
writer.putContent(is);
return content;
}
// comment-in to run from command line // comment-in to run from command line
public static void main(String args[]) public static void main(String args[])

View File

@@ -256,7 +256,7 @@ public class WorkflowDeployer extends AbstractLifecycleBean
userTransaction.begin(); userTransaction.begin();
// bootstrap the workflow models and static labels (from classpath) // bootstrap the workflow models and static labels (from classpath)
if (models != null && resourceBundles != null) if (models != null && resourceBundles != null && ((models.size() > 0) || (resourceBundles.size() > 0)))
{ {
DictionaryBootstrap dictionaryBootstrap = new DictionaryBootstrap(); DictionaryBootstrap dictionaryBootstrap = new DictionaryBootstrap();
dictionaryBootstrap.setDictionaryDAO(dictionaryDAO); dictionaryBootstrap.setDictionaryDAO(dictionaryDAO);

View File

@@ -0,0 +1,121 @@
<alfresco-config>
<!-- Example of overriding the search settings -->
<config>
<client>
<search-max-results>2</search-max-results>
<!-- Shelf component default visibility, set to false to hide the shelf by default -->
<shelf-visible>false</shelf-visible>
</client>
</config>
<!-- Example of adding languages to the list in the login page -->
<!--
<config evaluator="string-compare" condition="Languages">
<languages>
<language locale="ca_ES">Catalan</language>
<language locale="da_DK">Danish</language>
<language locale="de_DE">German</language>
<language locale="es_ES">Spanish</language>
<language locale="el_GR">Greek</language>
<language locale="fr_FR">French</language>
<language locale="it_IT">Italian</language>
<language locale="ja_JP">Japanese</language>
<language locale="du_NL">Dutch</language>
<language locale="pt_BR">Portuguese (Brazilian)</language>
<language locale="ru_RU">Russian</language>
<language locale="fi_FI">Finnish</language>
<language locale="tr_TR">Turkish</language>
<language locale="zh_CN">Simplified Chinese</language>
</languages>
</config>
-->
<!-- Example of configuring advanced search -->
<!--
<config evaluator="string-compare" condition="Advanced Search">
<advanced-search>
<content-types>
</content-types>
<custom-properties>
<meta-data aspect="app:simpleworkflow" property="app:approveStep" />
</custom-properties>
</advanced-search>
</config>
-->
<!-- Example of changing the sort direction for a view in the client -->
<!--
<config evaluator="string-compare" condition="Views">
<views>
<view-defaults>
<topic>
<sort-direction>ascending</sort-direction>
</topic>
</view-defaults>
</views>
</config>
-->
<!-- Example of adding a custom icon to the Create Space dialog -->
<!--
<config evaluator="string-compare" condition="cm:folder icons">
<icons>
<icon name="space-icon-custom" path="/images/icons/space-icon-custom.gif" />
</icons>
</config>
-->
<!-- The config below shows how to incorporate the example model-->
<!-- into the web client, for this to work you will need to -->
<!-- rename example-model-context.xml.sample to example-model-context.xml -->
<config evaluator="string-compare" condition="Content Wizards">
<content-types>
<type name="my:sop" />
</content-types>
</config>
<config evaluator="node-type" condition="my:sop">
<property-sheet>
<show-property name="mimetype" display-label-id="content_type"
component-generator="MimeTypeSelectorGenerator" />
<show-property name="size" display-label-id="size"
converter="org.alfresco.faces.ByteSizeConverter"
show-in-edit-mode="false" />
<show-property name="my:publishedDate" display-label-id="my.publishedDate" />
<show-association name="my:signOff" display-label-id="my.signOff" />
<show-property name="my:authorisedBy" display-label-id="my.authorisedBy" />
<show-child-association name="my:processSteps" display-label-id="my.processSteps" />
</property-sheet>
</config>
<config evaluator="aspect-name" condition="my:imageClassification">
<property-sheet>
<show-property name="my:width" display-label-id="my.width" />
<show-property name="my:height" display-label-id="my.height" />
<show-property name="my:resolution" display-label-id="my.resolution" />
</property-sheet>
</config>
<config evaluator="string-compare" condition="Action Wizards">
<aspects>
<aspect name="my:imageClassification"/>
</aspects>
</config>
<config evaluator="string-compare" condition="Advanced Search">
<advanced-search>
<content-types>
<type name="my:sop" />
</content-types>
<custom-properties>
<meta-data type="my:sop" property="my:authorisedBy" />
<meta-data aspect="my:imageClassification" property="my:resolution" />
</custom-properties>
</advanced-search>
</config>
</alfresco-config>

View File

@@ -0,0 +1,15 @@
# web client custom I18N message properties
# example model
# see display-label-ids added to the web-client-config-custom.xml sample
# my:sop
my.publishedDate= publié Published Date
my.authorisedBy=Authorised By
my.signOff= publié Sign Off
my.processSteps=Process Steps
# my:imageClassification
my.width=Width
my.height=Height
my.resolution=Resolution