Merged V2.1 to HEAD

6383: ML contributions
   6400: AR-1625 Empty translations track pivot translation


git-svn-id: https://svn.alfresco.com/repos/alfresco-enterprise/alfresco/HEAD/root@6406 c4b6b30b-aa2e-2d43-bbcb-ca4b014f7261
This commit is contained in:
Derek Hulley
2007-08-02 23:57:38 +00:00
parent 9f7c5d6443
commit 81e364ebd3
15 changed files with 913 additions and 264 deletions

View File

@@ -68,7 +68,7 @@
<!-- Multilingual specific service --> <!-- Multilingual specific service -->
<bean name="multilingualContentService" class="org.alfresco.repo.model.ml.MultilingualContentServiceImpl" > <bean name="multilingualContentService" class="org.alfresco.repo.model.ml.MultilingualContentServiceImpl" >
<property name="nodeService"> <property name="nodeService">
<ref bean="nodeService" /> <ref bean="mlAwareNodeService" />
</property> </property>
<property name="searchService"> <property name="searchService">
<ref bean="admSearchService" /> <ref bean="admSearchService" />
@@ -82,6 +82,9 @@
<property name="fileFolderService"> <property name="fileFolderService">
<ref bean="fileFolderService" /> <ref bean="fileFolderService" />
</property> </property>
<property name="policyBehaviourFilter">
<ref bean="policyBehaviourFilter" />
</property>
</bean> </bean>
<!-- Edition service --> <!-- Edition service -->

View File

@@ -8,6 +8,9 @@
<property name="nodeService"> <property name="nodeService">
<ref bean="mlAwareNodeService" /> <ref bean="mlAwareNodeService" />
</property> </property>
<property name="multilingualContentService">
<ref bean="multilingualContentService" />
</property>
<property name="dictionaryService"> <property name="dictionaryService">
<ref bean="dictionaryService" /> <ref bean="dictionaryService" />
</property> </property>

View File

@@ -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.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.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.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
</value> </value>
</property> </property>
</bean> </bean>

View File

@@ -120,7 +120,7 @@ public class EditionServiceImpl implements EditionService
// Version the container and its translations // Version the container and its translations
versionService.createVersion(mlContainerToVersion, versionProperties, true); 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 // Get the new starting point node, it will be returned
NodeRef startNode; NodeRef startNode;
@@ -169,6 +169,7 @@ public class EditionServiceImpl implements EditionService
// set the starting translation become the pivot. // set the starting translation become the pivot.
nodeService.setProperty(mlContainerToVersion, ContentModel.PROP_LOCALE, locale); nodeService.setProperty(mlContainerToVersion, ContentModel.PROP_LOCALE, locale);
nodeService.setProperty(mlContainerToVersion, ContentModel.PROP_AUTHOR, author); nodeService.setProperty(mlContainerToVersion, ContentModel.PROP_AUTHOR, author);
nodeService.setProperty(mlContainerToVersion, ContentModel.PROP_NAME, name);
// Done // Done
if (logger.isDebugEnabled()) if (logger.isDebugEnabled())

View File

