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>
|
</property>
|
||||||
</bean>
|
</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>
|
</beans>
|
@@ -600,7 +600,19 @@
|
|||||||
<!-- Data Dictionary -->
|
<!-- 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">
|
<bean id="dictionaryModelType" class="org.alfresco.repo.dictionary.DictionaryModelType" init-method="init">
|
||||||
<property name="dictionaryDAO">
|
<property name="dictionaryDAO">
|
||||||
@@ -624,6 +636,15 @@
|
|||||||
<constructor-arg index="0">
|
<constructor-arg index="0">
|
||||||
<ref bean="namespaceDAO" />
|
<ref bean="namespaceDAO" />
|
||||||
</constructor-arg>
|
</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>
|
||||||
|
|
||||||
<bean id="dictionaryService" class="org.alfresco.repo.dictionary.DictionaryComponent" depends-on="dictionaryBootstrap">
|
<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">
|
<bean id="dictionaryModelBootstrap" class="org.alfresco.repo.dictionary.DictionaryBootstrap" init-method="bootstrap" abstract="true">
|
||||||
<property name="dictionaryDAO"><ref local="dictionaryDAO"/></property>
|
<property name="dictionaryDAO"><ref local="dictionaryDAO"/></property>
|
||||||
|
<property name="tenantService">
|
||||||
|
<ref bean="tenantService"/>
|
||||||
|
</property>
|
||||||
</bean>
|
</bean>
|
||||||
|
|
||||||
<bean id="dictionaryBootstrap" parent="dictionaryModelBootstrap" depends-on="resourceBundles">
|
<bean id="dictionaryBootstrap" parent="dictionaryModelBootstrap" depends-on="resourceBundles">
|
||||||
@@ -690,24 +714,6 @@
|
|||||||
</list>
|
</list>
|
||||||
</property>
|
</property>
|
||||||
</bean>
|
</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 -->
|
<!-- Copy Service -->
|
||||||
|
@@ -354,4 +354,34 @@
|
|||||||
overflowToDisk="false"
|
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>
|
</ehcache>
|
@@ -650,6 +650,70 @@
|
|||||||
|
|
||||||
</cache>
|
</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>
|
</ehcache>
|
||||||
|
|
||||||
|
|
||||||
|
@@ -29,18 +29,19 @@ import java.util.ArrayList;
|
|||||||
import java.util.List;
|
import java.util.List;
|
||||||
|
|
||||||
import org.alfresco.i18n.I18NUtil;
|
import org.alfresco.i18n.I18NUtil;
|
||||||
|
import org.alfresco.repo.tenant.TenantService;
|
||||||
import org.alfresco.service.cmr.dictionary.DictionaryException;
|
import org.alfresco.service.cmr.dictionary.DictionaryException;
|
||||||
import org.apache.commons.logging.Log;
|
import org.apache.commons.logging.Log;
|
||||||
import org.apache.commons.logging.LogFactory;
|
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
|
* @author David Caruana
|
||||||
*
|
*
|
||||||
*/
|
*/
|
||||||
public class DictionaryBootstrap
|
public class DictionaryBootstrap implements DictionaryDeployer
|
||||||
{
|
{
|
||||||
// The list of models to bootstrap with
|
// The list of models to bootstrap with
|
||||||
private List<String> models = new ArrayList<String>();
|
private List<String> models = new ArrayList<String>();
|
||||||
@@ -50,6 +51,9 @@ public class DictionaryBootstrap
|
|||||||
|
|
||||||
// Dictionary DAO
|
// Dictionary DAO
|
||||||
private DictionaryDAO dictionaryDAO = null;
|
private DictionaryDAO dictionaryDAO = null;
|
||||||
|
|
||||||
|
// Tenant Service
|
||||||
|
private TenantService tenantService;
|
||||||
|
|
||||||
// Logger
|
// Logger
|
||||||
private static Log logger = LogFactory.getLog(DictionaryDAO.class);
|
private static Log logger = LogFactory.getLog(DictionaryDAO.class);
|
||||||
@@ -65,6 +69,16 @@ public class DictionaryBootstrap
|
|||||||
this.dictionaryDAO = dictionaryDAO;
|
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
|
* 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()
|
public void bootstrap()
|
||||||
{
|
{
|
||||||
// register models
|
initDictionary();
|
||||||
for (String bootstrapModel : models)
|
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);
|
// register models
|
||||||
if (modelStream == null)
|
for (String bootstrapModel : models)
|
||||||
{
|
{
|
||||||
throw new DictionaryException("Could not find bootstrap model " + bootstrapModel);
|
InputStream modelStream = getClass().getClassLoader().getResourceAsStream(bootstrapModel);
|
||||||
}
|
if (modelStream == null)
|
||||||
try
|
{
|
||||||
{
|
throw new DictionaryException("Could not find bootstrap model " + bootstrapModel);
|
||||||
if (logger.isInfoEnabled())
|
}
|
||||||
logger.info("Loading model from " + bootstrapModel);
|
try
|
||||||
|
{
|
||||||
M2Model model = M2Model.createModel(modelStream);
|
if (logger.isInfoEnabled())
|
||||||
dictionaryDAO.putModel(model);
|
logger.info("Loading model from " + bootstrapModel);
|
||||||
}
|
|
||||||
catch(DictionaryException e)
|
M2Model model = M2Model.createModel(modelStream);
|
||||||
{
|
dictionaryDAO.putModel(model);
|
||||||
throw new DictionaryException("Could not import bootstrap model " + bootstrapModel, e);
|
}
|
||||||
|
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)
|
for (String resourceBundle : resourceBundles)
|
||||||
{
|
{
|
||||||
I18NUtil.registerResourceBundle(resourceBundle);
|
I18NUtil.registerResourceBundle(resourceBundle);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
@@ -27,9 +27,9 @@ package org.alfresco.repo.dictionary;
|
|||||||
import java.util.ArrayList;
|
import java.util.ArrayList;
|
||||||
import java.util.Collection;
|
import java.util.Collection;
|
||||||
import java.util.HashSet;
|
import java.util.HashSet;
|
||||||
import java.util.LinkedHashSet;
|
|
||||||
import java.util.Map;
|
import java.util.Map;
|
||||||
|
|
||||||
|
import org.alfresco.repo.tenant.TenantDeployer;
|
||||||
import org.alfresco.service.cmr.dictionary.AspectDefinition;
|
import org.alfresco.service.cmr.dictionary.AspectDefinition;
|
||||||
import org.alfresco.service.cmr.dictionary.AssociationDefinition;
|
import org.alfresco.service.cmr.dictionary.AssociationDefinition;
|
||||||
import org.alfresco.service.cmr.dictionary.ClassDefinition;
|
import org.alfresco.service.cmr.dictionary.ClassDefinition;
|
||||||
@@ -48,7 +48,7 @@ import org.alfresco.util.ParameterCheck;
|
|||||||
*
|
*
|
||||||
* @author David Caruana
|
* @author David Caruana
|
||||||
*/
|
*/
|
||||||
public class DictionaryComponent implements DictionaryService
|
public class DictionaryComponent implements DictionaryService, TenantDeployer
|
||||||
{
|
{
|
||||||
private DictionaryDAO dictionaryDAO;
|
private DictionaryDAO dictionaryDAO;
|
||||||
|
|
||||||
@@ -339,6 +339,26 @@ public class DictionaryComponent implements DictionaryService
|
|||||||
}
|
}
|
||||||
return props;
|
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.
|
* Adds a model to the dictionary. The model is compiled and validated.
|
||||||
*
|
*
|
||||||
* @param model the model to add
|
* @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
|
* 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);
|
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.HashSet;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
import java.util.Map;
|
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.AspectDefinition;
|
||||||
import org.alfresco.service.cmr.dictionary.AssociationDefinition;
|
import org.alfresco.service.cmr.dictionary.AssociationDefinition;
|
||||||
import org.alfresco.service.cmr.dictionary.ClassDefinition;
|
import org.alfresco.service.cmr.dictionary.ClassDefinition;
|
||||||
@@ -59,20 +67,51 @@ public class DictionaryDAOImpl implements DictionaryDAO
|
|||||||
// registration of models, the ability to load models
|
// registration of models, the ability to load models
|
||||||
// from a persistent store, the refresh of the cache
|
// from a persistent store, the refresh of the cache
|
||||||
// and concurrent read/write of the models.
|
// 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
|
// Namespace Data Access
|
||||||
private NamespaceDAO namespaceDAO;
|
private NamespaceDAO namespaceDAO;
|
||||||
|
|
||||||
|
// Tenant Service
|
||||||
|
private TenantService tenantService;
|
||||||
|
|
||||||
// Map of Namespace URI usages to Models
|
// 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
|
// 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
|
// Logger
|
||||||
private static Log logger = LogFactory.getLog(DictionaryDAO.class);
|
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
|
* Construct
|
||||||
*
|
*
|
||||||
@@ -81,20 +120,111 @@ public class DictionaryDAOImpl implements DictionaryDAO
|
|||||||
public DictionaryDAOImpl(NamespaceDAO namespaceDAO)
|
public DictionaryDAOImpl(NamespaceDAO namespaceDAO)
|
||||||
{
|
{
|
||||||
this.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)
|
/* (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)
|
||||||
*/
|
*/
|
||||||
public void putModel(M2Model model)
|
public QName putModel(M2Model model)
|
||||||
{
|
{
|
||||||
// Compile model definition
|
// Compile model definition
|
||||||
CompiledModel compiledModel = model.compile(this, namespaceDAO);
|
CompiledModel compiledModel = model.compile(this, namespaceDAO);
|
||||||
QName modelName = compiledModel.getModelDefinition().getName();
|
QName modelName = compiledModel.getModelDefinition().getName();
|
||||||
|
|
||||||
// Remove namespace definitions for previous model, if it exists
|
// Remove namespace definitions for previous model, if it exists
|
||||||
CompiledModel previousVersion = compiledModels.get(modelName);
|
CompiledModel previousVersion = getCompiledModels().get(modelName);
|
||||||
if (previousVersion != null)
|
if (previousVersion != null)
|
||||||
{
|
{
|
||||||
for (M2Namespace namespace : previousVersion.getM2Model().getNamespaces())
|
for (M2Namespace namespace : previousVersion.getM2Model().getNamespaces())
|
||||||
@@ -122,7 +252,7 @@ public class DictionaryDAOImpl implements DictionaryDAO
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Publish new Model Definition
|
// Publish new Model Definition
|
||||||
compiledModels.put(modelName, compiledModel);
|
getCompiledModels().put(modelName, compiledModel);
|
||||||
|
|
||||||
if (logger.isInfoEnabled())
|
if (logger.isInfoEnabled())
|
||||||
{
|
{
|
||||||
@@ -132,6 +262,8 @@ public class DictionaryDAOImpl implements DictionaryDAO
|
|||||||
logger.info("Registered namespace '" + namespace.getUri() + "' (prefix '" + namespace.getPrefix() + "')");
|
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)
|
public void removeModel(QName modelName)
|
||||||
{
|
{
|
||||||
CompiledModel compiledModel = this.compiledModels.get(modelName);
|
CompiledModel compiledModel = getCompiledModels().get(modelName);
|
||||||
if (compiledModel != null)
|
if (compiledModel != null)
|
||||||
{
|
{
|
||||||
// Remove the namespaces from the namespace service
|
// Remove the namespaces from the namespace service
|
||||||
@@ -153,7 +285,7 @@ public class DictionaryDAOImpl implements DictionaryDAO
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Remove the model from the list
|
// 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)
|
private void mapUriToModel(String uri, CompiledModel model)
|
||||||
{
|
{
|
||||||
List<CompiledModel> models = uriToModels.get(uri);
|
List<CompiledModel> models = getUriToModels().get(uri);
|
||||||
if (models == null)
|
if (models == null)
|
||||||
{
|
{
|
||||||
models = new ArrayList<CompiledModel>();
|
models = new ArrayList<CompiledModel>();
|
||||||
uriToModels.put(uri, models);
|
getUriToModels().put(uri, models);
|
||||||
}
|
}
|
||||||
if (!models.contains(model))
|
if (!models.contains(model))
|
||||||
{
|
{
|
||||||
@@ -187,7 +319,7 @@ public class DictionaryDAOImpl implements DictionaryDAO
|
|||||||
*/
|
*/
|
||||||
private void unmapUriToModel(String uri, CompiledModel model)
|
private void unmapUriToModel(String uri, CompiledModel model)
|
||||||
{
|
{
|
||||||
List<CompiledModel> models = uriToModels.get(uri);
|
List<CompiledModel> models = getUriToModels().get(uri);
|
||||||
if (models != null)
|
if (models != null)
|
||||||
{
|
{
|
||||||
models.remove(model);
|
models.remove(model);
|
||||||
@@ -203,25 +335,93 @@ public class DictionaryDAOImpl implements DictionaryDAO
|
|||||||
*/
|
*/
|
||||||
private List<CompiledModel> getModelsForUri(String uri)
|
private List<CompiledModel> getModelsForUri(String uri)
|
||||||
{
|
{
|
||||||
List<CompiledModel> models = uriToModels.get(uri);
|
// note: special case, if running as System - e.g. addAuditAspect
|
||||||
if (models == null)
|
String currentUserName = AuthenticationUtil.getCurrentUserName();
|
||||||
{
|
|
||||||
models = Collections.emptyList();
|
if ((tenantService.isTenantUser()) ||
|
||||||
}
|
(tenantService.isTenantName(uri) && (currentUserName != null) && (currentUserName.equals(AuthenticationUtil.getSystemUserName()))))
|
||||||
return models;
|
{
|
||||||
|
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
|
* @param modelName the model name
|
||||||
* @return the compiled model of the given name
|
* @return the compiled model of the given name
|
||||||
*/
|
*/
|
||||||
private CompiledModel getCompiledModel(QName modelName)
|
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)
|
if (model == null)
|
||||||
{
|
{
|
||||||
// TODO: Load model from persistent store
|
|
||||||
throw new DictionaryException("d_dictionary.model.err.no_model", modelName);
|
throw new DictionaryException("d_dictionary.model.err.no_model", modelName);
|
||||||
}
|
}
|
||||||
return model;
|
return model;
|
||||||
@@ -251,12 +451,39 @@ public class DictionaryDAOImpl implements DictionaryDAO
|
|||||||
*/
|
*/
|
||||||
public DataTypeDefinition getDataType(Class javaClass)
|
public DataTypeDefinition getDataType(Class javaClass)
|
||||||
{
|
{
|
||||||
for (CompiledModel model : compiledModels.values())
|
if (tenantService.isTenantUser() == true)
|
||||||
{
|
{
|
||||||
DataTypeDefinition dataTypeDef = model.getDataType(javaClass);
|
// get tenant models (if any)
|
||||||
if (dataTypeDef != null)
|
for (CompiledModel model : getCompiledModels().values())
|
||||||
{
|
{
|
||||||
return dataTypeDef;
|
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;
|
return null;
|
||||||
@@ -315,6 +542,11 @@ public class DictionaryDAOImpl implements DictionaryDAO
|
|||||||
public ClassDefinition getClass(QName className)
|
public ClassDefinition getClass(QName className)
|
||||||
{
|
{
|
||||||
List<CompiledModel> models = getModelsForUri(className.getNamespaceURI());
|
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)
|
for (CompiledModel model : models)
|
||||||
{
|
{
|
||||||
ClassDefinition classDef = model.getClass(className);
|
ClassDefinition classDef = model.getClass(className);
|
||||||
@@ -386,9 +618,56 @@ public class DictionaryDAOImpl implements DictionaryDAO
|
|||||||
*/
|
*/
|
||||||
public Collection<QName> getModels()
|
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)
|
/* (non-Javadoc)
|
||||||
* @see org.alfresco.repo.dictionary.impl.DictionaryDAO#getModel(org.alfresco.repo.ref.QName)
|
* @see org.alfresco.repo.dictionary.impl.DictionaryDAO#getModel(org.alfresco.repo.ref.QName)
|
||||||
@@ -479,4 +758,196 @@ public class DictionaryDAOImpl implements DictionaryDAO
|
|||||||
return properties;
|
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;
|
package org.alfresco.repo.dictionary;
|
||||||
|
|
||||||
import java.io.Serializable;
|
|
||||||
import java.util.ArrayList;
|
import java.util.ArrayList;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
import java.util.Map;
|
import java.util.Map;
|
||||||
|
|
||||||
import junit.framework.TestCase;
|
import junit.framework.TestCase;
|
||||||
|
import net.sf.ehcache.Cache;
|
||||||
|
import net.sf.ehcache.CacheManager;
|
||||||
|
|
||||||
import org.alfresco.i18n.I18NUtil;
|
import org.alfresco.i18n.I18NUtil;
|
||||||
|
import org.alfresco.repo.cache.EhCacheAdapter;
|
||||||
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.TenantService;
|
||||||
import org.alfresco.service.cmr.dictionary.AssociationDefinition;
|
import org.alfresco.service.cmr.dictionary.AssociationDefinition;
|
||||||
import org.alfresco.service.cmr.dictionary.ClassDefinition;
|
import org.alfresco.service.cmr.dictionary.ClassDefinition;
|
||||||
import org.alfresco.service.cmr.dictionary.Constraint;
|
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.PropertyDefinition;
|
||||||
import org.alfresco.service.cmr.dictionary.TypeDefinition;
|
import org.alfresco.service.cmr.dictionary.TypeDefinition;
|
||||||
import org.alfresco.service.namespace.QName;
|
import org.alfresco.service.namespace.QName;
|
||||||
import org.alfresco.service.namespace.RegexQNamePattern;
|
|
||||||
|
|
||||||
|
|
||||||
public class DictionaryDAOTest extends TestCase
|
public class DictionaryDAOTest extends TestCase
|
||||||
@@ -65,8 +68,14 @@ public class DictionaryDAOTest extends TestCase
|
|||||||
I18NUtil.registerResourceBundle(TEST_RESOURCE_MESSAGES);
|
I18NUtil.registerResourceBundle(TEST_RESOURCE_MESSAGES);
|
||||||
|
|
||||||
// Instantiate Dictionary Service
|
// 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);
|
DictionaryDAOImpl dictionaryDAO = new DictionaryDAOImpl(namespaceDAO);
|
||||||
|
dictionaryDAO.setTenantService(tenantService);
|
||||||
|
initDictionaryCaches(dictionaryDAO);
|
||||||
|
|
||||||
// Populate with appropriate models
|
// Populate with appropriate models
|
||||||
DictionaryBootstrap bootstrap = new DictionaryBootstrap();
|
DictionaryBootstrap bootstrap = new DictionaryBootstrap();
|
||||||
@@ -78,6 +87,7 @@ public class DictionaryDAOTest extends TestCase
|
|||||||
bootstrap.setModels(bootstrapModels);
|
bootstrap.setModels(bootstrapModels);
|
||||||
bootstrap.setLabels(labels);
|
bootstrap.setLabels(labels);
|
||||||
bootstrap.setDictionaryDAO(dictionaryDAO);
|
bootstrap.setDictionaryDAO(dictionaryDAO);
|
||||||
|
bootstrap.setTenantService(tenantService);
|
||||||
bootstrap.bootstrap();
|
bootstrap.bootstrap();
|
||||||
|
|
||||||
DictionaryComponent component = new DictionaryComponent();
|
DictionaryComponent component = new DictionaryComponent();
|
||||||
@@ -85,11 +95,55 @@ public class DictionaryDAOTest extends TestCase
|
|||||||
service = component;
|
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()
|
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);
|
DictionaryDAOImpl dictionaryDAO = new DictionaryDAOImpl(namespaceDAO);
|
||||||
|
dictionaryDAO.setTenantService(tenantService);
|
||||||
|
initDictionaryCaches(dictionaryDAO);
|
||||||
|
|
||||||
DictionaryBootstrap bootstrap = new DictionaryBootstrap();
|
DictionaryBootstrap bootstrap = new DictionaryBootstrap();
|
||||||
List<String> bootstrapModels = new ArrayList<String>();
|
List<String> bootstrapModels = new ArrayList<String>();
|
||||||
@@ -107,7 +161,8 @@ public class DictionaryDAOTest extends TestCase
|
|||||||
|
|
||||||
bootstrap.setModels(bootstrapModels);
|
bootstrap.setModels(bootstrapModels);
|
||||||
bootstrap.setDictionaryDAO(dictionaryDAO);
|
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 java.util.Map;
|
||||||
|
|
||||||
import org.alfresco.model.ContentModel;
|
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.repo.transaction.RetryingTransactionHelper.RetryingTransactionCallback;
|
||||||
import org.alfresco.service.cmr.repository.ContentReader;
|
import org.alfresco.service.cmr.repository.ContentReader;
|
||||||
import org.alfresco.service.cmr.repository.ContentService;
|
import org.alfresco.service.cmr.repository.ContentService;
|
||||||
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.repository.StoreRef;
|
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.cmr.search.SearchService;
|
||||||
|
import org.alfresco.service.namespace.NamespaceService;
|
||||||
import org.alfresco.service.transaction.TransactionService;
|
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
|
* Bootstrap the dictionary from specified locations within the repository
|
||||||
*
|
*
|
||||||
* @author Roy Wetherall
|
* @author Roy Wetherall, JanV
|
||||||
*/
|
*/
|
||||||
public class DictionaryRepositoryBootstrap
|
public class DictionaryRepositoryBootstrap extends AbstractLifecycleBean implements TenantDeployer, DictionaryDeployer, MessageDeployer
|
||||||
{
|
{
|
||||||
/** Loactions in the respository fro which models should be loaded */
|
// Logging support
|
||||||
private List<RepositoryLocation> repositoryLocations = new ArrayList<RepositoryLocation>();
|
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 */
|
/** Dictionary DAO */
|
||||||
private DictionaryDAO dictionaryDAO = null;
|
private DictionaryDAO dictionaryDAO = null;
|
||||||
@@ -59,12 +76,24 @@ public class DictionaryRepositoryBootstrap
|
|||||||
|
|
||||||
/** The content service */
|
/** The content service */
|
||||||
private ContentService contentService;
|
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 */
|
/** The transaction service */
|
||||||
private TransactionService transactionService;
|
private TransactionService transactionService;
|
||||||
|
|
||||||
/** The authentication component */
|
|
||||||
private AuthenticationComponent authenticationComponent;
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Sets the Dictionary DAO
|
* Sets the Dictionary DAO
|
||||||
@@ -95,7 +124,57 @@ public class DictionaryRepositoryBootstrap
|
|||||||
{
|
{
|
||||||
this.contentService = contentService;
|
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
|
* 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
|
* @param repositoryModelsLocations list of the repository models locations
|
||||||
*/
|
*/ public void setRepositoryModelsLocations(
|
||||||
public void setAuthenticationComponent(
|
List<RepositoryLocation> repositoryLocations)
|
||||||
AuthenticationComponent authenticationComponent)
|
|
||||||
{
|
{
|
||||||
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)
|
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
|
public Object execute() throws Exception
|
||||||
{
|
{
|
||||||
DictionaryRepositoryBootstrap.this.authenticationComponent.setCurrentUser(
|
initDictionary();
|
||||||
DictionaryRepositoryBootstrap.this.authenticationComponent.getSystemUserName());
|
initMessages();
|
||||||
try
|
|
||||||
{
|
return (Object)null;
|
||||||
bootstrapImpl();
|
|
||||||
}
|
|
||||||
finally
|
|
||||||
{
|
|
||||||
DictionaryRepositoryBootstrap.this.authenticationComponent.clearCurrentSecurityContext();
|
|
||||||
}
|
|
||||||
return null;
|
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
public void destroy()
|
||||||
* Bootstrap the Dictionary
|
{
|
||||||
*/
|
// NOOP - will be destroyed directly via DictionaryComponent
|
||||||
public void bootstrapImpl()
|
}
|
||||||
|
|
||||||
|
public void initDictionary()
|
||||||
{
|
{
|
||||||
Map<String, M2Model> modelMap = new HashMap<String, M2Model>();
|
if (this.repositoryModelsLocations != null)
|
||||||
|
{
|
||||||
// Register the models found in the respository
|
Map<String, M2Model> modelMap = new HashMap<String, M2Model>();
|
||||||
for (RepositoryLocation repositoryLocation : this.repositoryLocations)
|
|
||||||
{
|
// Register the models found in the repository
|
||||||
ResultSet resultSet = null;
|
|
||||||
try
|
for (RepositoryLocation repositoryLocation : this.repositoryModelsLocations)
|
||||||
{
|
{
|
||||||
resultSet = this.searchService.query(repositoryLocation.getStoreRef(), SearchService.LANGUAGE_LUCENE, repositoryLocation.getQueryStatement());
|
StoreRef storeRef = repositoryLocation.getStoreRef();
|
||||||
|
|
||||||
for (NodeRef dictionaryModel : resultSet.getNodeRefs())
|
if (! nodeService.exists(storeRef))
|
||||||
{
|
{
|
||||||
M2Model model = createM2Model(dictionaryModel);
|
logger.warn("StoreRef '"+ storeRef+"' does not exist");
|
||||||
if (model != null)
|
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)
|
loadModel(modelMap, loadedModels, entry.getValue());
|
||||||
{
|
|
||||||
resultSet.close();
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
}
|
||||||
// Load the models ensuring that they are loaded in the correct order
|
|
||||||
List<String> loadedModels = new ArrayList<String>();
|
public void initMessages()
|
||||||
for (Map.Entry<String, M2Model> entry : modelMap.entrySet())
|
{
|
||||||
|
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 modelMap a map of the models to be loaded
|
||||||
* @param loadedModels the list of models already 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??
|
// TODO should we inactivate the model node and put the error somewhere??
|
||||||
return model;
|
return model;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
@Override
|
||||||
* Repositotry location object, defines a location in the repository from within which dictionary models should be loaded
|
protected void onBootstrap(ApplicationEvent event)
|
||||||
* for inclusion in the data dictionary.
|
|
||||||
*
|
|
||||||
* @author Roy Wetherall
|
|
||||||
*/
|
|
||||||
public class RepositoryLocation
|
|
||||||
{
|
{
|
||||||
/** Store protocol */
|
// run as System on bootstrap
|
||||||
private String storeProtocol;
|
AuthenticationUtil.runAs(new RunAsWork<Object>()
|
||||||
|
|
||||||
/** Store identifier */
|
|
||||||
private String storeId;
|
|
||||||
|
|
||||||
/** Path */
|
|
||||||
private String path;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Set the store protocol
|
|
||||||
*
|
|
||||||
* @param storeProtocol the store protocol
|
|
||||||
*/
|
|
||||||
public void setStoreProtocol(String storeProtocol)
|
|
||||||
{
|
{
|
||||||
this.storeProtocol = storeProtocol;
|
public Object doWork()
|
||||||
|
{
|
||||||
|
init();
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
}, AuthenticationUtil.getSystemUserName());
|
||||||
|
|
||||||
|
if (tenantService.isEnabled())
|
||||||
|
{
|
||||||
|
tenantDeployerService.deployTenants(this, logger);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
register();
|
||||||
* Set the store identifier
|
}
|
||||||
*
|
|
||||||
* @param storeId the store identifier
|
@Override
|
||||||
*/
|
protected void onShutdown(ApplicationEvent event)
|
||||||
public void setStoreId(String storeId)
|
{
|
||||||
{
|
unregister();
|
||||||
this.storeId = storeId;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
// run as System on shutdown
|
||||||
* Set the path
|
AuthenticationUtil.runAs(new RunAsWork<Object>()
|
||||||
*
|
|
||||||
* @param path the path
|
|
||||||
*/
|
|
||||||
public void setPath(String path)
|
|
||||||
{
|
{
|
||||||
this.path = path;
|
public Object doWork()
|
||||||
}
|
{
|
||||||
|
destroy();
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
}, AuthenticationUtil.getSystemUserName());
|
||||||
|
|
||||||
/**
|
if (tenantService.isEnabled())
|
||||||
* Get the store reference
|
|
||||||
*
|
|
||||||
* @return the store reference
|
|
||||||
*/
|
|
||||||
public StoreRef getStoreRef()
|
|
||||||
{
|
{
|
||||||
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);
|
||||||
|
|
||||||
/**
|
if (tenantService.isEnabled())
|
||||||
* Get the query statement, based on the path
|
|
||||||
*
|
|
||||||
* @return the query statement
|
|
||||||
*/
|
|
||||||
public String getQueryStatement()
|
|
||||||
{
|
{
|
||||||
String result = "+TYPE:\"" + ContentModel.TYPE_DICTIONARY_MODEL.toString() + "\"";
|
// register dictionary repository bootstrap
|
||||||
if (this.path != null)
|
tenantDeployerService.register(this);
|
||||||
{
|
|
||||||
result += " +PATH:\"" + this.path + "\"";
|
// register repository message (I18N) service
|
||||||
}
|
tenantDeployerService.register(messageService);
|
||||||
return result;
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 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.model.ContentModel;
|
||||||
import org.alfresco.repo.content.MimetypeMap;
|
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.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.DictionaryException;
|
||||||
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.search.SearchService;
|
import org.alfresco.service.cmr.search.SearchService;
|
||||||
|
import org.alfresco.service.namespace.NamespaceService;
|
||||||
import org.alfresco.service.namespace.QName;
|
import org.alfresco.service.namespace.QName;
|
||||||
import org.alfresco.service.transaction.TransactionService;
|
import org.alfresco.service.transaction.TransactionService;
|
||||||
import org.alfresco.util.BaseAlfrescoSpringTest;
|
import org.alfresco.util.BaseAlfrescoSpringTest;
|
||||||
@@ -67,9 +69,18 @@ public class DictionaryRepositoryBootstrapTest extends BaseAlfrescoSpringTest
|
|||||||
|
|
||||||
/** The transaction service */
|
/** The transaction service */
|
||||||
private TransactionService transactionService;
|
private TransactionService transactionService;
|
||||||
|
|
||||||
/** The authentication service */
|
/** The tenant service */
|
||||||
private AuthenticationComponent authenticationComponent;
|
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()
|
* @see org.springframework.test.AbstractTransactionalSpringContextTests#onSetUpInTransaction()
|
||||||
@@ -85,24 +96,35 @@ public class DictionaryRepositoryBootstrapTest extends BaseAlfrescoSpringTest
|
|||||||
|
|
||||||
this.searchService = (SearchService)this.applicationContext.getBean("searchService");
|
this.searchService = (SearchService)this.applicationContext.getBean("searchService");
|
||||||
this.dictionaryDAO = (DictionaryDAO)this.applicationContext.getBean("dictionaryDAO");
|
this.dictionaryDAO = (DictionaryDAO)this.applicationContext.getBean("dictionaryDAO");
|
||||||
this.transactionService = (TransactionService)this.applicationContext.getBean("transactionComponent");
|
this.transactionService = (TransactionService)this.applicationContext.getBean("transactionComponent");
|
||||||
this.authenticationComponent = (AuthenticationComponent)this.applicationContext.getBean("authenticationComponent");
|
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 = new DictionaryRepositoryBootstrap();
|
||||||
this.bootstrap.setContentService(this.contentService);
|
this.bootstrap.setContentService(this.contentService);
|
||||||
this.bootstrap.setSearchService(this.searchService);
|
this.bootstrap.setSearchService(this.searchService);
|
||||||
this.bootstrap.setDictionaryDAO(this.dictionaryDAO);
|
this.bootstrap.setDictionaryDAO(this.dictionaryDAO);
|
||||||
this.bootstrap.setAuthenticationComponent(this.authenticationComponent);
|
this.bootstrap.setTransactionService(this.transactionService);
|
||||||
this.bootstrap.setTransactionService(this.transactionService);
|
this.bootstrap.setTenantService(this.tenantService);
|
||||||
|
this.bootstrap.setTenantDeployerService(this.tenantDeployerService);
|
||||||
RepositoryLocation location = this.bootstrap.new RepositoryLocation();
|
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.setStoreProtocol(this.storeRef.getProtocol());
|
||||||
location.setStoreId(this.storeRef.getIdentifier());
|
location.setStoreId(this.storeRef.getIdentifier());
|
||||||
// NOTE: we are not setting the path for now .. in doing so we are searching the whole dictionary
|
// NOTE: we are not setting the path for now .. in doing so we are searching the whole dictionary
|
||||||
|
|
||||||
List<RepositoryLocation> locations = new ArrayList<RepositoryLocation>();
|
List<RepositoryLocation> locations = new ArrayList<RepositoryLocation>();
|
||||||
locations.add(location);
|
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
|
// Now do the bootstrap
|
||||||
this.bootstrap.bootstrap();
|
this.bootstrap.init();
|
||||||
|
|
||||||
// Check that the model is now there
|
// Check that the model is now there
|
||||||
ModelDefinition modelDefinition1 = this.dictionaryDAO.getModel(
|
ModelDefinition modelDefinition1 = this.dictionaryDAO.getModel(
|
||||||
|
@@ -66,4 +66,18 @@ public interface NamespaceDAO extends NamespacePrefixResolver
|
|||||||
*/
|
*/
|
||||||
public void removePrefix(String prefix);
|
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.Collections;
|
||||||
import java.util.HashMap;
|
import java.util.HashMap;
|
||||||
import java.util.List;
|
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.alfresco.service.namespace.NamespaceException;
|
||||||
|
import org.apache.commons.logging.Log;
|
||||||
|
import org.apache.commons.logging.LogFactory;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Simple in-memory namespace DAO
|
* Simple in-memory namespace DAO
|
||||||
*/
|
*/
|
||||||
public class NamespaceDAOImpl implements NamespaceDAO
|
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>();
|
// Dependencies
|
||||||
private HashMap<String, String> prefixes = new HashMap<String, String>();
|
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()
|
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()
|
* @see org.alfresco.repo.ref.NamespacePrefixResolver#getPrefixes()
|
||||||
*/
|
*/
|
||||||
public Collection<String> 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)
|
public void addURI(String uri)
|
||||||
{
|
{
|
||||||
if (uris.contains(uri))
|
if (getUrisCtx().contains(uri))
|
||||||
{
|
{
|
||||||
throw new NamespaceException("URI " + uri + " has already been defined");
|
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)
|
public void addPrefix(String prefix, String uri)
|
||||||
{
|
{
|
||||||
if (!uris.contains(uri))
|
if (!getUrisCtx().contains(uri))
|
||||||
{
|
{
|
||||||
throw new NamespaceException("Namespace URI " + uri + " does not exist");
|
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)
|
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)
|
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)
|
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)
|
public Collection<String> getPrefixes(String URI)
|
||||||
{
|
{
|
||||||
Collection<String> uriPrefixes = new ArrayList<String>();
|
if (! tenantService.isTenantUser())
|
||||||
for (String key : prefixes.keySet())
|
|
||||||
{
|
{
|
||||||
String uri = prefixes.get(key);
|
Collection<String> uriPrefixes = new ArrayList<String>();
|
||||||
if ((uri != null) && (uri.equals(URI)))
|
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.ArrayList;
|
||||||
import java.util.List;
|
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
|
// 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);
|
DictionaryDAOImpl dictionaryDAO = new DictionaryDAOImpl(namespaceDAO);
|
||||||
|
dictionaryDAO.setTenantService(tenantService);
|
||||||
|
|
||||||
|
initDictionaryCaches(dictionaryDAO);
|
||||||
|
|
||||||
// bootstrap dao
|
// bootstrap dao
|
||||||
try
|
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