mirror of
https://github.com/Alfresco/alfresco-community-repo.git
synced 2025-07-24 17:32:48 +00:00
First-cut dynamic Dictionary & Namespaces - updated caches to be cluster-aware & tenant-aware
git-svn-id: https://svn.alfresco.com/repos/alfresco-enterprise/alfresco/HEAD/root@6675 c4b6b30b-aa2e-2d43-bbcb-ca4b014f7261
This commit is contained in:
@@ -345,4 +345,137 @@
|
||||
</property>
|
||||
</bean>
|
||||
|
||||
|
||||
<!-- ===================================== -->
|
||||
<!-- Dictionary / Namespace Caches -->
|
||||
<!-- ===================================== -->
|
||||
|
||||
<!-- The cross-transaction shared cache for In-Memory UriToModels -->
|
||||
|
||||
<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>10</value>
|
||||
</property>
|
||||
</bean>
|
||||
|
||||
<!-- The cross-transaction shared cache for In-Memory CompiledModels -->
|
||||
|
||||
<bean name="compiledModelsSharedCache" 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.compiledModelsCache</value>
|
||||
</property>
|
||||
</bean>
|
||||
</property>
|
||||
</bean>
|
||||
|
||||
<!-- The transactional cache for In-Memory CompiledModels -->
|
||||
|
||||
<bean name="compiledModelsCache" class="org.alfresco.repo.cache.TransactionalCache">
|
||||
<property name="sharedCache">
|
||||
<ref bean="compiledModelsSharedCache" />
|
||||
</property>
|
||||
<property name="cacheManager" >
|
||||
<ref bean="transactionalEHCacheManager" />
|
||||
</property>
|
||||
<property name="name">
|
||||
<value>org.alfresco.compiledModelsTransactionalCache</value>
|
||||
</property>
|
||||
<property name="maxCacheSize">
|
||||
<value>10</value>
|
||||
</property>
|
||||
</bean>
|
||||
|
||||
<!-- The cross-transaction shared cache for In-Memory Namespace Uris -->
|
||||
|
||||
<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>10</value>
|
||||
</property>
|
||||
</bean>
|
||||
|
||||
<!-- The cross-transaction shared cache for In-Memory Namespace Prefixes -->
|
||||
|
||||
<bean name="prefixesSharedCache" 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.prefixesCache</value>
|
||||
</property>
|
||||
</bean>
|
||||
</property>
|
||||
</bean>
|
||||
|
||||
<!-- The transactional cache for In-Memory Namespace Prefixes -->
|
||||
|
||||
<bean name="prefixesCache" class="org.alfresco.repo.cache.TransactionalCache">
|
||||
<property name="sharedCache">
|
||||
<ref bean="prefixesSharedCache" />
|
||||
</property>
|
||||
<property name="cacheManager" >
|
||||
<ref bean="transactionalEHCacheManager" />
|
||||
</property>
|
||||
<property name="name">
|
||||
<value>org.alfresco.prefixesTransactionalCache</value>
|
||||
</property>
|
||||
<property name="maxCacheSize">
|
||||
<value>10</value>
|
||||
</property>
|
||||
</bean>
|
||||
|
||||
</beans>
|
@@ -600,7 +600,19 @@
|
||||
<!-- Data Dictionary -->
|
||||
<!-- -->
|
||||
|
||||
<bean id="namespaceDAO" class="org.alfresco.repo.dictionary.NamespaceDAOImpl" />
|
||||
<bean id="namespaceDAO" class="org.alfresco.repo.dictionary.NamespaceDAOImpl">
|
||||
|
||||
<property name="tenantService">
|
||||
<ref bean="tenantService"/>
|
||||
</property>
|
||||
<property name="urisCache">
|
||||
<ref bean="urisCache"/>
|
||||
</property>
|
||||
<property name="prefixesCache">
|
||||
<ref bean="prefixesCache"/>
|
||||
</property>
|
||||
|
||||
</bean>
|
||||
|
||||
<bean id="dictionaryModelType" class="org.alfresco.repo.dictionary.DictionaryModelType" init-method="init">
|
||||
<property name="dictionaryDAO">
|
||||
@@ -624,6 +636,15 @@
|
||||
<constructor-arg index="0">
|
||||
<ref bean="namespaceDAO" />
|
||||
</constructor-arg>
|
||||
<property name="tenantService">
|
||||
<ref bean="tenantService"/>
|
||||
</property>
|
||||
<property name="uriToModelsCache">
|
||||
<ref bean="uriToModelsCache"/>
|
||||
</property>
|
||||
<property name="compiledModelsCache">
|
||||
<ref bean="compiledModelsCache"/>
|
||||
</property>
|
||||
</bean>
|
||||
|
||||
<bean id="dictionaryService" class="org.alfresco.repo.dictionary.DictionaryComponent" depends-on="dictionaryBootstrap">
|
||||
@@ -641,6 +662,9 @@
|
||||
|
||||
<bean id="dictionaryModelBootstrap" class="org.alfresco.repo.dictionary.DictionaryBootstrap" init-method="bootstrap" abstract="true">
|
||||
<property name="dictionaryDAO"><ref local="dictionaryDAO"/></property>
|
||||
<property name="tenantService">
|
||||
<ref bean="tenantService"/>
|
||||
</property>
|
||||
</bean>
|
||||
|
||||
<bean id="dictionaryBootstrap" parent="dictionaryModelBootstrap" depends-on="resourceBundles">
|
||||
@@ -690,24 +714,6 @@
|
||||
</list>
|
||||
</property>
|
||||
</bean>
|
||||
|
||||
<bean id="dictionaryRepositoryBootstrap" class="org.alfresco.repo.dictionary.DictionaryRepositoryBootstrap" init-method="bootstrap">
|
||||
<property name="dictionaryDAO">
|
||||
<ref local="dictionaryDAO"/>
|
||||
</property>
|
||||
<property name="contentService">
|
||||
<ref bean="contentService"/>
|
||||
</property>
|
||||
<property name="searchService">
|
||||
<ref bean="searchService"/>
|
||||
</property>
|
||||
<property name="transactionService">
|
||||
<ref bean="transactionService"/>
|
||||
</property>
|
||||
<property name="authenticationComponent">
|
||||
<ref bean="authenticationComponent"/>
|
||||
</property>
|
||||
</bean>
|
||||
|
||||
<!-- -->
|
||||
<!-- Copy Service -->
|
||||
|
@@ -354,4 +354,34 @@
|
||||
overflowToDisk="false"
|
||||
/>
|
||||
|
||||
<!-- Dictionary / Namespace (tenant-based) -->
|
||||
|
||||
<cache
|
||||
name="org.alfresco.cache.uriToModelsCache"
|
||||
maxElementsInMemory="100"
|
||||
eternal="true"
|
||||
overflowToDisk="false"
|
||||
/>
|
||||
|
||||
<cache
|
||||
name="org.alfresco.cache.compiledModelsCache"
|
||||
maxElementsInMemory="100"
|
||||
eternal="true"
|
||||
overflowToDisk="false"
|
||||
/>
|
||||
|
||||
<cache
|
||||
name="org.alfresco.cache.urisCache"
|
||||
maxElementsInMemory="100"
|
||||
eternal="true"
|
||||
overflowToDisk="false"
|
||||
/>
|
||||
|
||||
<cache
|
||||
name="org.alfresco.cache.prefixesCache"
|
||||
maxElementsInMemory="100"
|
||||
eternal="true"
|
||||
overflowToDisk="false"
|
||||
/>
|
||||
|
||||
</ehcache>
|
@@ -650,6 +650,70 @@
|
||||
|
||||
</cache>
|
||||
|
||||
<!-- 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
|
||||
name="org.alfresco.cache.compiledModelsCache"
|
||||
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
|
||||
name="org.alfresco.cache.urisCache"
|
||||
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
|
||||
name="org.alfresco.cache.prefixesCache"
|
||||
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>
|
||||
|
||||
</ehcache>
|
||||
|
||||
|
||||
|
@@ -29,18 +29,19 @@ import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
||||
import org.alfresco.i18n.I18NUtil;
|
||||
import org.alfresco.repo.tenant.TenantService;
|
||||
import org.alfresco.service.cmr.dictionary.DictionaryException;
|
||||
import org.apache.commons.logging.Log;
|
||||
import org.apache.commons.logging.LogFactory;
|
||||
|
||||
|
||||
/**
|
||||
* Bootstrap Dictionary DAO with pre-defined models
|
||||
* Bootstrap Dictionary DAO with pre-defined models & message resources (from classpath)
|
||||
*
|
||||
* @author David Caruana
|
||||
*
|
||||
*/
|
||||
public class DictionaryBootstrap
|
||||
public class DictionaryBootstrap implements DictionaryDeployer
|
||||
{
|
||||
// The list of models to bootstrap with
|
||||
private List<String> models = new ArrayList<String>();
|
||||
@@ -50,6 +51,9 @@ public class DictionaryBootstrap
|
||||
|
||||
// Dictionary DAO
|
||||
private DictionaryDAO dictionaryDAO = null;
|
||||
|
||||
// Tenant Service
|
||||
private TenantService tenantService;
|
||||
|
||||
// Logger
|
||||
private static Log logger = LogFactory.getLog(DictionaryDAO.class);
|
||||
@@ -65,6 +69,16 @@ public class DictionaryBootstrap
|
||||
this.dictionaryDAO = dictionaryDAO;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the Tenant Service
|
||||
*
|
||||
* @param tenantService
|
||||
*/
|
||||
public void setTenantService(TenantService tenantService)
|
||||
{
|
||||
this.tenantService = tenantService;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the initial list of models to bootstrap with
|
||||
*
|
||||
@@ -86,37 +100,65 @@ public class DictionaryBootstrap
|
||||
}
|
||||
|
||||
/**
|
||||
* Bootstrap the Dictionary
|
||||
* Bootstrap the Dictionary - register and populate
|
||||
*
|
||||
*/
|
||||
public void bootstrap()
|
||||
{
|
||||
// register models
|
||||
for (String bootstrapModel : models)
|
||||
initDictionary();
|
||||
initStaticMessages();
|
||||
|
||||
register();
|
||||
}
|
||||
|
||||
/**
|
||||
* Register with the Dictionary
|
||||
*/
|
||||
public void register()
|
||||
{
|
||||
dictionaryDAO.register(this);
|
||||
}
|
||||
|
||||
/**
|
||||
* Populate the Dictionary
|
||||
*/
|
||||
public void initDictionary()
|
||||
{
|
||||
if ((tenantService == null) || (! tenantService.isTenantUser()))
|
||||
{
|
||||
InputStream modelStream = getClass().getClassLoader().getResourceAsStream(bootstrapModel);
|
||||
if (modelStream == null)
|
||||
// register models
|
||||
for (String bootstrapModel : models)
|
||||
{
|
||||
throw new DictionaryException("Could not find bootstrap model " + bootstrapModel);
|
||||
}
|
||||
try
|
||||
{
|
||||
if (logger.isInfoEnabled())
|
||||
logger.info("Loading model from " + bootstrapModel);
|
||||
|
||||
M2Model model = M2Model.createModel(modelStream);
|
||||
dictionaryDAO.putModel(model);
|
||||
}
|
||||
catch(DictionaryException e)
|
||||
{
|
||||
throw new DictionaryException("Could not import bootstrap model " + bootstrapModel, e);
|
||||
InputStream modelStream = getClass().getClassLoader().getResourceAsStream(bootstrapModel);
|
||||
if (modelStream == null)
|
||||
{
|
||||
throw new DictionaryException("Could not find bootstrap model " + bootstrapModel);
|
||||
}
|
||||
try
|
||||
{
|
||||
if (logger.isInfoEnabled())
|
||||
logger.info("Loading model from " + bootstrapModel);
|
||||
|
||||
M2Model model = M2Model.createModel(modelStream);
|
||||
dictionaryDAO.putModel(model);
|
||||
}
|
||||
catch(DictionaryException e)
|
||||
{
|
||||
throw new DictionaryException("Could not import bootstrap model " + bootstrapModel, e);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// register models
|
||||
}
|
||||
|
||||
/**
|
||||
* Register the static resource bundles
|
||||
*/
|
||||
private void initStaticMessages()
|
||||
{
|
||||
// register messages
|
||||
for (String resourceBundle : resourceBundles)
|
||||
{
|
||||
I18NUtil.registerResourceBundle(resourceBundle);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
@@ -27,9 +27,9 @@ package org.alfresco.repo.dictionary;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Collection;
|
||||
import java.util.HashSet;
|
||||
import java.util.LinkedHashSet;
|
||||
import java.util.Map;
|
||||
|
||||
import org.alfresco.repo.tenant.TenantDeployer;
|
||||
import org.alfresco.service.cmr.dictionary.AspectDefinition;
|
||||
import org.alfresco.service.cmr.dictionary.AssociationDefinition;
|
||||
import org.alfresco.service.cmr.dictionary.ClassDefinition;
|
||||
@@ -48,7 +48,7 @@ import org.alfresco.util.ParameterCheck;
|
||||
*
|
||||
* @author David Caruana
|
||||
*/
|
||||
public class DictionaryComponent implements DictionaryService
|
||||
public class DictionaryComponent implements DictionaryService, TenantDeployer
|
||||
{
|
||||
private DictionaryDAO dictionaryDAO;
|
||||
|
||||
@@ -339,6 +339,26 @@ public class DictionaryComponent implements DictionaryService
|
||||
}
|
||||
return props;
|
||||
}
|
||||
|
||||
public void init()
|
||||
{
|
||||
dictionaryDAO.init();
|
||||
}
|
||||
|
||||
public void destroy()
|
||||
{
|
||||
dictionaryDAO.destroy();
|
||||
}
|
||||
|
||||
public void onEnableTenant()
|
||||
{
|
||||
dictionaryDAO.reset(); // to initialise empty dictionary and re-populate
|
||||
}
|
||||
|
||||
public void onDisableTenant()
|
||||
{
|
||||
dictionaryDAO.destroy();
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
@@ -93,8 +93,9 @@ public interface DictionaryDAO extends ModelQuery
|
||||
* Adds a model to the dictionary. The model is compiled and validated.
|
||||
*
|
||||
* @param model the model to add
|
||||
* @return QName name of model
|
||||
*/
|
||||
public void putModel(M2Model model);
|
||||
public QName putModel(M2Model model);
|
||||
|
||||
/**
|
||||
* Removes a model from the dictionary. The types and aspect in the model will no longer be
|
||||
@@ -114,4 +115,26 @@ public interface DictionaryDAO extends ModelQuery
|
||||
*/
|
||||
public Collection<PropertyDefinition> getProperties(QName modelName, QName dataType);
|
||||
|
||||
/**
|
||||
*
|
||||
* Register with the Dictionary
|
||||
*
|
||||
* @param dictionaryDeployer
|
||||
*/
|
||||
public void register(DictionaryDeployer dictionaryDeployer);
|
||||
|
||||
/**
|
||||
* Reset the Dictionary - destroy & re-initialise
|
||||
*/
|
||||
public void reset();
|
||||
|
||||
/**
|
||||
* Initialise the Dictionary
|
||||
*/
|
||||
public void init();
|
||||
|
||||
/**
|
||||
* Destroy the Dictionary
|
||||
*/
|
||||
public void destroy();
|
||||
}
|
||||
|
@@ -31,7 +31,15 @@ import java.util.HashMap;
|
||||
import java.util.HashSet;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.concurrent.locks.Lock;
|
||||
import java.util.concurrent.locks.ReadWriteLock;
|
||||
import java.util.concurrent.locks.ReentrantReadWriteLock;
|
||||
|
||||
import org.alfresco.error.AlfrescoRuntimeException;
|
||||
import org.alfresco.repo.cache.SimpleCache;
|
||||
import org.alfresco.repo.security.authentication.AuthenticationUtil;
|
||||
import org.alfresco.repo.security.authentication.AuthenticationUtil.RunAsWork;
|
||||
import org.alfresco.repo.tenant.TenantService;
|
||||
import org.alfresco.service.cmr.dictionary.AspectDefinition;
|
||||
import org.alfresco.service.cmr.dictionary.AssociationDefinition;
|
||||
import org.alfresco.service.cmr.dictionary.ClassDefinition;
|
||||
@@ -59,20 +67,51 @@ public class DictionaryDAOImpl implements DictionaryDAO
|
||||
// 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
|
||||
*/
|
||||
private ReadWriteLock lock = new ReentrantReadWriteLock();
|
||||
private Lock readLock = lock.readLock();
|
||||
private Lock writeLock = lock.writeLock();
|
||||
|
||||
// Namespace Data Access
|
||||
private NamespaceDAO namespaceDAO;
|
||||
|
||||
// Tenant Service
|
||||
private TenantService tenantService;
|
||||
|
||||
// Map of Namespace URI usages to Models
|
||||
private Map<String, List<CompiledModel>> uriToModels = new HashMap<String, List<CompiledModel>>();
|
||||
|
||||
private SimpleCache<String, Map<String, List<CompiledModel>>> uriToModelsCache;
|
||||
|
||||
// Map of model name to compiled model
|
||||
private Map<QName,CompiledModel> compiledModels = new HashMap<QName,CompiledModel>();
|
||||
private SimpleCache<String, Map<QName,CompiledModel>> compiledModelsCache;
|
||||
|
||||
// Static list of registered dictionary deployers
|
||||
private List<DictionaryDeployer> dictionaryDeployers = new ArrayList<DictionaryDeployer>();
|
||||
|
||||
// Logger
|
||||
private static Log logger = LogFactory.getLog(DictionaryDAO.class);
|
||||
|
||||
|
||||
// inject dependencies
|
||||
|
||||
public void setTenantService(TenantService tenantService)
|
||||
{
|
||||
this.tenantService = tenantService;
|
||||
}
|
||||
|
||||
public void setUriToModelsCache(SimpleCache<String, Map<String, List<CompiledModel>>> uriToModelsCache)
|
||||
{
|
||||
this.uriToModelsCache = uriToModelsCache;
|
||||
}
|
||||
|
||||
public void setCompiledModelsCache(SimpleCache<String, Map<QName,CompiledModel>> compiledModelsCache)
|
||||
{
|
||||
this.compiledModelsCache = compiledModelsCache;
|
||||
}
|
||||
|
||||
/**
|
||||
* Construct
|
||||
*
|
||||
@@ -81,20 +120,111 @@ public class DictionaryDAOImpl implements DictionaryDAO
|
||||
public DictionaryDAOImpl(NamespaceDAO namespaceDAO)
|
||||
{
|
||||
this.namespaceDAO = namespaceDAO;
|
||||
this.namespaceDAO.registerDictionary(this);
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* Register with the Dictionary
|
||||
*/
|
||||
public void register(DictionaryDeployer dictionaryDeployer)
|
||||
{
|
||||
if (! dictionaryDeployers.contains(dictionaryDeployer))
|
||||
{
|
||||
dictionaryDeployers.add(dictionaryDeployer);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Initialise the Dictionary & Namespaces
|
||||
*/
|
||||
public void init()
|
||||
{
|
||||
String tenantDomain = getTenantDomain();
|
||||
|
||||
// initialise empty dictionary & namespaces
|
||||
putCompiledModels(tenantDomain, new HashMap<QName,CompiledModel>());
|
||||
putUriToModels(tenantDomain, new HashMap<String, List<CompiledModel>>());
|
||||
|
||||
namespaceDAO.init();
|
||||
|
||||
// populate the dictionary
|
||||
for (DictionaryDeployer dictionaryDeployer : dictionaryDeployers)
|
||||
{
|
||||
dictionaryDeployer.initDictionary();
|
||||
}
|
||||
|
||||
logger.info("Dictionary initialised");
|
||||
}
|
||||
|
||||
/**
|
||||
* Destroy the Dictionary & Namespaces
|
||||
*/
|
||||
public void destroy()
|
||||
{
|
||||
String tenantDomain = getTenantDomain();
|
||||
|
||||
removeCompiledModels(tenantDomain);
|
||||
removeUriToModels(tenantDomain);
|
||||
|
||||
namespaceDAO.destroy();
|
||||
|
||||
logger.info("Dictionary destroyed");
|
||||
}
|
||||
|
||||
/**
|
||||
* Reset the Dictionary & Namespaces
|
||||
*/
|
||||
public void reset()
|
||||
{
|
||||
reset(getTenantDomain());
|
||||
}
|
||||
|
||||
private void reset(String tenantDomain)
|
||||
{
|
||||
if (logger.isDebugEnabled())
|
||||
{
|
||||
logger.debug("Resetting dictionary ...");
|
||||
}
|
||||
|
||||
String userName;
|
||||
if (tenantDomain == "")
|
||||
{
|
||||
userName = AuthenticationUtil.getSystemUserName();
|
||||
}
|
||||
else
|
||||
{
|
||||
userName = tenantService.getDomainUser(TenantService.ADMIN_BASENAME, tenantDomain);
|
||||
}
|
||||
|
||||
AuthenticationUtil.runAs(new RunAsWork<Object>()
|
||||
{
|
||||
public Object doWork()
|
||||
{
|
||||
destroy();
|
||||
init();
|
||||
|
||||
return null;
|
||||
}
|
||||
}, userName);
|
||||
|
||||
if (logger.isDebugEnabled())
|
||||
{
|
||||
logger.debug("... resetting dictionary completed");
|
||||
}
|
||||
}
|
||||
|
||||
/* (non-Javadoc)
|
||||
* @see org.alfresco.repo.dictionary.impl.DictionaryDAO#putModel(org.alfresco.repo.dictionary.impl.M2Model)
|
||||
*/
|
||||
public void putModel(M2Model model)
|
||||
public QName putModel(M2Model model)
|
||||
{
|
||||
// Compile model definition
|
||||
CompiledModel compiledModel = model.compile(this, namespaceDAO);
|
||||
QName modelName = compiledModel.getModelDefinition().getName();
|
||||
|
||||
// Remove namespace definitions for previous model, if it exists
|
||||
CompiledModel previousVersion = compiledModels.get(modelName);
|
||||
CompiledModel previousVersion = getCompiledModels().get(modelName);
|
||||
if (previousVersion != null)
|
||||
{
|
||||
for (M2Namespace namespace : previousVersion.getM2Model().getNamespaces())
|
||||
@@ -122,7 +252,7 @@ public class DictionaryDAOImpl implements DictionaryDAO
|
||||
}
|
||||
|
||||
// Publish new Model Definition
|
||||
compiledModels.put(modelName, compiledModel);
|
||||
getCompiledModels().put(modelName, compiledModel);
|
||||
|
||||
if (logger.isInfoEnabled())
|
||||
{
|
||||
@@ -132,6 +262,8 @@ public class DictionaryDAOImpl implements DictionaryDAO
|
||||
logger.info("Registered namespace '" + namespace.getUri() + "' (prefix '" + namespace.getPrefix() + "')");
|
||||
}
|
||||
}
|
||||
|
||||
return modelName;
|
||||
}
|
||||
|
||||
|
||||
@@ -140,7 +272,7 @@ public class DictionaryDAOImpl implements DictionaryDAO
|
||||
*/
|
||||
public void removeModel(QName modelName)
|
||||
{
|
||||
CompiledModel compiledModel = this.compiledModels.get(modelName);
|
||||
CompiledModel compiledModel = getCompiledModels().get(modelName);
|
||||
if (compiledModel != null)
|
||||
{
|
||||
// Remove the namespaces from the namespace service
|
||||
@@ -153,7 +285,7 @@ public class DictionaryDAOImpl implements DictionaryDAO
|
||||
}
|
||||
|
||||
// Remove the model from the list
|
||||
this.compiledModels.remove(modelName);
|
||||
getCompiledModels().remove(modelName);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -166,11 +298,11 @@ public class DictionaryDAOImpl implements DictionaryDAO
|
||||
*/
|
||||
private void mapUriToModel(String uri, CompiledModel model)
|
||||
{
|
||||
List<CompiledModel> models = uriToModels.get(uri);
|
||||
List<CompiledModel> models = getUriToModels().get(uri);
|
||||
if (models == null)
|
||||
{
|
||||
models = new ArrayList<CompiledModel>();
|
||||
uriToModels.put(uri, models);
|
||||
getUriToModels().put(uri, models);
|
||||
}
|
||||
if (!models.contains(model))
|
||||
{
|
||||
@@ -187,7 +319,7 @@ public class DictionaryDAOImpl implements DictionaryDAO
|
||||
*/
|
||||
private void unmapUriToModel(String uri, CompiledModel model)
|
||||
{
|
||||
List<CompiledModel> models = uriToModels.get(uri);
|
||||
List<CompiledModel> models = getUriToModels().get(uri);
|
||||
if (models != null)
|
||||
{
|
||||
models.remove(model);
|
||||
@@ -203,25 +335,93 @@ public class DictionaryDAOImpl implements DictionaryDAO
|
||||
*/
|
||||
private List<CompiledModel> getModelsForUri(String uri)
|
||||
{
|
||||
List<CompiledModel> models = uriToModels.get(uri);
|
||||
if (models == null)
|
||||
{
|
||||
models = Collections.emptyList();
|
||||
}
|
||||
return models;
|
||||
// note: special case, if running as System - e.g. addAuditAspect
|
||||
String currentUserName = AuthenticationUtil.getCurrentUserName();
|
||||
|
||||
if ((tenantService.isTenantUser()) ||
|
||||
(tenantService.isTenantName(uri) && (currentUserName != null) && (currentUserName.equals(AuthenticationUtil.getSystemUserName()))))
|
||||
{
|
||||
String tenantDomain = null;
|
||||
if (currentUserName.equals(AuthenticationUtil.getSystemUserName()))
|
||||
{
|
||||
tenantDomain = tenantService.getDomain(uri);
|
||||
}
|
||||
else
|
||||
{
|
||||
tenantDomain = tenantService.getCurrentUserDomain();
|
||||
}
|
||||
uri = tenantService.getBaseName(uri, true);
|
||||
|
||||
// get non-tenant models (if any)
|
||||
List<CompiledModel> models = getUriToModels("").get(uri);
|
||||
|
||||
List<CompiledModel> filteredModels = new ArrayList<CompiledModel>();
|
||||
if (models != null)
|
||||
{
|
||||
filteredModels.addAll(models);
|
||||
}
|
||||
|
||||
// get tenant models (if any)
|
||||
List<CompiledModel> tenantModels = getUriToModels(tenantDomain).get(uri);
|
||||
if (tenantModels != null)
|
||||
{
|
||||
if (models != null)
|
||||
{
|
||||
// check to see if tenant model overrides a non-tenant model
|
||||
for (CompiledModel tenantModel : tenantModels)
|
||||
{
|
||||
for (CompiledModel model : models)
|
||||
{
|
||||
if (tenantModel.getM2Model().getName().equals(model.getM2Model().getName()))
|
||||
{
|
||||
filteredModels.remove(model);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
filteredModels.addAll(tenantModels);
|
||||
models = filteredModels;
|
||||
}
|
||||
|
||||
if (models == null)
|
||||
{
|
||||
models = Collections.emptyList();
|
||||
}
|
||||
return models;
|
||||
}
|
||||
else
|
||||
{
|
||||
List<CompiledModel> models = getUriToModels().get(uri);
|
||||
if (models == null)
|
||||
{
|
||||
models = Collections.emptyList();
|
||||
}
|
||||
return models;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* @param modelName the model name
|
||||
* @return the compiled model of the given name
|
||||
*/
|
||||
private CompiledModel getCompiledModel(QName modelName)
|
||||
{
|
||||
CompiledModel model = compiledModels.get(modelName);
|
||||
if (tenantService.isTenantUser())
|
||||
{
|
||||
// get tenant-specific model (if any)
|
||||
CompiledModel model = getCompiledModels().get(modelName);
|
||||
if (model != null)
|
||||
{
|
||||
return model;
|
||||
}
|
||||
// else drop down to check for shared (core/system) models ...
|
||||
}
|
||||
|
||||
// get non-tenant model (if any)
|
||||
CompiledModel model = getCompiledModels("").get(modelName);
|
||||
if (model == null)
|
||||
{
|
||||
// TODO: Load model from persistent store
|
||||
throw new DictionaryException("d_dictionary.model.err.no_model", modelName);
|
||||
}
|
||||
return model;
|
||||
@@ -251,12 +451,39 @@ public class DictionaryDAOImpl implements DictionaryDAO
|
||||
*/
|
||||
public DataTypeDefinition getDataType(Class javaClass)
|
||||
{
|
||||
for (CompiledModel model : compiledModels.values())
|
||||
if (tenantService.isTenantUser() == true)
|
||||
{
|
||||
DataTypeDefinition dataTypeDef = model.getDataType(javaClass);
|
||||
if (dataTypeDef != null)
|
||||
{
|
||||
return dataTypeDef;
|
||||
// get tenant models (if any)
|
||||
for (CompiledModel model : getCompiledModels().values())
|
||||
{
|
||||
DataTypeDefinition dataTypeDef = model.getDataType(javaClass);
|
||||
if (dataTypeDef != null)
|
||||
{
|
||||
return dataTypeDef;
|
||||
}
|
||||
}
|
||||
|
||||
// get non-tenant models (if any)
|
||||
for (CompiledModel model : getCompiledModels("").values())
|
||||
{
|
||||
DataTypeDefinition dataTypeDef = model.getDataType(javaClass);
|
||||
if (dataTypeDef != null)
|
||||
{
|
||||
return dataTypeDef;
|
||||
}
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
else
|
||||
{
|
||||
for (CompiledModel model : getCompiledModels().values())
|
||||
{
|
||||
DataTypeDefinition dataTypeDef = model.getDataType(javaClass);
|
||||
if (dataTypeDef != null)
|
||||
{
|
||||
return dataTypeDef;
|
||||
}
|
||||
}
|
||||
}
|
||||
return null;
|
||||
@@ -315,6 +542,11 @@ public class DictionaryDAOImpl implements DictionaryDAO
|
||||
public ClassDefinition getClass(QName className)
|
||||
{
|
||||
List<CompiledModel> models = getModelsForUri(className.getNamespaceURI());
|
||||
|
||||
// note: special case, if running as System - e.g. addAuditAspect
|
||||
// now force, even for System user
|
||||
className = tenantService.getBaseName(className, true);
|
||||
|
||||
for (CompiledModel model : models)
|
||||
{
|
||||
ClassDefinition classDef = model.getClass(className);
|
||||
@@ -386,9 +618,56 @@ public class DictionaryDAOImpl implements DictionaryDAO
|
||||
*/
|
||||
public Collection<QName> getModels()
|
||||
{
|
||||
return compiledModels.keySet();
|
||||
}
|
||||
if (tenantService.isTenantUser())
|
||||
{
|
||||
// return all tenant-specific models and all shared (non-overridden) models
|
||||
Collection<QName> filteredModels = new ArrayList<QName>();
|
||||
Collection<QName> tenantModels = new ArrayList<QName>();
|
||||
Collection<QName> nontenantModels = new ArrayList<QName>();
|
||||
|
||||
// get tenant models (if any)
|
||||
for (QName key : getCompiledModels().keySet())
|
||||
{
|
||||
tenantModels.add(key);
|
||||
}
|
||||
|
||||
// get non-tenant models (if any)
|
||||
// note: these will be shared, if not overridden - could be core/system model or additional custom model shared between tenants
|
||||
for (QName key : getCompiledModels("").keySet())
|
||||
{
|
||||
nontenantModels.add(key);
|
||||
}
|
||||
|
||||
// check for overrides
|
||||
filteredModels.addAll(nontenantModels);
|
||||
|
||||
for (QName tenantModel : tenantModels)
|
||||
{
|
||||
for (QName nontenantModel : nontenantModels)
|
||||
{
|
||||
if (tenantModel.equals(nontenantModel))
|
||||
{
|
||||
// override
|
||||
filteredModels.remove(nontenantModel);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
filteredModels.addAll(tenantModels);
|
||||
return filteredModels;
|
||||
}
|
||||
else
|
||||
{
|
||||
return getCompiledModels().keySet();
|
||||
}
|
||||
}
|
||||
|
||||
// used for clean-up, e.g. when deleting a tenant
|
||||
protected Collection<QName> getNonSharedModels()
|
||||
{
|
||||
return getCompiledModels().keySet();
|
||||
}
|
||||
|
||||
/* (non-Javadoc)
|
||||
* @see org.alfresco.repo.dictionary.impl.DictionaryDAO#getModel(org.alfresco.repo.ref.QName)
|
||||
@@ -479,4 +758,196 @@ public class DictionaryDAOImpl implements DictionaryDAO
|
||||
return properties;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get compiledModels from the cache (in the context of the current user's tenant domain)
|
||||
*
|
||||
* @param tenantDomain
|
||||
*/
|
||||
/* package */ Map<QName,CompiledModel> getCompiledModels()
|
||||
{
|
||||
return getCompiledModels(getTenantDomain());
|
||||
}
|
||||
|
||||
/**
|
||||
* Get compiledModels from the cache (in the context of the given tenant domain)
|
||||
*
|
||||
* @param tenantDomain
|
||||
*/
|
||||
private Map<QName,CompiledModel> getCompiledModels(String tenantDomain)
|
||||
{
|
||||
Map<QName,CompiledModel> compiledModels = null;
|
||||
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();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Get uriToModels from the cache (in the context of the current user's tenant domain)
|
||||
*
|
||||
* @param tenantDomain
|
||||
*/
|
||||
private Map<String, List<CompiledModel>> getUriToModels()
|
||||
{
|
||||
return getUriToModels(getTenantDomain());
|
||||
}
|
||||
|
||||
/**
|
||||
* Get uriToModels from the cache (in the context of the given tenant domain)
|
||||
*
|
||||
* @param tenantDomain
|
||||
*/
|
||||
private Map<String, List<CompiledModel>> getUriToModels(String tenantDomain)
|
||||
{
|
||||
Map<String, List<CompiledModel>> uriToModels = null;
|
||||
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();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Local helper - returns tenant domain (or empty string if default non-tenant)
|
||||
*/
|
||||
private String getTenantDomain()
|
||||
{
|
||||
return tenantService.getCurrentUserDomain();
|
||||
}
|
||||
}
|
||||
|
@@ -24,16 +24,20 @@
|
||||
*/
|
||||
package org.alfresco.repo.dictionary;
|
||||
|
||||
import java.io.Serializable;
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
|
||||
import junit.framework.TestCase;
|
||||
import net.sf.ehcache.Cache;
|
||||
import net.sf.ehcache.CacheManager;
|
||||
|
||||
import org.alfresco.i18n.I18NUtil;
|
||||
import org.alfresco.repo.cache.EhCacheAdapter;
|
||||
import org.alfresco.repo.dictionary.constraint.RegexConstraint;
|
||||
import org.alfresco.repo.dictionary.constraint.StringLengthConstraint;
|
||||
import org.alfresco.repo.tenant.SingleTServiceImpl;
|
||||
import org.alfresco.repo.tenant.TenantService;
|
||||
import org.alfresco.service.cmr.dictionary.AssociationDefinition;
|
||||
import org.alfresco.service.cmr.dictionary.ClassDefinition;
|
||||
import org.alfresco.service.cmr.dictionary.Constraint;
|
||||
@@ -45,7 +49,6 @@ import org.alfresco.service.cmr.dictionary.ModelDefinition;
|
||||
import org.alfresco.service.cmr.dictionary.PropertyDefinition;
|
||||
import org.alfresco.service.cmr.dictionary.TypeDefinition;
|
||||
import org.alfresco.service.namespace.QName;
|
||||
import org.alfresco.service.namespace.RegexQNamePattern;
|
||||
|
||||
|
||||
public class DictionaryDAOTest extends TestCase
|
||||
@@ -65,8 +68,14 @@ public class DictionaryDAOTest extends TestCase
|
||||
I18NUtil.registerResourceBundle(TEST_RESOURCE_MESSAGES);
|
||||
|
||||
// Instantiate Dictionary Service
|
||||
NamespaceDAO namespaceDAO = new NamespaceDAOImpl();
|
||||
TenantService tenantService = new SingleTServiceImpl();
|
||||
NamespaceDAOImpl namespaceDAO = new NamespaceDAOImpl();
|
||||
namespaceDAO.setTenantService(tenantService);
|
||||
initNamespaceCaches(namespaceDAO);
|
||||
|
||||
DictionaryDAOImpl dictionaryDAO = new DictionaryDAOImpl(namespaceDAO);
|
||||
dictionaryDAO.setTenantService(tenantService);
|
||||
initDictionaryCaches(dictionaryDAO);
|
||||
|
||||
// Populate with appropriate models
|
||||
DictionaryBootstrap bootstrap = new DictionaryBootstrap();
|
||||
@@ -78,6 +87,7 @@ public class DictionaryDAOTest extends TestCase
|
||||
bootstrap.setModels(bootstrapModels);
|
||||
bootstrap.setLabels(labels);
|
||||
bootstrap.setDictionaryDAO(dictionaryDAO);
|
||||
bootstrap.setTenantService(tenantService);
|
||||
bootstrap.bootstrap();
|
||||
|
||||
DictionaryComponent component = new DictionaryComponent();
|
||||
@@ -85,11 +95,55 @@ public class DictionaryDAOTest extends TestCase
|
||||
service = component;
|
||||
}
|
||||
|
||||
private void initDictionaryCaches(DictionaryDAOImpl dictionaryDAO)
|
||||
{
|
||||
CacheManager cacheManager = new CacheManager();
|
||||
|
||||
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>>>();
|
||||
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>>();
|
||||
compileModelCache.setCache(compileModelsEhCache);
|
||||
|
||||
dictionaryDAO.setCompiledModelsCache(compileModelCache);
|
||||
}
|
||||
|
||||
private void initNamespaceCaches(NamespaceDAOImpl namespaceDAO)
|
||||
{
|
||||
CacheManager cacheManager = new CacheManager();
|
||||
|
||||
Cache urisEhCache = new Cache("urisCache", 50, false, true, 0L, 0L);
|
||||
cacheManager.addCache(urisEhCache);
|
||||
EhCacheAdapter<String, List<String>> urisCache = new EhCacheAdapter<String, List<String>>();
|
||||
urisCache.setCache(urisEhCache);
|
||||
|
||||
namespaceDAO.setUrisCache(urisCache);
|
||||
|
||||
Cache prefixesEhCache = new Cache("prefixesCache", 50, false, true, 0L, 0L);
|
||||
cacheManager.addCache(prefixesEhCache);
|
||||
EhCacheAdapter<String, Map<String, String>> prefixesCache = new EhCacheAdapter<String, Map<String, String>>();
|
||||
prefixesCache.setCache(prefixesEhCache);
|
||||
|
||||
namespaceDAO.setPrefixesCache(prefixesCache);
|
||||
}
|
||||
|
||||
|
||||
public void testBootstrap()
|
||||
{
|
||||
NamespaceDAO namespaceDAO = new NamespaceDAOImpl();
|
||||
TenantService tenantService = new SingleTServiceImpl();
|
||||
NamespaceDAOImpl namespaceDAO = new NamespaceDAOImpl();
|
||||
namespaceDAO.setTenantService(tenantService);
|
||||
initNamespaceCaches(namespaceDAO);
|
||||
|
||||
DictionaryDAOImpl dictionaryDAO = new DictionaryDAOImpl(namespaceDAO);
|
||||
dictionaryDAO.setTenantService(tenantService);
|
||||
initDictionaryCaches(dictionaryDAO);
|
||||
|
||||
DictionaryBootstrap bootstrap = new DictionaryBootstrap();
|
||||
List<String> bootstrapModels = new ArrayList<String>();
|
||||
@@ -107,7 +161,8 @@ public class DictionaryDAOTest extends TestCase
|
||||
|
||||
bootstrap.setModels(bootstrapModels);
|
||||
bootstrap.setDictionaryDAO(dictionaryDAO);
|
||||
bootstrap.bootstrap();
|
||||
bootstrap.setTenantService(tenantService);
|
||||
bootstrap.bootstrap();
|
||||
}
|
||||
|
||||
|
||||
|
45
source/java/org/alfresco/repo/dictionary/DictionaryDeployer.java
Executable file
45
source/java/org/alfresco/repo/dictionary/DictionaryDeployer.java
Executable file
@@ -0,0 +1,45 @@
|
||||
/*
|
||||
* Copyright (C) 2005-2007 Alfresco Software Limited.
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU General Public License
|
||||
* as published by the Free Software Foundation; either version 2
|
||||
* of the License, or (at your option) any later version.
|
||||
|
||||
* This program 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 General Public License for more details.
|
||||
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program; if not, write to the Free Software
|
||||
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
|
||||
|
||||
* As a special exception to the terms and conditions of version 2.0 of
|
||||
* the GPL, you may redistribute this Program in connection with Free/Libre
|
||||
* and Open Source Software ("FLOSS") applications as described in Alfresco's
|
||||
* FLOSS exception. You should have recieved a copy of the text describing
|
||||
* the FLOSS exception, and it is also available here:
|
||||
* http://www.alfresco.com/legal/licensing"
|
||||
*/
|
||||
package org.alfresco.repo.dictionary;
|
||||
|
||||
|
||||
/**
|
||||
* Dictionary Deployer interface.
|
||||
* <p>
|
||||
* This interface allows DictionaryDAO to be (re-)initialised.
|
||||
* Dictionary Deployer components must register with the DictionaryService.
|
||||
*
|
||||
*/
|
||||
|
||||
public interface DictionaryDeployer
|
||||
{
|
||||
// callback for (re-)initialising the Dictionary caches
|
||||
public void initDictionary();
|
||||
|
||||
// register prior to bootstrap
|
||||
public void register();
|
||||
}
|
||||
|
||||
|
@@ -30,26 +30,43 @@ import java.util.List;
|
||||
import java.util.Map;
|
||||
|
||||
import org.alfresco.model.ContentModel;
|
||||
import org.alfresco.repo.security.authentication.AuthenticationComponent;
|
||||
import org.alfresco.repo.i18n.MessageDeployer;
|
||||
import org.alfresco.repo.i18n.MessageService;
|
||||
import org.alfresco.repo.security.authentication.AuthenticationUtil;
|
||||
import org.alfresco.repo.security.authentication.AuthenticationUtil.RunAsWork;
|
||||
import org.alfresco.repo.tenant.TenantDeployer;
|
||||
import org.alfresco.repo.tenant.TenantDeployerService;
|
||||
import org.alfresco.repo.tenant.TenantService;
|
||||
import org.alfresco.repo.transaction.RetryingTransactionHelper.RetryingTransactionCallback;
|
||||
import org.alfresco.service.cmr.repository.ContentReader;
|
||||
import org.alfresco.service.cmr.repository.ContentService;
|
||||
import org.alfresco.service.cmr.repository.NodeRef;
|
||||
import org.alfresco.service.cmr.repository.NodeService;
|
||||
import org.alfresco.service.cmr.repository.StoreRef;
|
||||
import org.alfresco.service.cmr.search.ResultSet;
|
||||
import org.alfresco.service.cmr.search.SearchService;
|
||||
import org.alfresco.service.namespace.NamespaceService;
|
||||
import org.alfresco.service.transaction.TransactionService;
|
||||
|
||||
import org.alfresco.util.AbstractLifecycleBean;
|
||||
import org.apache.commons.logging.Log;
|
||||
import org.apache.commons.logging.LogFactory;
|
||||
import org.springframework.context.ApplicationEvent;
|
||||
|
||||
/**
|
||||
* Bootstrap the dictionary from specified locations within the repository
|
||||
*
|
||||
* @author Roy Wetherall
|
||||
* @author Roy Wetherall, JanV
|
||||
*/
|
||||
public class DictionaryRepositoryBootstrap
|
||||
{
|
||||
/** Loactions in the respository fro which models should be loaded */
|
||||
private List<RepositoryLocation> repositoryLocations = new ArrayList<RepositoryLocation>();
|
||||
public class DictionaryRepositoryBootstrap extends AbstractLifecycleBean implements TenantDeployer, DictionaryDeployer, MessageDeployer
|
||||
{
|
||||
// Logging support
|
||||
private static Log logger = LogFactory
|
||||
.getLog("org.alfresco.repo.dictionary.DictionaryRepositoryBootstrap");
|
||||
|
||||
/** Locations in the repository from which models should be loaded */
|
||||
private List<RepositoryLocation> repositoryModelsLocations = new ArrayList<RepositoryLocation>();
|
||||
|
||||
/** Locations in the repository from which messages should be loaded */
|
||||
private List<RepositoryLocation> repositoryMessagesLocations = new ArrayList<RepositoryLocation>();
|
||||
|
||||
/** Dictionary DAO */
|
||||
private DictionaryDAO dictionaryDAO = null;
|
||||
@@ -59,12 +76,24 @@ public class DictionaryRepositoryBootstrap
|
||||
|
||||
/** The content service */
|
||||
private ContentService contentService;
|
||||
|
||||
/** The node service */
|
||||
private NodeService nodeService;
|
||||
|
||||
/** The tenant service */
|
||||
private TenantService tenantService;
|
||||
|
||||
/** The tenant deployer service */
|
||||
private TenantDeployerService tenantDeployerService;
|
||||
|
||||
/** The namespace service */
|
||||
private NamespaceService namespaceService;
|
||||
|
||||
/** The message service */
|
||||
private MessageService messageService;
|
||||
|
||||
/** The transaction service */
|
||||
private TransactionService transactionService;
|
||||
|
||||
/** The authentication component */
|
||||
private AuthenticationComponent authenticationComponent;
|
||||
|
||||
/**
|
||||
* Sets the Dictionary DAO
|
||||
@@ -95,7 +124,57 @@ public class DictionaryRepositoryBootstrap
|
||||
{
|
||||
this.contentService = contentService;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the node service
|
||||
*
|
||||
* @param nodeService the node service
|
||||
*/
|
||||
public void setNodeService(NodeService nodeService)
|
||||
{
|
||||
this.nodeService = nodeService;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the tenant service
|
||||
*
|
||||
* @param tenantService the tenant service
|
||||
*/
|
||||
public void setTenantService(TenantService tenantService)
|
||||
{
|
||||
this.tenantService = tenantService;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the tenant admin service
|
||||
*
|
||||
* @param tenantAdminService the tenant admin service
|
||||
*/
|
||||
public void setTenantDeployerService(TenantDeployerService tenantDeployerService)
|
||||
{
|
||||
this.tenantDeployerService = tenantDeployerService;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the namespace service
|
||||
*
|
||||
* @param namespaceService the namespace service
|
||||
*/
|
||||
public void setNamespaceService(NamespaceService namespaceService)
|
||||
{
|
||||
this.namespaceService = namespaceService;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the message service
|
||||
*
|
||||
* @param messageService the message service
|
||||
*/
|
||||
public void setMessageService(MessageService messageService)
|
||||
{
|
||||
this.messageService = messageService;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the transaction service
|
||||
*
|
||||
@@ -107,95 +186,175 @@ public class DictionaryRepositoryBootstrap
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the authentication service
|
||||
* Set the repository models locations
|
||||
*
|
||||
* @param authenticationComponent the authentication component
|
||||
*/
|
||||
public void setAuthenticationComponent(
|
||||
AuthenticationComponent authenticationComponent)
|
||||
* @param repositoryModelsLocations list of the repository models locations
|
||||
*/ public void setRepositoryModelsLocations(
|
||||
List<RepositoryLocation> repositoryLocations)
|
||||
{
|
||||
this.authenticationComponent = authenticationComponent;
|
||||
this.repositoryModelsLocations = repositoryLocations;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the respository locations
|
||||
* Set the repository messages (resource bundle) locations
|
||||
*
|
||||
* @param repositoryLocations list of the repository locaitons
|
||||
* @param repositoryLocations
|
||||
* list of the repository messages locations
|
||||
*/
|
||||
public void setRepositoryLocations(
|
||||
public void setRepositoryMessagesLocations(
|
||||
List<RepositoryLocation> repositoryLocations)
|
||||
{
|
||||
this.repositoryLocations = repositoryLocations;
|
||||
this.repositoryMessagesLocations = repositoryLocations;
|
||||
}
|
||||
|
||||
@SuppressWarnings("unchecked")
|
||||
public void bootstrap()
|
||||
|
||||
|
||||
/**
|
||||
* Initialise - after bootstrap of schema and tenant admin service
|
||||
*/
|
||||
public void init()
|
||||
{
|
||||
transactionService.getRetryingTransactionHelper().doInTransaction(new RetryingTransactionCallback()
|
||||
transactionService.getRetryingTransactionHelper().doInTransaction(new RetryingTransactionCallback<Object>()
|
||||
{
|
||||
public Object execute() throws Exception
|
||||
{
|
||||
DictionaryRepositoryBootstrap.this.authenticationComponent.setCurrentUser(
|
||||
DictionaryRepositoryBootstrap.this.authenticationComponent.getSystemUserName());
|
||||
try
|
||||
{
|
||||
bootstrapImpl();
|
||||
}
|
||||
finally
|
||||
{
|
||||
DictionaryRepositoryBootstrap.this.authenticationComponent.clearCurrentSecurityContext();
|
||||
}
|
||||
return null;
|
||||
initDictionary();
|
||||
initMessages();
|
||||
|
||||
return (Object)null;
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Bootstrap the Dictionary
|
||||
*/
|
||||
public void bootstrapImpl()
|
||||
public void destroy()
|
||||
{
|
||||
// NOOP - will be destroyed directly via DictionaryComponent
|
||||
}
|
||||
|
||||
public void initDictionary()
|
||||
{
|
||||
Map<String, M2Model> modelMap = new HashMap<String, M2Model>();
|
||||
|
||||
// Register the models found in the respository
|
||||
for (RepositoryLocation repositoryLocation : this.repositoryLocations)
|
||||
{
|
||||
ResultSet resultSet = null;
|
||||
try
|
||||
if (this.repositoryModelsLocations != null)
|
||||
{
|
||||
Map<String, M2Model> modelMap = new HashMap<String, M2Model>();
|
||||
|
||||
// Register the models found in the repository
|
||||
|
||||
for (RepositoryLocation repositoryLocation : this.repositoryModelsLocations)
|
||||
{
|
||||
resultSet = this.searchService.query(repositoryLocation.getStoreRef(), SearchService.LANGUAGE_LUCENE, repositoryLocation.getQueryStatement());
|
||||
|
||||
for (NodeRef dictionaryModel : resultSet.getNodeRefs())
|
||||
StoreRef storeRef = repositoryLocation.getStoreRef();
|
||||
|
||||
if (! nodeService.exists(storeRef))
|
||||
{
|
||||
M2Model model = createM2Model(dictionaryModel);
|
||||
if (model != null)
|
||||
logger.warn("StoreRef '"+ storeRef+"' does not exist");
|
||||
continue; // skip this location
|
||||
}
|
||||
|
||||
if (repositoryLocation.getQueryLanguage().equals(
|
||||
SearchService.LANGUAGE_XPATH))
|
||||
{
|
||||
NodeRef rootNode = nodeService.getRootNode(storeRef);
|
||||
|
||||
List<NodeRef> nodeRefs = searchService.selectNodes(rootNode,
|
||||
repositoryLocation.getXPathQueryStatement(ContentModel.TYPE_DICTIONARY_MODEL.getPrefixedQName(namespaceService)),
|
||||
null,
|
||||
namespaceService,
|
||||
false);
|
||||
|
||||
for (NodeRef dictionaryModel : nodeRefs)
|
||||
{
|
||||
for (M2Namespace namespace : model.getNamespaces())
|
||||
// TODO - should validate in case of re-deploy - e.g. update or delete
|
||||
M2Model model = createM2Model(dictionaryModel);
|
||||
if (model != null)
|
||||
{
|
||||
modelMap.put(namespace.getUri(), model);
|
||||
}
|
||||
for (M2Namespace namespace : model.getNamespaces())
|
||||
{
|
||||
modelMap.put(namespace.getUri(), model);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
finally
|
||||
|
||||
// Load the models ensuring that they are loaded in the correct order
|
||||
List<String> loadedModels = new ArrayList<String>();
|
||||
for (Map.Entry<String, M2Model> entry : modelMap.entrySet())
|
||||
{
|
||||
if (resultSet != null)
|
||||
{
|
||||
resultSet.close();
|
||||
}
|
||||
loadModel(modelMap, loadedModels, entry.getValue());
|
||||
}
|
||||
}
|
||||
|
||||
// Load the models ensuring that they are loaded in the correct order
|
||||
List<String> loadedModels = new ArrayList<String>();
|
||||
for (Map.Entry<String, M2Model> entry : modelMap.entrySet())
|
||||
}
|
||||
|
||||
public void initMessages()
|
||||
{
|
||||
if (this.repositoryMessagesLocations != null)
|
||||
{
|
||||
loadModel(modelMap, loadedModels, entry.getValue());
|
||||
// Register the messages found in the repository
|
||||
for (RepositoryLocation repositoryLocation : this.repositoryMessagesLocations)
|
||||
{
|
||||
StoreRef storeRef = repositoryLocation.getStoreRef();
|
||||
String path = repositoryLocation.getPath();
|
||||
|
||||
if (! nodeService.exists(storeRef))
|
||||
{
|
||||
logger.warn("StoreRef '"+ storeRef+"' does not exist");
|
||||
continue; // skip this location
|
||||
}
|
||||
|
||||
if (repositoryLocation.getQueryLanguage().equals(
|
||||
SearchService.LANGUAGE_XPATH))
|
||||
{
|
||||
NodeRef rootNode = nodeService.getRootNode(storeRef);
|
||||
|
||||
List<NodeRef> nodeRefs = searchService.selectNodes(rootNode,
|
||||
repositoryLocation.getXPathQueryStatement(ContentModel.TYPE_CONTENT.getPrefixedQName(namespaceService)),
|
||||
null,
|
||||
namespaceService,
|
||||
false);
|
||||
|
||||
List<String> resourceBundleBaseNames = new ArrayList<String>();
|
||||
|
||||
for (NodeRef messageResource : nodeRefs)
|
||||
{
|
||||
String name = (String) nodeService.getProperty(
|
||||
messageResource, ContentModel.PROP_NAME);
|
||||
|
||||
// convert resource file name to a resource bundle basename
|
||||
// e.g. either 'workflow_fr_FR.properties' or 'workflow.properties' should be converted to 'workflow'
|
||||
// note: this assumes that the baseName itself does not contain underscore !
|
||||
int idx = name.indexOf("_");
|
||||
if (idx > 0)
|
||||
{
|
||||
name = name.substring(0, idx - 1);
|
||||
}
|
||||
else
|
||||
{
|
||||
int idx1 = name.indexOf(".");
|
||||
if (idx1 > 0)
|
||||
{
|
||||
name = name.substring(0, idx1);
|
||||
}
|
||||
}
|
||||
|
||||
if (!resourceBundleBaseNames.contains(name))
|
||||
{
|
||||
resourceBundleBaseNames.add(name);
|
||||
}
|
||||
}
|
||||
|
||||
// Only need to register resource bundle names
|
||||
for (String resourceBundleBaseName : resourceBundleBaseNames)
|
||||
{
|
||||
logger.info("Register bundle: " + resourceBundleBaseName);
|
||||
|
||||
messageService.registerResourceBundle(storeRef.toString() + path + "/cm:" + resourceBundleBaseName);
|
||||
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Loads a model (and it dependants) if it does not exist in the list of loaded models.
|
||||
* Loads a model (and its dependents) if it does not exist in the list of loaded models.
|
||||
*
|
||||
* @param modelMap a map of the models to be loaded
|
||||
* @param loadedModels the list of models already loaded
|
||||
@@ -240,77 +399,92 @@ public class DictionaryRepositoryBootstrap
|
||||
// TODO should we inactivate the model node and put the error somewhere??
|
||||
return model;
|
||||
}
|
||||
|
||||
/**
|
||||
* Repositotry location object, defines a location in the repository from within which dictionary models should be loaded
|
||||
* for inclusion in the data dictionary.
|
||||
*
|
||||
* @author Roy Wetherall
|
||||
*/
|
||||
public class RepositoryLocation
|
||||
|
||||
@Override
|
||||
protected void onBootstrap(ApplicationEvent event)
|
||||
{
|
||||
/** Store protocol */
|
||||
private String storeProtocol;
|
||||
|
||||
/** Store identifier */
|
||||
private String storeId;
|
||||
|
||||
/** Path */
|
||||
private String path;
|
||||
|
||||
/**
|
||||
* Set the store protocol
|
||||
*
|
||||
* @param storeProtocol the store protocol
|
||||
*/
|
||||
public void setStoreProtocol(String storeProtocol)
|
||||
// run as System on bootstrap
|
||||
AuthenticationUtil.runAs(new RunAsWork<Object>()
|
||||
{
|
||||
this.storeProtocol = storeProtocol;
|
||||
public Object doWork()
|
||||
{
|
||||
init();
|
||||
return null;
|
||||
}
|
||||
}, AuthenticationUtil.getSystemUserName());
|
||||
|
||||
if (tenantService.isEnabled())
|
||||
{
|
||||
tenantDeployerService.deployTenants(this, logger);
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the store identifier
|
||||
*
|
||||
* @param storeId the store identifier
|
||||
*/
|
||||
public void setStoreId(String storeId)
|
||||
{
|
||||
this.storeId = storeId;
|
||||
}
|
||||
register();
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void onShutdown(ApplicationEvent event)
|
||||
{
|
||||
unregister();
|
||||
|
||||
/**
|
||||
* Set the path
|
||||
*
|
||||
* @param path the path
|
||||
*/
|
||||
public void setPath(String path)
|
||||
// run as System on shutdown
|
||||
AuthenticationUtil.runAs(new RunAsWork<Object>()
|
||||
{
|
||||
this.path = path;
|
||||
}
|
||||
public Object doWork()
|
||||
{
|
||||
destroy();
|
||||
return null;
|
||||
}
|
||||
}, AuthenticationUtil.getSystemUserName());
|
||||
|
||||
/**
|
||||
* Get the store reference
|
||||
*
|
||||
* @return the store reference
|
||||
*/
|
||||
public StoreRef getStoreRef()
|
||||
if (tenantService.isEnabled())
|
||||
{
|
||||
return new StoreRef(this.storeProtocol, this.storeId);
|
||||
tenantDeployerService.undeployTenants(this, logger);
|
||||
}
|
||||
}
|
||||
|
||||
public void onEnableTenant()
|
||||
{
|
||||
init(); // will be called in context of tenant
|
||||
}
|
||||
|
||||
public void onDisableTenant()
|
||||
{
|
||||
destroy(); // will be called in context of tenant
|
||||
}
|
||||
|
||||
/**
|
||||
* Register
|
||||
*/
|
||||
public void register()
|
||||
{
|
||||
// register with Dictionary Service to allow (re-)init
|
||||
dictionaryDAO.register(this);
|
||||
|
||||
// register with Message Service to allow (re-)init
|
||||
messageService.register(this);
|
||||
|
||||
/**
|
||||
* Get the query statement, based on the path
|
||||
*
|
||||
* @return the query statement
|
||||
*/
|
||||
public String getQueryStatement()
|
||||
if (tenantService.isEnabled())
|
||||
{
|
||||
String result = "+TYPE:\"" + ContentModel.TYPE_DICTIONARY_MODEL.toString() + "\"";
|
||||
if (this.path != null)
|
||||
{
|
||||
result += " +PATH:\"" + this.path + "\"";
|
||||
}
|
||||
return result;
|
||||
// register dictionary repository bootstrap
|
||||
tenantDeployerService.register(this);
|
||||
|
||||
// register repository message (I18N) service
|
||||
tenantDeployerService.register(messageService);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Unregister
|
||||
*/
|
||||
protected void unregister()
|
||||
{
|
||||
if (tenantService.isEnabled())
|
||||
{
|
||||
// register dictionary repository bootstrap
|
||||
tenantDeployerService.unregister(this);
|
||||
|
||||
// register repository message (I18N) service
|
||||
tenantDeployerService.unregister(messageService);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@@ -6,14 +6,16 @@ import java.util.List;
|
||||
|
||||
import org.alfresco.model.ContentModel;
|
||||
import org.alfresco.repo.content.MimetypeMap;
|
||||
import org.alfresco.repo.dictionary.DictionaryRepositoryBootstrap.RepositoryLocation;
|
||||
import org.alfresco.repo.i18n.MessageService;
|
||||
import org.alfresco.repo.policy.BehaviourFilter;
|
||||
import org.alfresco.repo.security.authentication.AuthenticationComponent;
|
||||
import org.alfresco.repo.tenant.TenantDeployerService;
|
||||
import org.alfresco.repo.tenant.TenantService;
|
||||
import org.alfresco.service.cmr.dictionary.DictionaryException;
|
||||
import org.alfresco.service.cmr.dictionary.ModelDefinition;
|
||||
import org.alfresco.service.cmr.repository.ContentWriter;
|
||||
import org.alfresco.service.cmr.repository.NodeRef;
|
||||
import org.alfresco.service.cmr.search.SearchService;
|
||||
import org.alfresco.service.namespace.NamespaceService;
|
||||
import org.alfresco.service.namespace.QName;
|
||||
import org.alfresco.service.transaction.TransactionService;
|
||||
import org.alfresco.util.BaseAlfrescoSpringTest;
|
||||
@@ -67,9 +69,18 @@ public class DictionaryRepositoryBootstrapTest extends BaseAlfrescoSpringTest
|
||||
|
||||
/** The transaction service */
|
||||
private TransactionService transactionService;
|
||||
|
||||
/** The authentication service */
|
||||
private AuthenticationComponent authenticationComponent;
|
||||
|
||||
/** The tenant service */
|
||||
private TenantService tenantService;
|
||||
|
||||
/** The tenant deployer service */
|
||||
private TenantDeployerService tenantDeployerService;
|
||||
|
||||
/** The namespace service */
|
||||
private NamespaceService namespaceService;
|
||||
|
||||
/** The message service */
|
||||
private MessageService messageService;
|
||||
|
||||
/**
|
||||
* @see org.springframework.test.AbstractTransactionalSpringContextTests#onSetUpInTransaction()
|
||||
@@ -85,24 +96,35 @@ public class DictionaryRepositoryBootstrapTest extends BaseAlfrescoSpringTest
|
||||
|
||||
this.searchService = (SearchService)this.applicationContext.getBean("searchService");
|
||||
this.dictionaryDAO = (DictionaryDAO)this.applicationContext.getBean("dictionaryDAO");
|
||||
this.transactionService = (TransactionService)this.applicationContext.getBean("transactionComponent");
|
||||
this.authenticationComponent = (AuthenticationComponent)this.applicationContext.getBean("authenticationComponent");
|
||||
this.transactionService = (TransactionService)this.applicationContext.getBean("transactionComponent");
|
||||
this.tenantService = (TenantService)this.applicationContext.getBean("tenantService");
|
||||
this.tenantDeployerService = (TenantDeployerService)this.applicationContext.getBean("tenantAdminService");
|
||||
this.namespaceService = (NamespaceService)this.applicationContext.getBean("namespaceService");
|
||||
this.messageService = (MessageService)this.applicationContext.getBean("messageService");
|
||||
|
||||
this.bootstrap = new DictionaryRepositoryBootstrap();
|
||||
this.bootstrap.setContentService(this.contentService);
|
||||
this.bootstrap.setSearchService(this.searchService);
|
||||
this.bootstrap.setDictionaryDAO(this.dictionaryDAO);
|
||||
this.bootstrap.setAuthenticationComponent(this.authenticationComponent);
|
||||
this.bootstrap.setTransactionService(this.transactionService);
|
||||
|
||||
RepositoryLocation location = this.bootstrap.new RepositoryLocation();
|
||||
this.bootstrap.setTransactionService(this.transactionService);
|
||||
this.bootstrap.setTenantService(this.tenantService);
|
||||
this.bootstrap.setTenantDeployerService(this.tenantDeployerService);
|
||||
this.bootstrap.setNodeService(this.nodeService);
|
||||
this.bootstrap.setNamespaceService(this.namespaceService);
|
||||
this.bootstrap.setMessageService(this.messageService);
|
||||
|
||||
RepositoryLocation location = new RepositoryLocation();
|
||||
location.setStoreProtocol(this.storeRef.getProtocol());
|
||||
location.setStoreId(this.storeRef.getIdentifier());
|
||||
// NOTE: we are not setting the path for now .. in doing so we are searching the whole dictionary
|
||||
|
||||
List<RepositoryLocation> locations = new ArrayList<RepositoryLocation>();
|
||||
locations.add(location);
|
||||
this.bootstrap.setRepositoryLocations(locations);
|
||||
|
||||
this.bootstrap.setRepositoryModelsLocations(locations);
|
||||
|
||||
// register with dictionary service
|
||||
this.bootstrap.register();
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -148,7 +170,7 @@ public class DictionaryRepositoryBootstrapTest extends BaseAlfrescoSpringTest
|
||||
}
|
||||
|
||||
// Now do the bootstrap
|
||||
this.bootstrap.bootstrap();
|
||||
this.bootstrap.init();
|
||||
|
||||
// Check that the model is now there
|
||||
ModelDefinition modelDefinition1 = this.dictionaryDAO.getModel(
|
||||
|
@@ -66,4 +66,18 @@ public interface NamespaceDAO extends NamespacePrefixResolver
|
||||
*/
|
||||
public void removePrefix(String prefix);
|
||||
|
||||
/**
|
||||
* Initialise Namespaces
|
||||
*/
|
||||
public void init();
|
||||
|
||||
/**
|
||||
* Destroy Namespaces
|
||||
*/
|
||||
public void destroy();
|
||||
|
||||
/**
|
||||
* Register with the Dictionary
|
||||
*/
|
||||
public void registerDictionary(DictionaryDAO dictionaryDAO);
|
||||
}
|
||||
|
@@ -29,22 +29,153 @@ import java.util.Collection;
|
||||
import java.util.Collections;
|
||||
import java.util.HashMap;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.concurrent.locks.Lock;
|
||||
import java.util.concurrent.locks.ReadWriteLock;
|
||||
import java.util.concurrent.locks.ReentrantReadWriteLock;
|
||||
|
||||
import org.alfresco.error.AlfrescoRuntimeException;
|
||||
import org.alfresco.repo.cache.SimpleCache;
|
||||
import org.alfresco.repo.tenant.TenantService;
|
||||
import org.alfresco.service.namespace.NamespaceException;
|
||||
import org.apache.commons.logging.Log;
|
||||
import org.apache.commons.logging.LogFactory;
|
||||
|
||||
/**
|
||||
* Simple in-memory namespace DAO
|
||||
*/
|
||||
public class NamespaceDAOImpl implements NamespaceDAO
|
||||
{
|
||||
private static final Log logger = LogFactory.getLog(NamespaceDAOImpl.class);
|
||||
|
||||
/**
|
||||
* Lock objects
|
||||
*/
|
||||
private ReadWriteLock lock = new ReentrantReadWriteLock();
|
||||
private Lock readLock = lock.readLock();
|
||||
private Lock writeLock = lock.writeLock();
|
||||
|
||||
// internal caches that are clusterable
|
||||
private SimpleCache<String, List<String>> urisCache;
|
||||
private SimpleCache<String, Map<String, String>> prefixesCache;
|
||||
|
||||
private List<String> uris = new ArrayList<String>();
|
||||
private HashMap<String, String> prefixes = new HashMap<String, String>();
|
||||
// Dependencies
|
||||
private TenantService tenantService;
|
||||
|
||||
|
||||
public void setTenantService(TenantService tenantService)
|
||||
{
|
||||
this.tenantService = tenantService;
|
||||
}
|
||||
|
||||
public void setUrisCache(SimpleCache<String, List<String>> urisCache)
|
||||
{
|
||||
this.urisCache = urisCache;
|
||||
}
|
||||
|
||||
public void setPrefixesCache(SimpleCache<String, Map<String, String>> prefixesCache)
|
||||
{
|
||||
this.prefixesCache = prefixesCache;
|
||||
}
|
||||
|
||||
|
||||
private DictionaryDAO dictionaryDAO;
|
||||
|
||||
public void registerDictionary(DictionaryDAO dictionaryDAO)
|
||||
{
|
||||
this.dictionaryDAO = dictionaryDAO;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Initialise empty namespaces
|
||||
*/
|
||||
public void init()
|
||||
{
|
||||
String tenantDomain = getTenantDomain();
|
||||
|
||||
putUrisCtx(tenantDomain, new ArrayList<String>());
|
||||
putPrefixesCtx(tenantDomain, new HashMap<String, String>());
|
||||
|
||||
if (logger.isDebugEnabled())
|
||||
{
|
||||
logger.debug("Empty namespaces initialised");
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Destroy the namespaces
|
||||
*/
|
||||
public void destroy()
|
||||
{
|
||||
String tenantDomain = getTenantDomain();
|
||||
|
||||
removeUrisCtx(tenantDomain);
|
||||
removePrefixesCtx(tenantDomain);
|
||||
|
||||
if (logger.isDebugEnabled())
|
||||
{
|
||||
logger.debug("Namespaces destroyed");
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Resets the namespaces (by resetting the dictionary)
|
||||
*/
|
||||
private void reset()
|
||||
{
|
||||
if (logger.isDebugEnabled())
|
||||
{
|
||||
logger.debug("Resetting namespaces ...");
|
||||
}
|
||||
|
||||
if (dictionaryDAO == null)
|
||||
{
|
||||
// Unexpected
|
||||
throw new AlfrescoRuntimeException("Dictionary should be registered in order to perform reset");
|
||||
}
|
||||
else
|
||||
{
|
||||
dictionaryDAO.reset();
|
||||
}
|
||||
|
||||
if (logger.isDebugEnabled())
|
||||
{
|
||||
logger.debug("... resetting namespaces completed");
|
||||
}
|
||||
}
|
||||
|
||||
/* (non-Javadoc)
|
||||
* @see org.alfresco.repo.ref.NamespacePrefixResolver#getURIs()
|
||||
*/
|
||||
public Collection<String> getURIs()
|
||||
{
|
||||
return Collections.unmodifiableCollection(uris);
|
||||
if (! tenantService.isTenantUser())
|
||||
{
|
||||
return Collections.unmodifiableCollection(getUrisCtx());
|
||||
}
|
||||
else
|
||||
{
|
||||
// Get tenant-specific URIs
|
||||
List<String> domainUris = getUrisCtx();
|
||||
|
||||
// Get non-tenant-specific URIs (and filter out, if overridden)
|
||||
List<String> urisFiltered = new ArrayList<String>();
|
||||
for(String uri : getUrisCtx(""))
|
||||
{
|
||||
if (domainUris.contains(uri))
|
||||
{
|
||||
// overridden, hence skip this default prefix
|
||||
continue;
|
||||
}
|
||||
urisFiltered.add(uri);
|
||||
}
|
||||
|
||||
// default (non-overridden) + tenant-specific
|
||||
urisFiltered.addAll(domainUris);
|
||||
|
||||
return Collections.unmodifiableCollection(urisFiltered);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -52,8 +183,33 @@ public class NamespaceDAOImpl implements NamespaceDAO
|
||||
* @see org.alfresco.repo.ref.NamespacePrefixResolver#getPrefixes()
|
||||
*/
|
||||
public Collection<String> getPrefixes()
|
||||
{
|
||||
return Collections.unmodifiableCollection(prefixes.keySet());
|
||||
{
|
||||
if (! tenantService.isTenantUser())
|
||||
{
|
||||
return Collections.unmodifiableCollection(getPrefixesCtx().keySet());
|
||||
}
|
||||
else
|
||||
{
|
||||
// Get tenant-specific prefixes
|
||||
Collection<String> domainPrefixes = getPrefixesCtx().keySet();
|
||||
|
||||
// Get non-tenant-specific URIs (and filter out, if overridden)
|
||||
List<String> prefixesFiltered = new ArrayList<String>();
|
||||
for(String prefix : getPrefixesCtx("").keySet())
|
||||
{
|
||||
if (domainPrefixes.contains(prefix))
|
||||
{
|
||||
// overridden, hence skip this default prefix
|
||||
continue;
|
||||
}
|
||||
prefixesFiltered.add(prefix);
|
||||
}
|
||||
|
||||
// default (non-overridden) + tenant-specific
|
||||
prefixesFiltered.addAll(domainPrefixes);
|
||||
|
||||
return Collections.unmodifiableCollection(prefixesFiltered);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -62,11 +218,11 @@ public class NamespaceDAOImpl implements NamespaceDAO
|
||||
*/
|
||||
public void addURI(String uri)
|
||||
{
|
||||
if (uris.contains(uri))
|
||||
if (getUrisCtx().contains(uri))
|
||||
{
|
||||
throw new NamespaceException("URI " + uri + " has already been defined");
|
||||
}
|
||||
uris.add(uri);
|
||||
getUrisCtx().add(uri);
|
||||
}
|
||||
|
||||
|
||||
@@ -75,11 +231,11 @@ public class NamespaceDAOImpl implements NamespaceDAO
|
||||
*/
|
||||
public void addPrefix(String prefix, String uri)
|
||||
{
|
||||
if (!uris.contains(uri))
|
||||
if (!getUrisCtx().contains(uri))
|
||||
{
|
||||
throw new NamespaceException("Namespace URI " + uri + " does not exist");
|
||||
}
|
||||
prefixes.put(prefix, uri);
|
||||
getPrefixesCtx().put(prefix, uri);
|
||||
}
|
||||
|
||||
|
||||
@@ -88,7 +244,7 @@ public class NamespaceDAOImpl implements NamespaceDAO
|
||||
*/
|
||||
public void removeURI(String uri)
|
||||
{
|
||||
uris.remove(uri);
|
||||
getUrisCtx().remove(uri);
|
||||
}
|
||||
|
||||
|
||||
@@ -97,7 +253,7 @@ public class NamespaceDAOImpl implements NamespaceDAO
|
||||
*/
|
||||
public void removePrefix(String prefix)
|
||||
{
|
||||
prefixes.remove(prefix);
|
||||
getPrefixesCtx().remove(prefix);
|
||||
}
|
||||
|
||||
|
||||
@@ -106,7 +262,25 @@ public class NamespaceDAOImpl implements NamespaceDAO
|
||||
*/
|
||||
public String getNamespaceURI(String prefix)
|
||||
{
|
||||
return prefixes.get(prefix);
|
||||
if (! tenantService.isTenantUser())
|
||||
{
|
||||
return getPrefixesCtx().get(prefix);
|
||||
}
|
||||
else
|
||||
{
|
||||
// first look for tenant-specific prefix
|
||||
String uri = getPrefixesCtx().get(prefix);
|
||||
if (uri != null)
|
||||
{
|
||||
// found tenant specific uri
|
||||
return uri;
|
||||
}
|
||||
else
|
||||
{
|
||||
// try with default (non-tenant-specific) prefix
|
||||
return getPrefixesCtx("").get(prefix);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -115,16 +289,255 @@ public class NamespaceDAOImpl implements NamespaceDAO
|
||||
*/
|
||||
public Collection<String> getPrefixes(String URI)
|
||||
{
|
||||
Collection<String> uriPrefixes = new ArrayList<String>();
|
||||
for (String key : prefixes.keySet())
|
||||
if (! tenantService.isTenantUser())
|
||||
{
|
||||
String uri = prefixes.get(key);
|
||||
if ((uri != null) && (uri.equals(URI)))
|
||||
Collection<String> uriPrefixes = new ArrayList<String>();
|
||||
for (String key : getPrefixesCtx().keySet())
|
||||
{
|
||||
uriPrefixes.add(key);
|
||||
String uri = getPrefixesCtx().get(key);
|
||||
if ((uri != null) && (uri.equals(URI)))
|
||||
{
|
||||
uriPrefixes.add(key);
|
||||
}
|
||||
}
|
||||
return uriPrefixes;
|
||||
}
|
||||
return uriPrefixes;
|
||||
else
|
||||
{
|
||||
// check domain prefixes
|
||||
Collection<String> domainUriPrefixes = new ArrayList<String>();
|
||||
for (String key : getPrefixesCtx().keySet())
|
||||
{
|
||||
String uri = getPrefixesCtx().get(key);
|
||||
if ((uri != null) && (uri.equals(URI)))
|
||||
{
|
||||
domainUriPrefixes.add(key);
|
||||
}
|
||||
}
|
||||
|
||||
// check non-domain prefixes
|
||||
Collection<String> uriPrefixes = new ArrayList<String>();
|
||||
for (String key : getPrefixesCtx("").keySet())
|
||||
{
|
||||
String uri = getPrefixesCtx("").get(key);
|
||||
if ((uri != null) && (uri.equals(URI)))
|
||||
{
|
||||
if (domainUriPrefixes != null)
|
||||
{
|
||||
if (domainUriPrefixes.contains(key))
|
||||
{
|
||||
// overridden, hence skip this default prefix
|
||||
continue;
|
||||
}
|
||||
}
|
||||
|
||||
uriPrefixes.add(key);
|
||||
}
|
||||
}
|
||||
|
||||
if (domainUriPrefixes != null)
|
||||
{
|
||||
// default (non-overridden) + domain
|
||||
uriPrefixes.addAll(domainUriPrefixes);
|
||||
}
|
||||
|
||||
return uriPrefixes;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Get URIs from the cache (in the context of the current user's tenant domain)
|
||||
*
|
||||
* @return URIs
|
||||
*/
|
||||
private List<String> getUrisCtx()
|
||||
{
|
||||
return getUrisCtx(getTenantDomain());
|
||||
}
|
||||
|
||||
/**
|
||||
* Get URIs from the cache
|
||||
*
|
||||
* @param tenantDomain
|
||||
* @return URIs
|
||||
*/
|
||||
private List<String> getUrisCtx(String tenantDomain)
|
||||
{
|
||||
List<String> uris = null;
|
||||
try
|
||||
{
|
||||
readLock.lock();
|
||||
uris = urisCache.get(tenantDomain);
|
||||
}
|
||||
finally
|
||||
{
|
||||
readLock.unlock();
|
||||
}
|
||||
|
||||
|
||||
if (uris == null)
|
||||
{
|
||||
reset(); // reset caches - may have been invalidated (e.g. in a cluster)
|
||||
|
||||
try
|
||||
{
|
||||
readLock.lock();
|
||||
uris = urisCache.get(tenantDomain);
|
||||
}
|
||||
finally
|
||||
{
|
||||
readLock.unlock();
|
||||
}
|
||||
|
||||
if (uris == null)
|
||||
{
|
||||
// unexpected
|
||||
throw new AlfrescoRuntimeException("Failed to re-initialise urisCache " + tenantDomain);
|
||||
}
|
||||
}
|
||||
return uris;
|
||||
}
|
||||
|
||||
/**
|
||||
* Put URIs into the cache
|
||||
*
|
||||
* @param tenantDomain
|
||||
* @param uris
|
||||
*/
|
||||
private void putUrisCtx(String tenantDomain, List<String> uris)
|
||||
{
|
||||
try
|
||||
{
|
||||
writeLock.lock();
|
||||
urisCache.put(tenantDomain, uris);
|
||||
}
|
||||
finally
|
||||
{
|
||||
writeLock.unlock();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Remove URIs from the cache
|
||||
*
|
||||
* @param tenantDomain
|
||||
*/
|
||||
private void removeUrisCtx(String tenantDomain)
|
||||
{
|
||||
try
|
||||
{
|
||||
writeLock.lock();
|
||||
if (urisCache.get(tenantDomain) != null)
|
||||
{
|
||||
urisCache.get(tenantDomain).clear();
|
||||
urisCache.remove(tenantDomain);
|
||||
}
|
||||
}
|
||||
finally
|
||||
{
|
||||
writeLock.unlock();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Get prefixes from the cache
|
||||
*
|
||||
* @return prefixes
|
||||
*/
|
||||
private Map<String, String> getPrefixesCtx()
|
||||
{
|
||||
return getPrefixesCtx(getTenantDomain());
|
||||
}
|
||||
|
||||
/**
|
||||
* Get prefixes from the cache
|
||||
*
|
||||
* @param tenantDomain
|
||||
* @return prefixes
|
||||
*/
|
||||
private Map<String, String> getPrefixesCtx(String tenantDomain)
|
||||
{
|
||||
Map<String, String> prefixes = null;
|
||||
try
|
||||
{
|
||||
readLock.lock();
|
||||
prefixes = prefixesCache.get(tenantDomain);
|
||||
}
|
||||
finally
|
||||
{
|
||||
readLock.unlock();
|
||||
}
|
||||
|
||||
if (prefixes == null)
|
||||
{
|
||||
reset(); // reset caches - may have been invalidated (e.g. in a cluster)
|
||||
|
||||
try
|
||||
{
|
||||
readLock.lock();
|
||||
prefixes = prefixesCache.get(tenantDomain);
|
||||
}
|
||||
finally
|
||||
{
|
||||
readLock.unlock();
|
||||
}
|
||||
|
||||
if (prefixes == null)
|
||||
{
|
||||
// unexpected
|
||||
throw new AlfrescoRuntimeException("Failed to re-initialise prefixesCache " + tenantDomain);
|
||||
}
|
||||
}
|
||||
|
||||
return prefixes;
|
||||
}
|
||||
|
||||
/**
|
||||
* Put prefixes into the cache
|
||||
*
|
||||
* @param tenantDomain
|
||||
* @param prefixes
|
||||
*/
|
||||
private void putPrefixesCtx(String tenantDomain, Map<String, String> prefixes)
|
||||
{
|
||||
try
|
||||
{
|
||||
writeLock.lock();
|
||||
prefixesCache.put(tenantDomain, prefixes);
|
||||
}
|
||||
finally
|
||||
{
|
||||
writeLock.unlock();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Remove prefixes from the cache
|
||||
*
|
||||
* @param tenantDomain
|
||||
*/
|
||||
private void removePrefixesCtx(String tenantDomain)
|
||||
{
|
||||
try
|
||||
{
|
||||
writeLock.lock();
|
||||
if (prefixesCache.get(tenantDomain) != null)
|
||||
{
|
||||
prefixesCache.get(tenantDomain).clear();
|
||||
prefixesCache.remove(tenantDomain);
|
||||
}
|
||||
}
|
||||
finally
|
||||
{
|
||||
writeLock.unlock();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Local helper - returns tenant domain (or empty string if default non-tenant)
|
||||
*/
|
||||
private String getTenantDomain()
|
||||
{
|
||||
return tenantService.getCurrentUserDomain();
|
||||
}
|
||||
}
|
||||
|
186
source/java/org/alfresco/repo/dictionary/RepositoryLocation.java
Executable file
186
source/java/org/alfresco/repo/dictionary/RepositoryLocation.java
Executable file
@@ -0,0 +1,186 @@
|
||||
/*
|
||||
* Copyright (C) 2005-2007 Alfresco Software Limited.
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU General Public License
|
||||
* as published by the Free Software Foundation; either version 2
|
||||
* of the License, or (at your option) any later version.
|
||||
|
||||
* This program 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 General Public License for more details.
|
||||
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program; if not, write to the Free Software
|
||||
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
|
||||
|
||||
* As a special exception to the terms and conditions of version 2.0 of
|
||||
* the GPL, you may redistribute this Program in connection with Free/Libre
|
||||
* and Open Source Software ("FLOSS") applications as described in Alfresco's
|
||||
* FLOSS exception. You should have recieved a copy of the text describing
|
||||
* the FLOSS exception, and it is also available here:
|
||||
* http://www.alfresco.com/legal/licensing"
|
||||
*/
|
||||
package org.alfresco.repo.dictionary;
|
||||
|
||||
import org.alfresco.repo.search.SearcherException;
|
||||
import org.alfresco.service.cmr.repository.StoreRef;
|
||||
import org.alfresco.service.cmr.search.SearchService;
|
||||
import org.alfresco.service.namespace.QName;
|
||||
|
||||
/**
|
||||
* Repository location object, defines a location in the repository from which dictionary models/resources should be loaded
|
||||
* for inclusion in the data dictionary.
|
||||
*
|
||||
*/
|
||||
public class RepositoryLocation
|
||||
{
|
||||
/** Store protocol */
|
||||
private String storeProtocol = StoreRef.PROTOCOL_WORKSPACE; // default
|
||||
|
||||
/** Store identifier */
|
||||
private String storeId = "SpacesStore"; // default
|
||||
|
||||
/** Path */
|
||||
private String path = ""; // default
|
||||
|
||||
/** Search Language */
|
||||
private String queryLanguage = "xpath"; // default
|
||||
|
||||
|
||||
/**
|
||||
*/
|
||||
public RepositoryLocation()
|
||||
{
|
||||
}
|
||||
|
||||
/**
|
||||
* Constructor
|
||||
*
|
||||
* @param storeRef the store reference (e.g. 'workspace://SpacesStore' )
|
||||
* @param path the path (e.g. '/app:company_home/app:dictionary/app:models' )
|
||||
* @param queryLanguage the query language (e.g. 'xpath' or 'lucence')
|
||||
*/
|
||||
public RepositoryLocation(StoreRef storeRef, String path, String queryLanguage)
|
||||
{
|
||||
this.storeProtocol = storeRef.getProtocol();
|
||||
this.storeId = storeRef.getIdentifier();
|
||||
this.path = path;
|
||||
|
||||
setQueryLanguage(queryLanguage);
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the store protocol
|
||||
*
|
||||
* @param storeProtocol the store protocol
|
||||
*/
|
||||
public void setStoreProtocol(String storeProtocol)
|
||||
{
|
||||
this.storeProtocol = storeProtocol;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the store identifier
|
||||
*
|
||||
* @param storeId the store identifier
|
||||
*/
|
||||
public void setStoreId(String storeId)
|
||||
{
|
||||
this.storeId = storeId;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the path
|
||||
*
|
||||
* Example path: /app:company_home/app:dictionary/app:models
|
||||
*
|
||||
* @param path the path
|
||||
*/
|
||||
public void setPath(String path)
|
||||
{
|
||||
this.path = path;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the queru language
|
||||
*
|
||||
* @param path the search language
|
||||
*/
|
||||
public void setQueryLanguage(String queryLanguage)
|
||||
{
|
||||
if (queryLanguage.equals(SearchService.LANGUAGE_LUCENE) || queryLanguage.equals(SearchService.LANGUAGE_XPATH))
|
||||
{
|
||||
this.queryLanguage = queryLanguage;
|
||||
}
|
||||
else
|
||||
{
|
||||
throw new SearcherException("Unknown query language: " + queryLanguage);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the store reference
|
||||
*
|
||||
* @return the store reference
|
||||
*/
|
||||
public StoreRef getStoreRef()
|
||||
{
|
||||
return new StoreRef(this.storeProtocol, this.storeId);
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the path
|
||||
*
|
||||
* @return the path
|
||||
*/
|
||||
public String getPath()
|
||||
{
|
||||
return this.path;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the query language
|
||||
*
|
||||
* @return the query language
|
||||
*/
|
||||
public String getQueryLanguage()
|
||||
{
|
||||
return this.queryLanguage;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the Lucene query statement for models, based on the path
|
||||
*
|
||||
* @return the Lucene query statement
|
||||
*/
|
||||
public String getLuceneQueryStatement(QName contentModelType)
|
||||
{
|
||||
String result = "+TYPE:\"" + contentModelType.toString() + "\"";
|
||||
|
||||
if (this.path != null)
|
||||
{
|
||||
result += " +PATH:\"" + this.path + "\"";
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the XPath query statement for models, based on the path
|
||||
*
|
||||
* @return the XPath query statement
|
||||
*/
|
||||
public String getXPathQueryStatement(QName prefixResolvedContentModelType)
|
||||
{
|
||||
String result = "/*[subtypeOf('" + prefixResolvedContentModelType.toPrefixString() + "')]"; // immediate children only
|
||||
|
||||
if (this.path != null)
|
||||
{
|
||||
result = this.path + result;
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
}
|
@@ -26,6 +26,15 @@ package org.alfresco.repo.dictionary;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
|
||||
import net.sf.ehcache.Cache;
|
||||
import net.sf.ehcache.CacheManager;
|
||||
|
||||
import org.alfresco.repo.cache.EhCacheAdapter;
|
||||
import org.alfresco.repo.tenant.SingleTServiceImpl;
|
||||
import org.alfresco.repo.tenant.TenantService;
|
||||
import org.alfresco.service.namespace.QName;
|
||||
|
||||
|
||||
/**
|
||||
@@ -67,8 +76,17 @@ public class TestModel
|
||||
}
|
||||
|
||||
// construct dictionary dao
|
||||
NamespaceDAO namespaceDAO = new NamespaceDAOImpl();
|
||||
TenantService tenantService = new SingleTServiceImpl();
|
||||
|
||||
NamespaceDAOImpl namespaceDAO = new NamespaceDAOImpl();
|
||||
namespaceDAO.setTenantService(tenantService);
|
||||
|
||||
initNamespaceCaches(namespaceDAO);
|
||||
|
||||
DictionaryDAOImpl dictionaryDAO = new DictionaryDAOImpl(namespaceDAO);
|
||||
dictionaryDAO.setTenantService(tenantService);
|
||||
|
||||
initDictionaryCaches(dictionaryDAO);
|
||||
|
||||
// bootstrap dao
|
||||
try
|
||||
@@ -90,4 +108,42 @@ public class TestModel
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private static void initDictionaryCaches(DictionaryDAOImpl dictionaryDAO)
|
||||
{
|
||||
CacheManager cacheManager = new CacheManager();
|
||||
|
||||
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>>>();
|
||||
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>>();
|
||||
compileModelCache.setCache(compileModelsEhCache);
|
||||
|
||||
dictionaryDAO.setCompiledModelsCache(compileModelCache);
|
||||
}
|
||||
|
||||
private static void initNamespaceCaches(NamespaceDAOImpl namespaceDAO)
|
||||
{
|
||||
CacheManager cacheManager = new CacheManager();
|
||||
|
||||
Cache urisEhCache = new Cache("urisCache", 50, false, true, 0L, 0L);
|
||||
cacheManager.addCache(urisEhCache);
|
||||
EhCacheAdapter<String, List<String>> urisCache = new EhCacheAdapter<String, List<String>>();
|
||||
urisCache.setCache(urisEhCache);
|
||||
|
||||
namespaceDAO.setUrisCache(urisCache);
|
||||
|
||||
Cache prefixesEhCache = new Cache("prefixesCache", 50, false, true, 0L, 0L);
|
||||
cacheManager.addCache(prefixesEhCache);
|
||||
EhCacheAdapter<String, Map<String, String>> prefixesCache = new EhCacheAdapter<String, Map<String, String>>();
|
||||
prefixesCache.setCache(prefixesEhCache);
|
||||
|
||||
namespaceDAO.setPrefixesCache(prefixesCache);
|
||||
}
|
||||
}
|
Reference in New Issue
Block a user