From e0bfdca5ea1c7fa7b918cb4d4bfd3935f113a487 Mon Sep 17 00:00:00 2001 From: Derek Hulley Date: Thu, 24 May 2007 04:11:50 +0000 Subject: [PATCH] Fixed failing ML tests - These worked on the branch a flaw showed up on HEAD - Moved ContentReader spoofing up into FileFolderService and ContentService using an interceptor. Fixed bug when attempting to delete an archived item that was ML. git-svn-id: https://svn.alfresco.com/repos/alfresco-enterprise/alfresco/HEAD/root@5768 c4b6b30b-aa2e-2d43-bbcb-ca4b014f7261 --- .../model-specific-services-context.xml | 12 ++ config/alfresco/node-services-context.xml | 5 +- config/alfresco/public-services-context.xml | 11 +- .../repo/model/ml/MLContentInterceptor.java | 125 ++++++++++++++++++ .../ml/MultilingualContentServiceImpl.java | 53 +++++++- .../repo/node/MLPropertyInterceptor.java | 55 ++------ 6 files changed, 198 insertions(+), 63 deletions(-) create mode 100644 source/java/org/alfresco/repo/model/ml/MLContentInterceptor.java 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)