@@ -24,6 +24,7 @@
*/ */
package org.alfresco.repo.model.ml; package org.alfresco.repo.model.ml;
import java.io.Serializable;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.HashMap; import java.util.HashMap;
import java.util.List; import java.util.List;
@@ -31,13 +32,18 @@ import java.util.Locale;
import java.util.Map; import java.util.Map;
import java.util.Set; import java.util.Set;
import javax.transaction.SystemException;
import org.alfresco.error.AlfrescoRuntimeException; import org.alfresco.error.AlfrescoRuntimeException;
import org.alfresco.i18n.I18NUtil; import org.alfresco.i18n.I18NUtil;
import org.alfresco.model.ContentModel; import org.alfresco.model.ContentModel;
import org.alfresco.repo.policy.BehaviourFilter;
import org.alfresco.service.cmr.ml.ContentFilterLanguagesService; import org.alfresco.service.cmr.ml.ContentFilterLanguagesService;
import org.alfresco.service.cmr.ml.MultilingualContentService; 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.FileFolderService;
import org.alfresco.service.cmr.model.FileInfo; 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.ChildAssociationRef;
import org.alfresco.service.cmr.repository.ContentData; import org.alfresco.service.cmr.repository.ContentData;
import org.alfresco.service.cmr.repository.NodeRef; import org.alfresco.service.cmr.repository.NodeRef;
@@ -86,6 +92,8 @@ public class MultilingualContentServiceImpl implements MultilingualContentServic
private ContentFilterLanguagesService contentFilterLanguagesService; private ContentFilterLanguagesService contentFilterLanguagesService;
private FileFolderService fileFolderService; private FileFolderService fileFolderService;
private BehaviourFilter policyBehaviourFilter;
public MultilingualContentServiceImpl() public MultilingualContentServiceImpl()
{ {
searchParametersMLRoot = new SearchParameters(); searchParametersMLRoot = new SearchParameters();
@@ -284,8 +292,12 @@ public class MultilingualContentServiceImpl implements MultilingualContentServic
// Make one // Make one
mlContainerNodeRef = getOrCreateMLContainer(contentNodeRef, true); 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_LOCALE, locale);
nodeService.setProperty(mlContainerNodeRef, ContentModel.PROP_NAME, containerFunctionalName);
} }
else 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<Locale, NodeRef> 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) public void unmakeTranslation(NodeRef translationNodeRef)
{ {
// Get the container // Get the container
@@ -622,7 +684,9 @@ public class MultilingualContentServiceImpl implements MultilingualContentServic
public NodeRef addEmptyTranslation(NodeRef translationOfNodeRef, String name, Locale locale) public NodeRef addEmptyTranslation(NodeRef translationOfNodeRef, String name, Locale locale)
{ {
boolean hasMLAspect = nodeService.hasAspect(translationOfNodeRef, ContentModel.ASPECT_MULTILINGUAL_DOCUMENT); 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 // Get the pivot translation
NodeRef pivotTranslationNodeRef = getPivotTranslation(translationOfNodeRef); NodeRef pivotTranslationNodeRef = getPivotTranslation(translationOfNodeRef);
@@ -717,6 +781,168 @@ public class MultilingualContentServiceImpl implements MultilingualContentServic
return newTranslationNodeRef; return newTranslationNodeRef;
} }
/**
* @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<Locale, NodeRef> 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 setNodeService(NodeService nodeService) public void setNodeService(NodeService nodeService)
{ {
this.nodeService = nodeService; this.nodeService = nodeService;
@@ -742,13 +968,8 @@ public class MultilingualContentServiceImpl implements MultilingualContentServic
this.fileFolderService = fileFolderService; this.fileFolderService = fileFolderService;
} }
public NodeRef copyTranslationContainer(NodeRef translationNodeRef, NodeRef newParentRef) public void setPolicyBehaviourFilter(BehaviourFilter policyBehaviourFilter)
{ {
throw new UnsupportedOperationException("This operation is not yet supported"); this.policyBehaviourFilter = policyBehaviourFilter;
}
public void moveTranslationContainer(NodeRef translationNodeRef, NodeRef newParentRef)
{
throw new UnsupportedOperationException("This operation is not yet supported");
} }
} }

View File

@@ -35,7 +35,6 @@ import org.alfresco.repo.node.NodeServicePolicies;
import org.alfresco.repo.policy.JavaBehaviour; import org.alfresco.repo.policy.JavaBehaviour;
import org.alfresco.repo.policy.PolicyComponent; import org.alfresco.repo.policy.PolicyComponent;
import org.alfresco.repo.policy.PolicyScope; import org.alfresco.repo.policy.PolicyScope;
import org.alfresco.repo.version.VersionServicePolicies;
import org.alfresco.service.cmr.ml.MultilingualContentService; import org.alfresco.service.cmr.ml.MultilingualContentService;
import org.alfresco.service.cmr.repository.NodeRef; import org.alfresco.service.cmr.repository.NodeRef;
import org.alfresco.service.cmr.repository.NodeService; import org.alfresco.service.cmr.repository.NodeService;
@@ -54,22 +53,10 @@ import org.alfresco.service.namespace.RegexQNamePattern;
*/ */
public class MultilingualDocumentAspect implements public class MultilingualDocumentAspect implements
CopyServicePolicies.OnCopyNodePolicy, CopyServicePolicies.OnCopyNodePolicy,
CopyServicePolicies.OnCopyCompletePolicy,
NodeServicePolicies.BeforeDeleteNodePolicy, NodeServicePolicies.BeforeDeleteNodePolicy,
NodeServicePolicies.OnUpdatePropertiesPolicy, NodeServicePolicies.OnUpdatePropertiesPolicy
VersionServicePolicies.OnCreateVersionPolicy
{ {
/**
* 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 // Dependencies
private PolicyComponent policyComponent; private PolicyComponent policyComponent;
private MultilingualContentService multilingualContentService; private MultilingualContentService multilingualContentService;
@@ -88,11 +75,6 @@ public class MultilingualDocumentAspect implements
ContentModel.ASPECT_MULTILINGUAL_DOCUMENT, ContentModel.ASPECT_MULTILINGUAL_DOCUMENT,
new JavaBehaviour(this, "onCopyNode")); new JavaBehaviour(this, "onCopyNode"));
this.policyComponent.bindClassBehaviour(
QName.createQName(NamespaceService.ALFRESCO_URI, "onCopyComplete"),
ContentModel.ASPECT_MULTILINGUAL_DOCUMENT,
new JavaBehaviour(this, "onCopyComplete"));
this.policyComponent.bindClassBehaviour( this.policyComponent.bindClassBehaviour(
QName.createQName(NamespaceService.ALFRESCO_URI, "beforeDeleteNode"), QName.createQName(NamespaceService.ALFRESCO_URI, "beforeDeleteNode"),
ContentModel.ASPECT_MULTILINGUAL_DOCUMENT, ContentModel.ASPECT_MULTILINGUAL_DOCUMENT,
@@ -103,11 +85,6 @@ public class MultilingualDocumentAspect implements
ContentModel.ASPECT_MULTILINGUAL_DOCUMENT, ContentModel.ASPECT_MULTILINGUAL_DOCUMENT,
new JavaBehaviour(this, "onUpdateProperties")); 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); copyDetails.removeAspect(ContentModel.ASPECT_MULTILINGUAL_DOCUMENT);
} }
/**
* The copy of <b>mlDocument</b> 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<NodeRef, NodeRef> copyMap)
{
nodeService.removeProperty(destinationRef, ContentModel.PROP_LOCALE);
}
/** /**
* If this is not an empty translation, then ensure that the node is properly * If this is not an empty translation, then ensure that the node is properly
* unhooked from the translation mechanism first. * 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 // the after local property type can be either Locale or String
Serializable objLocaleAfter = after.get(ContentModel.PROP_LOCALE); Serializable objLocaleAfter = after.get(ContentModel.PROP_LOCALE);
if (objLocaleAfter instanceof Locale ) if (objLocaleAfter instanceof Locale )
{ {
localeAfter = (Locale) objLocaleAfter; localeAfter = (Locale) objLocaleAfter;
} }
else else
{ {
@@ -242,19 +209,4 @@ public class MultilingualDocumentAspect implements
// else no action to perform // 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<String, Serializable> versionProperties, PolicyScope nodeDetails)
{
for(QName prop : PROPERTIES_TO_VERSION)
{
nodeDetails.addProperty(prop, nodeService.getProperty(versionableNode, prop));
}
}
} }

View File

@@ -28,7 +28,6 @@ import java.io.Serializable;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.Collection; import java.util.Collection;
import java.util.Collections; import java.util.Collections;
import java.util.Comparator;
import java.util.HashMap; import java.util.HashMap;
import java.util.List; import java.util.List;
import java.util.Locale; import java.util.Locale;
@@ -36,6 +35,7 @@ import java.util.Map;
import org.alfresco.model.ContentModel; import org.alfresco.model.ContentModel;
import org.alfresco.repo.version.VersionModel; 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.repository.NodeRef;
import org.alfresco.service.cmr.version.Version; import org.alfresco.service.cmr.version.Version;
import org.alfresco.service.cmr.version.VersionHistory; import org.alfresco.service.cmr.version.VersionHistory;
@@ -210,24 +210,12 @@ public class EditionServiceImplTest extends AbstractMultilingualTestCases
return multilingualContentService.getTranslationContainer(chineseContentNodeRef); 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") @SuppressWarnings("unchecked")
private List<Version> orderVersions(Collection<Version> allVersions) private List<Version> orderVersions(Collection<Version> allVersions)
{ {
List<Version> versionsAsList = new ArrayList<Version>(allVersions.size()); List<Version> versionsAsList = new ArrayList<Version>(allVersions.size());
versionsAsList.addAll(allVersions); versionsAsList.addAll(allVersions);
Collections.sort(versionsAsList, versionComparator); Collections.sort(versionsAsList, new VersionLabelComparator());
return versionsAsList; return versionsAsList;
} }
} }

View File

@@ -24,8 +24,11 @@
*/ */
package org.alfresco.repo.model.ml.tools; package org.alfresco.repo.model.ml.tools;
import java.util.ArrayList;
import java.util.Collection;
import java.util.List; import java.util.List;
import java.util.Locale; import java.util.Locale;
import java.util.Map;
import net.sf.acegisecurity.Authentication; import net.sf.acegisecurity.Authentication;
@@ -284,4 +287,284 @@ public class MultilingualContentServiceImplTest extends AbstractMultilingualTest
try { authenticationComponent.setCurrentAuthentication(authentication); } catch (Throwable e) {} 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<Locale, NodeRef> sourceTranslations = multilingualContentService.getTranslations(mlContainerNodeRef);
// get the copies
Map<Locale, NodeRef> 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<Locale, NodeRef> 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<Locale, NodeRef> sourceTranslations = multilingualContentService.getTranslations(mlContainerNodeRef);
// get the copies
Map<Locale, NodeRef> 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<Locale, NodeRef> 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));
}
} }

