diff --git a/config/alfresco/model-specific-services-context.xml b/config/alfresco/model-specific-services-context.xml
index c27800d16b..6b3d8bbdd2 100644
--- a/config/alfresco/model-specific-services-context.xml
+++ b/config/alfresco/model-specific-services-context.xml
@@ -36,6 +36,18 @@
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/config/alfresco/node-services-context.xml b/config/alfresco/node-services-context.xml
index 2676074cfa..8ca3f4e320 100644
--- a/config/alfresco/node-services-context.xml
+++ b/config/alfresco/node-services-context.xml
@@ -5,12 +5,9 @@
-
+
-
-
-
diff --git a/config/alfresco/public-services-context.xml b/config/alfresco/public-services-context.xml
index cd9a51be6a..b268015c92 100644
--- a/config/alfresco/public-services-context.xml
+++ b/config/alfresco/public-services-context.xml
@@ -105,6 +105,7 @@
+
@@ -676,20 +677,12 @@
+
-
-
-
-
-
-
-
-
-
diff --git a/source/java/org/alfresco/repo/model/ml/MLContentInterceptor.java b/source/java/org/alfresco/repo/model/ml/MLContentInterceptor.java
new file mode 100644
index 0000000000..d1e2a7928d
--- /dev/null
+++ b/source/java/org/alfresco/repo/model/ml/MLContentInterceptor.java
@@ -0,0 +1,125 @@
+/*
+ * 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.model.ml;
+
+import org.alfresco.model.ContentModel;
+import org.alfresco.service.cmr.ml.MultilingualContentService;
+import org.alfresco.service.cmr.model.FileFolderService;
+import org.alfresco.service.cmr.repository.ContentReader;
+import org.alfresco.service.cmr.repository.ContentService;
+import org.alfresco.service.cmr.repository.NodeRef;
+import org.alfresco.service.cmr.repository.NodeService;
+import org.alfresco.service.namespace.QName;
+import org.aopalliance.intercept.MethodInterceptor;
+import org.aopalliance.intercept.MethodInvocation;
+import org.apache.commons.logging.Log;
+import org.apache.commons.logging.LogFactory;
+
+/**
+ * Replaces content readers according to the empty translation status.
+ *
+ * @see ContentService#getReader(NodeRef, QName)
+ * @see FileFolderService#getReader(NodeRef)
+ * @since 2.1
+ * @author Derek Hulley
+ */
+public class MLContentInterceptor implements MethodInterceptor
+{
+ private static Log logger = LogFactory.getLog(MLContentInterceptor.class);
+
+ /** Direct access to the NodeService */
+ private NodeService nodeService;
+ /** Direct access to the ContentService */
+ private ContentService contentService;
+ /** Direct access to the ML Content Service */
+ private MultilingualContentService multilingualContentService;
+
+ public void setNodeService(NodeService bean)
+ {
+ this.nodeService = bean;
+ }
+
+ public void setContentService(ContentService directContentService)
+ {
+ this.contentService = directContentService;
+ }
+
+ public void setMultilingualContentService(MultilingualContentService directMultilingualContentService)
+ {
+ this.multilingualContentService = directMultilingualContentService;
+ }
+
+ public Object invoke(MethodInvocation invocation) throws Throwable
+ {
+ String methodName = invocation.getMethod().getName();
+ Object[] args = invocation.getArguments();
+
+ Object ret = null;
+
+ if (methodName.equals("getReader"))
+ {
+ NodeRef nodeRef = (NodeRef) args[0];
+
+ // Shortcut it if the node is not an empty translation
+ if (!nodeService.hasAspect(nodeRef, ContentModel.ASPECT_MULTILINGUAL_EMPTY_TRANSLATION))
+ {
+ return invocation.proceed();
+ }
+
+ // Get the content property required
+ QName propertyQName = null;
+ if (args.length == 1)
+ {
+ // Assume that the default cm:content is required
+ propertyQName = ContentModel.PROP_CONTENT;
+ }
+ else
+ {
+ // The request is specific
+ propertyQName = (QName) args[1];
+ }
+ // Get the pivot translation
+ NodeRef pivotNodeRef = multilingualContentService.getPivotTranslation(nodeRef);
+ // Get the reader from that
+ ContentReader pivotContentReader = contentService.getReader(pivotNodeRef, propertyQName);
+ // Done
+ if (logger.isDebugEnabled())
+ {
+ logger.debug(
+ "Converted reader for empty translation: \n" +
+ " Empty Translation: " + nodeRef + "\n" +
+ " Pivot Translation: " + pivotNodeRef + "\n" +
+ " Reader: " + pivotContentReader);
+ }
+ ret = pivotContentReader;
+ }
+ else
+ {
+ ret = invocation.proceed();
+ }
+ // done
+ return ret;
+ }
+}
diff --git a/source/java/org/alfresco/repo/model/ml/MultilingualContentServiceImpl.java b/source/java/org/alfresco/repo/model/ml/MultilingualContentServiceImpl.java
index c59c0fe74f..0ac46f8ecc 100644
--- a/source/java/org/alfresco/repo/model/ml/MultilingualContentServiceImpl.java
+++ b/source/java/org/alfresco/repo/model/ml/MultilingualContentServiceImpl.java
@@ -141,6 +141,39 @@ public class MultilingualContentServiceImpl implements MultilingualContentServic
return assocRef.getChildRef();
}
+ /**
+ * Get the ML Container of the given node, allowing null
+ * @param mlDocumentNodeRef the translation
+ * @param allowNull true if a null value may be returned
+ * @return Returns the cm:mlContainer or null if there isn't one
+ * @throws AlfrescoRuntimeException if there is no container
+ */
+ private NodeRef getMLContainer(NodeRef mlDocumentNodeRef, boolean allowNull)
+ {
+ NodeRef mlContainerNodeRef = null;
+ List parentAssocRefs = nodeService.getParentAssocs(
+ mlDocumentNodeRef,
+ ContentModel.ASSOC_MULTILINGUAL_CHILD,
+ RegexQNamePattern.MATCH_ALL);
+ if (parentAssocRefs.size() == 0)
+ {
+ if (!allowNull)
+ {
+ throw new AlfrescoRuntimeException(
+ "No multilingual container exists for document node: " + mlDocumentNodeRef);
+ }
+ mlContainerNodeRef = null;
+ }
+ else if (parentAssocRefs.size() >= 1)
+ {
+ // Just get it
+ ChildAssociationRef toKeepAssocRef = parentAssocRefs.get(0);
+ mlContainerNodeRef = toKeepAssocRef.getParentRef();
+ }
+ // Done
+ return mlContainerNodeRef;
+ }
+
/**
* Retrieve or create a cm:mlDocument container for the given node, which must have the
* cm:mlDocument already applied.
@@ -324,12 +357,21 @@ public class MultilingualContentServiceImpl implements MultilingualContentServic
/** @inheritDoc */
public void unmakeTranslation(NodeRef translationNodeRef)
{
- boolean isPivot = isPivotTranslation(translationNodeRef);
-
- if (isPivot)
+ // Get the container
+ NodeRef containerNodeRef = getMLContainer(translationNodeRef, true);
+ if (containerNodeRef == null)
+ {
+ if (nodeService.hasAspect(translationNodeRef, ContentModel.ASPECT_MULTILINGUAL_EMPTY_TRANSLATION))
+ {
+ nodeService.deleteNode(translationNodeRef);
+ }
+ else
+ {
+ nodeService.removeAspect(translationNodeRef, ContentModel.ASPECT_MULTILINGUAL_DOCUMENT);
+ }
+ }
+ else if (isPivotTranslation(translationNodeRef))
{
- // Get the container
- NodeRef containerNodeRef = getOrCreateMLContainer(translationNodeRef, false);
// Get all translation child associations
List mlChildAssocs = nodeService.getChildAssocs(
containerNodeRef,
@@ -360,7 +402,6 @@ public class MultilingualContentServiceImpl implements MultilingualContentServic
else
{
// Get the container and break the association to it
- NodeRef containerNodeRef = getOrCreateMLContainer(translationNodeRef, false);
nodeService.removeChild(containerNodeRef, translationNodeRef);
nodeService.removeAspect(translationNodeRef, ContentModel.ASPECT_MULTILINGUAL_DOCUMENT);
}
diff --git a/source/java/org/alfresco/repo/node/MLPropertyInterceptor.java b/source/java/org/alfresco/repo/node/MLPropertyInterceptor.java
index 492c16e743..3de9929f1d 100644
--- a/source/java/org/alfresco/repo/node/MLPropertyInterceptor.java
+++ b/source/java/org/alfresco/repo/node/MLPropertyInterceptor.java
@@ -30,11 +30,9 @@ 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.MLText;
import org.alfresco.service.cmr.repository.NodeRef;
import org.alfresco.service.cmr.repository.NodeService;
@@ -73,9 +71,7 @@ public class MLPropertyInterceptor implements MethodInterceptor
private static ThreadLocal mlAware = new ThreadLocal();
/** Direct access to the NodeService */
- private NodeService directNodeService;
- /** Direct access to the ML Content Service */
- private MultilingualContentService directMultilingualContentService;
+ private NodeService nodeService;
/** Used to access property definitions */
private DictionaryService dictionaryService;
@@ -108,16 +104,11 @@ public class MLPropertyInterceptor implements MethodInterceptor
}
}
- public void setDirectNodeService(NodeService bean)
+ public void setNodeService(NodeService bean)
{
- this.directNodeService = bean;
+ this.nodeService = bean;
}
- public void setDirectMultilingualContentService(MultilingualContentService directMultilingualContentService)
- {
- this.directMultilingualContentService = directMultilingualContentService;
- }
-
public void setDictionaryService(DictionaryService dictionaryService)
{
this.dictionaryService = dictionaryService;
@@ -184,7 +175,7 @@ public class MLPropertyInterceptor implements MethodInterceptor
NodeRef nodeRef = (NodeRef) args[0];
Map newProperties =(Map) args[1];
// Get the current properties for the node
- Map currentProperties = directNodeService.getProperties(nodeRef);
+ Map currentProperties = nodeService.getProperties(nodeRef);
// Convert all properties
Map convertedProperties = new HashMap(newProperties.size() * 2);
for (Map.Entry entry : newProperties.entrySet())
@@ -199,7 +190,7 @@ public class MLPropertyInterceptor implements MethodInterceptor
convertedProperties.put(propertyQName, inboundValue);
}
// Now complete the call by passing the converted properties
- directNodeService.setProperties(nodeRef, convertedProperties);
+ nodeService.setProperties(nodeRef, convertedProperties);
// Done
}
else if (methodName.equals("setProperty"))
@@ -212,7 +203,7 @@ public class MLPropertyInterceptor implements MethodInterceptor
inboundValue = convertInboundProperty(contentLocale, nodeRef, propertyQName, inboundValue, null);
// Pass this through to the node service
- directNodeService.setProperty(nodeRef, propertyQName, inboundValue);
+ nodeService.setProperty(nodeRef, propertyQName, inboundValue);
// Done
}
else
@@ -233,36 +224,12 @@ public class MLPropertyInterceptor implements MethodInterceptor
Serializable outboundValue)
{
Serializable ret = null;
- PropertyDefinition propertyDef = this.dictionaryService.getProperty(propertyQName);
// Is it content?
- if (propertyDef != null && propertyDef.getDataType().getName().equals(DataTypeDefinition.CONTENT))
+ if (outboundValue != null && outboundValue instanceof MLText)
{
- // Check if the document is an empty translation
- if (directNodeService.hasAspect(nodeRef, ContentModel.ASPECT_MULTILINGUAL_EMPTY_TRANSLATION))
- {
- // Ignore the value and take it directly from the pivot translation
- NodeRef pivotNodeRef = directMultilingualContentService.getPivotTranslation(nodeRef);
- if (pivotNodeRef == null)
- {
- // This is very bad, but we don't fail the server for it
- logger.warn("No pivot translation found for empty translation: " + nodeRef);
- ret = outboundValue;
- }
- else
- {
- // Get the corresponding property from the pivot
- ret = directNodeService.getProperty(pivotNodeRef, propertyQName);
- }
- }
- else
- {
- ret = outboundValue;
- }
- }
- else if (outboundValue != null && outboundValue instanceof MLText)
- {
- MLText mlText = (MLText) outboundValue;
- ret = mlText.getClosestValue(contentLocale);
+ // It is MLText
+ MLText mlText = (MLText) outboundValue;
+ ret = mlText.getClosestValue(contentLocale);
}
else
{
@@ -310,7 +277,7 @@ public class MLPropertyInterceptor implements MethodInterceptor
// Get the current value from the node service, if not provided
if (currentValue == null)
{
- currentValue = directNodeService.getProperty(nodeRef, propertyQName);
+ currentValue = nodeService.getProperty(nodeRef, propertyQName);
}
MLText returnMLValue = new MLText();
if (currentValue != null)