mirror of
https://github.com/Alfresco/alfresco-community-repo.git
synced 2025-07-24 17:32:48 +00:00
MNT-18700 - Dynamic Message bundles do not deploy/reload automatically (#805)
* Restored the ability to register dynamic messages on bootstrap * Added unit tests on bootstrap to verify if the dynamic messages are registered on bootstrap * Added unit tests for the Repo Admin Console regarding registering dynamic messages and classpath files
This commit is contained in:
@@ -415,12 +415,13 @@ implements TenantDeployer, DictionaryListener, /*TenantDictionaryListener, */Mes
|
||||
|
||||
for (NodeRef messageResource : nodeRefs)
|
||||
{
|
||||
String resourceName = (String) nodeService.getProperty(messageResource, ContentModel.PROP_NAME);
|
||||
|
||||
String bundleBaseName = messageService.getBaseBundleName(resourceName);
|
||||
String messageResourcePath = nodeService.getPath(messageResource).toPrefixString(namespaceService);
|
||||
String bundleBasePrefixedName = messageResourcePath.substring(messageResourcePath.lastIndexOf("/"));
|
||||
String bundleBaseName = messageService.getBaseBundleName(bundleBasePrefixedName);
|
||||
|
||||
if (!resourceBundleBaseNames.contains(bundleBaseName))
|
||||
{
|
||||
messageService.registerResourceBundle(storeRef.toString() + repositoryLocation.getPath() + bundleBaseName);
|
||||
resourceBundleBaseNames.add(bundleBaseName);
|
||||
}
|
||||
}
|
||||
|
@@ -31,17 +31,18 @@ import java.io.PrintWriter;
|
||||
import java.io.Serializable;
|
||||
import java.io.StringWriter;
|
||||
import java.io.UnsupportedEncodingException;
|
||||
import java.util.Collections;
|
||||
import java.util.HashMap;
|
||||
import java.util.List;
|
||||
import java.util.Locale;
|
||||
import java.util.Map;
|
||||
|
||||
import junit.framework.TestCase;
|
||||
|
||||
import org.alfresco.error.AlfrescoRuntimeException;
|
||||
import org.alfresco.model.ContentModel;
|
||||
import org.alfresco.repo.content.MimetypeMap;
|
||||
import org.alfresco.repo.dictionary.DictionaryDAO;
|
||||
import org.alfresco.repo.dictionary.NamespaceDAO;
|
||||
import org.alfresco.repo.i18n.MessageService;
|
||||
import org.alfresco.repo.node.db.DbNodeServiceImpl;
|
||||
import org.alfresco.repo.policy.BehaviourFilter;
|
||||
import org.alfresco.repo.security.authentication.AuthenticationUtil;
|
||||
@@ -50,6 +51,7 @@ import org.alfresco.repo.transaction.RetryingTransactionHelper.RetryingTransacti
|
||||
import org.alfresco.service.cmr.admin.RepoAdminService;
|
||||
import org.alfresco.service.cmr.dictionary.ClassDefinition;
|
||||
import org.alfresco.service.cmr.dictionary.DictionaryService;
|
||||
import org.alfresco.service.cmr.repository.ChildAssociationRef;
|
||||
import org.alfresco.service.cmr.repository.ContentService;
|
||||
import org.alfresco.service.cmr.repository.ContentWriter;
|
||||
import org.alfresco.service.cmr.repository.NodeRef;
|
||||
@@ -67,6 +69,8 @@ import org.apache.commons.logging.LogFactory;
|
||||
import org.junit.experimental.categories.Category;
|
||||
import org.springframework.context.ApplicationContext;
|
||||
|
||||
import junit.framework.TestCase;
|
||||
|
||||
/**
|
||||
* @see RepoAdminServiceImpl
|
||||
*
|
||||
@@ -88,6 +92,7 @@ public class RepoAdminServiceImplTest extends TestCase
|
||||
private NamespaceService namespaceService;
|
||||
private BehaviourFilter behaviourFilter;
|
||||
private DictionaryDAO dictionaryDAO;
|
||||
private MessageService messageService;
|
||||
|
||||
final String modelPrefix = "model-";
|
||||
final static String MKR = "{MKR}";
|
||||
@@ -140,6 +145,7 @@ public class RepoAdminServiceImplTest extends TestCase
|
||||
namespaceService = (NamespaceService) ctx.getBean("NamespaceService");
|
||||
behaviourFilter = (BehaviourFilter)ctx.getBean("policyBehaviourFilter");
|
||||
dictionaryDAO = (DictionaryDAO) ctx.getBean("dictionaryDAO");
|
||||
messageService = (MessageService) ctx.getBean("MessageService");
|
||||
|
||||
DbNodeServiceImpl dbNodeService = (DbNodeServiceImpl)ctx.getBean("dbNodeService");
|
||||
dbNodeService.setEnableTimestampPropagation(false);
|
||||
@@ -866,7 +872,181 @@ public class RepoAdminServiceImplTest extends TestCase
|
||||
}
|
||||
}
|
||||
|
||||
//
|
||||
// TODO - Test custom message management
|
||||
//
|
||||
// Test deploy bundle from classpath
|
||||
public void testDeployMessageBundleFromClasspath() throws Exception
|
||||
{
|
||||
String bundleBaseName = "mycustommessages";
|
||||
String resourceClasspath = "alfresco/extension/messages/" + bundleBaseName;
|
||||
|
||||
final String message_key = "mycustommessages.key1";
|
||||
final String message_value_default = "This is a custom message";
|
||||
final String message_value_fr = "Ceci est un message personnalis\\u00e9";
|
||||
final String message_value_de = "Dies ist eine benutzerdefinierte Nachricht";
|
||||
|
||||
// Undeploy the bundle
|
||||
if (repoAdminService.getMessageBundles().contains(bundleBaseName))
|
||||
{
|
||||
repoAdminService.undeployMessageBundle(bundleBaseName);
|
||||
}
|
||||
|
||||
// Verify the custom bundle is registered
|
||||
assertFalse("The custom bundle should not be deployed", repoAdminService.getMessageBundles().contains(bundleBaseName));
|
||||
|
||||
// Depoly the message bundle
|
||||
repoAdminService.deployMessageBundle(resourceClasspath);
|
||||
|
||||
// Reload the messages
|
||||
repoAdminService.reloadMessageBundle(bundleBaseName);
|
||||
|
||||
// Verify the custom bundle is registered
|
||||
assertTrue("The custom bundle should be deployed", repoAdminService.getMessageBundles().contains(bundleBaseName));
|
||||
|
||||
// Verify we have the messages for each locale
|
||||
AuthenticationUtil.setFullyAuthenticatedUser(AuthenticationUtil.getAdminUserName());
|
||||
|
||||
assertMessageValue("Cannot retrieve default message value", message_value_default, message_key, Locale.getDefault());
|
||||
assertMessageValue("Cannot retrieve french message value", message_value_fr, message_key, Locale.FRANCE);
|
||||
assertMessageValue("Cannot retrieve german message value", message_value_de, message_key, Locale.GERMANY);
|
||||
|
||||
// Test deploy a non existent bundle
|
||||
try
|
||||
{
|
||||
repoAdminService.deployMessageBundle("alfresco/extension/messages/inexistentbundle");
|
||||
fail("Bundle was not supposed to be deployed");
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
// Expected to fail
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
// Test deploy bundle from repo and reload bundles
|
||||
public void testDeployMessageBundleFromRepo() throws Exception
|
||||
{
|
||||
final String bundleBaseName = "repoBundle";
|
||||
final String message_key = "repoBundle.key1";
|
||||
final String message_value = "Value 1";
|
||||
final String message_value_fr = "Value FR";
|
||||
final String message_value_de = "Value DE";
|
||||
final String message_value_new = "New Value 1";
|
||||
|
||||
// Set location
|
||||
NodeRef rootNodeRef = nodeService.getRootNode(StoreRef.STORE_REF_WORKSPACE_SPACESSTORE);
|
||||
List<NodeRef> nodeRefs = searchService.selectNodes(rootNodeRef, "/app:company_home/app:dictionary/app:messages", null,
|
||||
namespaceService, false);
|
||||
assertEquals(1, nodeRefs.size());
|
||||
NodeRef messagesNodeRef = nodeRefs.get(0);
|
||||
|
||||
// Clear messages of this bundle if they exist and are registered
|
||||
clearRepoBundles(messagesNodeRef);
|
||||
|
||||
assertEquals(0, repoAdminService.getMessageBundles().size());
|
||||
|
||||
// Create and upload the message files
|
||||
NodeRef messageNode_default = createMessagesNodeWithSingleKey(messagesNodeRef, bundleBaseName, message_key, null,
|
||||
message_value);
|
||||
createMessagesNodeWithSingleKey(messagesNodeRef, bundleBaseName, message_key, Locale.FRANCE.toString(), message_value_fr);
|
||||
createMessagesNodeWithSingleKey(messagesNodeRef, bundleBaseName, message_key, Locale.GERMANY.toString(),
|
||||
message_value_de);
|
||||
|
||||
// Reload the messages
|
||||
repoAdminService.reloadMessageBundle(bundleBaseName);
|
||||
|
||||
// Verify we have the messages for each locale
|
||||
AuthenticationUtil.setFullyAuthenticatedUser(AuthenticationUtil.getAdminUserName());
|
||||
|
||||
assertMessageValue("Cannot retrieve default message value", message_value, message_key, Locale.getDefault());
|
||||
assertMessageValue("Cannot retrieve french message value", message_value_fr, message_key, Locale.FRANCE);
|
||||
assertMessageValue("Cannot retrieve german message value", message_value_de, message_key, Locale.GERMANY);
|
||||
|
||||
// Change the values
|
||||
putContentInMessageNode(messageNode_default, message_key, message_value_new);
|
||||
|
||||
// Verify we still have the old value
|
||||
assertMessageValue("Unexpected change of message value", message_value, message_key, Locale.getDefault());
|
||||
|
||||
// Reload the messages
|
||||
repoAdminService.reloadMessageBundle(bundleBaseName);
|
||||
|
||||
// Verify new values
|
||||
assertMessageValue("Change of message value not reflected", message_value_new, message_key, Locale.getDefault());
|
||||
}
|
||||
|
||||
/**
|
||||
* Create messages node
|
||||
*/
|
||||
private NodeRef createMessagesNodeWithSingleKey(NodeRef parentNode, String bundleName, String key, String locale,
|
||||
String localeValue)
|
||||
{
|
||||
String msg_extension = ".properties";
|
||||
String filename = bundleName + msg_extension;
|
||||
String messageValue = localeValue;
|
||||
|
||||
if (locale != null)
|
||||
{
|
||||
filename = bundleName + "_" + locale + msg_extension;
|
||||
}
|
||||
// Create a model node
|
||||
NodeRef messageNode = this.nodeService.createNode(
|
||||
parentNode,
|
||||
ContentModel.ASSOC_CONTAINS,
|
||||
QName.createQName(NamespaceService.CONTENT_MODEL_1_0_URI, filename),
|
||||
ContentModel.TYPE_CONTENT,
|
||||
Collections.<QName, Serializable> singletonMap(ContentModel.PROP_NAME, filename)
|
||||
).getChildRef();
|
||||
|
||||
putContentInMessageNode(messageNode, key, messageValue);
|
||||
|
||||
return messageNode;
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* Write content of message node
|
||||
*/
|
||||
private void putContentInMessageNode(NodeRef nodeRef, String key, String value)
|
||||
{
|
||||
ContentWriter contentWriter = contentService.getWriter(nodeRef, ContentModel.PROP_CONTENT, true);
|
||||
contentWriter.setEncoding("UTF-8");
|
||||
contentWriter.setMimetype(MimetypeMap.MIMETYPE_TEXT_PLAIN);
|
||||
String messagesString = key + "=" + value;
|
||||
contentWriter.putContent(messagesString);
|
||||
}
|
||||
|
||||
/**
|
||||
* Clear Repo Bundle
|
||||
*/
|
||||
private void clearRepoBundles(NodeRef parentNode)
|
||||
{
|
||||
List<String> repoBundles = repoAdminService.getMessageBundles();
|
||||
for (String repoBundle : repoBundles)
|
||||
{
|
||||
repoAdminService.undeployMessageBundle(repoBundle);
|
||||
}
|
||||
|
||||
List<ChildAssociationRef> messageNodes = nodeService.getChildAssocs(parentNode);
|
||||
for (ChildAssociationRef messageChildRef : messageNodes)
|
||||
{
|
||||
NodeRef messageNode = messageChildRef.getChildRef();
|
||||
nodeService.deleteNode(messageNode);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Clear Repo Bundle
|
||||
*/
|
||||
private void assertMessageValue(String errorMessage, String expectedValue, String key, Locale locale)
|
||||
{
|
||||
transactionService.getRetryingTransactionHelper()
|
||||
.doInTransaction(new RetryingTransactionHelper.RetryingTransactionCallback<Void>()
|
||||
{
|
||||
public Void execute() throws Throwable
|
||||
{
|
||||
assertEquals(errorMessage, expectedValue, messageService.getMessage(key, locale));
|
||||
return null;
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
}
|
||||
|
@@ -25,9 +25,14 @@
|
||||
*/
|
||||
package org.alfresco.repo.dictionary;
|
||||
|
||||
import java.io.Serializable;
|
||||
import java.text.MessageFormat;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Collections;
|
||||
import java.util.List;
|
||||
import java.util.Locale;
|
||||
|
||||
import javax.transaction.UserTransaction;
|
||||
|
||||
import org.alfresco.model.ContentModel;
|
||||
import org.alfresco.repo.content.MimetypeMap;
|
||||
@@ -53,8 +58,6 @@ import org.junit.After;
|
||||
import org.junit.Before;
|
||||
import org.junit.Test;
|
||||
import org.junit.experimental.categories.Category;
|
||||
|
||||
import javax.transaction.UserTransaction;
|
||||
import org.springframework.transaction.annotation.Transactional;
|
||||
|
||||
@Category(BaseSpringTestsCategory.class)
|
||||
@@ -94,6 +97,14 @@ public class DictionaryRepositoryBootstrapTest extends BaseSpringTest
|
||||
|
||||
"</model>";
|
||||
|
||||
public static final String MESSAGES_KEY = "my_bootstrap_test";
|
||||
public static final String MESSAGES_VALUE = "My Message";
|
||||
public static final String MESSAGES_VALUE_FR = "Mon message";
|
||||
public static final String FOLDERNAME_MODELS = "models";
|
||||
public static final String FOLDERNAME_MESSAGES = "messages";
|
||||
public static final String BUNDLENAME_MESSAGES = "testBootstap";
|
||||
public static final String FILENAME_MESSAGES_EXT = ".properties";
|
||||
|
||||
/** Behaviour filter */
|
||||
private BehaviourFilter behaviourFilter;
|
||||
|
||||
@@ -123,7 +134,8 @@ public class DictionaryRepositoryBootstrapTest extends BaseSpringTest
|
||||
|
||||
private UserTransaction txn;
|
||||
private StoreRef storeRef;
|
||||
private NodeRef rootNodeRef;
|
||||
private NodeRef rootModelsNodeRef;
|
||||
private NodeRef rootMessagesNodeRef;
|
||||
|
||||
@Before
|
||||
public void before() throws Exception
|
||||
@@ -151,7 +163,17 @@ public class DictionaryRepositoryBootstrapTest extends BaseSpringTest
|
||||
|
||||
// Create the store and get the root node
|
||||
this.storeRef = this.nodeService.createStore(StoreRef.PROTOCOL_WORKSPACE, "Test_" + System.currentTimeMillis());
|
||||
this.rootNodeRef = this.nodeService.getRootNode(this.storeRef);
|
||||
|
||||
NodeRef rootNodeRef = this.nodeService.getRootNode(this.storeRef);
|
||||
this.rootModelsNodeRef = this.nodeService
|
||||
.createNode(rootNodeRef, ContentModel.ASSOC_CHILDREN,
|
||||
QName.createQName(NamespaceService.CONTENT_MODEL_1_0_URI, FOLDERNAME_MODELS), ContentModel.TYPE_FOLDER)
|
||||
.getChildRef();
|
||||
|
||||
this.rootMessagesNodeRef = this.nodeService
|
||||
.createNode(rootNodeRef, ContentModel.ASSOC_CHILDREN,
|
||||
QName.createQName(NamespaceService.CONTENT_MODEL_1_0_URI, FOLDERNAME_MESSAGES), ContentModel.TYPE_FOLDER)
|
||||
.getChildRef();
|
||||
|
||||
txn.commit();
|
||||
|
||||
@@ -168,16 +190,18 @@ public class DictionaryRepositoryBootstrapTest extends BaseSpringTest
|
||||
this.bootstrap.setMessageService(this.messageService);
|
||||
this.bootstrap.setPolicyComponent(this.policyComponent);
|
||||
|
||||
RepositoryLocation location = new RepositoryLocation();
|
||||
location.setStoreProtocol(this.storeRef.getProtocol());
|
||||
location.setStoreId(this.storeRef.getIdentifier());
|
||||
location.setQueryLanguage(RepositoryLocation.LANGUAGE_PATH);
|
||||
// NOTE: we are not setting the path for now .. in doing so we are searching the root node only
|
||||
RepositoryLocation modelsLocation = new RepositoryLocation(this.storeRef,
|
||||
this.nodeService.getPath(rootModelsNodeRef).toPrefixString(namespaceService), RepositoryLocation.LANGUAGE_PATH);
|
||||
RepositoryLocation messagesLocation = new RepositoryLocation(this.storeRef,
|
||||
this.nodeService.getPath(rootMessagesNodeRef).toPrefixString(namespaceService), RepositoryLocation.LANGUAGE_PATH);
|
||||
|
||||
List<RepositoryLocation> locations = new ArrayList<RepositoryLocation>();
|
||||
locations.add(location);
|
||||
List<RepositoryLocation> modelsLocations = new ArrayList<RepositoryLocation>();
|
||||
modelsLocations.add(modelsLocation);
|
||||
List<RepositoryLocation> messagesLocations = new ArrayList<RepositoryLocation>();
|
||||
messagesLocations.add(messagesLocation);
|
||||
|
||||
this.bootstrap.setRepositoryModelsLocations(locations);
|
||||
this.bootstrap.setRepositoryModelsLocations(modelsLocations);
|
||||
this.bootstrap.setRepositoryMessagesLocations(messagesLocations);
|
||||
|
||||
// register with dictionary service
|
||||
this.bootstrap.register();
|
||||
@@ -225,6 +249,14 @@ public class DictionaryRepositoryBootstrapTest extends BaseSpringTest
|
||||
"base1",
|
||||
"prop1");
|
||||
|
||||
// Create a message file for the default locale
|
||||
NodeRef messageNodeDefaultLoc = createMessagesNode(null, null);
|
||||
// Create a message file for the french locale
|
||||
createMessagesNode(Locale.FRANCE.toString(), MESSAGES_VALUE_FR);
|
||||
// Construct baseBundleName for validation
|
||||
String baseBundleName = storeRef.toString()
|
||||
+ messageService.getBaseBundleName(nodeService.getPath(messageNodeDefaultLoc).toPrefixString(namespaceService));
|
||||
|
||||
// Check that the model is not in the dictionary yet
|
||||
try
|
||||
{
|
||||
@@ -251,6 +283,12 @@ public class DictionaryRepositoryBootstrapTest extends BaseSpringTest
|
||||
QName.createQName("http://www.alfresco.org/model/test3DictionaryBootstrapFromRepo/1.0", "testModel3"));
|
||||
assertNotNull(modelDefinition3);
|
||||
|
||||
// Check if the messages were registered correctly
|
||||
assertTrue("The message bundle should be registered", messageService.getRegisteredBundles().contains(baseBundleName));
|
||||
assertEquals("The default message value is not as expected", MESSAGES_VALUE, messageService.getMessage(MESSAGES_KEY));
|
||||
assertEquals("The message value in french is not as expected", MESSAGES_VALUE_FR,
|
||||
messageService.getMessage(MESSAGES_KEY, Locale.FRANCE));
|
||||
|
||||
txn.commit();
|
||||
}
|
||||
|
||||
@@ -277,7 +315,7 @@ public class DictionaryRepositoryBootstrapTest extends BaseSpringTest
|
||||
{
|
||||
// Create a model node
|
||||
NodeRef model = this.nodeService.createNode(
|
||||
this.rootNodeRef,
|
||||
this.rootModelsNodeRef,
|
||||
ContentModel.ASSOC_CHILDREN,
|
||||
QName.createQName("{test}models"),
|
||||
ContentModel.TYPE_DICTIONARY_MODEL).getChildRef();
|
||||
@@ -300,6 +338,39 @@ public class DictionaryRepositoryBootstrapTest extends BaseSpringTest
|
||||
return model;
|
||||
}
|
||||
|
||||
/**
|
||||
* Create messages node
|
||||
*
|
||||
* @return NodeRef
|
||||
*/
|
||||
private NodeRef createMessagesNode(String locale, String localeValue)
|
||||
{
|
||||
String filename = BUNDLENAME_MESSAGES + FILENAME_MESSAGES_EXT;
|
||||
String messageValue = MESSAGES_VALUE;
|
||||
|
||||
if (locale != null)
|
||||
{
|
||||
filename = BUNDLENAME_MESSAGES + "_" + locale + FILENAME_MESSAGES_EXT;
|
||||
messageValue = localeValue;
|
||||
}
|
||||
// Create a model node
|
||||
NodeRef messageNode = this.nodeService.createNode(
|
||||
this.rootMessagesNodeRef,
|
||||
ContentModel.ASSOC_CHILDREN,
|
||||
QName.createQName(NamespaceService.CONTENT_MODEL_1_0_URI, filename),
|
||||
ContentModel.TYPE_CONTENT,
|
||||
Collections.<QName, Serializable> singletonMap(ContentModel.PROP_NAME, filename)
|
||||
).getChildRef();
|
||||
|
||||
ContentWriter contentWriter = this.contentService.getWriter(messageNode, ContentModel.PROP_CONTENT, true);
|
||||
contentWriter.setEncoding("UTF-8");
|
||||
contentWriter.setMimetype(MimetypeMap.MIMETYPE_TEXT_PLAIN);
|
||||
String messagesString = MESSAGES_KEY + "=" + messageValue;
|
||||
contentWriter.putContent(messagesString);
|
||||
|
||||
return messageNode;
|
||||
}
|
||||
|
||||
/**
|
||||
*
|
||||
* Gets the model string
|
||||
|
@@ -0,0 +1 @@
|
||||
mycustommessages.key1=This is a custom message
|
@@ -0,0 +1 @@
|
||||
mycustommessages.key1=Dies ist eine benutzerdefinierte Nachricht
|
@@ -0,0 +1 @@
|
||||
mycustommessages.key1=Ceci est un message personnalis\u00e9
|
Reference in New Issue
Block a user