diff --git a/config/alfresco/model-specific-services-context.xml b/config/alfresco/model-specific-services-context.xml
index 998b150827..c1a5e98e6c 100644
--- a/config/alfresco/model-specific-services-context.xml
+++ b/config/alfresco/model-specific-services-context.xml
@@ -68,7 +68,7 @@
-
+
@@ -82,6 +82,9 @@
+
+
+
diff --git a/config/alfresco/node-services-context.xml b/config/alfresco/node-services-context.xml
index 34f64c7d1e..d14d9c3a56 100644
--- a/config/alfresco/node-services-context.xml
+++ b/config/alfresco/node-services-context.xml
@@ -8,6 +8,9 @@
+
+
+
diff --git a/config/alfresco/public-services-security-context.xml b/config/alfresco/public-services-security-context.xml
index 6ce5623fe2..a20bb7a19f 100644
--- a/config/alfresco/public-services-security-context.xml
+++ b/config/alfresco/public-services-security-context.xml
@@ -544,6 +544,7 @@
org.alfresco.service.cmr.ml.MultilingualContentService.addEmptyTranslation=ACL_NODE.0.sys:base.Read,ACL_NODE.0.sys:base.CreateChildren
org.alfresco.service.cmr.ml.MultilingualContentService.copyTranslationContainer=ACL_NODE.0.sys:base.Read,ACL_NODE.1.sys:base.CreateChildren
org.alfresco.service.cmr.ml.MultilingualContentService.moveTranslationContainer=ACL_NODE.0.sys:base.DeleteNode,ACL_NODE.1.sys:base.CreateChildren
+ org.alfresco.service.cmr.ml.MultilingualContentService.deleteTranslationContainer=ACL_NODE.0.sys:base.DeleteNode,ACL_NODE.0.sys:base.DeleteChildren
diff --git a/source/java/org/alfresco/repo/model/ml/EditionServiceImpl.java b/source/java/org/alfresco/repo/model/ml/EditionServiceImpl.java
index 94c8afdfbc..02bf2c2fbd 100644
--- a/source/java/org/alfresco/repo/model/ml/EditionServiceImpl.java
+++ b/source/java/org/alfresco/repo/model/ml/EditionServiceImpl.java
@@ -120,7 +120,7 @@ public class EditionServiceImpl implements EditionService
// Version the container and its translations
versionService.createVersion(mlContainerToVersion, versionProperties, true);
- // 2. Third step: prepare the current edition of the mlContainer
+ // 2. second step: prepare the current edition of the mlContainer
// Get the new starting point node, it will be returned
NodeRef startNode;
@@ -169,6 +169,7 @@ public class EditionServiceImpl implements EditionService
// set the starting translation become the pivot.
nodeService.setProperty(mlContainerToVersion, ContentModel.PROP_LOCALE, locale);
nodeService.setProperty(mlContainerToVersion, ContentModel.PROP_AUTHOR, author);
+ nodeService.setProperty(mlContainerToVersion, ContentModel.PROP_NAME, name);
// Done
if (logger.isDebugEnabled())
diff --git a/source/java/org/alfresco/repo/model/ml/MultilingualContentServiceImpl.java b/source/java/org/alfresco/repo/model/ml/MultilingualContentServiceImpl.java
index e2c0c86dfd..d39d4b004f 100644
--- a/source/java/org/alfresco/repo/model/ml/MultilingualContentServiceImpl.java
+++ b/source/java/org/alfresco/repo/model/ml/MultilingualContentServiceImpl.java
@@ -24,6 +24,7 @@
*/
package org.alfresco.repo.model.ml;
+import java.io.Serializable;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
@@ -31,13 +32,18 @@ import java.util.Locale;
import java.util.Map;
import java.util.Set;
+import javax.transaction.SystemException;
+
import org.alfresco.error.AlfrescoRuntimeException;
import org.alfresco.i18n.I18NUtil;
import org.alfresco.model.ContentModel;
+import org.alfresco.repo.policy.BehaviourFilter;
import org.alfresco.service.cmr.ml.ContentFilterLanguagesService;
import org.alfresco.service.cmr.ml.MultilingualContentService;
+import org.alfresco.service.cmr.model.FileExistsException;
import org.alfresco.service.cmr.model.FileFolderService;
import org.alfresco.service.cmr.model.FileInfo;
+import org.alfresco.service.cmr.model.FileNotFoundException;
import org.alfresco.service.cmr.repository.ChildAssociationRef;
import org.alfresco.service.cmr.repository.ContentData;
import org.alfresco.service.cmr.repository.NodeRef;
@@ -86,6 +92,8 @@ public class MultilingualContentServiceImpl implements MultilingualContentServic
private ContentFilterLanguagesService contentFilterLanguagesService;
private FileFolderService fileFolderService;
+ private BehaviourFilter policyBehaviourFilter;
+
public MultilingualContentServiceImpl()
{
searchParametersMLRoot = new SearchParameters();
@@ -284,8 +292,12 @@ public class MultilingualContentServiceImpl implements MultilingualContentServic
// Make one
mlContainerNodeRef = getOrCreateMLContainer(contentNodeRef, true);
- // set the pivot language
+ Serializable containerFunctionalName = nodeService.getProperty(contentNodeRef, ContentModel.PROP_NAME);
+
+ // set the pivot language and the functional name
nodeService.setProperty(mlContainerNodeRef, ContentModel.PROP_LOCALE, locale);
+ nodeService.setProperty(mlContainerNodeRef, ContentModel.PROP_NAME, containerFunctionalName);
+
}
else
{
@@ -369,7 +381,57 @@ public class MultilingualContentServiceImpl implements MultilingualContentServic
}
}
- /** {@inheritDoc} */
+
+ /** @inheritDoc */
+ public void deleteTranslationContainer(NodeRef mlContainerNodeRef)
+ {
+ if(!ContentModel.TYPE_MULTILINGUAL_CONTAINER.equals(nodeService.getType(mlContainerNodeRef)))
+ {
+ throw new IllegalArgumentException(
+ "Node type must be " + ContentModel.TYPE_MULTILINGUAL_CONTAINER);
+ }
+
+ // get the translations
+ Map translations = this.getTranslations(mlContainerNodeRef);
+
+ // remember the number of childs
+ int translationCount = translations.size();
+
+ // remove the translations
+ for(NodeRef translationToRemove : translations.values())
+ {
+ // unmake the translation
+ this.unmakeTranslation(translationToRemove);
+
+ // remove it
+ if(nodeService.exists(translationToRemove))
+ {
+ nodeService.deleteNode(translationToRemove);
+ }
+ }
+
+ // if the mlContainer is not removed with the pivot,
+ if(nodeService.exists(mlContainerNodeRef))
+ {
+ // force its deletion
+ nodeService.deleteNode(mlContainerNodeRef);
+
+ if (logger.isWarnEnabled())
+ {
+ logger.warn("The ML container " + mlContainerNodeRef + " was not removed with it's pivot translation in the unmakeTranslation process.");
+ }
+ }
+
+ // done
+ if (logger.isDebugEnabled())
+ {
+ logger.debug("ML container removed: \n" +
+ " Container: " + mlContainerNodeRef + "\n" +
+ " Number of translations: " + translationCount);
+ }
+ }
+
+ /** @inheritDoc */
public void unmakeTranslation(NodeRef translationNodeRef)
{
// Get the container
@@ -622,7 +684,9 @@ public class MultilingualContentServiceImpl implements MultilingualContentServic
public NodeRef addEmptyTranslation(NodeRef translationOfNodeRef, String name, Locale locale)
{
boolean hasMLAspect = nodeService.hasAspect(translationOfNodeRef, ContentModel.ASPECT_MULTILINGUAL_DOCUMENT);
- if (hasMLAspect)
+ boolean isMLContainer = nodeService.getType(translationOfNodeRef).equals(ContentModel.TYPE_MULTILINGUAL_CONTAINER);
+
+ if (hasMLAspect || isMLContainer)
{
// Get the pivot translation
NodeRef pivotTranslationNodeRef = getPivotTranslation(translationOfNodeRef);
@@ -717,15 +781,177 @@ public class MultilingualContentServiceImpl implements MultilingualContentServic
return newTranslationNodeRef;
}
- public void setNodeService(NodeService nodeService)
- {
- this.nodeService = nodeService;
+ /**
+ * @throws SystemException
+ * @throws Exception
+ * @throws FileNotFoundException
+ * @throws FileExistsException
+ * @inheritDoc
+ */
+ public NodeRef copyTranslationContainer(NodeRef mlContainerNodeRef, NodeRef newParentRef, String prefixName) throws Exception
+ {
+ if(!ContentModel.TYPE_MULTILINGUAL_CONTAINER.equals(nodeService.getType(mlContainerNodeRef)))
+ {
+ throw new IllegalArgumentException(
+ "Node type must be " + ContentModel.TYPE_MULTILINGUAL_CONTAINER);
+ }
+
+ // if the container has no translation: nothing to do
+ if(nodeService.getChildAssocs(mlContainerNodeRef, ContentModel.ASSOC_MULTILINGUAL_CHILD, RegexQNamePattern.MATCH_ALL).size() < 1)
+ {
+ if (logger.isDebugEnabled())
+ {
+ logger.debug("MLContainer has no translation " + mlContainerNodeRef);
+ }
+
+ return null;
+ }
+
+ // keep a reference to the containing space before copy
+ NodeRef spaceBefore = nodeService.getPrimaryParent(getPivotTranslation(mlContainerNodeRef)).getParentRef();
+
+ if(spaceBefore.equals(newParentRef))
+ {
+ throw new AlfrescoRuntimeException(
+ "Impossible to copy the mlContainer, source folder is the same as the destination container.");
+ }
+
+ // get the pivot translation and its locale
+ NodeRef pivotNodeRef = getPivotTranslation(mlContainerNodeRef);
+ Locale pivotLocale = (Locale) nodeService.getProperty(pivotNodeRef, ContentModel.PROP_LOCALE);
+ String pivotName = prefixName + (String) nodeService.getProperty(pivotNodeRef, ContentModel.PROP_NAME);
+
+ if(prefixName == null)
+ {
+ prefixName = "";
+ }
+
+ NodeRef pivotCopyNodeRef = null;
+
+ pivotCopyNodeRef = fileFolderService.copy(pivotNodeRef, newParentRef, pivotName).getNodeRef();
+
+ // make the new pivot multilingual
+ this.makeTranslation(pivotCopyNodeRef, pivotLocale);
+
+ // get a reference to the new mlContainer
+ NodeRef newMLContainerNodeRef = getMLContainer(pivotCopyNodeRef, false);
+
+ // copy each other translation and make them multilingual too
+ for(Map.Entry entry : getTranslations(mlContainerNodeRef).entrySet())
+ {
+ Locale translationLocale = entry.getKey();
+ NodeRef translationNodeRef = entry.getValue();
+
+ String name = prefixName + (String) nodeService.getProperty(translationNodeRef, ContentModel.PROP_NAME);
+
+ if(!translationNodeRef.equals(pivotNodeRef))
+ {
+ if(nodeService.hasAspect(translationNodeRef, ContentModel.ASPECT_MULTILINGUAL_EMPTY_TRANSLATION))
+ {
+ // Turn off any empty translation policy behaviours to enabled the copy.
+ this.policyBehaviourFilter.disableBehaviour(ContentModel.ASPECT_MULTILINGUAL_EMPTY_TRANSLATION);
+ this.policyBehaviourFilter.disableBehaviour(ContentModel.ASPECT_MULTILINGUAL_DOCUMENT);
+
+ try
+ {
+ // copy the translation
+ NodeRef copyNodeRef = fileFolderService.copy(translationNodeRef, newParentRef, name).getNodeRef();
+
+ // Add it to the newMLContainer
+ nodeService.addChild(
+ newMLContainerNodeRef,
+ copyNodeRef,
+ ContentModel.ASSOC_MULTILINGUAL_CHILD,
+ QNAME_ML_TRANSLATION);
+ }
+ finally
+ {
+ this.policyBehaviourFilter.enableBehaviour(ContentModel.ASPECT_MULTILINGUAL_EMPTY_TRANSLATION);
+ this.policyBehaviourFilter.enableBehaviour(ContentModel.ASPECT_MULTILINGUAL_DOCUMENT);
+ }
+ }
+ else
+ {
+ // copy the translation
+ NodeRef copyNodeRef = fileFolderService.copy(translationNodeRef, newParentRef, name).getNodeRef();
+
+ // add it to the mlContainer
+ this.addTranslation(copyNodeRef, newMLContainerNodeRef, translationLocale);
+ // set its locale property
+ nodeService.setProperty(copyNodeRef, ContentModel.PROP_LOCALE, translationLocale);
+ }
+ }
+ else
+ {
+ // the pivot is already created
+ }
+ }
+
+ if (logger.isDebugEnabled())
+ {
+ logger.debug("MLContainer copied: \n" +
+ " Copy of : " + mlContainerNodeRef + "(translations located in " + spaceBefore + ") \n" +
+ " Copy : " + newMLContainerNodeRef + "(translations located in " + newParentRef + ") \n");
+ }
+
+ return newMLContainerNodeRef;
+ }
+
+ /**
+ * @inheritDoc
+ */
+ public void moveTranslationContainer(NodeRef mlContainerNodeRef, NodeRef newParentRef) throws FileExistsException, FileNotFoundException
+ {
+ if(!ContentModel.TYPE_MULTILINGUAL_CONTAINER.equals(nodeService.getType(mlContainerNodeRef)))
+ {
+ throw new IllegalArgumentException(
+ "Node type must be " + ContentModel.TYPE_MULTILINGUAL_CONTAINER);
+ }
+
+ // if the container has no translation: nothing to do
+ if(nodeService.getChildAssocs(mlContainerNodeRef, ContentModel.ASSOC_MULTILINGUAL_CHILD, RegexQNamePattern.MATCH_ALL).size() < 1)
+ {
+ if (logger.isDebugEnabled())
+ {
+ logger.debug("MLContainer has no translation " + mlContainerNodeRef);
+ }
+
+ return;
+ }
+
+ // keep a reference to the containing space before moving
+ NodeRef spaceBefore = nodeService.getPrimaryParent(getPivotTranslation(mlContainerNodeRef)).getParentRef();
+
+ if(spaceBefore.equals(newParentRef))
+ {
+ // nothing to do
+ return;
+ }
+
+ // move each translation
+ for(NodeRef translationToMove : getTranslations(mlContainerNodeRef).values())
+ {
+ fileFolderService.move(translationToMove, newParentRef, null);
+ }
+
+ if (logger.isDebugEnabled())
+ {
+ logger.debug("MLContainer moved: \n" +
+ " Old location of " + mlContainerNodeRef + " : " + spaceBefore + ") \n" +
+ " New location of " + mlContainerNodeRef + " : " + newParentRef + ")");
+ }
}
- public void setSearchService(SearchService searchService)
- {
+
+ public void setNodeService(NodeService nodeService)
+ {
+ this.nodeService = nodeService;
+ }
+
+ public void setSearchService(SearchService searchService)
+ {
this.searchService = searchService;
- }
+ }
public void setPermissionService(PermissionService permissionService)
{
@@ -742,13 +968,8 @@ public class MultilingualContentServiceImpl implements MultilingualContentServic
this.fileFolderService = fileFolderService;
}
- public NodeRef copyTranslationContainer(NodeRef translationNodeRef, NodeRef newParentRef)
+ public void setPolicyBehaviourFilter(BehaviourFilter policyBehaviourFilter)
{
- throw new UnsupportedOperationException("This operation is not yet supported");
- }
-
- public void moveTranslationContainer(NodeRef translationNodeRef, NodeRef newParentRef)
- {
- throw new UnsupportedOperationException("This operation is not yet supported");
+ this.policyBehaviourFilter = policyBehaviourFilter;
}
}
\ No newline at end of file
diff --git a/source/java/org/alfresco/repo/model/ml/MultilingualDocumentAspect.java b/source/java/org/alfresco/repo/model/ml/MultilingualDocumentAspect.java
index 3762fcbe1d..45b8b2d28f 100644
--- a/source/java/org/alfresco/repo/model/ml/MultilingualDocumentAspect.java
+++ b/source/java/org/alfresco/repo/model/ml/MultilingualDocumentAspect.java
@@ -35,7 +35,6 @@ import org.alfresco.repo.node.NodeServicePolicies;
import org.alfresco.repo.policy.JavaBehaviour;
import org.alfresco.repo.policy.PolicyComponent;
import org.alfresco.repo.policy.PolicyScope;
-import org.alfresco.repo.version.VersionServicePolicies;
import org.alfresco.service.cmr.ml.MultilingualContentService;
import org.alfresco.service.cmr.repository.NodeRef;
import org.alfresco.service.cmr.repository.NodeService;
@@ -54,22 +53,10 @@ import org.alfresco.service.namespace.RegexQNamePattern;
*/
public class MultilingualDocumentAspect implements
CopyServicePolicies.OnCopyNodePolicy,
- CopyServicePolicies.OnCopyCompletePolicy,
NodeServicePolicies.BeforeDeleteNodePolicy,
- NodeServicePolicies.OnUpdatePropertiesPolicy,
- VersionServicePolicies.OnCreateVersionPolicy
+ NodeServicePolicies.OnUpdatePropertiesPolicy
{
- /**
- * List of properties to set persistent when a version of the mlDocument is created
- */
- public static final QName[] PROPERTIES_TO_VERSION = {
- ContentModel.PROP_AUTHOR,
- ContentModel.PROP_LOCALE,
- ContentModel.PROP_TITLE,
- ContentModel.PROP_DESCRIPTION,
- };
-
// Dependencies
private PolicyComponent policyComponent;
private MultilingualContentService multilingualContentService;
@@ -88,11 +75,6 @@ public class MultilingualDocumentAspect implements
ContentModel.ASPECT_MULTILINGUAL_DOCUMENT,
new JavaBehaviour(this, "onCopyNode"));
- this.policyComponent.bindClassBehaviour(
- QName.createQName(NamespaceService.ALFRESCO_URI, "onCopyComplete"),
- ContentModel.ASPECT_MULTILINGUAL_DOCUMENT,
- new JavaBehaviour(this, "onCopyComplete"));
-
this.policyComponent.bindClassBehaviour(
QName.createQName(NamespaceService.ALFRESCO_URI, "beforeDeleteNode"),
ContentModel.ASPECT_MULTILINGUAL_DOCUMENT,
@@ -103,11 +85,6 @@ public class MultilingualDocumentAspect implements
ContentModel.ASPECT_MULTILINGUAL_DOCUMENT,
new JavaBehaviour(this, "onUpdateProperties"));
- this.policyComponent.bindClassBehaviour(
- QName.createQName(NamespaceService.ALFRESCO_URI, "onCreateVersion"),
- ContentModel.ASPECT_MULTILINGUAL_DOCUMENT,
- new JavaBehaviour(this, "onCreateVersion"));
-
}
/**
@@ -145,16 +122,6 @@ public class MultilingualDocumentAspect implements
copyDetails.removeAspect(ContentModel.ASPECT_MULTILINGUAL_DOCUMENT);
}
- /**
- * The copy of mlDocument don't keep the 'locale' property.
- *
- * @see org.alfresco.repo.copy.CopyServicePolicies.OnCopyCompletePolicy#onCopyComplete(org.alfresco.service.namespace.QName, org.alfresco.service.cmr.repository.NodeRef, org.alfresco.service.cmr.repository.NodeRef, boolean, java.util.Map)
- */
- public void onCopyComplete(QName classRef, NodeRef sourceNodeRef, NodeRef destinationRef, boolean copyToNewNode, Map copyMap)
- {
- nodeService.removeProperty(destinationRef, ContentModel.PROP_LOCALE);
- }
-
/**
* If this is not an empty translation, then ensure that the node is properly
* unhooked from the translation mechanism first.
@@ -191,10 +158,10 @@ public class MultilingualDocumentAspect implements
// the after local property type can be either Locale or String
Serializable objLocaleAfter = after.get(ContentModel.PROP_LOCALE);
+
if (objLocaleAfter instanceof Locale )
{
localeAfter = (Locale) objLocaleAfter;
-
}
else
{
@@ -242,19 +209,4 @@ public class MultilingualDocumentAspect implements
// else no action to perform
}
-
- /**
- * Persist some specific properties in the version store
- *
- * @see org.alfresco.repo.model.ml.MultilingualDocumentAspect.PROPERTIES_TO_VERSION
- * @see org.alfresco.repo.version.VersionServicePolicies.OnCreateVersionPolicy#onCreateVersion(org.alfresco.service.namespace.QName, org.alfresco.service.cmr.repository.NodeRef, java.util.Map, org.alfresco.repo.policy.PolicyScope)
- */
- public void onCreateVersion(QName classRef, NodeRef versionableNode, Map versionProperties, PolicyScope nodeDetails)
- {
- for(QName prop : PROPERTIES_TO_VERSION)
- {
- nodeDetails.addProperty(prop, nodeService.getProperty(versionableNode, prop));
- }
- }
-
}
diff --git a/source/java/org/alfresco/repo/model/ml/tools/EditionServiceImplTest.java b/source/java/org/alfresco/repo/model/ml/tools/EditionServiceImplTest.java
index 19beae7053..a8cef3f691 100644
--- a/source/java/org/alfresco/repo/model/ml/tools/EditionServiceImplTest.java
+++ b/source/java/org/alfresco/repo/model/ml/tools/EditionServiceImplTest.java
@@ -28,7 +28,6 @@ import java.io.Serializable;
import java.util.ArrayList;
import java.util.Collection;
import java.util.Collections;
-import java.util.Comparator;
import java.util.HashMap;
import java.util.List;
import java.util.Locale;
@@ -36,6 +35,7 @@ import java.util.Map;
import org.alfresco.model.ContentModel;
import org.alfresco.repo.version.VersionModel;
+import org.alfresco.repo.version.common.VersionLabelComparator;
import org.alfresco.service.cmr.repository.NodeRef;
import org.alfresco.service.cmr.version.Version;
import org.alfresco.service.cmr.version.VersionHistory;
@@ -210,24 +210,12 @@ public class EditionServiceImplTest extends AbstractMultilingualTestCases
return multilingualContentService.getTranslationContainer(chineseContentNodeRef);
}
- private Comparator versionComparator = new Comparator()
- {
- public int compare(Object o1, Object o2)
- {
- String label01 = ((Version) o1).getVersionLabel();
- String label02 = ((Version) o2).getVersionLabel();
-
- // sort the list ascending
- return label02.compareTo(label01);
- }
- };
-
@SuppressWarnings("unchecked")
private List orderVersions(Collection allVersions)
{
List versionsAsList = new ArrayList(allVersions.size());
versionsAsList.addAll(allVersions);
- Collections.sort(versionsAsList, versionComparator);
+ Collections.sort(versionsAsList, new VersionLabelComparator());
return versionsAsList;
}
}
diff --git a/source/java/org/alfresco/repo/model/ml/tools/MultilingualContentServiceImplTest.java b/source/java/org/alfresco/repo/model/ml/tools/MultilingualContentServiceImplTest.java
index ea65fd55c4..a4893fc48d 100644
--- a/source/java/org/alfresco/repo/model/ml/tools/MultilingualContentServiceImplTest.java
+++ b/source/java/org/alfresco/repo/model/ml/tools/MultilingualContentServiceImplTest.java
@@ -15,17 +15,20 @@
* 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:
+ * 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.model.ml.tools;
+import java.util.ArrayList;
+import java.util.Collection;
import java.util.List;
import java.util.Locale;
+import java.util.Map;
import net.sf.acegisecurity.Authentication;
@@ -39,13 +42,13 @@ import org.alfresco.service.cmr.security.PermissionService;
/**
* @see org.alfresco.repo.ml.MultilingualContentServiceImpl
- *
+ *
* @author Derek Hulley
* @author Philippe Dubois
*/
public class MultilingualContentServiceImplTest extends AbstractMultilingualTestCases
{
-
+
public void testMakeTranslation() throws Exception
{
NodeRef chineseContentNodeRef = createContent();
@@ -57,7 +60,7 @@ public class MultilingualContentServiceImplTest extends AbstractMultilingualTest
// Check the container child count
assertEquals("Incorrect number of child nodes", 1, nodeService.getChildAssocs(mlContainerNodeRef).size());
}
-
+
public void testAddTranslationUsingContent() throws Exception
{
// Make a container with a single translation
@@ -77,58 +80,58 @@ public class MultilingualContentServiceImplTest extends AbstractMultilingualTest
// Check the container child count
assertEquals("Incorrect number of child nodes", 2, nodeService.getChildAssocs(mlContainerNodeRef).size());
}
-
- @SuppressWarnings("unused")
+
+ @SuppressWarnings("unused")
public void testGetMissingTranslation() throws Exception
{
List langList = contentFilterLanguagesService.getFilterLanguages();
int langListSize = langList.size();
-
+
// make sure that it exists at least tree language filter
assertFalse("The testGetMissingTranslation test case needs at least three language", langListSize < 3);
-
- // get the first tree locale of the content filter language list
+
+ // get the first tree locale of the content filter language list
Locale loc1 = I18NUtil.parseLocale(langList.get(0));
Locale loc2 = I18NUtil.parseLocale(langList.get(1));
Locale loc3 = I18NUtil.parseLocale(langList.get(2));
-
- // create three content
+
+ // create three content
NodeRef nodeRef1 = createContent();
NodeRef nodeRef2 = createContent();
NodeRef nodeRef3 = createContent();
-
+
multilingualContentService.makeTranslation(nodeRef1, loc1);
-
- List missing = multilingualContentService.getMissingTranslations(nodeRef1, false);
-
- // make sure that the missing language list size is correct
+
+ List missing = multilingualContentService.getMissingTranslations(nodeRef1, false);
+
+ // make sure that the missing language list size is correct
assertFalse("Missing Translation Size false. " +
"Real size : " + missing.size() + ". Normal Size " + (langListSize - 1), missing.size() != (langListSize - 1));
-
+
// make sure that the missing language list is correct
assertFalse("Missing Translation List false. Locale " + loc1 + " found", missing.contains(loc1.toString()));
-
+
multilingualContentService.addTranslation(nodeRef2, nodeRef1, loc2);
multilingualContentService.addTranslation(nodeRef3, nodeRef1, loc3);
-
+
// Add the missing translations in
missing = multilingualContentService.getMissingTranslations(nodeRef1, false);
-
- // Make sure that the missing language list size is correct
+
+ // Make sure that the missing language list size is correct
assertFalse("Missing Translation Size false. " +
"Real size : " + missing.size() + ". Normal Size " + (langListSize - 3), missing.size() != (langListSize - 3));
-
+
// make sure that the missing language list is correct
assertFalse("Missing Translation List false. Locale " + loc2 + " or " + loc3 + " found", missing.contains(loc2.toString()) || missing.contains(loc3.toString()));
}
-
+
public void testGetTranslationForLocale() throws Exception
{
NodeRef chineseContentNodeRef = createContent();
multilingualContentService.makeTranslation(chineseContentNodeRef, Locale.CHINESE);
- NodeRef frenchContentNodeRef = createContent();
+ NodeRef frenchContentNodeRef = createContent();
multilingualContentService.addTranslation(frenchContentNodeRef, chineseContentNodeRef, Locale.FRENCH);
-
+
// Get the chinese translation
assertEquals("Chinese translation should be present",
chineseContentNodeRef,
@@ -142,61 +145,61 @@ public class MultilingualContentServiceImplTest extends AbstractMultilingualTest
chineseContentNodeRef,
multilingualContentService.getTranslationForLocale(chineseContentNodeRef, Locale.ITALIAN));
}
-
- @SuppressWarnings("unused")
+
+ @SuppressWarnings("unused")
public void testGetPivotTranslation() throws Exception
{
NodeRef chineseContentNodeRef = createContent();
multilingualContentService.makeTranslation(chineseContentNodeRef, Locale.CHINESE);
NodeRef mlContainerNodeRef = multilingualContentService.getTranslationContainer(chineseContentNodeRef);
-
+
// make sure that the pivot language is set
assertNotNull("Pivot language not set", nodeService.getProperty(mlContainerNodeRef, ContentModel.PROP_LOCALE));
-
+
// make sure that the pivot language is correctly set
- assertEquals("Pivot language not correctly set", Locale.CHINESE, nodeService.getProperty(mlContainerNodeRef, ContentModel.PROP_LOCALE));
-
- NodeRef frenchContentNodeRef = createContent();
+ assertEquals("Pivot language not correctly set", Locale.CHINESE, nodeService.getProperty(mlContainerNodeRef, ContentModel.PROP_LOCALE));
+
+ NodeRef frenchContentNodeRef = createContent();
multilingualContentService.addTranslation(frenchContentNodeRef, chineseContentNodeRef, Locale.FRENCH);
-
+
// make sure that the pivot noderef is correct
- assertEquals("Unable to get pivot from container", chineseContentNodeRef, multilingualContentService.getPivotTranslation(mlContainerNodeRef));
- assertEquals("Unable to get pivot from translation", chineseContentNodeRef, multilingualContentService.getPivotTranslation(frenchContentNodeRef));
-
- // modify the pivot language
+ assertEquals("Unable to get pivot from container", chineseContentNodeRef, multilingualContentService.getPivotTranslation(mlContainerNodeRef));
+ assertEquals("Unable to get pivot from translation", chineseContentNodeRef, multilingualContentService.getPivotTranslation(frenchContentNodeRef));
+
+ // modify the pivot language
nodeService.setProperty(mlContainerNodeRef, ContentModel.PROP_LOCALE, Locale.FRENCH);
-
+
// make sure that the modified pivot noderef is correct
assertEquals("Pivot node ref not correct", frenchContentNodeRef, multilingualContentService.getPivotTranslation(mlContainerNodeRef));
}
-
- @SuppressWarnings("unused")
+
+ @SuppressWarnings("unused")
public void testCreateEmptyTranslation() throws Exception
{
NodeRef chineseContentNodeRef = createContent("Document.txt");
multilingualContentService.makeTranslation(chineseContentNodeRef, Locale.CHINESE);
-
+
// This should use the pivot language
NodeRef emptyNodeRef = multilingualContentService.addEmptyTranslation(chineseContentNodeRef, "Document.txt", Locale.CANADA);
-
+
// Ensure that the empty translation is not null
assertNotNull("The creation of the empty document failed ", emptyNodeRef);
// Ensure that the empty translation has the mlDocument aspect
assertTrue("The empty document must have the mlDocument aspect",
nodeService.hasAspect(emptyNodeRef, ContentModel.ASPECT_MULTILINGUAL_DOCUMENT));
- // Ensure that the empty translation has the mlEmptyTranslation aspect
+ // Ensure that the empty translation has the mlEmptyTranslation aspect
assertTrue("The empty document must have the mlEmptyTranslation aspect",
nodeService.hasAspect(emptyNodeRef, ContentModel.ASPECT_MULTILINGUAL_EMPTY_TRANSLATION));
// Check that the auto renaming worked
String emptyName = DefaultTypeConverter.INSTANCE.convert(String.class,
nodeService.getProperty(emptyNodeRef, ContentModel.PROP_NAME));
assertEquals("Empty auto-rename didn't work for same-named document", "Document_en_CA.txt", emptyName);
-
+
// Check that the content is identical
ContentData chineseContentData = fileFolderService.getReader(chineseContentNodeRef).getContentData();
ContentData emptyContentData = fileFolderService.getReader(emptyNodeRef).getContentData();
}
-
+
public void testCreateEmptyTranslationNames() throws Exception
{
NodeRef chineseContentNodeRef = createContent("Document.txt");
@@ -225,7 +228,7 @@ public class MultilingualContentServiceImplTest extends AbstractMultilingualTest
String differentName = fileFolderService.getFileInfo(differentNameNodeRef).getName();
assertEquals("Empty translation name not generated correctly.", "Document2.txt", differentName);
}
-
+
public void testGetTranslationContainerPermissions() throws Exception
{
// Grant the guest user rights to our working folder
@@ -252,7 +255,7 @@ public class MultilingualContentServiceImplTest extends AbstractMultilingualTest
try { authenticationComponent.setCurrentAuthentication(authentication); } catch (Throwable e) {}
}
}
-
+
/**
* Check whether non-admin users can take part in ML document manipulation
*/
@@ -284,4 +287,284 @@ public class MultilingualContentServiceImplTest extends AbstractMultilingualTest
try { authenticationComponent.setCurrentAuthentication(authentication); } catch (Throwable e) {}
}
}
+
+ public void testDeleteMultilingualContent() throws Exception
+ {
+ NodeRef chineseContentNodeRef = createContent();
+ NodeRef frenchContentNodeRef = createContent();
+ NodeRef japaneseContentNodeRef = createContent();
+ NodeRef emptyGermanContentNodeRef = null;
+
+ multilingualContentService.makeTranslation(chineseContentNodeRef, Locale.CHINESE);
+ multilingualContentService.addTranslation(frenchContentNodeRef, chineseContentNodeRef, Locale.FRENCH);
+ multilingualContentService.addTranslation(japaneseContentNodeRef, chineseContentNodeRef, Locale.JAPANESE);
+ emptyGermanContentNodeRef = multilingualContentService.addEmptyTranslation(chineseContentNodeRef, null, Locale.GERMAN);
+
+ // the mlContainer to remove
+ NodeRef mlContainerNodeRef = multilingualContentService.getTranslationContainer(chineseContentNodeRef);
+
+ // Ensure that the the mlContainer is correctly created
+ assertEquals("Incorrect number of translations", 4, multilingualContentService.getTranslations(mlContainerNodeRef).size());
+
+ // remove the mlContainer
+ multilingualContentService.deleteTranslationContainer(mlContainerNodeRef);
+
+ // get the archived node ref
+ NodeRef archivedChineseContentNodeRef = nodeArchiveService.getArchivedNode(chineseContentNodeRef);
+ NodeRef archivedFrenchContentNodeRef = nodeArchiveService.getArchivedNode(frenchContentNodeRef);
+ NodeRef archivedJapaneseContentNodeRef = nodeArchiveService.getArchivedNode(japaneseContentNodeRef);
+ NodeRef archivedEmptyGermanContentNodeRef = nodeArchiveService.getArchivedNode(emptyGermanContentNodeRef);
+ NodeRef archivedMlContainerNodeRef = nodeArchiveService.getArchivedNode(mlContainerNodeRef);
+
+ // Ensure that the mlContainer is removed
+ assertFalse("The multilingual container must be removed", nodeService.exists(mlContainerNodeRef));
+ // Ensure that the mlContainer IS NOT archived
+ assertFalse("The multilingual container can't be archived", nodeService.exists(archivedMlContainerNodeRef));
+ // Ensure that the translations are removed
+ assertFalse("The translation must be removed: " + Locale.CHINESE, nodeService.exists(chineseContentNodeRef));
+ assertFalse("The translation must be removed: " + Locale.JAPANESE, nodeService.exists(japaneseContentNodeRef));
+ assertFalse("The translation must be removed: " + Locale.FRENCH, nodeService.exists(frenchContentNodeRef));
+ assertFalse("The empty translation must be removed: " + Locale.GERMAN, nodeService.exists(emptyGermanContentNodeRef));
+
+ // Ensure that the translations ARE archived
+ assertTrue("The translation must be archived: " + Locale.CHINESE, nodeService.exists(archivedChineseContentNodeRef));
+ assertTrue("The translation must be archived: " + Locale.JAPANESE, nodeService.exists(archivedJapaneseContentNodeRef));
+ assertTrue("The translation must be archived: " + Locale.FRENCH, nodeService.exists(archivedFrenchContentNodeRef));
+
+ // Ensure that the empty translation IS NOT archived
+ assertFalse("The empty document can't be archived: " + Locale.GERMAN, nodeService.exists(archivedEmptyGermanContentNodeRef));
+
+ // Ensure that the mlDocument aspect is removed
+ assertFalse("The " + ContentModel.ASPECT_MULTILINGUAL_DOCUMENT + " aspect must be removed for " + Locale.CHINESE, nodeService.hasAspect(archivedChineseContentNodeRef, ContentModel.ASPECT_MULTILINGUAL_DOCUMENT));
+ assertFalse("The " + ContentModel.ASPECT_MULTILINGUAL_DOCUMENT + " aspect must be removed for " + Locale.JAPANESE, nodeService.hasAspect(archivedJapaneseContentNodeRef, ContentModel.ASPECT_MULTILINGUAL_DOCUMENT));
+ assertFalse("The " + ContentModel.ASPECT_MULTILINGUAL_DOCUMENT + " aspect must be removed for " + Locale.FRENCH, nodeService.hasAspect(archivedFrenchContentNodeRef, ContentModel.ASPECT_MULTILINGUAL_DOCUMENT));
+
+ }
+
+ @SuppressWarnings("unused")
+ public void testCopyMLContainerInNewSpace() throws Exception
+ {
+ NodeRef chineseContentNodeRef = createContent();
+ NodeRef frenchContentNodeRef = createContent();
+ NodeRef japaneseContentNodeRef = createContent();
+ NodeRef emptyGermanContentNodeRef = null;
+
+ multilingualContentService.makeTranslation(chineseContentNodeRef, Locale.CHINESE);
+ multilingualContentService.addTranslation(frenchContentNodeRef, chineseContentNodeRef, Locale.FRENCH);
+ multilingualContentService.addTranslation(japaneseContentNodeRef, chineseContentNodeRef, Locale.JAPANESE);
+ emptyGermanContentNodeRef = multilingualContentService.addEmptyTranslation(chineseContentNodeRef, null, Locale.GERMAN);
+
+ // the mlContainer to copy
+ NodeRef mlContainerNodeRef = multilingualContentService.getTranslationContainer(chineseContentNodeRef);
+
+ // Ensure that the the mlContainer is correctly created
+ assertEquals("Incorrect number of translations", 4, multilingualContentService.getTranslations(mlContainerNodeRef).size());
+
+ // get the actual space
+ NodeRef actualSpace = folderNodeRef;
+ // create a new space
+ NodeRef destinationSpace = fileFolderService.create(folderNodeRef, "testCopyMLContainerInNewSpace" + System.currentTimeMillis(), ContentModel.TYPE_FOLDER).getNodeRef();
+
+ // Ensure that the new space is created
+ assertTrue("The destiation space is not created " + destinationSpace, nodeService.exists(destinationSpace));
+
+ // copy the mlContainer
+ NodeRef newMLContainer = multilingualContentService.copyTranslationContainer(mlContainerNodeRef, destinationSpace, "");
+
+ assertEquals("Incorrect number of translations for the new mlContainer", 4, multilingualContentService.getTranslations(newMLContainer).size());
+
+ // Ensure that a new mlContainer is created
+ assertTrue("The new mlContainer is not created ", nodeService.exists(newMLContainer));
+ // Ensure that the newMLContainer is a copy of the source mlContainer
+ assertFalse("The newMLContainer is not a copy of the source mlContainer, the ref is the same " + newMLContainer , newMLContainer.equals(mlContainerNodeRef));
+ assertEquals("The newMLContainer is not a copy of the source mlContainer, the locales are not the same " + newMLContainer ,
+ nodeService.getProperty(mlContainerNodeRef, ContentModel.PROP_LOCALE),
+ nodeService.getProperty(newMLContainer, ContentModel.PROP_LOCALE));
+ assertEquals("The newMLContainer is not a copy of the source mlContainer, the authors are not the same " + newMLContainer ,
+ nodeService.getProperty(mlContainerNodeRef, ContentModel.PROP_AUTHOR),
+ nodeService.getProperty(newMLContainer, ContentModel.PROP_AUTHOR));
+
+ // get the source translations
+ Map sourceTranslations = multilingualContentService.getTranslations(mlContainerNodeRef);
+ // get the copies
+ Map copyTranslations = multilingualContentService.getTranslations(newMLContainer);
+
+ // Ensure that the translations are copies from the source translations
+ assertEquals("They are not the same number of translation in the source mlContainer and in its copy", sourceTranslations.size(), copyTranslations.size());
+
+ for(Map.Entry entry : sourceTranslations.entrySet())
+ {
+ Locale locale = entry.getKey();
+
+ NodeRef sourceNodeRef = entry.getValue();
+ NodeRef sourceParent = nodeService.getPrimaryParent(sourceNodeRef).getParentRef();
+
+ NodeRef copyTranslation = multilingualContentService.getTranslationForLocale(newMLContainer, locale);
+ NodeRef copyParent = nodeService.getPrimaryParent(copyTranslation).getParentRef();
+
+ // Ensure that the copy exists
+ assertNotNull("No copy found for the locale " + locale, copyTranslation);
+ assertTrue("No copy exists for the locale " + locale, nodeService.exists(copyTranslation));
+
+ // Ensure that the copy has the mlDocument aspect
+ assertTrue("The copy must have the mlDocument aspect",
+ nodeService.hasAspect(copyTranslation, ContentModel.ASPECT_MULTILINGUAL_DOCUMENT));
+
+ // Ensure that the copy is an empty translation if the source too
+ assertEquals("The call of nodeService.hasAspect(nodeRef, ContentModel.ASPECT_MULTILINGUAL_EMPTY_TRANSLATION) must return the same result for the source and the copy",
+ nodeService.hasAspect(sourceNodeRef, ContentModel.ASPECT_MULTILINGUAL_EMPTY_TRANSLATION),
+ nodeService.hasAspect(copyTranslation, ContentModel.ASPECT_MULTILINGUAL_EMPTY_TRANSLATION));
+
+
+ // Ensure that the copy and the source are different
+ assertNotSame("The copy has the same ref as the source", sourceNodeRef, copyTranslation);
+
+ // Ensure that the parent of the source is correct
+ assertEquals("The source would not be moved", sourceParent, actualSpace);
+ // Ensure that the parent of the copy is correct
+ assertEquals("The copy is not in the right space", copyParent, destinationSpace);
+ }
+ }
+
+ @SuppressWarnings("unused")
+ public void testCopyMLContainerInSameSpace() throws Exception
+ {
+ NodeRef chineseContentNodeRef = createContent();
+ NodeRef frenchContentNodeRef = createContent();
+ NodeRef japaneseContentNodeRef = createContent();
+ NodeRef emptyGermanContentNodeRef = null;
+
+ multilingualContentService.makeTranslation(chineseContentNodeRef, Locale.CHINESE);
+ multilingualContentService.addTranslation(frenchContentNodeRef, chineseContentNodeRef, Locale.FRENCH);
+ multilingualContentService.addTranslation(japaneseContentNodeRef, chineseContentNodeRef, Locale.JAPANESE);
+ emptyGermanContentNodeRef = multilingualContentService.addEmptyTranslation(chineseContentNodeRef, null, Locale.GERMAN);
+
+ // the mlContainer to copy
+ NodeRef mlContainerNodeRef = multilingualContentService.getTranslationContainer(chineseContentNodeRef);
+
+ // Ensure that the the mlContainer is correctly created
+ assertEquals("Incorrect number of translations", 4, multilingualContentService.getTranslations(mlContainerNodeRef).size());
+
+ // get the actual space
+ NodeRef actualSpace = folderNodeRef;
+
+ try
+ {
+ // copy the mlContainer
+ NodeRef newMLContainer = multilingualContentService.copyTranslationContainer(mlContainerNodeRef, actualSpace, "");
+
+ fail("The copy of the mlContainer in the same space would faile");
+ }
+ catch(Exception e)
+ {
+ // test asserted
+ }
+ }
+
+ @SuppressWarnings("unused")
+ public void testCopyAndRenameMLContainer() throws Exception
+ {
+ NodeRef chineseContentNodeRef = createContent();
+ NodeRef frenchContentNodeRef = createContent();
+ NodeRef japaneseContentNodeRef = createContent();
+ NodeRef emptyGermanContentNodeRef = null;
+
+ multilingualContentService.makeTranslation(chineseContentNodeRef, Locale.CHINESE);
+ multilingualContentService.addTranslation(frenchContentNodeRef, chineseContentNodeRef, Locale.FRENCH);
+ multilingualContentService.addTranslation(japaneseContentNodeRef, chineseContentNodeRef, Locale.JAPANESE);
+ emptyGermanContentNodeRef = multilingualContentService.addEmptyTranslation(chineseContentNodeRef, null, Locale.GERMAN);
+
+ // the mlContainer to copy
+ NodeRef mlContainerNodeRef = multilingualContentService.getTranslationContainer(chineseContentNodeRef);
+
+ // Ensure that the the mlContainer is correctly created
+ assertEquals("Incorrect number of translations", 4, multilingualContentService.getTranslations(mlContainerNodeRef).size());
+
+ // get the actual space
+ NodeRef actualSpace = folderNodeRef;
+
+ // create a new space
+ NodeRef destinationSpace = fileFolderService.create(folderNodeRef, "testCopyMLContainerInNewSpace" + System.currentTimeMillis(), ContentModel.TYPE_FOLDER).getNodeRef();
+
+ // Ensure that the new space is created
+ assertTrue("The destiation space is not created " + destinationSpace, nodeService.exists(destinationSpace));
+
+ String PREFIX = "COPY OF " ;
+
+ NodeRef newMLContainer = multilingualContentService.copyTranslationContainer(mlContainerNodeRef, destinationSpace, PREFIX);
+
+ // Ensure that a new mlContainer is created
+ assertTrue("The new mlContainer is not created ", nodeService.exists(newMLContainer));
+ // Ensure that the newMLContainer is a copy of the source mlContainer
+ assertFalse("The newMLContainer is not a copy of the source mlContainer, the ref is the same " + newMLContainer , newMLContainer.equals(mlContainerNodeRef));
+
+ // get the source translations
+ Map sourceTranslations = multilingualContentService.getTranslations(mlContainerNodeRef);
+ // get the copies
+ Map copyTranslations = multilingualContentService.getTranslations(newMLContainer);
+
+ // Ensure that the translations are copies from the source translations
+ assertEquals("They are not the same number of translation in the source mlContainer and in its copy", sourceTranslations.size(), copyTranslations.size());
+
+ for(Map.Entry entry : sourceTranslations.entrySet())
+ {
+ Locale locale = entry.getKey();
+
+ NodeRef sourceNodeRef = entry.getValue();
+ NodeRef copyNodeRef = multilingualContentService.getTranslationForLocale(newMLContainer, locale);
+
+ String sourceName = (String) nodeService.getProperty(sourceNodeRef, ContentModel.PROP_NAME);
+ String copyName = (String) nodeService.getProperty(copyNodeRef, ContentModel.PROP_NAME);
+
+ String theoricalCopyName = PREFIX + sourceName;
+
+ // Ensure that the name of the copy is correct
+ assertTrue("The name of the copied translation is incorect: " + copyName + " and should be " + theoricalCopyName, theoricalCopyName.equals(copyName));
+ }
+
+ }
+
+ @SuppressWarnings("unused")
+ public void testMoveMLContainer() throws Exception
+ {
+ NodeRef chineseContentNodeRef = createContent();
+ NodeRef frenchContentNodeRef = createContent();
+ NodeRef japaneseContentNodeRef = createContent();
+ NodeRef emptyGermanContentNodeRef = null;
+
+ multilingualContentService.makeTranslation(chineseContentNodeRef, Locale.CHINESE);
+ multilingualContentService.addTranslation(frenchContentNodeRef, chineseContentNodeRef, Locale.FRENCH);
+ multilingualContentService.addTranslation(japaneseContentNodeRef, chineseContentNodeRef, Locale.JAPANESE);
+ emptyGermanContentNodeRef = multilingualContentService.addEmptyTranslation(chineseContentNodeRef, null, Locale.GERMAN);
+
+ // the mlContainer to copy
+ NodeRef mlContainerNodeRef = multilingualContentService.getTranslationContainer(chineseContentNodeRef);
+
+ // Ensure that the the mlContainer is correctly created
+ assertEquals("Incorrect number of translations", 4, multilingualContentService.getTranslations(mlContainerNodeRef).size());
+
+ // get the actual space
+ NodeRef actualSpace = folderNodeRef;
+ // create a new space
+ NodeRef destinationSpace = fileFolderService.create(folderNodeRef, "testCopyMLContainerInNewSpace", ContentModel.TYPE_FOLDER).getNodeRef();
+
+ // Ensure that the new space is created
+ assertTrue("The destiation space is not created " + destinationSpace, nodeService.exists(destinationSpace));
+
+ // move the mlContainer
+ multilingualContentService.moveTranslationContainer(mlContainerNodeRef, destinationSpace);
+
+ // Esure that the nodes are moved
+ assertEquals("The node should be moved", destinationSpace, nodeService.getPrimaryParent(chineseContentNodeRef).getParentRef());
+ assertEquals("The node should be moved", destinationSpace, nodeService.getPrimaryParent(frenchContentNodeRef).getParentRef());
+ assertEquals("The node should be moved", destinationSpace, nodeService.getPrimaryParent(japaneseContentNodeRef).getParentRef());
+ assertEquals("The node should be moved", destinationSpace, nodeService.getPrimaryParent(emptyGermanContentNodeRef).getParentRef());
+
+ // Ensure the mlContainer is not changed
+ assertEquals("The mlContainer should not be changed", mlContainerNodeRef, multilingualContentService.getTranslationContainer(chineseContentNodeRef));
+ assertEquals("The mlContainer should not be changed", mlContainerNodeRef, multilingualContentService.getTranslationContainer(frenchContentNodeRef));
+ assertEquals("The mlContainer should not be changed", mlContainerNodeRef, multilingualContentService.getTranslationContainer(japaneseContentNodeRef));
+ assertEquals("The mlContainer should not be changed", mlContainerNodeRef, multilingualContentService.getTranslationContainer(emptyGermanContentNodeRef));
+
+ }
}
diff --git a/source/java/org/alfresco/repo/model/ml/tools/MultilingualDocumentAspectTest.java b/source/java/org/alfresco/repo/model/ml/tools/MultilingualDocumentAspectTest.java
index 132541d0e4..3822be4b09 100644
--- a/source/java/org/alfresco/repo/model/ml/tools/MultilingualDocumentAspectTest.java
+++ b/source/java/org/alfresco/repo/model/ml/tools/MultilingualDocumentAspectTest.java
@@ -15,11 +15,11 @@
* 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:
+ * 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.model.ml.tools;
@@ -34,62 +34,59 @@ import org.alfresco.service.namespace.QName;
/**
* Multilingual document aspect test cases
- *
+ *
* @see org.alfresco.service.cmr.ml.MultilingualDocumentAspect
- *
+ *
* @author Yannick Pignot
*/
-public class MultilingualDocumentAspectTest extends AbstractMultilingualTestCases
+public class MultilingualDocumentAspectTest extends AbstractMultilingualTestCases
{
public void testCopy() throws Exception
{
NodeRef original = createContent();
multilingualContentService.makeTranslation(original, Locale.FRENCH);
NodeRef mlContainer = multilingualContentService.getTranslationContainer(original);
-
- NodeRef copy =
+
+ NodeRef copy =
fileFolderService.copy(original, nodeService.getPrimaryParent(original).getParentRef(), "COPY" + System.currentTimeMillis()).getNodeRef();
// Ensure that the copy removes the mlDocument aspect
assertFalse("The copy of a mlDocument can't have the multilingual aspect", nodeService.hasAspect(copy, ContentModel.ASPECT_MULTILINGUAL_DOCUMENT));
-
+
// Ensure that the copy removes the association between the mlConatiner and the new node
assertEquals("The copy of a mlDocument can't be a children of the mlContainer", 1, multilingualContentService.getTranslations(mlContainer).size());
-
- // Ensure that the copy removes the Locale property of the new node
- assertNull("The copy of a mlDocument can't keep the locale property", nodeService.getProperty(copy, ContentModel.PROP_LOCALE));
}
-
+
public void testDeleteNode() throws Exception
{
NodeRef trad1 = createContent();
NodeRef trad2 = createContent();
NodeRef trad3 = createContent();
-
+
NodeRef parent = nodeService.getPrimaryParent(trad1).getParentRef();
-
+
multilingualContentService.makeTranslation(trad1, Locale.FRENCH);
multilingualContentService.addTranslation(trad2, trad1, Locale.GERMAN);
multilingualContentService.addTranslation(trad3, trad1, Locale.ITALIAN);
-
+
nodeService.deleteNode(trad3);
// Ensure that the deleted node is romoved from its space
- assertEquals("The deleted node must be removed to the space", 2, nodeService.getChildAssocs(parent).size());
- // Ensure that the mlContainer doesn't keep an association to the deleted node
+ assertEquals("The deleted node must be removed to the space", 2, nodeService.getChildAssocs(parent).size());
+ // Ensure that the mlContainer doesn't keep an association to the deleted node
assertEquals("The deleted node must be removed to the child associations of the mlContainer", 2, multilingualContentService.getTranslations(trad1).size());
// retore the deleted node
NodeRef restoredNode = nodeArchiveService.restoreArchivedNode(nodeArchiveService.getArchivedNode(trad3)).getRestoredNodeRef();
- // Ensure that the restored node is restored to it s original space
- assertEquals("The restored node must be restaured to the the space", 3, nodeService.getChildAssocs(parent).size());
- // Ensure that the restored node is not linked to the mlContainer
+ // Ensure that the restored node is restored to it s original space
+ assertEquals("The restored node must be restaured to the the space", 3, nodeService.getChildAssocs(parent).size());
+ // Ensure that the restored node is not linked to the mlContainer
assertEquals("The restored node would not be restaured to the mlContainer", 2, multilingualContentService.getTranslations(trad1).size());
// Ensure that the restored node doesn't keep the mlDocument aspect
assertFalse("The restored node can't keep the multilingual aspect", nodeService.hasAspect(restoredNode, ContentModel.ASPECT_MULTILINGUAL_DOCUMENT));
}
-
+
public void testDeletePivot() throws Exception
{
NodeRef pivot = createContent();
@@ -97,11 +94,11 @@ public class MultilingualDocumentAspectTest extends AbstractMultilingualTestCase
multilingualContentService.makeTranslation(pivot, Locale.FRENCH);
NodeRef mlContainer = multilingualContentService.getTranslationContainer(pivot);
multilingualContentService.addTranslation(trans1, pivot, Locale.KOREAN);
-
+
//nodeService.deleteNode(trans1);
nodeService.deleteNode(pivot);
- // Ensure that pivot is removed
+ // Ensure that pivot is removed
assertFalse("The pivot would be removed", nodeService.exists(pivot));
// Ensure that the mlContainer is removed
assertFalse("The mlContainer must be removed if the pivot is removed", nodeService.exists(mlContainer));
@@ -110,25 +107,25 @@ public class MultilingualDocumentAspectTest extends AbstractMultilingualTestCase
// Ensure that trans1 has no mlDocument aspect
assertFalse("The last translation can't keep the multilingual aspect", nodeService.hasAspect(trans1, ContentModel.ASPECT_MULTILINGUAL_DOCUMENT));
}
-
+
public void testDeleteLastNode() throws Exception
{
NodeRef pivot = createContent();
multilingualContentService.makeTranslation(pivot, Locale.FRENCH);
NodeRef mlContainer = multilingualContentService.getTranslationContainer(pivot);
-
+
nodeService.deleteNode(pivot);
-
+
// Ensure that the mlContainer is removed too
assertFalse("The mlContainer must be removed if the last translation is removed", nodeService.exists(mlContainer));
-
+
}
-
+
public void testRemoveAspect() throws Exception
{
// entierly covered by the delete tests
}
-
+
public void testUpdateLocale() throws Exception
{
NodeRef pivot = createContent();
@@ -136,12 +133,12 @@ public class MultilingualDocumentAspectTest extends AbstractMultilingualTestCase
multilingualContentService.makeTranslation(pivot, Locale.FRENCH);
NodeRef mlContainer = multilingualContentService.getTranslationContainer(pivot);
multilingualContentService.addTranslation(trans1, pivot, Locale.KOREAN);
-
+
// modify the locale for the translation
Map props = nodeService.getProperties(trans1);
props.put(ContentModel.PROP_LOCALE, Locale.GERMAN);
nodeService.setProperties(trans1, props);
-
+
// Ensure that the pivot reference is not changed for the mlContainer and the locale is changed for the translation
assertEquals("The locale for the pivot would be changed ",Locale.GERMAN, nodeService.getProperty(trans1, ContentModel.PROP_LOCALE));
assertEquals("The pivot reference would not be changed in the mlContainer", Locale.FRENCH, nodeService.getProperty(mlContainer, ContentModel.PROP_LOCALE));
@@ -150,68 +147,68 @@ public class MultilingualDocumentAspectTest extends AbstractMultilingualTestCase
props = nodeService.getProperties(pivot);
props.put(ContentModel.PROP_LOCALE, Locale.US);
nodeService.setProperties(pivot, props);
-
+
// Ensure that the pivot reference is changed (in the pivot and in the mlContainer)
assertEquals("The locale for the pivot would be changed ", Locale.US, nodeService.getProperty(pivot, ContentModel.PROP_LOCALE));
assertEquals("The pivot reference would be changes in the mlContainer", Locale.US, nodeService.getProperty(mlContainer, ContentModel.PROP_LOCALE));
}
-
+
public void testUpdateRedundantLocale() throws Exception
{
NodeRef pivot = createContent();
NodeRef trans1 = createContent();
NodeRef trans2 = createContent();
-
+
multilingualContentService.makeTranslation(pivot, Locale.FRENCH);
multilingualContentService.addTranslation(trans1, pivot, Locale.KOREAN);
multilingualContentService.addTranslation(trans2, pivot, Locale.JAPANESE);
-
+
// 1. Try with redundant locale
-
+
// modify the locale for the translation 2
Map props = nodeService.getProperties(trans2);
props.put(ContentModel.PROP_LOCALE, Locale.KOREAN);
-
+
boolean exceptionCatched = false;
-
- try
+
+ try
{
nodeService.setProperties(trans2, props);
- // test failed
- } catch (Exception ignore)
+ // test failed
+ } catch (Exception ignore)
{
exceptionCatched = true;
}
-
+
// Ensure that the the exception was catched.
assertTrue("The modification of this locale must catch an exception because it is already in use in another translation", exceptionCatched);
// Ensure that the locale of the trans2 is unchanged
- assertEquals("The locale must not be changed",
- Locale.JAPANESE,
+ assertEquals("The locale must not be changed",
+ Locale.JAPANESE,
(Locale) nodeService.getProperty(trans2, ContentModel.PROP_LOCALE));
-
+
// 2. Try with a non-redundant locale
-
+
props = nodeService.getProperties(trans2);
props.put(ContentModel.PROP_LOCALE, Locale.ITALIAN);
-
+
exceptionCatched = false;
-
- try
+
+ try
{
nodeService.setProperties(trans2, props);
- } catch (Exception ignore)
+ } catch (Exception ignore)
{
- // test failed
+ // test failed
exceptionCatched = true;
}
-
+
// Ensure that the exception was not catched
assertFalse("The modification of the locale would not throws an exception", exceptionCatched);
- // Ensure that the locale is modified
- assertEquals("The locale must be changed",
- Locale.ITALIAN,
+ // Ensure that the locale is modified
+ assertEquals("The locale must be changed",
+ Locale.ITALIAN,
(Locale) nodeService.getProperty(trans2, ContentModel.PROP_LOCALE));
}
}
diff --git a/source/java/org/alfresco/repo/node/MLPropertyInterceptor.java b/source/java/org/alfresco/repo/node/MLPropertyInterceptor.java
index 2c529980e7..0fe9151467 100644
--- a/source/java/org/alfresco/repo/node/MLPropertyInterceptor.java
+++ b/source/java/org/alfresco/repo/node/MLPropertyInterceptor.java
@@ -25,19 +25,24 @@
package org.alfresco.repo.node;
import java.io.Serializable;
+import java.util.Date;
import java.util.HashMap;
import java.util.Locale;
import java.util.Map;
import org.alfresco.i18n.I18NUtil;
+import org.alfresco.model.ContentModel;
import org.alfresco.service.cmr.dictionary.DataTypeDefinition;
import org.alfresco.service.cmr.dictionary.DictionaryService;
import org.alfresco.service.cmr.dictionary.PropertyDefinition;
+import org.alfresco.service.cmr.ml.MultilingualContentService;
+import org.alfresco.service.cmr.repository.ContentData;
import org.alfresco.service.cmr.repository.MLText;
import org.alfresco.service.cmr.repository.NodeRef;
import org.alfresco.service.cmr.repository.NodeService;
import org.alfresco.service.cmr.repository.datatype.DefaultTypeConverter;
import org.alfresco.service.namespace.QName;
+import org.alfresco.util.EqualsHelper;
import org.aopalliance.intercept.MethodInterceptor;
import org.aopalliance.intercept.MethodInvocation;
import org.apache.commons.logging.Log;
@@ -71,6 +76,8 @@ public class MLPropertyInterceptor implements MethodInterceptor
/** Direct access to the NodeService */
private NodeService nodeService;
+ /** Direct access to the MultilingualContentService */
+ private MultilingualContentService multilingualContentService;
/** Used to access property definitions */
private DictionaryService dictionaryService;
@@ -108,7 +115,12 @@ public class MLPropertyInterceptor implements MethodInterceptor
this.nodeService = bean;
}
- public void setDictionaryService(DictionaryService dictionaryService)
+ public void setMultilingualContentService(MultilingualContentService multilingualContentService)
+ {
+ this.multilingualContentService = multilingualContentService;
+ }
+
+ public void setDictionaryService(DictionaryService dictionaryService)
{
this.dictionaryService = dictionaryService;
}
@@ -142,13 +154,19 @@ public class MLPropertyInterceptor implements MethodInterceptor
NodeRef nodeRef = (NodeRef) args[0];
QName propertyQName = (QName) args[1];
+ // Get the pivot translation, if appropriate
+ NodeRef pivotNodeRef = getPivotNodeRef(nodeRef);
+
Serializable value = (Serializable) invocation.proceed();
- ret = convertOutboundProperty(contentLocale, nodeRef, propertyQName, value);
+ ret = convertOutboundProperty(contentLocale, nodeRef, pivotNodeRef, propertyQName, value);
}
else if (methodName.equals("getProperties"))
{
NodeRef nodeRef = (NodeRef) args[0];
+ // Get the pivot translation, if appropriate
+ NodeRef pivotNodeRef = getPivotNodeRef(nodeRef);
+
Map properties = (Map) invocation.proceed();
Map convertedProperties = new HashMap(properties.size() * 2);
// Check each return value type
@@ -156,7 +174,7 @@ public class MLPropertyInterceptor implements MethodInterceptor
{
QName propertyQName = entry.getKey();
Serializable value = entry.getValue();
- Serializable convertedValue = convertOutboundProperty(contentLocale, nodeRef, propertyQName, value);
+ Serializable convertedValue = convertOutboundProperty(contentLocale, nodeRef, pivotNodeRef, propertyQName, value);
// Add it to the return map
convertedProperties.put(propertyQName, convertedValue);
}
@@ -173,6 +191,10 @@ public class MLPropertyInterceptor implements MethodInterceptor
else if (methodName.equals("setProperties"))
{
NodeRef nodeRef = (NodeRef) args[0];
+
+ // Get the pivot translation, if appropriate
+ NodeRef pivotNodeRef = getPivotNodeRef(nodeRef);
+
Map newProperties =(Map) args[1];
// Get the current properties for the node
Map currentProperties = nodeService.getProperties(nodeRef);
@@ -185,7 +207,7 @@ public class MLPropertyInterceptor implements MethodInterceptor
// Get the current property value
Serializable currentValue = currentProperties.get(propertyQName);
// Convert the inbound property value
- inboundValue = convertInboundProperty(contentLocale, nodeRef, propertyQName, inboundValue, currentValue);
+ inboundValue = convertInboundProperty(contentLocale, nodeRef, pivotNodeRef, propertyQName, inboundValue, currentValue);
// Put the value into the map
convertedProperties.put(propertyQName, inboundValue);
}
@@ -199,8 +221,11 @@ public class MLPropertyInterceptor implements MethodInterceptor
QName propertyQName = (QName) args[1];
Serializable inboundValue = (Serializable) args[2];
+ // Get the pivot translation, if appropriate
+ NodeRef pivotNodeRef = getPivotNodeRef(nodeRef);
+
// Convert the property
- inboundValue = convertInboundProperty(contentLocale, nodeRef, propertyQName, inboundValue, null);
+ inboundValue = convertInboundProperty(contentLocale, nodeRef, pivotNodeRef, propertyQName, inboundValue, null);
// Pass this through to the node service
nodeService.setProperty(nodeRef, propertyQName, inboundValue);
@@ -214,23 +239,73 @@ public class MLPropertyInterceptor implements MethodInterceptor
return ret;
}
+ /**
+ * @param nodeRef
+ * a potential empty translation
+ * @return
+ * the pivot translation node or null
+ */
+ private NodeRef getPivotNodeRef(NodeRef nodeRef)
+ {
+ if (nodeService.hasAspect(nodeRef, ContentModel.ASPECT_MULTILINGUAL_EMPTY_TRANSLATION))
+ {
+ return multilingualContentService.getPivotTranslation(nodeRef);
+ }
+ else
+ {
+ return null;
+ }
+ }
+
/**
* Ensure that content is spoofed for empty translations.
*/
private Serializable convertOutboundProperty(
Locale contentLocale,
NodeRef nodeRef,
+ NodeRef pivotNodeRef,
QName propertyQName,
Serializable outboundValue)
{
Serializable ret = null;
- // Is it content?
- if (outboundValue != null && outboundValue instanceof MLText)
+ if (outboundValue == null)
+ {
+ ret = null;
+ }
+ if (outboundValue instanceof MLText)
{
// It is MLText
MLText mlText = (MLText) outboundValue;
ret = mlText.getClosestValue(contentLocale);
}
+ else if (pivotNodeRef != null) // It is an empty translation
+ {
+ if (propertyQName.equals(ContentModel.PROP_MODIFIED))
+ {
+ // An empty translation's modified date must be the later of its own
+ // modified date and the pivot translation's modified date
+ Date emptyLastModified = (Date) outboundValue;
+ Date pivotLastModified = (Date) nodeService.getProperty(pivotNodeRef, ContentModel.PROP_MODIFIED);
+ if (emptyLastModified.compareTo(pivotLastModified) < 0)
+ {
+ ret = pivotLastModified;
+ }
+ else
+ {
+ ret = emptyLastModified;
+ }
+ }
+ else if (propertyQName.equals(ContentModel.PROP_CONTENT))
+ {
+ // An empty translation's cm:content must track the cm:content of the
+ // pivot translation.
+ ret = nodeService.getProperty(pivotNodeRef, ContentModel.PROP_CONTENT);
+ }
+ else
+ {
+ ret = outboundValue;
+ }
+ }
else
{
ret = outboundValue;
@@ -257,6 +332,7 @@ public class MLPropertyInterceptor implements MethodInterceptor
private Serializable convertInboundProperty(
Locale contentLocale,
NodeRef nodeRef,
+ NodeRef pivotNodeRef,
QName propertyQName,
Serializable inboundValue,
Serializable currentValue)
@@ -264,7 +340,11 @@ public class MLPropertyInterceptor implements MethodInterceptor
Serializable ret = null;
PropertyDefinition propertyDef = this.dictionaryService.getProperty(propertyQName);
//if no type definition associated to the name then just proceed
- if (propertyDef != null && propertyDef.getDataType().getName().equals(DataTypeDefinition.MLTEXT))
+ if (propertyDef == null)
+ {
+ ret = inboundValue;
+ }
+ else if (propertyDef.getDataType().getName().equals(DataTypeDefinition.MLTEXT))
{
// Don't mess with multivalued properties or instances already of type MLText
if (propertyDef.isMultiValued() || (inboundValue instanceof MLText) )
@@ -293,7 +373,25 @@ public class MLPropertyInterceptor implements MethodInterceptor
ret = returnMLValue;
}
}
- else // It is not defined as d:mltext in the dictionary
+ else if (pivotNodeRef != null && propertyQName.equals(ContentModel.PROP_CONTENT))
+ {
+ // It is an empty translation. The content must not change if it matches
+ // the content of the pivot translation
+ ContentData pivotContentData = (ContentData) nodeService.getProperty(pivotNodeRef, ContentModel.PROP_CONTENT);
+ ContentData emptyContentData = (ContentData) inboundValue;
+ String pivotContentUrl = pivotContentData == null ? null : pivotContentData.getContentUrl();
+ String emptyContentUrl = emptyContentData == null ? null : emptyContentData.getContentUrl();
+ if (EqualsHelper.nullSafeEquals(pivotContentUrl, emptyContentUrl))
+ {
+ // They are a match. So the empty translation must be reset to it's original value
+ ret = (ContentData) nodeService.getProperty(nodeRef, ContentModel.PROP_CONTENT);
+ }
+ else
+ {
+ ret = inboundValue;
+ }
+ }
+ else
{
ret = inboundValue;
}
diff --git a/source/java/org/alfresco/repo/service/ServiceDescriptorRegistry.java b/source/java/org/alfresco/repo/service/ServiceDescriptorRegistry.java
index 0365149b58..ef3f43109c 100644
--- a/source/java/org/alfresco/repo/service/ServiceDescriptorRegistry.java
+++ b/source/java/org/alfresco/repo/service/ServiceDescriptorRegistry.java
@@ -15,11 +15,11 @@
* 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:
+ * 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.service;
@@ -39,6 +39,8 @@ import org.alfresco.service.cmr.coci.CheckOutCheckInService;
import org.alfresco.service.cmr.dictionary.DictionaryService;
import org.alfresco.service.cmr.lock.LockService;
import org.alfresco.service.cmr.ml.ContentFilterLanguagesService;
+import org.alfresco.service.cmr.ml.EditionService;
+import org.alfresco.service.cmr.ml.MultilingualContentService;
import org.alfresco.service.cmr.model.FileFolderService;
import org.alfresco.service.cmr.repository.ContentService;
import org.alfresco.service.cmr.repository.CopyService;
@@ -71,7 +73,7 @@ import org.springframework.beans.factory.BeanFactoryAware;
/**
* Implementation of a Service Registry based on the definition of
* Services contained within a Spring Bean Factory.
- *
+ *
* @author David Caruana
*/
public class ServiceDescriptorRegistry
@@ -80,7 +82,7 @@ public class ServiceDescriptorRegistry
// Bean Factory within which the registry lives
private BeanFactory beanFactory = null;
-
+
/* (non-Javadoc)
* @see org.springframework.beans.factory.BeanFactoryAware#setBeanFactory(org.springframework.beans.factory.BeanFactory)
*/
@@ -88,7 +90,7 @@ public class ServiceDescriptorRegistry
{
this.beanFactory = beanFactory;
}
-
+
/* (non-Javadoc)
* @see org.alfresco.repo.service.ServiceRegistry#getServices()
*/
@@ -112,7 +114,7 @@ public class ServiceDescriptorRegistry
*/
public Object getService(QName service)
{
- return beanFactory.getBean(service.getLocalName());
+ return beanFactory.getBean(service.getLocalName());
}
/* (non-Javadoc)
@@ -122,7 +124,7 @@ public class ServiceDescriptorRegistry
{
return (DescriptorService)getService(DESCRIPTOR_SERVICE);
}
-
+
/* (non-Javadoc)
* @see org.alfresco.repo.service.ServiceRegistry#getNodeService()
*/
@@ -186,7 +188,7 @@ public class ServiceDescriptorRegistry
{
return (SearchService)getService(SEARCH_SERVICE);
}
-
+
/* (non-Javadoc)
* @see org.alfresco.service.ServiceRegistry#getTransactionService()
*/
@@ -218,7 +220,7 @@ public class ServiceDescriptorRegistry
{
return (CheckOutCheckInService)getService(COCI_SERVICE);
}
-
+
/* (non-Javadoc)
* @see org.alfresco.service.ServiceRegistry#getCategoryService()
*/
@@ -234,7 +236,7 @@ public class ServiceDescriptorRegistry
{
return (NamespaceService)getService(NAMESPACE_SERVICE);
}
-
+
/* (non-Javadoc)
* @see org.alfresco.service.ServiceRegistry#getImporterService()
*/
@@ -250,7 +252,7 @@ public class ServiceDescriptorRegistry
{
return (ExporterService)getService(EXPORTER_SERVICE);
}
-
+
/* (non-Javadoc)
* @see org.alfresco.service.ServiceRegistry#getRuleService()
*/
@@ -258,7 +260,7 @@ public class ServiceDescriptorRegistry
{
return (RuleService)getService(RULE_SERVICE);
}
-
+
/*
* (non-Javadoc)
* @see org.alfresco.service.ServiceRegistry#getActionService()
@@ -275,7 +277,7 @@ public class ServiceDescriptorRegistry
{
return (PermissionService)getService(PERMISSIONS_SERVICE);
}
-
+
/* (non-Javadoc)
* @see org.alfresco.service.ServiceRegistry#getAuthorityService()
*/
@@ -315,7 +317,7 @@ public class ServiceDescriptorRegistry
{
return (WorkflowService)getService(WORKFLOW_SERVICE);
}
-
+
/* (non-Javadoc)
* @see org.alfresco.service.ServiceRegistry#getWorkflowService()
*/
@@ -366,7 +368,7 @@ public class ServiceDescriptorRegistry
{
return (PersonService)getService(PERSON_SERVICE);
}
-
+
/* (non-Javadoc)
* @see org.alfresco.service.ServiceRegistry#getCrossRepositoryCopyService()
*/
@@ -386,7 +388,7 @@ public class ServiceDescriptorRegistry
/* (non-Javadoc)
* @see org.alfresco.service.ServiceRegistry#getContentFilterLanguagesService()
*/
- public ContentFilterLanguagesService getContentFilterLanguagesService()
+ public ContentFilterLanguagesService getContentFilterLanguagesService()
{
return (ContentFilterLanguagesService) getService(CONTENT_FILTER_LANGUAGES_SERVICE);
}
@@ -406,4 +408,20 @@ public class ServiceDescriptorRegistry
{
return (VirtServerRegistry)getService(VIRT_SERVER_REGISTRY);
}
+
+ /* (non-Javadoc)
+ * @see org.alfresco.service.ServiceRegistry#getEditionService()
+ */
+ public EditionService getEditionService()
+ {
+ return (EditionService) getService(EDITION_SERVICE);
+ }
+
+ /* (non-Javadoc)
+ * @see org.alfresco.service.ServiceRegistry#getMultilingualContentService()
+ */
+ public MultilingualContentService getMultilingualContentService()
+ {
+ return (MultilingualContentService) getService(MULTILINGUAL_CONTENT_SERVICE);
+ }
}
diff --git a/source/java/org/alfresco/repo/version/VersionServiceImpl.java b/source/java/org/alfresco/repo/version/VersionServiceImpl.java
index f092e429fc..b18a24e901 100644
--- a/source/java/org/alfresco/repo/version/VersionServiceImpl.java
+++ b/source/java/org/alfresco/repo/version/VersionServiceImpl.java
@@ -378,6 +378,11 @@ public class VersionServiceImpl extends AbstractVersionServiceImpl
ContentModel.PROP_VERSION_LABEL,
version.getVersionLabel());
+ // Freeze the version label property
+ Map versionLabelAsMap = new HashMap(1);
+ versionLabelAsMap.put(ContentModel.PROP_VERSION_LABEL, version.getVersionLabel());
+ this.freezeProperties(newVersionRef, versionLabelAsMap);
+
// Invoke the policy behaviour
invokeAfterCreateVersion(nodeRef, version);
diff --git a/source/java/org/alfresco/repo/version/common/VersionLabelComparator.java b/source/java/org/alfresco/repo/version/common/VersionLabelComparator.java
new file mode 100644
index 0000000000..de57d03ca6
--- /dev/null
+++ b/source/java/org/alfresco/repo/version/common/VersionLabelComparator.java
@@ -0,0 +1,47 @@
+/*
+ * 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.version.common;
+
+import java.util.Comparator;
+
+import org.alfresco.service.cmr.version.Version;
+
+/**
+ * A comparator to sort a version list according theires version labels ascending
+ *
+ * @author Yanick Pignot
+ */
+public class VersionLabelComparator implements Comparator
+{
+
+ public int compare(Object version1, Object version2)
+ {
+ String labelV1 = ((Version) version1).getVersionLabel();
+ String labelV2 = ((Version) version2).getVersionLabel();
+
+ // sort the list ascending
+ return labelV2.compareTo(labelV1);
+ }
+}
diff --git a/source/java/org/alfresco/service/ServiceRegistry.java b/source/java/org/alfresco/service/ServiceRegistry.java
index af79387ec3..e7838bd144 100644
--- a/source/java/org/alfresco/service/ServiceRegistry.java
+++ b/source/java/org/alfresco/service/ServiceRegistry.java
@@ -15,11 +15,11 @@
* 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:
+ * 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.service;
@@ -38,6 +38,8 @@ import org.alfresco.service.cmr.coci.CheckOutCheckInService;
import org.alfresco.service.cmr.dictionary.DictionaryService;
import org.alfresco.service.cmr.lock.LockService;
import org.alfresco.service.cmr.ml.ContentFilterLanguagesService;
+import org.alfresco.service.cmr.ml.EditionService;
+import org.alfresco.service.cmr.ml.MultilingualContentService;
import org.alfresco.service.cmr.model.FileFolderService;
import org.alfresco.service.cmr.repository.ContentService;
import org.alfresco.service.cmr.repository.CopyService;
@@ -67,15 +69,15 @@ import org.alfresco.service.transaction.TransactionService;
/**
* This interface represents the registry of public Repository Services.
* The registry provides meta-data about each service and provides
- * access to the service interface.
- *
+ * access to the service interface.
+ *
* @author David Caruana
*/
@PublicService
public interface ServiceRegistry
{
// Service Bean Names
-
+
static final String SERVICE_REGISTRY = "ServiceRegistry";
static final QName REGISTRY_SERVICE = QName.createQName(NamespaceService.ALFRESCO_URI, "ServiceRegistry");
@@ -89,6 +91,8 @@ public interface ServiceRegistry
static final QName CONTENT_SERVICE = QName.createQName(NamespaceService.ALFRESCO_URI, "ContentService");
static final QName MIMETYPE_SERVICE = QName.createQName(NamespaceService.ALFRESCO_URI, "MimetypeService");
static final QName CONTENT_FILTER_LANGUAGES_SERVICE = QName.createQName(NamespaceService.ALFRESCO_URI, "ContentFilterLanguagesService");
+ static final QName MULTILINGUAL_CONTENT_SERVICE = QName.createQName(NamespaceService.ALFRESCO_URI, "MultilingualContentService");
+ static final QName EDITION_SERVICE = QName.createQName(NamespaceService.ALFRESCO_URI, "EditionService");
static final QName SEARCH_SERVICE = QName.createQName(NamespaceService.ALFRESCO_URI, "SearchService");
static final QName CATEGORY_SERVICE = QName.createQName(NamespaceService.ALFRESCO_URI, "CategoryService");
static final QName COPY_SERVICE = QName.createQName(NamespaceService.ALFRESCO_URI, "CopyService");
@@ -126,14 +130,14 @@ public interface ServiceRegistry
/**
* Is the specified service provided by the Repository?
- *
+ *
* @param service name of service to test provision of
* @return true => provided, false => not provided
*/
@NotAuditable
boolean isServiceProvided(QName service);
- /**
+ /**
* Get the specified service.
*
* @param service name of service to retrieve
@@ -141,13 +145,13 @@ public interface ServiceRegistry
*/
@NotAuditable
Object getService(QName service);
-
+
/**
* @return the descriptor service
*/
@NotAuditable
DescriptorService getDescriptorService();
-
+
/**
* @return the transaction service
*/
@@ -165,13 +169,13 @@ public interface ServiceRegistry
*/
@NotAuditable
NamespaceService getNamespaceService();
-
+
/**
* @return the authentication service (or null, if one is not provided)
*/
@NotAuditable
AuthenticationService getAuthenticationService();
-
+
/**
* @return the node service (or null, if one is not provided)
*/
@@ -183,7 +187,7 @@ public interface ServiceRegistry
*/
@NotAuditable
ContentService getContentService();
-
+
/**
* @return the mimetype service (or null, if one is not provided)
*/
@@ -195,19 +199,19 @@ public interface ServiceRegistry
*/
@NotAuditable
ContentFilterLanguagesService getContentFilterLanguagesService();
-
+
/**
* @return the search service (or null, if one is not provided)
*/
@NotAuditable
SearchService getSearchService();
-
+
/**
* @return the version service (or null, if one is not provided)
*/
@NotAuditable
VersionService getVersionService();
-
+
/**
* @return the lock service (or null, if one is not provided)
*/
@@ -219,73 +223,73 @@ public interface ServiceRegistry
*/
@NotAuditable
DictionaryService getDictionaryService();
-
+
/**
* @return the copy service (or null, if one is not provided)
*/
@NotAuditable
CopyService getCopyService();
-
+
/**
* @return the checkout / checkin service (or null, if one is not provided)
*/
@NotAuditable
- CheckOutCheckInService getCheckOutCheckInService();
-
+ CheckOutCheckInService getCheckOutCheckInService();
+
/**
* @return the category service (or null, if one is not provided)
*/
@NotAuditable
CategoryService getCategoryService();
-
+
/**
* @return the importer service or null if not present
*/
@NotAuditable
ImporterService getImporterService();
-
+
/**
* @return the exporter service or null if not present
*/
@NotAuditable
ExporterService getExporterService();
-
+
/**
* @return the rule service (or null, if one is not provided)
*/
@NotAuditable
RuleService getRuleService();
-
+
/**
* @return the action service (or null if one is not provided)
*/
@NotAuditable
ActionService getActionService();
-
+
/**
* @return the permission service (or null if one is not provided)
*/
@NotAuditable
PermissionService getPermissionService();
-
+
/**
* @return the authority service (or null if one is not provided)
*/
@NotAuditable
AuthorityService getAuthorityService();
-
+
/**
* @return the template service (or null if one is not provided)
*/
@NotAuditable
TemplateService getTemplateService();
-
+
/**
* @return the file-folder manipulation service (or null if one is not provided)
*/
@NotAuditable
FileFolderService getFileFolderService();
-
+
/**
* @return the script execution service (or null if one is not provided)
*/
@@ -297,7 +301,7 @@ public interface ServiceRegistry
*/
@NotAuditable
WorkflowService getWorkflowService();
-
+
/**
* @return the audit service (or null if one is not provided)
*/
@@ -306,13 +310,13 @@ public interface ServiceRegistry
/**
* Get the AVMService.
- * @return The AVM service (or null if one is not provided);
+ * @return The AVM service (or null if one is not provided);
*/
@NotAuditable
AVMService getAVMService();
/**
- * Get the AVMLockingAwareService.
+ * Get the AVMLockingAwareService.
* @return The AVM locking aware service (or null if one is not provided);
*/
@NotAuditable
@@ -331,39 +335,53 @@ public interface ServiceRegistry
*/
@NotAuditable
OwnableService getOwnableService();
-
+
/**
* Get the person service (or null if one is not provided)
* @return
*/
@NotAuditable
PersonService getPersonService();
-
+
/**
* Get the cross repository copy service (or null if one is not provided)
* @return
*/
@NotAuditable
CrossRepositoryCopyService getCrossRepositoryCopyService();
-
+
/**
* Get the attribute service (or null if one is not provided)
* @return
*/
@NotAuditable
AttributeService getAttributeService();
-
+
/**
* Get the AVM locking service (or null if one is not provided)
* @return
*/
@NotAuditable
AVMLockingService getAVMLockingService();
-
+
/**
* Get the Virtualisation Server registry service bean
* @return
*/
@NotAuditable
VirtServerRegistry getVirtServerRegistry();
+
+ /**
+ * Get the Multilingual Content Service
+ * @return
+ */
+ @NotAuditable
+ MultilingualContentService getMultilingualContentService();
+
+ /**
+ * Get the Edition Service
+ * @return
+ */
+ @NotAuditable
+ EditionService getEditionService();
}
diff --git a/source/java/org/alfresco/service/cmr/ml/MultilingualContentService.java b/source/java/org/alfresco/service/cmr/ml/MultilingualContentService.java
index 6a20407d7d..ae73a446c4 100644
--- a/source/java/org/alfresco/service/cmr/ml/MultilingualContentService.java
+++ b/source/java/org/alfresco/service/cmr/ml/MultilingualContentService.java
@@ -31,6 +31,8 @@ import java.util.Set;
import org.alfresco.service.Auditable;
import org.alfresco.service.PublicService;
+import org.alfresco.service.cmr.model.FileExistsException;
+import org.alfresco.service.cmr.model.FileNotFoundException;
import org.alfresco.service.cmr.repository.NodeRef;
/**
@@ -171,10 +173,14 @@ public interface MultilingualContentService
*
* @param translationNodeRef The cm:mlContainer to copy
* @param newParentRef The new parent of the copied cm:mlDocument
+ * @param prefixName The prefix of the name of the copied translations. Can be null.
* @return The copied cm:mlContainer
+ * @throws FileNotFoundException
+ * @throws FileExistsException
+ * @throws Exception
*/
- @Auditable(key = Auditable.Key.ARG_0, parameters = {"translationNodeRef", "newParentRef"})
- NodeRef copyTranslationContainer(NodeRef translationNodeRef, NodeRef newParentRef);
+ @Auditable(key = Auditable.Key.ARG_0, parameters = {"mlContainerNodeRef", "newParentRef"})
+ NodeRef copyTranslationContainer(NodeRef mlContainerNodeRef, NodeRef newParentRef, String prefixName) throws FileExistsException, FileNotFoundException, Exception;
/**
* Moves the location of the given cm:mlContainer.
@@ -184,10 +190,18 @@ public interface MultilingualContentService
*
* @param translationNodeRef The cm:mlContainer to move
* @param newParentRef The new parent of the moved cm:mlDocument
+ * @throws FileExistsException
+ * @throws FileNotFoundException
*/
- @Auditable(key = Auditable.Key.ARG_0, parameters = {"translationNodeRef", "newParentRef"})
- void moveTranslationContainer(NodeRef translationNodeRef, NodeRef newParentRef);
-
-
+ @Auditable(key = Auditable.Key.ARG_0, parameters = {"mlContainerNodeRef", "newParentRef"})
+ void moveTranslationContainer(NodeRef mlContainerNodeRef, NodeRef newParentRef) throws FileExistsException, FileNotFoundException;
+ /**
+ * Delete the given mlContainer and its translations. The translations will lost their cm:mlDocument aspect and
+ * will be archved. The empty translations will be permanently deleted.
+ *
+ * @param mlContainerNodeRef The cm:mlContainer to remove
+ */
+ @Auditable(key = Auditable.Key.ARG_0, parameters = {"mlContainerNodeRef"})
+ void deleteTranslationContainer(NodeRef mlContainerNodeRef);
}