View File

@@ -55,9 +55,6 @@ public class MultilingualDocumentAspectTest extends AbstractMultilingualTestCase
// Ensure that the copy removes the association between the mlConatiner and the new node // 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()); 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 public void testDeleteNode() throws Exception

View File

@@ -25,19 +25,24 @@
package org.alfresco.repo.node; package org.alfresco.repo.node;
import java.io.Serializable; import java.io.Serializable;
import java.util.Date;
import java.util.HashMap; import java.util.HashMap;
import java.util.Locale; import java.util.Locale;
import java.util.Map; import java.util.Map;
import org.alfresco.i18n.I18NUtil; import org.alfresco.i18n.I18NUtil;
import org.alfresco.model.ContentModel;
import org.alfresco.service.cmr.dictionary.DataTypeDefinition; import org.alfresco.service.cmr.dictionary.DataTypeDefinition;
import org.alfresco.service.cmr.dictionary.DictionaryService; import org.alfresco.service.cmr.dictionary.DictionaryService;
import org.alfresco.service.cmr.dictionary.PropertyDefinition; 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.MLText;
import org.alfresco.service.cmr.repository.NodeRef; import org.alfresco.service.cmr.repository.NodeRef;
import org.alfresco.service.cmr.repository.NodeService; import org.alfresco.service.cmr.repository.NodeService;
import org.alfresco.service.cmr.repository.datatype.DefaultTypeConverter; import org.alfresco.service.cmr.repository.datatype.DefaultTypeConverter;
import org.alfresco.service.namespace.QName; import org.alfresco.service.namespace.QName;
import org.alfresco.util.EqualsHelper;
import org.aopalliance.intercept.MethodInterceptor; import org.aopalliance.intercept.MethodInterceptor;
import org.aopalliance.intercept.MethodInvocation; import org.aopalliance.intercept.MethodInvocation;
import org.apache.commons.logging.Log; import org.apache.commons.logging.Log;
@@ -71,6 +76,8 @@ public class MLPropertyInterceptor implements MethodInterceptor
/** Direct access to the NodeService */ /** Direct access to the NodeService */
private NodeService nodeService; private NodeService nodeService;
/** Direct access to the MultilingualContentService */
private MultilingualContentService multilingualContentService;
/** Used to access property definitions */ /** Used to access property definitions */
private DictionaryService dictionaryService; private DictionaryService dictionaryService;
@@ -108,6 +115,11 @@ public class MLPropertyInterceptor implements MethodInterceptor
this.nodeService = bean; this.nodeService = bean;
} }
public void setMultilingualContentService(MultilingualContentService multilingualContentService)
{
this.multilingualContentService = multilingualContentService;
}
public void setDictionaryService(DictionaryService dictionaryService) public void setDictionaryService(DictionaryService dictionaryService)
{ {
this.dictionaryService = dictionaryService; this.dictionaryService = dictionaryService;
@@ -142,13 +154,19 @@ public class MLPropertyInterceptor implements MethodInterceptor
NodeRef nodeRef = (NodeRef) args[0]; NodeRef nodeRef = (NodeRef) args[0];
QName propertyQName = (QName) args[1]; QName propertyQName = (QName) args[1];
// Get the pivot translation, if appropriate
NodeRef pivotNodeRef = getPivotNodeRef(nodeRef);
Serializable value = (Serializable) invocation.proceed(); Serializable value = (Serializable) invocation.proceed();
ret = convertOutboundProperty(contentLocale, nodeRef, propertyQName, value); ret = convertOutboundProperty(contentLocale, nodeRef, pivotNodeRef, propertyQName, value);
} }
else if (methodName.equals("getProperties")) else if (methodName.equals("getProperties"))
{ {
NodeRef nodeRef = (NodeRef) args[0]; NodeRef nodeRef = (NodeRef) args[0];
// Get the pivot translation, if appropriate
NodeRef pivotNodeRef = getPivotNodeRef(nodeRef);
Map<QName, Serializable> properties = (Map<QName, Serializable>) invocation.proceed(); Map<QName, Serializable> properties = (Map<QName, Serializable>) invocation.proceed();
Map<QName, Serializable> convertedProperties = new HashMap<QName, Serializable>(properties.size() * 2); Map<QName, Serializable> convertedProperties = new HashMap<QName, Serializable>(properties.size() * 2);
// Check each return value type // Check each return value type
@@ -156,7 +174,7 @@ public class MLPropertyInterceptor implements MethodInterceptor
{ {
QName propertyQName = entry.getKey(); QName propertyQName = entry.getKey();
Serializable value = entry.getValue(); 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 // Add it to the return map
convertedProperties.put(propertyQName, convertedValue); convertedProperties.put(propertyQName, convertedValue);
} }
@@ -173,6 +191,10 @@ public class MLPropertyInterceptor implements MethodInterceptor
else if (methodName.equals("setProperties")) else if (methodName.equals("setProperties"))
{ {
NodeRef nodeRef = (NodeRef) args[0]; NodeRef nodeRef = (NodeRef) args[0];
// Get the pivot translation, if appropriate
NodeRef pivotNodeRef = getPivotNodeRef(nodeRef);
Map<QName, Serializable> newProperties =(Map<QName, Serializable>) args[1]; Map<QName, Serializable> newProperties =(Map<QName, Serializable>) args[1];
// Get the current properties for the node // Get the current properties for the node
Map<QName, Serializable> currentProperties = nodeService.getProperties(nodeRef); Map<QName, Serializable> currentProperties = nodeService.getProperties(nodeRef);
@@ -185,7 +207,7 @@ public class MLPropertyInterceptor implements MethodInterceptor
// Get the current property value // Get the current property value
Serializable currentValue = currentProperties.get(propertyQName); Serializable currentValue = currentProperties.get(propertyQName);
// Convert the inbound property value // 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 // Put the value into the map
convertedProperties.put(propertyQName, inboundValue); convertedProperties.put(propertyQName, inboundValue);
} }
@@ -199,8 +221,11 @@ public class MLPropertyInterceptor implements MethodInterceptor
QName propertyQName = (QName) args[1]; QName propertyQName = (QName) args[1];
Serializable inboundValue = (Serializable) args[2]; Serializable inboundValue = (Serializable) args[2];
// Get the pivot translation, if appropriate
NodeRef pivotNodeRef = getPivotNodeRef(nodeRef);
// Convert the property // 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 // Pass this through to the node service
nodeService.setProperty(nodeRef, propertyQName, inboundValue); nodeService.setProperty(nodeRef, propertyQName, inboundValue);
@@ -214,23 +239,73 @@ public class MLPropertyInterceptor implements MethodInterceptor
return ret; return ret;
} }
/**
* @param nodeRef
* a potential empty translation
* @return
* the pivot translation node or <tt>null</tt>
*/
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. * Ensure that content is spoofed for empty translations.
*/ */
private Serializable convertOutboundProperty( private Serializable convertOutboundProperty(
Locale contentLocale, Locale contentLocale,
NodeRef nodeRef, NodeRef nodeRef,
NodeRef pivotNodeRef,
QName propertyQName, QName propertyQName,
Serializable outboundValue) Serializable outboundValue)
{ {
Serializable ret = null; Serializable ret = null;
// Is it content? if (outboundValue == null)
if (outboundValue != null && outboundValue instanceof MLText) {
ret = null;
}
if (outboundValue instanceof MLText)
{ {
// It is MLText // It is MLText
MLText mlText = (MLText) outboundValue; MLText mlText = (MLText) outboundValue;
ret = mlText.getClosestValue(contentLocale); 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 else
{ {
ret = outboundValue; ret = outboundValue;
@@ -257,6 +332,7 @@ public class MLPropertyInterceptor implements MethodInterceptor
private Serializable convertInboundProperty( private Serializable convertInboundProperty(
Locale contentLocale, Locale contentLocale,
NodeRef nodeRef, NodeRef nodeRef,
NodeRef pivotNodeRef,
QName propertyQName, QName propertyQName,
Serializable inboundValue, Serializable inboundValue,
Serializable currentValue) Serializable currentValue)
@@ -264,7 +340,11 @@ public class MLPropertyInterceptor implements MethodInterceptor
Serializable ret = null; Serializable ret = null;
PropertyDefinition propertyDef = this.dictionaryService.getProperty(propertyQName); PropertyDefinition propertyDef = this.dictionaryService.getProperty(propertyQName);
//if no type definition associated to the name then just proceed //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 // Don't mess with multivalued properties or instances already of type MLText
if (propertyDef.isMultiValued() || (inboundValue instanceof MLText) ) if (propertyDef.isMultiValued() || (inboundValue instanceof MLText) )
@@ -293,7 +373,25 @@ public class MLPropertyInterceptor implements MethodInterceptor
ret = returnMLValue; 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; ret = inboundValue;
} }

View File

@@ -39,6 +39,8 @@ import org.alfresco.service.cmr.coci.CheckOutCheckInService;
import org.alfresco.service.cmr.dictionary.DictionaryService; import org.alfresco.service.cmr.dictionary.DictionaryService;
import org.alfresco.service.cmr.lock.LockService; import org.alfresco.service.cmr.lock.LockService;
import org.alfresco.service.cmr.ml.ContentFilterLanguagesService; 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.model.FileFolderService;
import org.alfresco.service.cmr.repository.ContentService; import org.alfresco.service.cmr.repository.ContentService;
import org.alfresco.service.cmr.repository.CopyService; import org.alfresco.service.cmr.repository.CopyService;
@@ -406,4 +408,20 @@ public class ServiceDescriptorRegistry
{ {
return (VirtServerRegistry)getService(VIRT_SERVER_REGISTRY); 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);
}
} }

View File

@@ -378,6 +378,11 @@ public class VersionServiceImpl extends AbstractVersionServiceImpl
ContentModel.PROP_VERSION_LABEL, ContentModel.PROP_VERSION_LABEL,
version.getVersionLabel()); version.getVersionLabel());
// Freeze the version label property
Map<QName, Serializable> versionLabelAsMap = new HashMap<QName, Serializable>(1);
versionLabelAsMap.put(ContentModel.PROP_VERSION_LABEL, version.getVersionLabel());
this.freezeProperties(newVersionRef, versionLabelAsMap);
// Invoke the policy behaviour // Invoke the policy behaviour
invokeAfterCreateVersion(nodeRef, version); invokeAfterCreateVersion(nodeRef, version);

