enumKeys = resourcebundle.getKeys();
while (enumKeys.hasMoreElements() == true)
{
String key = enumKeys.nextElement();
props.remove(key);
}
}
loadedBundles.remove(resBundlePath);
}
}
}
}
// unregister resource bundle
if (resourceBundleBaseNamesForAllLocales != null)
{
resourceBundleBaseNamesForAllLocales.remove(resBundlePath);
logger.info("Unregistered message bundle '" + resBundlePath + "'");
}
clearLoadedResourceBundles(tenantDomain); // force re-load of message cache
}
finally
{
writeLock.unlock();
}
}
/**
* Get the messages for a locale.
*
* Will use cache where available otherwise will load into cache from bundles.
*
* @param locale the locale
* @return message map
*/
private Map getLocaleProperties(Locale locale)
{
Set loadedBundles = null;
Map props = null;
int loadedBundleCount = 0;
String tenantDomain = getTenantDomain();
boolean init = false;
Map> tenantLoadedResourceBundles = null;
Map> tenantCachedMessages = null;
Set tenantResourceBundleBaseNames = null;
try
{
readLock.lock();
tenantLoadedResourceBundles = getLoadedResourceBundles(tenantDomain);
loadedBundles = tenantLoadedResourceBundles.get(locale);
tenantCachedMessages = getMessages(tenantDomain);
props = tenantCachedMessages.get(locale);
tenantResourceBundleBaseNames = getResourceBundleBaseNames(tenantDomain);
loadedBundleCount = tenantResourceBundleBaseNames.size();
}
finally
{
readLock.unlock();
}
if (loadedBundles == null)
{
try
{
writeLock.lock();
loadedBundles = new HashSet();
tenantLoadedResourceBundles.put(locale, loadedBundles);
init = true;
}
finally
{
writeLock.unlock();
}
}
if (props == null)
{
try
{
writeLock.lock();
props = new HashMap();
tenantCachedMessages.put(locale, props);
init = true;
}
finally
{
writeLock.unlock();
}
}
if ((loadedBundles.size() != loadedBundleCount) || (init == true))
{
try
{
writeLock.lock();
// get registered resource bundles
Set resBundleBaseNames = getResourceBundleBaseNames(tenantDomain);
int count = 0;
// load resource bundles for given locale (by tenant, if applicable)
for (String resBundlePath : resBundleBaseNames)
{
if (loadedBundles.contains(resBundlePath) == false)
{
ResourceBundle resourcebundle = null;
int idx1 = resBundlePath.indexOf(StoreRef.URI_FILLER);
if (idx1 != -1)
{
// load from repository
int idx2 = resBundlePath.indexOf("/", idx1+3);
String store = resBundlePath.substring(0, idx2);
String path = resBundlePath.substring(idx2);
StoreRef storeRef = tenantService.getName(new StoreRef(store));
try
{
resourcebundle = getRepoResourceBundle(storeRef, path, locale);
}
catch (IOException ioe)
{
throw new AlfrescoRuntimeException("Failed to read message resource bundle from repository " + resBundlePath + " : " + ioe);
}
}
else
{
// load from classpath
resourcebundle = ResourceBundle.getBundle(resBundlePath, locale);
}
if (resourcebundle != null)
{
Enumeration enumKeys = resourcebundle.getKeys();
while (enumKeys.hasMoreElements() == true)
{
String key = enumKeys.nextElement();
props.put(key, resourcebundle.getString(key));
}
loadedBundles.add(resBundlePath);
count++;
}
}
}
logger.info("Message bundles (x " + count + ") loaded for locale " + locale);
}
finally
{
writeLock.unlock();
}
}
return props;
}
/*
* (non-Javadoc)
* @see org.alfresco.repo.i18n.MessageService#getRepoResourceBundle(org.alfresco.service.cmr.repository.StoreRef, java.lang.String, java.util.Locale)
*/
public ResourceBundle getRepoResourceBundle(StoreRef storeRef, String path, Locale locale) throws IOException
{
ResourceBundle resBundle = null;
// TODO - need to replace basic strategy with a more complete
// search & instantiation strategy similar to ResourceBundle.getBundle()
// Consider search query with basename* and then apply strategy ...
NodeRef rootNode = nodeService.getRootNode(storeRef);
// first attempt - with locale
List nodeRefs = searchService.selectNodes(rootNode, path+"_"+locale+PROPERTIES_FILE_SUFFIX, null, namespaceService, false);
if ((nodeRefs == null) || (nodeRefs.size() == 0))
{
// second attempt - basename
nodeRefs = searchService.selectNodes(rootNode, path+PROPERTIES_FILE_SUFFIX, null, namespaceService, false);
if ((nodeRefs == null) || (nodeRefs.size() == 0))
{
logger.debug("Could not find message resource bundle " + storeRef + "/" + path);
return null;
}
}
if (nodeRefs.size() > 1)
{
throw new RuntimeException("Found more than one message resource bundle " + storeRef + path);
}
else
{
NodeRef messageResourceNodeRef = nodeRefs.get(0);
ContentReader cr = contentService.getReader(messageResourceNodeRef, ContentModel.PROP_CONTENT);
resBundle = new MessagePropertyResourceBundle(new InputStreamReader(cr.getContentInputStream(), cr.getEncoding()));
}
return resBundle;
}
/*
* (non-Javadoc)
* @see org.alfresco.repo.tenant.TenantDeployer#onEnableTenant()
*/
public void onEnableTenant()
{
// NOOP - refer to DictionaryRepositoryBootstrap
}
/*
* (non-Javadoc)
* @see org.alfresco.repo.tenant.TenantDeployer#onDisableTenant()
*/
public void onDisableTenant()
{
destroy(); // will be called in context of tenant
}
/*
* (non-Javadoc)
* @see org.alfresco.repo.tenant.TenantDeployer#init()
*/
public void init()
{
// initialise empty message service
String tenantDomain = getTenantDomain();
putResourceBundleBaseNames(tenantDomain, new HashSet());
putLoadedResourceBundles(tenantDomain, new HashMap>());
putMessages(tenantDomain, new HashMap>());
logger.info("Empty message service initialised");
}
/*
* (non-Javadoc)
* @see org.alfresco.repo.tenant.TenantDeployer#destroy()
*/
public void destroy()
{
// used by reset and also as callback when destroying tenant(s) during shutdown
String tenantDomain = getTenantDomain();
removeLoadedResourceBundles(tenantDomain);
removeMessages(tenantDomain);
removeResourceBundleBaseNames(tenantDomain);
logger.info("Messages cache destroyed (all locales)");
}
/*
* (non-Javadoc)
* @see org.alfresco.repo.i18n.MessageService#getRegisteredBundles()
*/
public Set getRegisteredBundles()
{
try
{
readLock.lock();
return getResourceBundleBaseNames(getTenantDomain());
}
finally
{
readLock.unlock();
}
}
private Set getResourceBundleBaseNames(String tenantDomain)
{
Set resourceBundleBaseNames = resourceBundleBaseNamesCache.get(tenantDomain);
if (resourceBundleBaseNames == null)
{
try
{
// assume caller has read lock - upgrade lock manually
readLock.unlock();
writeLock.lock();
reset(tenantDomain); // reset caches - may have been invalidated (e.g. in a cluster)
resourceBundleBaseNames = resourceBundleBaseNamesCache.get(tenantDomain);
}
finally
{
readLock.lock(); // reacquire read without giving up write lock
writeLock.unlock(); // unlock write, still hold read - caller must unlock the read
}
if (resourceBundleBaseNames == null)
{
// unexpected
throw new AlfrescoRuntimeException("Failed to re-initialise resourceBundleBaseNamesCache " + tenantDomain);
}
}
return resourceBundleBaseNames;
}
private void putResourceBundleBaseNames(String tenantDomain, Set resourceBundleBaseNames)
{
resourceBundleBaseNamesCache.put(tenantDomain, resourceBundleBaseNames);
}
private void removeResourceBundleBaseNames(String tenantDomain)
{
if (resourceBundleBaseNamesCache.get(tenantDomain) != null)
{
resourceBundleBaseNamesCache.get(tenantDomain).clear();
resourceBundleBaseNamesCache.remove(tenantDomain);
}
}
private Map> getLoadedResourceBundles(String tenantDomain)
{
Map> loadedResourceBundles = loadedResourceBundlesCache.get(tenantDomain);
if (loadedResourceBundles == null)
{
try
{
// assume caller has read lock - upgrade lock manually
readLock.unlock();
writeLock.lock();
reset(tenantDomain); // reset caches - may have been invalidated (e.g. in a cluster)
loadedResourceBundles = loadedResourceBundlesCache.get(tenantDomain);
}
finally
{
readLock.lock(); // reacquire read without giving up write lock
writeLock.unlock(); // unlock write, still hold read - caller must unlock the read
}
if (loadedResourceBundles == null)
{
// unexpected
throw new AlfrescoRuntimeException("Failed to re-initialise loadedResourceBundlesCache " + tenantDomain);
}
}
return loadedResourceBundles;
}
private void putLoadedResourceBundles(String tenantDomain, Map> loadedResourceBundles)
{
loadedResourceBundlesCache.put(tenantDomain, loadedResourceBundles);
}
private void removeLoadedResourceBundles(String tenantDomain)
{
if (loadedResourceBundlesCache.get(tenantDomain) != null)
{
loadedResourceBundlesCache.get(tenantDomain).clear();
loadedResourceBundlesCache.remove(tenantDomain);
}
}
private void clearLoadedResourceBundles(String tenantDomain)
{
if (loadedResourceBundlesCache.get(tenantDomain) != null)
{
loadedResourceBundlesCache.get(tenantDomain).clear();
}
}
private Map> getMessages(String tenantDomain)
{
Map> messages = messagesCache.get(tenantDomain);
if (messages == null)
{
try
{
// assume caller has read lock - upgrade lock manually
readLock.unlock();
writeLock.lock();
reset(tenantDomain); // reset caches - may have been invalidated (e.g. in a cluster)
messages = messagesCache.get(tenantDomain);
}
finally
{
readLock.lock(); // reacquire read without giving up write lock
writeLock.unlock(); // unlock write, still hold read - caller must unlock the read
}
if (messages == null)
{
// unexpected
throw new AlfrescoRuntimeException("Failed to re-initialise messagesCache " + tenantDomain);
}
}
return messages;
}
private void putMessages(String tenantDomain, Map> messages)
{
messagesCache.put(tenantDomain, messages);
}
private void removeMessages(String tenantDomain)
{
if (messagesCache.get(tenantDomain) != null)
{
messagesCache.get(tenantDomain).clear();
messagesCache.remove(tenantDomain);
}
}
// local helper - returns tenant domain (or empty string if default non-tenant)
private String getTenantDomain()
{
return tenantService.getCurrentUserDomain();
}
/*
* (non-Javadoc)
* @see org.alfresco.repo.i18n.MessageService#register(org.alfresco.repo.i18n.MessageDeployer)
*/
public void register(MessageDeployer messageDeployer)
{
if (! messageDeployers.contains(messageDeployer))
{
messageDeployers.add(messageDeployer);
}
}
/**
* Resets the message service
*/
public void reset()
{
reset(getTenantDomain());
}
private void reset(String tenantDomain)
{
if (logger.isDebugEnabled())
{
logger.debug("Resetting messages ...");
}
AuthenticationUtil.runAs(new RunAsWork