mirror of
https://github.com/Alfresco/alfresco-community-repo.git
synced 2025-07-24 17:32:48 +00:00
Merging from EC-MC: Checkpoint before refactor
git-svn-id: https://svn.alfresco.com/repos/alfresco-enterprise/alfresco/HEAD/root@5744 c4b6b30b-aa2e-2d43-bbcb-ca4b014f7261
This commit is contained in:
@@ -30,6 +30,7 @@ import java.util.Collections;
|
||||
import java.util.HashMap;
|
||||
import java.util.Iterator;
|
||||
import java.util.List;
|
||||
import java.util.Locale;
|
||||
import java.util.Map;
|
||||
|
||||
import org.alfresco.error.AlfrescoRuntimeException;
|
||||
@@ -37,6 +38,7 @@ import org.alfresco.model.ContentModel;
|
||||
import org.alfresco.repo.search.QueryParameterDefImpl;
|
||||
import org.alfresco.service.cmr.dictionary.DataTypeDefinition;
|
||||
import org.alfresco.service.cmr.dictionary.DictionaryService;
|
||||
import org.alfresco.service.cmr.ml.MultilingualContentService;
|
||||
import org.alfresco.service.cmr.model.FileExistsException;
|
||||
import org.alfresco.service.cmr.model.FileFolderService;
|
||||
import org.alfresco.service.cmr.model.FileInfo;
|
||||
@@ -121,6 +123,7 @@ public class FileFolderServiceImpl implements FileFolderService
|
||||
private CopyService copyService;
|
||||
private SearchService searchService;
|
||||
private ContentService contentService;
|
||||
private MultilingualContentService multilingualContentService;
|
||||
private MimetypeService mimetypeService;
|
||||
|
||||
// TODO: Replace this with a more formal means of identifying "system" folders (i.e. aspect or UUID)
|
||||
@@ -164,6 +167,11 @@ public class FileFolderServiceImpl implements FileFolderService
|
||||
this.contentService = contentService;
|
||||
}
|
||||
|
||||
public void setMultilingualContentService(MultilingualContentService multilingualContentService)
|
||||
{
|
||||
this.multilingualContentService = multilingualContentService;
|
||||
}
|
||||
|
||||
public void setMimetypeService(MimetypeService mimetypeService)
|
||||
{
|
||||
this.mimetypeService = mimetypeService;
|
||||
@@ -198,7 +206,7 @@ public class FileFolderServiceImpl implements FileFolderService
|
||||
List<FileInfo> results = new ArrayList<FileInfo>(nodeRefs.size());
|
||||
for (NodeRef nodeRef : nodeRefs)
|
||||
{
|
||||
FileInfo fileInfo = toFileInfo(nodeRef);
|
||||
FileInfo fileInfo = toFileInfo(nodeRef, true);
|
||||
results.add(fileInfo);
|
||||
}
|
||||
return results;
|
||||
@@ -207,7 +215,7 @@ public class FileFolderServiceImpl implements FileFolderService
|
||||
/**
|
||||
* Helper method to convert a node reference instance to a file info
|
||||
*/
|
||||
private FileInfo toFileInfo(NodeRef nodeRef) throws InvalidTypeException
|
||||
private FileInfo toFileInfo(NodeRef nodeRef, boolean addTranslations) throws InvalidTypeException
|
||||
{
|
||||
// get the file attributes
|
||||
Map<QName, Serializable> properties = nodeService.getProperties(nodeRef);
|
||||
@@ -215,8 +223,33 @@ public class FileFolderServiceImpl implements FileFolderService
|
||||
QName typeQName = nodeService.getType(nodeRef);
|
||||
boolean isFolder = isFolder(typeQName);
|
||||
|
||||
Map<Locale, FileInfo> translations = null;
|
||||
if (!isFolder && addTranslations)
|
||||
{
|
||||
// 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);
|
||||
FileInfo fileInfo = new FileInfoImpl(nodeRef, isFolder, properties, translations);
|
||||
// done
|
||||
return fileInfo;
|
||||
}
|
||||
@@ -542,7 +575,7 @@ public class FileFolderServiceImpl implements FileFolderService
|
||||
private FileInfo moveOrCopy(NodeRef sourceNodeRef, NodeRef targetParentRef, String newName, boolean move) throws FileExistsException, FileNotFoundException
|
||||
{
|
||||
// get file/folder in its current state
|
||||
FileInfo beforeFileInfo = toFileInfo(sourceNodeRef);
|
||||
FileInfo beforeFileInfo = toFileInfo(sourceNodeRef, true);
|
||||
// check the name - null means keep the existing name
|
||||
if (newName == null)
|
||||
{
|
||||
@@ -634,7 +667,7 @@ public class FileFolderServiceImpl implements FileFolderService
|
||||
}
|
||||
|
||||
// get the details after the operation
|
||||
FileInfo afterFileInfo = toFileInfo(targetNodeRef);
|
||||
FileInfo afterFileInfo = toFileInfo(targetNodeRef, true);
|
||||
// done
|
||||
if (logger.isDebugEnabled())
|
||||
{
|
||||
@@ -705,11 +738,11 @@ public class FileFolderServiceImpl implements FileFolderService
|
||||
}
|
||||
|
||||
NodeRef nodeRef = assocRef.getChildRef();
|
||||
FileInfo fileInfo = toFileInfo(nodeRef);
|
||||
FileInfo fileInfo = toFileInfo(nodeRef, true);
|
||||
// done
|
||||
if (logger.isDebugEnabled())
|
||||
{
|
||||
FileInfo parentFileInfo = toFileInfo(parentNodeRef);
|
||||
FileInfo parentFileInfo = toFileInfo(parentNodeRef, false);
|
||||
logger.debug("Created: \n" +
|
||||
" parent: " + parentFileInfo + "\n" +
|
||||
" created: " + fileInfo);
|
||||
@@ -755,7 +788,7 @@ public class FileFolderServiceImpl implements FileFolderService
|
||||
}
|
||||
}
|
||||
// done
|
||||
FileInfo fileInfo = toFileInfo(currentParentRef);
|
||||
FileInfo fileInfo = toFileInfo(currentParentRef, true);
|
||||
return fileInfo;
|
||||
}
|
||||
|
||||
@@ -790,7 +823,7 @@ public class FileFolderServiceImpl implements FileFolderService
|
||||
continue;
|
||||
}
|
||||
// we found the root and expect to be building the path up
|
||||
FileInfo pathInfo = toFileInfo(childNodeRef);
|
||||
FileInfo pathInfo = toFileInfo(childNodeRef, true);
|
||||
results.add(pathInfo);
|
||||
}
|
||||
// check that we found the root
|
||||
@@ -861,7 +894,7 @@ public class FileFolderServiceImpl implements FileFolderService
|
||||
{
|
||||
try
|
||||
{
|
||||
return toFileInfo(nodeRef);
|
||||
return toFileInfo(nodeRef, true);
|
||||
}
|
||||
catch (InvalidTypeException e)
|
||||
{
|
||||
@@ -871,7 +904,7 @@ public class FileFolderServiceImpl implements FileFolderService
|
||||
|
||||
public ContentReader getReader(NodeRef nodeRef)
|
||||
{
|
||||
FileInfo fileInfo = toFileInfo(nodeRef);
|
||||
FileInfo fileInfo = toFileInfo(nodeRef, false);
|
||||
if (fileInfo.isFolder())
|
||||
{
|
||||
throw new InvalidTypeException("Unable to get a content reader for a folder: " + fileInfo);
|
||||
@@ -881,7 +914,7 @@ public class FileFolderServiceImpl implements FileFolderService
|
||||
|
||||
public ContentWriter getWriter(NodeRef nodeRef)
|
||||
{
|
||||
FileInfo fileInfo = toFileInfo(nodeRef);
|
||||
FileInfo fileInfo = toFileInfo(nodeRef, false);
|
||||
if (fileInfo.isFolder())
|
||||
{
|
||||
throw new InvalidTypeException("Unable to get a content writer for a folder: " + fileInfo);
|
||||
|
@@ -25,7 +25,9 @@
|
||||
package org.alfresco.repo.model.filefolder;
|
||||
|
||||
import java.io.Serializable;
|
||||
import java.util.Collections;
|
||||
import java.util.Date;
|
||||
import java.util.Locale;
|
||||
import java.util.Map;
|
||||
|
||||
import org.alfresco.model.ContentModel;
|
||||
@@ -44,6 +46,7 @@ public class FileInfoImpl implements FileInfo
|
||||
{
|
||||
private NodeRef nodeRef;
|
||||
private NodeRef linkNodeRef;
|
||||
private Map<Locale, FileInfo> translations;
|
||||
private boolean isFolder;
|
||||
private boolean isLink;
|
||||
private Map<QName, Serializable> properties;
|
||||
@@ -52,13 +55,34 @@ public class FileInfoImpl implements FileInfo
|
||||
* 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(
|
||||
NodeRef nodeRef,
|
||||
boolean isFolder,
|
||||
Map<QName, Serializable> properties,
|
||||
Map<Locale, FileInfo> translations)
|
||||
{
|
||||
this.nodeRef = nodeRef;
|
||||
this.isFolder = isFolder;
|
||||
this.properties = properties;
|
||||
if (translations == null || isFolder)
|
||||
{
|
||||
this.translations = Collections.<Locale, FileInfo>emptyMap();
|
||||
}
|
||||
else
|
||||
{
|
||||
this.translations = translations;
|
||||
}
|
||||
|
||||
// Check if this is a link node
|
||||
|
||||
if ( properties.containsKey( ContentModel.PROP_LINK_DESTINATION))
|
||||
{
|
||||
isLink = true;
|
||||
@@ -66,6 +90,31 @@ public class FileInfoImpl implements FileInfo
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @see #getNodeRef()
|
||||
* @see NodeRef#equals(Object)
|
||||
*/
|
||||
@Override
|
||||
public boolean equals(Object obj)
|
||||
{
|
||||
if (obj == null || this.getClass().isInstance(obj))
|
||||
{
|
||||
return false;
|
||||
}
|
||||
FileInfoImpl that = (FileInfoImpl) obj;
|
||||
return (this.getNodeRef().equals(that.getNodeRef()));
|
||||
}
|
||||
|
||||
/**
|
||||
* @see #getNodeRef()
|
||||
* @see NodeRef#hashCode()
|
||||
*/
|
||||
@Override
|
||||
public int hashCode()
|
||||
{
|
||||
return getNodeRef().hashCode();
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString()
|
||||
{
|
||||
@@ -81,6 +130,8 @@ public class FileInfoImpl implements FileInfo
|
||||
sb.append(linkNodeRef);
|
||||
}
|
||||
|
||||
sb.append(", translations=").append(translations.size());
|
||||
|
||||
sb.append("]");
|
||||
return sb.toString();
|
||||
}
|
||||
@@ -105,6 +156,11 @@ public class FileInfoImpl implements FileInfo
|
||||
return linkNodeRef;
|
||||
}
|
||||
|
||||
public Map<Locale, FileInfo> getTranslations()
|
||||
{
|
||||
return translations;
|
||||
}
|
||||
|
||||
public String getName()
|
||||
{
|
||||
return (String) properties.get(ContentModel.PROP_NAME);
|
||||
|
@@ -0,0 +1,256 @@
|
||||
/*
|
||||
* 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.filefolder;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.HashMap;
|
||||
import java.util.HashSet;
|
||||
import java.util.List;
|
||||
import java.util.Locale;
|
||||
import java.util.Map;
|
||||
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.model.FileFolderService;
|
||||
import org.alfresco.service.cmr.model.FileInfo;
|
||||
import org.alfresco.service.cmr.repository.NodeRef;
|
||||
import org.alfresco.service.cmr.repository.NodeService;
|
||||
import org.aopalliance.intercept.MethodInterceptor;
|
||||
import org.aopalliance.intercept.MethodInvocation;
|
||||
import org.apache.commons.logging.Log;
|
||||
import org.apache.commons.logging.LogFactory;
|
||||
|
||||
/**
|
||||
* An interceptor that replaces files nodes with their equivalent
|
||||
* translations according to the locale. It is to be used with the
|
||||
* {@link FileFolderService}.
|
||||
*
|
||||
* @since 2.1
|
||||
* @author Derek Hulley
|
||||
*/
|
||||
public class MLTranslationInterceptor implements MethodInterceptor
|
||||
{
|
||||
/**
|
||||
* Names of methods that return a <code>List</code> or <code>FileInfo</code> instances.
|
||||
*/
|
||||
private static final Set<String> METHOD_NAMES_LIST;
|
||||
/**
|
||||
* Names of methods that return a <code>FileInfo</code>.
|
||||
*/
|
||||
private static final Set<String> METHOD_NAMES_SINGLE;
|
||||
/**
|
||||
* Names of methods that don't need interception. This is used to catch any new methods
|
||||
* added to the interface.
|
||||
*/
|
||||
private static final Set<String> METHOD_NAMES_OTHER;
|
||||
static
|
||||
{
|
||||
METHOD_NAMES_LIST = new HashSet<String>(13);
|
||||
METHOD_NAMES_LIST.add("list");
|
||||
METHOD_NAMES_LIST.add("listFiles");
|
||||
METHOD_NAMES_LIST.add("listFolders");
|
||||
METHOD_NAMES_LIST.add("search");
|
||||
METHOD_NAMES_LIST.add("getNamePath");
|
||||
|
||||
METHOD_NAMES_SINGLE = new HashSet<String>(13);
|
||||
METHOD_NAMES_SINGLE.add("searchSimple");
|
||||
METHOD_NAMES_SINGLE.add("rename");
|
||||
METHOD_NAMES_SINGLE.add("move");
|
||||
METHOD_NAMES_SINGLE.add("copy");
|
||||
METHOD_NAMES_SINGLE.add("create");
|
||||
METHOD_NAMES_SINGLE.add("makeFolders");
|
||||
METHOD_NAMES_SINGLE.add("getNamePath");
|
||||
METHOD_NAMES_SINGLE.add("resolveNamePath");
|
||||
METHOD_NAMES_SINGLE.add("getFileInfo");
|
||||
|
||||
METHOD_NAMES_OTHER = new HashSet<String>(13);
|
||||
METHOD_NAMES_OTHER.add("delete");
|
||||
METHOD_NAMES_OTHER.add("getReader");
|
||||
METHOD_NAMES_OTHER.add("getWriter");
|
||||
}
|
||||
|
||||
private static Log logger = LogFactory.getLog(MLTranslationInterceptor.class);
|
||||
|
||||
private NodeService nodeService;
|
||||
private MultilingualContentService multilingualContentService;
|
||||
|
||||
/**
|
||||
* Constructor.
|
||||
*/
|
||||
public MLTranslationInterceptor()
|
||||
{
|
||||
}
|
||||
|
||||
public void setNodeService(NodeService nodeService)
|
||||
{
|
||||
this.nodeService = nodeService;
|
||||
}
|
||||
|
||||
public void setMultilingualContentService(MultilingualContentService multilingualContentService)
|
||||
{
|
||||
this.multilingualContentService = multilingualContentService;
|
||||
}
|
||||
|
||||
/**
|
||||
* Converts the node referenice where an alternative translation should be used.
|
||||
*
|
||||
* @param nodeRef the basic nodeRef
|
||||
* @return Returns the replacement if required
|
||||
*/
|
||||
private NodeRef getTranslatedNodeRef(NodeRef nodeRef)
|
||||
{
|
||||
// Ignore null
|
||||
if (nodeRef == null)
|
||||
{
|
||||
return nodeRef;
|
||||
}
|
||||
// Ignore everything without the correct aspect
|
||||
if (!nodeService.hasAspect(nodeRef, ContentModel.ASPECT_MULTILINGUAL_DOCUMENT))
|
||||
{
|
||||
return nodeRef;
|
||||
}
|
||||
// Find the translation
|
||||
Map<Locale, NodeRef> translations = multilingualContentService.getTranslations(nodeRef);
|
||||
Locale filterLocale = I18NUtil.getContentLocaleOrNull();
|
||||
Set<Locale> possibleLocales = translations.keySet();
|
||||
Locale localeToUse = I18NUtil.getNearestLocale(filterLocale, possibleLocales);
|
||||
// Select the node
|
||||
NodeRef translatedNodeRef = translations.get(localeToUse);
|
||||
// Done
|
||||
if (logger.isDebugEnabled())
|
||||
{
|
||||
if (nodeRef.equals(translatedNodeRef))
|
||||
{
|
||||
logger.debug("NodeRef substitution: " + nodeRef + " --> " + translatedNodeRef);
|
||||
}
|
||||
else
|
||||
{
|
||||
logger.debug("NodeRef substitution: " + nodeRef + " (no change)");
|
||||
}
|
||||
}
|
||||
return nodeRef;
|
||||
}
|
||||
|
||||
/**
|
||||
* Converts the file info where an alternative translation should be used.
|
||||
*
|
||||
* @param fileInfo the basic file or folder info
|
||||
* @return Returns a replacement if required
|
||||
*
|
||||
* @see FileInfo#getTranslations()
|
||||
*/
|
||||
private FileInfo getTranslatedFileInfo(FileInfo fileInfo)
|
||||
{
|
||||
// Ignore null
|
||||
if (fileInfo == null)
|
||||
{
|
||||
return null;
|
||||
}
|
||||
// Ignore folders
|
||||
if (fileInfo.isFolder())
|
||||
{
|
||||
return fileInfo;
|
||||
}
|
||||
// Ignore files without translations
|
||||
Map<Locale, FileInfo> translations = fileInfo.getTranslations();
|
||||
if (translations.size() == 0)
|
||||
{
|
||||
return fileInfo;
|
||||
}
|
||||
// Get the locale to use
|
||||
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))
|
||||
{
|
||||
logger.debug("FileInfo substitution: " + fileInfo + " --> " + translatedFileInfo);
|
||||
}
|
||||
else
|
||||
{
|
||||
logger.debug("FileInfo substitution: " + fileInfo + " (no change)");
|
||||
}
|
||||
}
|
||||
return translatedFileInfo;
|
||||
}
|
||||
|
||||
@SuppressWarnings("unchecked")
|
||||
public Object invoke(MethodInvocation invocation) throws Throwable
|
||||
{
|
||||
Object ret = null;
|
||||
String methodName = invocation.getMethod().getName();
|
||||
|
||||
if (METHOD_NAMES_LIST.contains(methodName))
|
||||
{
|
||||
List<FileInfo> fileInfos = (List<FileInfo>) invocation.proceed();
|
||||
// Compile a set to ensure we don't get duplicates
|
||||
Map<FileInfo, FileInfo> translatedFileInfos = new HashMap<FileInfo, FileInfo>(17);
|
||||
for (FileInfo fileInfo : fileInfos)
|
||||
{
|
||||
FileInfo translatedFileInfo = getTranslatedFileInfo(fileInfo);
|
||||
// Add this to the set
|
||||
translatedFileInfos.put(fileInfo, translatedFileInfo);
|
||||
}
|
||||
// Convert the set back to a list
|
||||
List<FileInfo> orderedResults = new ArrayList<FileInfo>(fileInfos.size());
|
||||
for (FileInfo info : fileInfos)
|
||||
{
|
||||
orderedResults.add(translatedFileInfos.get(info));
|
||||
}
|
||||
ret = orderedResults;
|
||||
}
|
||||
else if (METHOD_NAMES_SINGLE.contains(methodName))
|
||||
{
|
||||
Object obj = invocation.proceed();
|
||||
if (obj instanceof FileInfo)
|
||||
{
|
||||
FileInfo fileInfo = (FileInfo) obj;
|
||||
ret = getTranslatedFileInfo(fileInfo);
|
||||
}
|
||||
else if (obj instanceof NodeRef)
|
||||
{
|
||||
NodeRef nodeRef = (NodeRef) obj;
|
||||
ret = getTranslatedNodeRef(nodeRef);
|
||||
}
|
||||
}
|
||||
else if (METHOD_NAMES_OTHER.contains(methodName))
|
||||
{
|
||||
// There is nothing to do
|
||||
ret = invocation.proceed();
|
||||
}
|
||||
else
|
||||
{
|
||||
throw new RuntimeException("Method not handled by interceptor: " + methodName);
|
||||
}
|
||||
|
||||
// Done
|
||||
return ret;
|
||||
}
|
||||
}
|
Reference in New Issue
Block a user