View File

@@ -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);
}
}

View File

@@ -38,6 +38,8 @@ import org.alfresco.service.cmr.coci.CheckOutCheckInService;
import org.alfresco.service.cmr.dictionary.DictionaryService; import org.alfresco.service.cmr.dictionary.DictionaryService;
import org.alfresco.service.cmr.lock.LockService; import org.alfresco.service.cmr.lock.LockService;
import org.alfresco.service.cmr.ml.ContentFilterLanguagesService; 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.model.FileFolderService;
import org.alfresco.service.cmr.repository.ContentService; import org.alfresco.service.cmr.repository.ContentService;
import org.alfresco.service.cmr.repository.CopyService; import org.alfresco.service.cmr.repository.CopyService;
@@ -89,6 +91,8 @@ public interface ServiceRegistry
static final QName CONTENT_SERVICE = QName.createQName(NamespaceService.ALFRESCO_URI, "ContentService"); 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 MIMETYPE_SERVICE = QName.createQName(NamespaceService.ALFRESCO_URI, "MimetypeService");
static final QName CONTENT_FILTER_LANGUAGES_SERVICE = QName.createQName(NamespaceService.ALFRESCO_URI, "ContentFilterLanguagesService"); 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 SEARCH_SERVICE = QName.createQName(NamespaceService.ALFRESCO_URI, "SearchService");
static final QName CATEGORY_SERVICE = QName.createQName(NamespaceService.ALFRESCO_URI, "CategoryService"); static final QName CATEGORY_SERVICE = QName.createQName(NamespaceService.ALFRESCO_URI, "CategoryService");
static final QName COPY_SERVICE = QName.createQName(NamespaceService.ALFRESCO_URI, "CopyService"); static final QName COPY_SERVICE = QName.createQName(NamespaceService.ALFRESCO_URI, "CopyService");
@@ -366,4 +370,18 @@ public interface ServiceRegistry
*/ */
@NotAuditable @NotAuditable
VirtServerRegistry getVirtServerRegistry(); VirtServerRegistry getVirtServerRegistry();
/**
* Get the Multilingual Content Service
* @return
*/
@NotAuditable
MultilingualContentService getMultilingualContentService();
/**
* Get the Edition Service
* @return
*/
@NotAuditable
EditionService getEditionService();
} }

