mirror of
https://github.com/Alfresco/alfresco-community-repo.git
synced 2025-07-24 17:32:48 +00:00
Plugged in the correct mlTranslationInterceptor for FileFolderService and removed the NodeService interceptor.
Removed some unecessary interceptor work. Fixed content filtering to default to the pivot translation if there is no translation for a required language. Fixed content filtering when switching back to ALL LANGUAGES. git-svn-id: https://svn.alfresco.com/repos/alfresco-enterprise/alfresco/HEAD/root@5802 c4b6b30b-aa2e-2d43-bbcb-ca4b014f7261
This commit is contained in:
@@ -12,7 +12,6 @@
|
|||||||
<property name="copyService"><ref bean="copyService" /></property>
|
<property name="copyService"><ref bean="copyService" /></property>
|
||||||
<property name="searchService"><ref bean="admSearchService" /></property>
|
<property name="searchService"><ref bean="admSearchService" /></property>
|
||||||
<property name="contentService"><ref bean="contentService" /></property>
|
<property name="contentService"><ref bean="contentService" /></property>
|
||||||
<property name="multilingualContentService"><ref bean="multilingualContentService" /></property>
|
|
||||||
<property name="mimetypeService"><ref bean="mimetypeService" /></property>
|
<property name="mimetypeService"><ref bean="mimetypeService" /></property>
|
||||||
|
|
||||||
<property name="systemPaths">
|
<property name="systemPaths">
|
||||||
@@ -35,6 +34,9 @@
|
|||||||
<property name="multilingualContentService">
|
<property name="multilingualContentService">
|
||||||
<ref bean="multilingualContentService"/>
|
<ref bean="multilingualContentService"/>
|
||||||
</property>
|
</property>
|
||||||
|
<property name="fileFolderService">
|
||||||
|
<ref bean="fileFolderService"/>
|
||||||
|
</property>
|
||||||
</bean>
|
</bean>
|
||||||
|
|
||||||
<bean id="mlContentInterceptor" class="org.alfresco.repo.model.ml.MLContentInterceptor" >
|
<bean id="mlContentInterceptor" class="org.alfresco.repo.model.ml.MLContentInterceptor" >
|
||||||
|
@@ -13,15 +13,6 @@
|
|||||||
</property>
|
</property>
|
||||||
</bean>
|
</bean>
|
||||||
|
|
||||||
<bean id="mlTranslationInterceptor" class="org.alfresco.repo.node.MLTranslationInterceptor">
|
|
||||||
<property name="directNodeService">
|
|
||||||
<ref bean="mlAwareNodeService" />
|
|
||||||
</property>
|
|
||||||
<property name="directMultilingualContentService">
|
|
||||||
<ref bean="multilingualContentService" />
|
|
||||||
</property>
|
|
||||||
</bean>
|
|
||||||
|
|
||||||
<bean id="nodeService" class="org.springframework.aop.framework.ProxyFactoryBean" >
|
<bean id="nodeService" class="org.springframework.aop.framework.ProxyFactoryBean" >
|
||||||
<property name="targetName">
|
<property name="targetName">
|
||||||
<value>mlAwareNodeService</value>
|
<value>mlAwareNodeService</value>
|
||||||
|
@@ -30,7 +30,6 @@ import java.util.Collections;
|
|||||||
import java.util.HashMap;
|
import java.util.HashMap;
|
||||||
import java.util.Iterator;
|
import java.util.Iterator;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
import java.util.Locale;
|
|
||||||
import java.util.Map;
|
import java.util.Map;
|
||||||
|
|
||||||
import org.alfresco.error.AlfrescoRuntimeException;
|
import org.alfresco.error.AlfrescoRuntimeException;
|
||||||
@@ -123,7 +122,6 @@ public class FileFolderServiceImpl implements FileFolderService
|
|||||||
private CopyService copyService;
|
private CopyService copyService;
|
||||||
private SearchService searchService;
|
private SearchService searchService;
|
||||||
private ContentService contentService;
|
private ContentService contentService;
|
||||||
private MultilingualContentService multilingualContentService;
|
|
||||||
private MimetypeService mimetypeService;
|
private MimetypeService mimetypeService;
|
||||||
|
|
||||||
// TODO: Replace this with a more formal means of identifying "system" folders (i.e. aspect or UUID)
|
// TODO: Replace this with a more formal means of identifying "system" folders (i.e. aspect or UUID)
|
||||||
@@ -167,11 +165,6 @@ public class FileFolderServiceImpl implements FileFolderService
|
|||||||
this.contentService = contentService;
|
this.contentService = contentService;
|
||||||
}
|
}
|
||||||
|
|
||||||
public void setMultilingualContentService(MultilingualContentService multilingualContentService)
|
|
||||||
{
|
|
||||||
this.multilingualContentService = multilingualContentService;
|
|
||||||
}
|
|
||||||
|
|
||||||
public void setMimetypeService(MimetypeService mimetypeService)
|
public void setMimetypeService(MimetypeService mimetypeService)
|
||||||
{
|
{
|
||||||
this.mimetypeService = mimetypeService;
|
this.mimetypeService = mimetypeService;
|
||||||
@@ -217,40 +210,15 @@ public class FileFolderServiceImpl implements FileFolderService
|
|||||||
*/
|
*/
|
||||||
private FileInfo toFileInfo(NodeRef nodeRef, boolean addTranslations) throws InvalidTypeException
|
private FileInfo toFileInfo(NodeRef nodeRef, boolean addTranslations) throws InvalidTypeException
|
||||||
{
|
{
|
||||||
// get the file attributes
|
// Get the file attributes
|
||||||
Map<QName, Serializable> properties = nodeService.getProperties(nodeRef);
|
Map<QName, Serializable> properties = nodeService.getProperties(nodeRef);
|
||||||
// is it a folder
|
// Is it a folder
|
||||||
QName typeQName = nodeService.getType(nodeRef);
|
QName typeQName = nodeService.getType(nodeRef);
|
||||||
boolean isFolder = isFolder(typeQName);
|
boolean isFolder = isFolder(typeQName);
|
||||||
|
|
||||||
Map<Locale, FileInfo> translations = null;
|
// Construct the file info and add to the results
|
||||||
if (!isFolder && addTranslations)
|
FileInfo fileInfo = new FileInfoImpl(nodeRef, isFolder, properties);
|
||||||
{
|
// Done
|
||||||
// Get any translations
|
|
||||||
translations = new HashMap<Locale, FileInfo>(13);
|
|
||||||
// Check for the ML aspect
|
|
||||||
if (nodeService.hasAspect(nodeRef, ContentModel.ASPECT_MULTILINGUAL_DOCUMENT))
|
|
||||||
{
|
|
||||||
// Get all the translations
|
|
||||||
Map<Locale, NodeRef> translationsToConvert = multilingualContentService.getTranslations(nodeRef);
|
|
||||||
for (Map.Entry<Locale, NodeRef> entry : translationsToConvert.entrySet())
|
|
||||||
{
|
|
||||||
Locale locale = entry.getKey();
|
|
||||||
NodeRef nodeRefToConvert = entry.getValue();
|
|
||||||
FileInfo convertedFileInfo = toFileInfo(nodeRefToConvert, false);
|
|
||||||
// Add to map
|
|
||||||
translations.put(locale, convertedFileInfo);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
translations = Collections.<Locale, FileInfo>emptyMap();
|
|
||||||
}
|
|
||||||
|
|
||||||
// construct the file info and add to the results
|
|
||||||
FileInfo fileInfo = new FileInfoImpl(nodeRef, isFolder, properties, translations);
|
|
||||||
// done
|
|
||||||
return fileInfo;
|
return fileInfo;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@@ -25,9 +25,7 @@
|
|||||||
package org.alfresco.repo.model.filefolder;
|
package org.alfresco.repo.model.filefolder;
|
||||||
|
|
||||||
import java.io.Serializable;
|
import java.io.Serializable;
|
||||||
import java.util.Collections;
|
|
||||||
import java.util.Date;
|
import java.util.Date;
|
||||||
import java.util.Locale;
|
|
||||||
import java.util.Map;
|
import java.util.Map;
|
||||||
|
|
||||||
import org.alfresco.model.ContentModel;
|
import org.alfresco.model.ContentModel;
|
||||||
@@ -46,7 +44,6 @@ public class FileInfoImpl implements FileInfo
|
|||||||
{
|
{
|
||||||
private NodeRef nodeRef;
|
private NodeRef nodeRef;
|
||||||
private NodeRef linkNodeRef;
|
private NodeRef linkNodeRef;
|
||||||
private Map<Locale, FileInfo> translations;
|
|
||||||
private boolean isFolder;
|
private boolean isFolder;
|
||||||
private boolean isLink;
|
private boolean isLink;
|
||||||
private Map<QName, Serializable> properties;
|
private Map<QName, Serializable> properties;
|
||||||
@@ -54,33 +51,14 @@ public class FileInfoImpl implements FileInfo
|
|||||||
/**
|
/**
|
||||||
* Package-level constructor
|
* Package-level constructor
|
||||||
*/
|
*/
|
||||||
/* package */ FileInfoImpl(NodeRef nodeRef, boolean isFolder, Map<QName, Serializable> properties)
|
|
||||||
{
|
|
||||||
this(nodeRef, isFolder, properties, Collections.<Locale, FileInfo>emptyMap());
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Package-level constructor
|
|
||||||
*
|
|
||||||
* @param translations a map of translations including this instance. It may be null.
|
|
||||||
*/
|
|
||||||
/* package */ FileInfoImpl(
|
/* package */ FileInfoImpl(
|
||||||
NodeRef nodeRef,
|
NodeRef nodeRef,
|
||||||
boolean isFolder,
|
boolean isFolder,
|
||||||
Map<QName, Serializable> properties,
|
Map<QName, Serializable> properties)
|
||||||
Map<Locale, FileInfo> translations)
|
|
||||||
{
|
{
|
||||||
this.nodeRef = nodeRef;
|
this.nodeRef = nodeRef;
|
||||||
this.isFolder = isFolder;
|
this.isFolder = isFolder;
|
||||||
this.properties = properties;
|
this.properties = properties;
|
||||||
if (translations == null || isFolder)
|
|
||||||
{
|
|
||||||
this.translations = Collections.<Locale, FileInfo>emptyMap();
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
this.translations = translations;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Check if this is a link node
|
// Check if this is a link node
|
||||||
if ( properties.containsKey( ContentModel.PROP_LINK_DESTINATION))
|
if ( properties.containsKey( ContentModel.PROP_LINK_DESTINATION))
|
||||||
@@ -97,7 +75,15 @@ public class FileInfoImpl implements FileInfo
|
|||||||
@Override
|
@Override
|
||||||
public boolean equals(Object obj)
|
public boolean equals(Object obj)
|
||||||
{
|
{
|
||||||
if (obj == null || this.getClass().isInstance(obj))
|
if (obj == null)
|
||||||
|
{
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
else if (this == obj)
|
||||||
|
{
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
else if (obj instanceof FileInfoImpl == false)
|
||||||
{
|
{
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
@@ -130,8 +116,6 @@ public class FileInfoImpl implements FileInfo
|
|||||||
sb.append(linkNodeRef);
|
sb.append(linkNodeRef);
|
||||||
}
|
}
|
||||||
|
|
||||||
sb.append(", translations=").append(translations.size());
|
|
||||||
|
|
||||||
sb.append("]");
|
sb.append("]");
|
||||||
return sb.toString();
|
return sb.toString();
|
||||||
}
|
}
|
||||||
@@ -156,11 +140,6 @@ public class FileInfoImpl implements FileInfo
|
|||||||
return linkNodeRef;
|
return linkNodeRef;
|
||||||
}
|
}
|
||||||
|
|
||||||
public Map<Locale, FileInfo> getTranslations()
|
|
||||||
{
|
|
||||||
return translations;
|
|
||||||
}
|
|
||||||
|
|
||||||
public String getName()
|
public String getName()
|
||||||
{
|
{
|
||||||
return (String) properties.get(ContentModel.PROP_NAME);
|
return (String) properties.get(ContentModel.PROP_NAME);
|
||||||
|
@@ -97,6 +97,7 @@ public class MLTranslationInterceptor implements MethodInterceptor
|
|||||||
|
|
||||||
private NodeService nodeService;
|
private NodeService nodeService;
|
||||||
private MultilingualContentService multilingualContentService;
|
private MultilingualContentService multilingualContentService;
|
||||||
|
private FileFolderService fileFolderService;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Constructor.
|
* Constructor.
|
||||||
@@ -115,6 +116,11 @@ public class MLTranslationInterceptor implements MethodInterceptor
|
|||||||
this.multilingualContentService = multilingualContentService;
|
this.multilingualContentService = multilingualContentService;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public void setFileFolderService(FileFolderService fileFolderService)
|
||||||
|
{
|
||||||
|
this.fileFolderService = fileFolderService;
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Converts the node referenice where an alternative translation should be used.
|
* Converts the node referenice where an alternative translation should be used.
|
||||||
*
|
*
|
||||||
@@ -133,13 +139,14 @@ public class MLTranslationInterceptor implements MethodInterceptor
|
|||||||
{
|
{
|
||||||
return nodeRef;
|
return nodeRef;
|
||||||
}
|
}
|
||||||
// Find the translation
|
|
||||||
Map<Locale, NodeRef> translations = multilingualContentService.getTranslations(nodeRef);
|
|
||||||
Locale filterLocale = I18NUtil.getContentLocaleOrNull();
|
Locale filterLocale = I18NUtil.getContentLocaleOrNull();
|
||||||
Set<Locale> possibleLocales = translations.keySet();
|
if (filterLocale == null)
|
||||||
Locale localeToUse = I18NUtil.getNearestLocale(filterLocale, possibleLocales);
|
{
|
||||||
// Select the node
|
// We aren't doing any filtering
|
||||||
NodeRef translatedNodeRef = translations.get(localeToUse);
|
return nodeRef;
|
||||||
|
}
|
||||||
|
// Find the best translation. This won't return null.
|
||||||
|
NodeRef translatedNodeRef = multilingualContentService.getTranslationForLocale(nodeRef, filterLocale);
|
||||||
// Done
|
// Done
|
||||||
if (logger.isDebugEnabled())
|
if (logger.isDebugEnabled())
|
||||||
{
|
{
|
||||||
@@ -152,7 +159,7 @@ public class MLTranslationInterceptor implements MethodInterceptor
|
|||||||
logger.debug("NodeRef substitution: " + nodeRef + " (no change)");
|
logger.debug("NodeRef substitution: " + nodeRef + " (no change)");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return nodeRef;
|
return translatedNodeRef;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -160,8 +167,6 @@ public class MLTranslationInterceptor implements MethodInterceptor
|
|||||||
*
|
*
|
||||||
* @param fileInfo the basic file or folder info
|
* @param fileInfo the basic file or folder info
|
||||||
* @return Returns a replacement if required
|
* @return Returns a replacement if required
|
||||||
*
|
|
||||||
* @see FileInfo#getTranslations()
|
|
||||||
*/
|
*/
|
||||||
private FileInfo getTranslatedFileInfo(FileInfo fileInfo)
|
private FileInfo getTranslatedFileInfo(FileInfo fileInfo)
|
||||||
{
|
{
|
||||||
@@ -175,28 +180,20 @@ public class MLTranslationInterceptor implements MethodInterceptor
|
|||||||
{
|
{
|
||||||
return fileInfo;
|
return fileInfo;
|
||||||
}
|
}
|
||||||
// Ignore files without translations
|
NodeRef nodeRef = fileInfo.getNodeRef();
|
||||||
Map<Locale, FileInfo> translations = fileInfo.getTranslations();
|
// Get the best translation for the node
|
||||||
if (translations.size() == 0)
|
NodeRef translatedNodeRef = getTranslatedNodeRef(nodeRef);
|
||||||
|
// Convert to FileInfo, if required
|
||||||
|
FileInfo translatedFileInfo = null;
|
||||||
|
if (nodeRef.equals(translatedNodeRef))
|
||||||
{
|
{
|
||||||
return fileInfo;
|
// No need to do any more work
|
||||||
|
translatedFileInfo = fileInfo;
|
||||||
}
|
}
|
||||||
// Get the locale to use
|
else
|
||||||
Set<Locale> possibleLocales = translations.keySet();
|
|
||||||
Locale filterLocale = I18NUtil.getContentLocaleOrNull();
|
|
||||||
Locale localeToUse = I18NUtil.getNearestLocale(filterLocale, possibleLocales);
|
|
||||||
FileInfo translatedFileInfo = translations.get(localeToUse);
|
|
||||||
// Done
|
|
||||||
if (logger.isDebugEnabled())
|
|
||||||
{
|
{
|
||||||
if (fileInfo.equals(translatedFileInfo))
|
// Get the FileInfo
|
||||||
{
|
translatedFileInfo = fileFolderService.getFileInfo(translatedNodeRef);
|
||||||
logger.debug("FileInfo substitution: " + fileInfo + " --> " + translatedFileInfo);
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
logger.debug("FileInfo substitution: " + fileInfo + " (no change)");
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
return translatedFileInfo;
|
return translatedFileInfo;
|
||||||
}
|
}
|
||||||
@@ -207,7 +204,12 @@ public class MLTranslationInterceptor implements MethodInterceptor
|
|||||||
Object ret = null;
|
Object ret = null;
|
||||||
String methodName = invocation.getMethod().getName();
|
String methodName = invocation.getMethod().getName();
|
||||||
|
|
||||||
if (METHOD_NAMES_LIST.contains(methodName))
|
if (I18NUtil.getContentLocaleOrNull() == null)
|
||||||
|
{
|
||||||
|
// This can shortcut anything as there is no filtering going on
|
||||||
|
return invocation.proceed();
|
||||||
|
}
|
||||||
|
else if (METHOD_NAMES_LIST.contains(methodName))
|
||||||
{
|
{
|
||||||
List<FileInfo> fileInfos = (List<FileInfo>) invocation.proceed();
|
List<FileInfo> fileInfos = (List<FileInfo>) invocation.proceed();
|
||||||
// Compile a set to ensure we don't get duplicates
|
// Compile a set to ensure we don't get duplicates
|
||||||
@@ -223,13 +225,14 @@ public class MLTranslationInterceptor implements MethodInterceptor
|
|||||||
Set<FileInfo> alreadyPresent = new HashSet<FileInfo>(fileInfos.size() * 2 + 1);
|
Set<FileInfo> alreadyPresent = new HashSet<FileInfo>(fileInfos.size() * 2 + 1);
|
||||||
for (FileInfo info : fileInfos)
|
for (FileInfo info : fileInfos)
|
||||||
{
|
{
|
||||||
if (alreadyPresent.contains(info))
|
FileInfo translatedFileInfo = translatedFileInfos.get(info);
|
||||||
|
if (alreadyPresent.contains(translatedFileInfo))
|
||||||
{
|
{
|
||||||
// We've done this one
|
// We've done this one
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
alreadyPresent.add(info);
|
alreadyPresent.add(translatedFileInfo);
|
||||||
orderedResults.add(translatedFileInfos.get(info));
|
orderedResults.add(translatedFileInfo);
|
||||||
}
|
}
|
||||||
ret = orderedResults;
|
ret = orderedResults;
|
||||||
}
|
}
|
||||||
|
@@ -22,7 +22,6 @@
|
|||||||
* the FLOSS exception, and it is also available here:
|
* the FLOSS exception, and it is also available here:
|
||||||
* http://www.alfresco.com/legal/licensing"
|
* http://www.alfresco.com/legal/licensing"
|
||||||
*/
|
*/
|
||||||
|
|
||||||
package org.alfresco.repo.model.ml;
|
package org.alfresco.repo.model.ml;
|
||||||
|
|
||||||
import java.io.Serializable;
|
import java.io.Serializable;
|
||||||
@@ -51,17 +50,8 @@ import org.alfresco.service.namespace.QName;
|
|||||||
public class MLContainerType implements
|
public class MLContainerType implements
|
||||||
NodeServicePolicies.OnUpdatePropertiesPolicy
|
NodeServicePolicies.OnUpdatePropertiesPolicy
|
||||||
{
|
{
|
||||||
/**
|
|
||||||
* set a property with this QName when the deletion process is running on the mlContainer. In this case
|
|
||||||
* the policies of the remove aspect of mlDocument don't delete one more time the mlContainer.
|
|
||||||
*/
|
|
||||||
/*package*/ static QName PROP_NAME_DELETION_RUNNING = QName.createQName("__MLContanier_", "Deletion_Running");
|
|
||||||
|
|
||||||
// Dependencies
|
|
||||||
private PolicyComponent policyComponent;
|
private PolicyComponent policyComponent;
|
||||||
|
|
||||||
private NodeService nodeService;
|
private NodeService nodeService;
|
||||||
|
|
||||||
private MultilingualContentService multilingualContentService;
|
private MultilingualContentService multilingualContentService;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@@ -103,18 +103,26 @@ public class MLContentInterceptor implements MethodInterceptor
|
|||||||
}
|
}
|
||||||
// Get the pivot translation
|
// Get the pivot translation
|
||||||
NodeRef pivotNodeRef = multilingualContentService.getPivotTranslation(nodeRef);
|
NodeRef pivotNodeRef = multilingualContentService.getPivotTranslation(nodeRef);
|
||||||
// Get the reader from that
|
if (pivotNodeRef == null)
|
||||||
ContentReader pivotContentReader = contentService.getReader(pivotNodeRef, propertyQName);
|
|
||||||
// Done
|
|
||||||
if (logger.isDebugEnabled())
|
|
||||||
{
|
{
|
||||||
logger.debug(
|
// This is technically possible
|
||||||
"Converted reader for empty translation: \n" +
|
ret = invocation.proceed();
|
||||||
" Empty Translation: " + nodeRef + "\n" +
|
}
|
||||||
" Pivot Translation: " + pivotNodeRef + "\n" +
|
else
|
||||||
" Reader: " + pivotContentReader);
|
{
|
||||||
|
// 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;
|
||||||
}
|
}
|
||||||
ret = pivotContentReader;
|
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
|
@@ -561,6 +561,16 @@ public class MultilingualContentServiceImpl implements MultilingualContentServic
|
|||||||
Set<Locale> locales = nodeRefsByLocale.keySet();
|
Set<Locale> locales = nodeRefsByLocale.keySet();
|
||||||
Locale nearestLocale = I18NUtil.getNearestLocale(locale, locales);
|
Locale nearestLocale = I18NUtil.getNearestLocale(locale, locales);
|
||||||
NodeRef nearestNodeRef = nodeRefsByLocale.get(nearestLocale);
|
NodeRef nearestNodeRef = nodeRefsByLocale.get(nearestLocale);
|
||||||
|
if (nearestNodeRef == null)
|
||||||
|
{
|
||||||
|
// There is no translation for the locale, so get the pivot translation
|
||||||
|
nearestNodeRef = getPivotTranslation(translationNodeRef);
|
||||||
|
if (nearestNodeRef == null)
|
||||||
|
{
|
||||||
|
// There is no pivot translation, so just use the given node
|
||||||
|
nearestNodeRef = translationNodeRef;
|
||||||
|
}
|
||||||
|
}
|
||||||
// Done
|
// Done
|
||||||
if (logger.isDebugEnabled())
|
if (logger.isDebugEnabled())
|
||||||
{
|
{
|
||||||
@@ -629,24 +639,34 @@ public class MultilingualContentServiceImpl implements MultilingualContentServic
|
|||||||
/** @inheritDoc */
|
/** @inheritDoc */
|
||||||
public NodeRef getPivotTranslation(NodeRef nodeRef)
|
public NodeRef getPivotTranslation(NodeRef nodeRef)
|
||||||
{
|
{
|
||||||
|
Locale containerLocale = null;
|
||||||
if(nodeService.hasAspect(nodeRef, ContentModel.ASPECT_MULTILINGUAL_DOCUMENT))
|
if(nodeService.hasAspect(nodeRef, ContentModel.ASPECT_MULTILINGUAL_DOCUMENT))
|
||||||
{
|
{
|
||||||
NodeRef container = getTranslationContainer(nodeRef);
|
NodeRef container = getTranslationContainer(nodeRef);
|
||||||
Locale containerLocale = (Locale) nodeService.getProperty(container, ContentModel.PROP_LOCALE);
|
containerLocale = (Locale) nodeService.getProperty(container, ContentModel.PROP_LOCALE);
|
||||||
|
|
||||||
return getTranslationForLocale(nodeRef, containerLocale);
|
|
||||||
}
|
}
|
||||||
else if(ContentModel.TYPE_MULTILINGUAL_CONTAINER.equals(nodeService.getType(nodeRef)))
|
else if(ContentModel.TYPE_MULTILINGUAL_CONTAINER.equals(nodeService.getType(nodeRef)))
|
||||||
{
|
{
|
||||||
Locale containerLocale = (Locale) nodeService.getProperty(nodeRef, ContentModel.PROP_LOCALE);
|
containerLocale = (Locale) nodeService.getProperty(nodeRef, ContentModel.PROP_LOCALE);
|
||||||
return getTranslationForLocale(nodeRef, containerLocale);
|
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
logger.warn("The node is not multilingual " + nodeRef);
|
logger.warn("The node is not multilingual " + nodeRef);
|
||||||
|
}
|
||||||
|
// Get all the translations
|
||||||
|
Map<Locale, NodeRef> nodeRefsByLocale = getTranslations(nodeRef);
|
||||||
|
// Get the closest matching locale
|
||||||
|
Set<Locale> locales = nodeRefsByLocale.keySet();
|
||||||
|
Locale nearestLocale = I18NUtil.getNearestLocale(containerLocale, locales);
|
||||||
|
if (nearestLocale == null)
|
||||||
|
{
|
||||||
|
// There is pivot translation
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
return nodeRefsByLocale.get(nearestLocale);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@@ -137,31 +137,51 @@ public class MultilingualContentServiceImplTest extends AbstractMultilingualTest
|
|||||||
assertFalse("Missing Translation List false. Locale " + loc2 + " or " + loc3 + " found", missing.contains(loc2.toString()) || missing.contains(loc3.toString()));
|
assertFalse("Missing Translation List false. Locale " + loc2 + " or " + loc3 + " found", missing.contains(loc2.toString()) || missing.contains(loc3.toString()));
|
||||||
}
|
}
|
||||||
|
|
||||||
@SuppressWarnings("unused")
|
public void testGetTranslationForLocale() throws Exception
|
||||||
public void testPivotTranslation() throws Exception
|
|
||||||
{
|
{
|
||||||
NodeRef chineseContentNodeRef = createContent();
|
NodeRef chineseContentNodeRef = createContent();
|
||||||
|
NodeRef mlContainerNodeRef = multilingualContentService.makeTranslation(chineseContentNodeRef, Locale.CHINESE);
|
||||||
|
NodeRef frenchContentNodeRef = createContent();
|
||||||
|
multilingualContentService.addTranslation(frenchContentNodeRef, chineseContentNodeRef, Locale.FRENCH);
|
||||||
|
|
||||||
|
// Get the chinese translation
|
||||||
|
assertEquals("Chinese translation should be present",
|
||||||
|
chineseContentNodeRef,
|
||||||
|
multilingualContentService.getTranslationForLocale(mlContainerNodeRef, Locale.CHINESE));
|
||||||
|
// Get the french translation
|
||||||
|
assertEquals("French translation should be present",
|
||||||
|
frenchContentNodeRef,
|
||||||
|
multilingualContentService.getTranslationForLocale(mlContainerNodeRef, Locale.FRENCH));
|
||||||
|
// The Italian should return the pivot
|
||||||
|
assertEquals("French translation should be present",
|
||||||
|
chineseContentNodeRef,
|
||||||
|
multilingualContentService.getTranslationForLocale(mlContainerNodeRef, Locale.ITALIAN));
|
||||||
|
}
|
||||||
|
|
||||||
|
@SuppressWarnings("unused")
|
||||||
|
public void testGetPivotTranslation() throws Exception
|
||||||
|
{
|
||||||
|
NodeRef chineseContentNodeRef = createContent();
|
||||||
NodeRef mlContainerNodeRef = multilingualContentService.makeTranslation(chineseContentNodeRef, Locale.CHINESE);
|
NodeRef mlContainerNodeRef = multilingualContentService.makeTranslation(chineseContentNodeRef, Locale.CHINESE);
|
||||||
|
|
||||||
// make sure that the pivot language is set
|
// make sure that the pivot language is set
|
||||||
assertNotNull("Pivot language not set", nodeService.getProperty(mlContainerNodeRef, ContentModel.PROP_LOCALE));
|
assertNotNull("Pivot language not set", nodeService.getProperty(mlContainerNodeRef, ContentModel.PROP_LOCALE));
|
||||||
|
|
||||||
// make sure that the pivot language is correctly set
|
// make sure that the pivot language is correctly set
|
||||||
assertTrue("Pivot language not correctly set", nodeService.getProperty(mlContainerNodeRef, ContentModel.PROP_LOCALE).equals(Locale.CHINESE));
|
assertEquals("Pivot language not correctly set", Locale.CHINESE, nodeService.getProperty(mlContainerNodeRef, ContentModel.PROP_LOCALE));
|
||||||
|
|
||||||
NodeRef frenchContentNodeRef = createContent();
|
NodeRef frenchContentNodeRef = createContent();
|
||||||
multilingualContentService.addTranslation(frenchContentNodeRef, chineseContentNodeRef, Locale.FRENCH);
|
multilingualContentService.addTranslation(frenchContentNodeRef, chineseContentNodeRef, Locale.FRENCH);
|
||||||
|
|
||||||
// make sure that the pivot noderef is correct
|
// make sure that the pivot noderef is correct
|
||||||
assertTrue("Pivot node ref not correct", multilingualContentService.getPivotTranslation(mlContainerNodeRef).equals(chineseContentNodeRef));
|
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
|
// modify the pivot language
|
||||||
nodeService.setProperty(mlContainerNodeRef, ContentModel.PROP_LOCALE, Locale.FRENCH);
|
nodeService.setProperty(mlContainerNodeRef, ContentModel.PROP_LOCALE, Locale.FRENCH);
|
||||||
|
|
||||||
// make sure that the modified pivot noderef is correct
|
// make sure that the modified pivot noderef is correct
|
||||||
assertTrue("Pivot node ref not correct", multilingualContentService.getPivotTranslation(mlContainerNodeRef).equals(frenchContentNodeRef));
|
assertEquals("Pivot node ref not correct", frenchContentNodeRef, multilingualContentService.getPivotTranslation(mlContainerNodeRef));
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@SuppressWarnings("unused")
|
@SuppressWarnings("unused")
|
||||||
|
@@ -1,171 +0,0 @@
|
|||||||
/*
|
|
||||||
* 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.node;
|
|
||||||
|
|
||||||
import java.util.ArrayList;
|
|
||||||
import java.util.List;
|
|
||||||
import java.util.Locale;
|
|
||||||
import java.util.Set;
|
|
||||||
|
|
||||||
import org.alfresco.i18n.I18NUtil;
|
|
||||||
import org.alfresco.model.ContentModel;
|
|
||||||
import org.alfresco.service.cmr.ml.MultilingualContentService;
|
|
||||||
import org.alfresco.service.cmr.repository.ChildAssociationRef;
|
|
||||||
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;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Interceptor to
|
|
||||||
* - filter the multilingual nodes to display the documents in the prefered language of teh user
|
|
||||||
*
|
|
||||||
* @author yanipig
|
|
||||||
*/
|
|
||||||
public class MLTranslationInterceptor implements MethodInterceptor
|
|
||||||
{
|
|
||||||
private static Log logger = LogFactory.getLog(MLTranslationInterceptor.class);
|
|
||||||
|
|
||||||
private NodeService directNodeService;
|
|
||||||
|
|
||||||
private MultilingualContentService directMultilingualContentService;
|
|
||||||
|
|
||||||
@SuppressWarnings("unchecked")
|
|
||||||
public Object invoke(MethodInvocation invocation) throws Throwable
|
|
||||||
{
|
|
||||||
Object ret = null;
|
|
||||||
String methodName = invocation.getMethod().getName();
|
|
||||||
|
|
||||||
// intercept the methods getChildAssocs and getChildByNames to apply filter.
|
|
||||||
if (methodName.equals("getChildAssocs") || methodName.equals("getChildByName"))
|
|
||||||
{
|
|
||||||
ret = invocation.proceed();
|
|
||||||
|
|
||||||
NodeRef parent = (NodeRef) invocation.getArguments()[0];
|
|
||||||
|
|
||||||
// all the association returned by the method
|
|
||||||
List<ChildAssociationRef> allChildAssoc = (List<ChildAssociationRef>) ret;
|
|
||||||
|
|
||||||
// get the user content filter language
|
|
||||||
Locale filterLocale = I18NUtil.getContentLocaleOrNull();
|
|
||||||
|
|
||||||
if(filterLocale != null
|
|
||||||
&& directNodeService.getType(parent).equals(ContentModel.TYPE_FOLDER)
|
|
||||||
&& ret != null
|
|
||||||
&& !allChildAssoc.isEmpty()
|
|
||||||
)
|
|
||||||
{
|
|
||||||
|
|
||||||
// the list of Association to return
|
|
||||||
List<ChildAssociationRef> toReturn = new ArrayList();
|
|
||||||
// the ml containers found in the folder
|
|
||||||
List<NodeRef> mlContainers = new ArrayList();
|
|
||||||
|
|
||||||
// construct the list of ML Container
|
|
||||||
for (ChildAssociationRef assoc : allChildAssoc)
|
|
||||||
{
|
|
||||||
NodeRef child = assoc.getChildRef();
|
|
||||||
|
|
||||||
QName type = directNodeService.getType(child);
|
|
||||||
|
|
||||||
if(type.equals(ContentModel.TYPE_CONTENT) &&
|
|
||||||
directNodeService.hasAspect(child, ContentModel.ASPECT_MULTILINGUAL_DOCUMENT))
|
|
||||||
{
|
|
||||||
NodeRef container = directMultilingualContentService.getTranslationContainer(child);
|
|
||||||
|
|
||||||
if (!mlContainers.contains(container))
|
|
||||||
{
|
|
||||||
mlContainers.add(container);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
// no specific treatment for folder and non-multilingual document
|
|
||||||
toReturn.add(assoc);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// for each mlContainer found, choose the unique document to return
|
|
||||||
for(NodeRef container : mlContainers)
|
|
||||||
{
|
|
||||||
// get each translation language
|
|
||||||
Set<Locale> locales = directMultilingualContentService.getTranslations(container).keySet();
|
|
||||||
|
|
||||||
if(locales != null && locales.size() > 0)
|
|
||||||
{
|
|
||||||
Locale matchedLocal = I18NUtil.getNearestLocale(filterLocale, locales);
|
|
||||||
|
|
||||||
NodeRef matchedTranslation = null;
|
|
||||||
|
|
||||||
// if the filter language is not found
|
|
||||||
if(matchedLocal == null)
|
|
||||||
{
|
|
||||||
// get the pivot translation
|
|
||||||
matchedTranslation = directMultilingualContentService.getPivotTranslation(container);
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
// get the matched translation
|
|
||||||
matchedTranslation = directMultilingualContentService.getTranslations(container).get(matchedLocal);
|
|
||||||
}
|
|
||||||
|
|
||||||
toReturn.add(new ChildAssociationRef(null, null, null, matchedTranslation));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
ret = toReturn;
|
|
||||||
|
|
||||||
if (logger.isDebugEnabled())
|
|
||||||
{
|
|
||||||
logger.debug("Filter has found " +
|
|
||||||
allChildAssoc.size() + " entries, " +
|
|
||||||
mlContainers.size() + " different ML Container " +
|
|
||||||
"and returns " + toReturn.size() + " nodes");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
ret = invocation.proceed();
|
|
||||||
}
|
|
||||||
|
|
||||||
return ret;
|
|
||||||
}
|
|
||||||
|
|
||||||
public void setDirectMultilingualContentService(
|
|
||||||
MultilingualContentService multilingualContentService)
|
|
||||||
{
|
|
||||||
this.directMultilingualContentService = multilingualContentService;
|
|
||||||
}
|
|
||||||
|
|
||||||
public void setDirectNodeService(NodeService nodeService)
|
|
||||||
{
|
|
||||||
this.directNodeService = nodeService;
|
|
||||||
}
|
|
||||||
}
|
|
@@ -123,13 +123,13 @@ public interface MultilingualContentService
|
|||||||
/**
|
/**
|
||||||
* Given a <b>cm:mlDocument</b>, this method attempts to find the best translation for the given
|
* Given a <b>cm:mlDocument</b>, this method attempts to find the best translation for the given
|
||||||
* locale. If there is not even a
|
* locale. If there is not even a
|
||||||
* {@link org.alfresco.i18n.I18NUtil#getNearestLocale(Locale, Set) partial match}, then <tt>null</tt>
|
* {@link org.alfresco.i18n.I18NUtil#getNearestLocale(Locale, Set) partial match}, then the
|
||||||
* is returned.
|
* {@link #getPivotTranslation(NodeRef) pivot translation} is used. If that also gives no results
|
||||||
|
* then the translation itself is returned.
|
||||||
*
|
*
|
||||||
* @param translationNodeRef the <b>cm:mlDocument</b>
|
* @param translationNodeRef the <b>cm:mlDocument</b>
|
||||||
* @param locale the target locale
|
* @param locale the target locale
|
||||||
* @return Returns Returns the best match for the locale, or <tt>null</tt> if there
|
* @return Returns the best match for the locale (never <tt>null</tt>)
|
||||||
* is no near match.
|
|
||||||
*
|
*
|
||||||
* @see #getTranslations(NodeRef)
|
* @see #getTranslations(NodeRef)
|
||||||
* @see org.alfresco.i18n.I18NUtil#getNearestLocale(Locale, Set)
|
* @see org.alfresco.i18n.I18NUtil#getNearestLocale(Locale, Set)
|
||||||
@@ -157,7 +157,8 @@ public interface MultilingualContentService
|
|||||||
*
|
*
|
||||||
* @param nodeRef a <b>cm:mlDocument</b>
|
* @param nodeRef a <b>cm:mlDocument</b>
|
||||||
* @return Returns a corresponding <b>cm:mlDocument</b> that matches the locale of
|
* @return Returns a corresponding <b>cm:mlDocument</b> that matches the locale of
|
||||||
* of the <b>cm:mlContainer</b>.
|
* of the <b>cm:mlContainer</b>. <tt>null</tt> is returned if there is no
|
||||||
|
* pivot translation.
|
||||||
*/
|
*/
|
||||||
@Auditable(key = Auditable.Key.ARG_0, parameters = {"nodeRef"})
|
@Auditable(key = Auditable.Key.ARG_0, parameters = {"nodeRef"})
|
||||||
NodeRef getPivotTranslation(NodeRef nodeRef);
|
NodeRef getPivotTranslation(NodeRef nodeRef);
|
||||||
|
@@ -62,15 +62,6 @@ public interface FileInfo
|
|||||||
*/
|
*/
|
||||||
public NodeRef getLinkNodeRef();
|
public NodeRef getLinkNodeRef();
|
||||||
|
|
||||||
/**
|
|
||||||
* Get all translated versions of the file info. The map will always be empty if this
|
|
||||||
* instance references {@link #isFolder() a folder}. The map may also be empty if the
|
|
||||||
* file represented is not multilingual.
|
|
||||||
*
|
|
||||||
* @return Returns a map of transalations keyed on locale
|
|
||||||
*/
|
|
||||||
public Map<Locale, FileInfo> getTranslations();
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @return Returns the name of the file or folder within the parent folder
|
* @return Returns the name of the file or folder within the parent folder
|
||||||
*/
|
*/
|
||||||
|
Reference in New Issue
Block a user