View File

@@ -31,6 +31,8 @@ import java.util.Set;
import org.alfresco.service.Auditable; import org.alfresco.service.Auditable;
import org.alfresco.service.PublicService; 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; import org.alfresco.service.cmr.repository.NodeRef;
/** /**
@@ -171,10 +173,14 @@ public interface MultilingualContentService
* *
* @param translationNodeRef The <b>cm:mlContainer</b> to copy * @param translationNodeRef The <b>cm:mlContainer</b> to copy
* @param newParentRef The new parent of the copied <b>cm:mlDocument</b> * @param newParentRef The new parent of the copied <b>cm:mlDocument</b>
* @param prefixName The prefix of the name of the copied translations. Can be null.
* @return The copied <b>cm:mlContainer</b> * @return The copied <b>cm:mlContainer</b>
* @throws FileNotFoundException
* @throws FileExistsException
* @throws Exception
*/ */
@Auditable(key = Auditable.Key.ARG_0, parameters = {"translationNodeRef", "newParentRef"}) @Auditable(key = Auditable.Key.ARG_0, parameters = {"mlContainerNodeRef", "newParentRef"})
NodeRef copyTranslationContainer(NodeRef translationNodeRef, NodeRef newParentRef); NodeRef copyTranslationContainer(NodeRef mlContainerNodeRef, NodeRef newParentRef, String prefixName) throws FileExistsException, FileNotFoundException, Exception;
/** /**
* Moves the location of the given <b>cm:mlContainer</b>. * Moves the location of the given <b>cm:mlContainer</b>.
@@ -184,10 +190,18 @@ public interface MultilingualContentService
* *
* @param translationNodeRef The <b>cm:mlContainer</b> to move * @param translationNodeRef The <b>cm:mlContainer</b> to move
* @param newParentRef The new parent of the moved <b>cm:mlDocument</b> * @param newParentRef The new parent of the moved <b>cm:mlDocument</b>
* @throws FileExistsException
* @throws FileNotFoundException
*/ */
@Auditable(key = Auditable.Key.ARG_0, parameters = {"translationNodeRef", "newParentRef"}) @Auditable(key = Auditable.Key.ARG_0, parameters = {"mlContainerNodeRef", "newParentRef"})
void moveTranslationContainer(NodeRef translationNodeRef, NodeRef newParentRef); void moveTranslationContainer(NodeRef mlContainerNodeRef, NodeRef newParentRef) throws FileExistsException, FileNotFoundException;
/**
* Delete the given mlContainer and its translations. The translations will lost their <b>cm:mlDocument</b> aspect and
* will be archved. The empty translations will be permanently deleted.
*
* @param mlContainerNodeRef The <b>cm:mlContainer</b> to remove
*/
@Auditable(key = Auditable.Key.ARG_0, parameters = {"mlContainerNodeRef"})
void deleteTranslationContainer(NodeRef mlContainerNodeRef);
} }