Phase one of merge of EC multilingual work

These files are their changes plus adjustments for formatting and immediate clashes
I anticipate that this will break the build, but there are too many changes coming to risk it.


git-svn-id: https://svn.alfresco.com/repos/alfresco-enterprise/alfresco/HEAD/root@5740 c4b6b30b-aa2e-2d43-bbcb-ca4b014f7261
This commit is contained in:
Derek Hulley
2007-05-22 04:47:14 +00:00
parent 2f68bf73da
commit 2e79d2e6d2
33 changed files with 3885 additions and 197 deletions

View File

@@ -101,7 +101,7 @@ public interface ContentModel
// copy aspect constants
static final QName ASPECT_COPIEDFROM = QName.createQName(NamespaceService.CONTENT_MODEL_1_0_URI, "copiedfrom");
static final QName PROP_COPY_REFERENCE = QName.createQName(NamespaceService.CONTENT_MODEL_1_0_URI, "source");
// working copy aspect contants
static final QName ASPECT_WORKING_COPY = QName.createQName(NamespaceService.CONTENT_MODEL_1_0_URI, "workingcopy");
static final QName PROP_WORKING_COPY_OWNER = QName.createQName(NamespaceService.CONTENT_MODEL_1_0_URI, "workingCopyOwner");
@@ -142,7 +142,7 @@ public interface ContentModel
public final static QName PROP_LOCK_OWNER = QName.createQName(NamespaceService.CONTENT_MODEL_1_0_URI, "lockOwner");
public final static QName PROP_LOCK_TYPE = QName.createQName(NamespaceService.CONTENT_MODEL_1_0_URI, "lockType");
public final static QName PROP_EXPIRY_DATE = QName.createQName(NamespaceService.CONTENT_MODEL_1_0_URI, "expiryDate");
// version aspect
static final QName ASPECT_VERSIONABLE = QName.createQName(NamespaceService.CONTENT_MODEL_1_0_URI, "versionable");
static final QName PROP_VERSION_LABEL = QName.createQName(NamespaceService.CONTENT_MODEL_1_0_URI, "versionLabel");
@@ -212,6 +212,7 @@ public interface ContentModel
static final QName TYPE_MULTILINGUAL_CONTAINER = QName.createQName(NamespaceService.CONTENT_MODEL_1_0_URI, "mlContainer");
static final QName ASSOC_MULTILINGUAL_CHILD = QName.createQName(NamespaceService.CONTENT_MODEL_1_0_URI, "mlChild");
static final QName ASPECT_MULTILINGUAL_DOCUMENT = QName.createQName(NamespaceService.CONTENT_MODEL_1_0_URI, "mlDocument");
static final QName ASPECT_MULTILINGUAL_EMPTY_TRANSLATION = QName.createQName(NamespaceService.CONTENT_MODEL_1_0_URI, "mlEmptyTranslation");
//
// User Model Definitions

View File

@@ -27,10 +27,13 @@ package org.alfresco.repo.content;
import java.io.Serializable;
import java.util.Collection;
import java.util.HashSet;
import java.util.List;
import java.util.Locale;
import java.util.Map;
import java.util.Set;
import org.alfresco.error.AlfrescoRuntimeException;
import org.alfresco.model.ContentModel;
import org.alfresco.repo.avm.AVMNodeConverter;
import org.alfresco.repo.content.ContentServicePolicies.OnContentReadPolicy;
import org.alfresco.repo.content.ContentServicePolicies.OnContentUpdatePolicy;
@@ -47,6 +50,7 @@ import org.alfresco.service.cmr.dictionary.DataTypeDefinition;
import org.alfresco.service.cmr.dictionary.DictionaryService;
import org.alfresco.service.cmr.dictionary.InvalidTypeException;
import org.alfresco.service.cmr.dictionary.PropertyDefinition;
import org.alfresco.service.cmr.repository.ChildAssociationRef;
import org.alfresco.service.cmr.repository.ContentData;
import org.alfresco.service.cmr.repository.ContentIOException;
import org.alfresco.service.cmr.repository.ContentReader;
@@ -59,6 +63,7 @@ import org.alfresco.service.cmr.repository.NodeService;
import org.alfresco.service.cmr.repository.StoreRef;
import org.alfresco.service.namespace.NamespaceService;
import org.alfresco.service.namespace.QName;
import org.alfresco.service.namespace.RegexQNamePattern;
import org.alfresco.service.transaction.TransactionService;
import org.alfresco.util.EqualsHelper;
import org.alfresco.util.Pair;
@@ -143,9 +148,9 @@ public class RoutingContentService implements ContentService
}
public void setPolicyComponent(PolicyComponent policyComponent)
{
this.policyComponent = policyComponent;
}
{
this.policyComponent = policyComponent;
}
public void setAvmService(AVMService service)
{
@@ -162,23 +167,23 @@ public class RoutingContentService implements ContentService
*/
public void init()
{
// Bind on update properties behaviour
this.policyComponent.bindClassBehaviour(
QName.createQName(NamespaceService.ALFRESCO_URI, "onUpdateProperties"),
this,
new JavaBehaviour(this, "onUpdateProperties"));
// Register on content update policy
this.onContentUpdateDelegate = this.policyComponent.registerClassPolicy(OnContentUpdatePolicy.class);
// Bind on update properties behaviour
this.policyComponent.bindClassBehaviour(
QName.createQName(NamespaceService.ALFRESCO_URI, "onUpdateProperties"),
this,
new JavaBehaviour(this, "onUpdateProperties"));
// Register on content update policy
this.onContentUpdateDelegate = this.policyComponent.registerClassPolicy(OnContentUpdatePolicy.class);
this.onContentReadDelegate = this.policyComponent.registerClassPolicy(OnContentReadPolicy.class);
}
/**
* Update properties policy behaviour
*
* @param nodeRef the node reference
* @param before the before values of the properties
* @param after the after values of the properties
* @param nodeRef the node reference
* @param before the before values of the properties
* @param after the after values of the properties
*/
public void onUpdateProperties(
NodeRef nodeRef,
@@ -274,7 +279,7 @@ public class RoutingContentService implements ContentService
}
private ContentReader getReader(NodeRef nodeRef, QName propertyQName, boolean fireContentReadPolicy)
{
{
ContentData contentData = null;
Serializable propValue = nodeService.getProperty(nodeRef, propertyQName);
if (propValue instanceof Collection)
@@ -293,8 +298,9 @@ public class RoutingContentService implements ContentService
if (contentData == null)
{
// if no value or a value other content, and a property definition has been provided, ensure that it's CONTENT or ANY
PropertyDefinition contentPropDef = dictionaryService.getProperty(propertyQName);
// if no value or a value other content, and a property definition has been provided, ensure that it's CONTENT or ANY
if (contentPropDef != null &&
(!(contentPropDef.getDataType().getName().equals(DataTypeDefinition.CONTENT) ||
contentPropDef.getDataType().getName().equals(DataTypeDefinition.ANY))))
@@ -310,8 +316,66 @@ public class RoutingContentService implements ContentService
// check that the URL is available
if (contentData == null || contentData.getContentUrl() == null)
{
// there is no URL - the interface specifies that this is not an error condition
return null;
// if the node is an empty translation, the reader must be the reader of its pivot translation
if(nodeService.hasAspect(nodeRef, ContentModel.ASPECT_MULTILINGUAL_DOCUMENT)
&& nodeService.hasAspect(nodeRef, ContentModel.ASPECT_MULTILINGUAL_EMPTY_TRANSLATION))
{
// NOTE : don't use the MultilingualContentService here because :
// A valid SecureContext can't be provided in the RequestContext
List<ChildAssociationRef> parentAssocRefs = nodeService.getParentAssocs(
nodeRef,
ContentModel.ASSOC_MULTILINGUAL_CHILD,
RegexQNamePattern.MATCH_ALL);
if (parentAssocRefs.size() == 1)
{
// Get the ml container and its locale
NodeRef container = parentAssocRefs.get(0).getParentRef();
Locale containerLocale = (Locale) nodeService.getProperty(container, ContentModel.PROP_LOCALE);
// Get each translation
List<ChildAssociationRef> assocRefs = nodeService.getChildAssocs(
container,
ContentModel.ASSOC_MULTILINGUAL_CHILD,
RegexQNamePattern.MATCH_ALL);
// found the pivot translation
NodeRef pivot = null;
for(ChildAssociationRef assoc : assocRefs)
{
pivot = assoc.getChildRef();
Locale pivotLocale = (Locale) nodeService.getProperty(pivot, ContentModel.PROP_LOCALE);
if(containerLocale.equals(pivotLocale))
{
break; // the pivot is set
}
else
{
pivot = null;
}
}
// returns the reader of this pivot translation if it's different to
// the node in parameter
if (pivot != null && !nodeRef.getId().equals(pivot.getId()))
{
return getReader(pivot, propertyQName, fireContentReadPolicy);
}
}
}
else
{
// there is no URL - the interface specifies that this is not an error condition
return null;
}
}
String contentUrl = contentData.getContentUrl();
@@ -541,4 +605,4 @@ public class RoutingContentService implements ContentService
}
}
}
}
}

View File

@@ -0,0 +1,119 @@
/*
* 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.List;
import org.alfresco.model.ContentModel;
import org.alfresco.repo.node.NodeServicePolicies;
import org.alfresco.repo.policy.JavaBehaviour;
import org.alfresco.repo.policy.PolicyComponent;
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.NamespaceService;
import org.alfresco.service.namespace.QName;
import org.alfresco.service.namespace.RegexQNamePattern;
/**
* Class containing behaviour for the folder type.
*
* {@link ContentModel#TYPE_FOLDER folder type}
*
* @author yanipig
*/
public class FolderType implements
NodeServicePolicies.BeforeDeleteNodePolicy
{
// Dependencies
private PolicyComponent policyComponent;
private NodeService nodeService;
/**
* Initialise the Folder type
*
* Ensures that the {@link ContentModel#TYPE_FOLDER} folder type
*/
public void init()
{
this.policyComponent.bindClassBehaviour(
QName.createQName(NamespaceService.ALFRESCO_URI, "beforeDeleteNode"),
ContentModel.TYPE_FOLDER,
new JavaBehaviour(this, "beforeDeleteNode"));
}
/**
* @param policyComponent the policy component to register behaviour with
*/
public void setPolicyComponent(PolicyComponent policyComponent)
{
this.policyComponent = policyComponent;
}
/**
* @param nodeService the Node Service to set
*/
public void setNodeService(NodeService nodeService)
{
this.nodeService = nodeService;
}
/**
* Since the multilingual document don't keep their <b>mlDocument</b> aspect, the <b>mlEmptyTranslation<b>
* can't be archived and the deletion of a container doesn't call the right policies, the deletion of a
* folder must explicitly remove this aspect.
*
* @see org.alfresco.repo.node.NodeServicePolicies.BeforeDeleteNodePolicy#beforeDeleteNode(org.alfresco.service.cmr.repository.NodeRef)
*/
public void beforeDeleteNode(NodeRef nodeRef)
{
List<ChildAssociationRef> childAssociations = nodeService.getChildAssocs(nodeRef, ContentModel.ASSOC_CONTAINS, RegexQNamePattern.MATCH_ALL);
for(ChildAssociationRef childAssoc : childAssociations)
{
NodeRef child = childAssoc.getChildRef();
if(nodeService.exists(child))
{
// Remove the mlDocument aspect of each multilingual node contained in the folder.
// The policies of this aspect perform the right logic.
if(nodeService.hasAspect(child, ContentModel.ASPECT_MULTILINGUAL_DOCUMENT))
{
nodeService.removeAspect(child, ContentModel.ASPECT_MULTILINGUAL_DOCUMENT);
}
// Recurse the process if needed
else if(nodeService.getType(child).equals(ContentModel.TYPE_FOLDER))
{
beforeDeleteNode(child);
}
}
}
}
}

View File

@@ -0,0 +1,114 @@
/*
* 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.Locale;
import org.alfresco.model.ContentModel;
import org.alfresco.repo.model.ml.tools.AbstractMultilingualTestCases;
import org.alfresco.service.cmr.repository.NodeRef;
/**
* Multilingual container type test cases
*
* @see org.alfresco.service.cmr.ml.MLContainerType
*
* @author yanipig
*/
public class FolderTypeTest extends AbstractMultilingualTestCases {
@SuppressWarnings("unused")
public void testRemoveSpace() throws Exception
{
NodeRef pivot = createContent();
NodeRef trans2 = createContent();
NodeRef trans3 = createContent();
NodeRef empty;
NodeRef mlContainer = multilingualContentService.makeTranslation(pivot, Locale.FRENCH);
multilingualContentService.addTranslation(trans2, pivot, Locale.GERMAN);
multilingualContentService.addTranslation(trans3, pivot, Locale.ITALIAN);;
empty = multilingualContentService.addEmptyTranslation(pivot, "Empty_" + System.currentTimeMillis(), Locale.ENGLISH);
NodeRef space = fileFolderService.create(
nodeService.getPrimaryParent(pivot).getParentRef(),
"folder_" + System.currentTimeMillis(),
ContentModel.TYPE_FOLDER).getNodeRef();
nodeService.moveNode(pivot, space, ContentModel.ASSOC_CONTAINS, this.nodeService.getPrimaryParent(pivot).getQName());
nodeService.moveNode(trans2, space, ContentModel.ASSOC_CONTAINS, this.nodeService.getPrimaryParent(trans2).getQName());
nodeService.moveNode(trans3, space, ContentModel.ASSOC_CONTAINS, this.nodeService.getPrimaryParent(trans3).getQName());
nodeService.moveNode(empty, space, ContentModel.ASSOC_CONTAINS, this.nodeService.getPrimaryParent(empty).getQName());
// Ensure that the nodes are correctly moved
assertEquals("Move nodes failed", 4, nodeService.getChildAssocs(space).size());
// 1. Delete space
nodeService.deleteNode(space);
// Ensute that the space is deleted
assertFalse("The deletion of the space failed", nodeService.exists(space));
// Ensure that the nodes are archived
assertTrue("The space " + space + " must be archived", nodeService.exists(nodeArchiveService.getArchivedNode(trans2)));
assertTrue("The node " + pivot + " must be archived", nodeService.exists(nodeArchiveService.getArchivedNode(pivot)));
assertTrue("The node " + trans2 + " must be archived", nodeService.exists(nodeArchiveService.getArchivedNode(trans2)));
assertTrue("The node " + trans3 + " must be archived", nodeService.exists(nodeArchiveService.getArchivedNode(trans3)));
// Ensure that the mlContainer is deleted and not archived
assertFalse("The mlContainer " + mlContainer + " must be deleted", nodeService.exists(mlContainer));
assertFalse("The mlContainer " + mlContainer + " can't be archived", nodeService.exists(nodeArchiveService.getArchivedNode(mlContainer)));
// 2. Restore space
nodeArchiveService.restoreArchivedNode(nodeArchiveService.getArchivedNode(space));
// Ensure that the nodes are restaured
assertFalse("The space " + space + "must be restored", nodeService.exists(nodeArchiveService.getArchivedNode(space)));
assertFalse("The node " + pivot + "must be restored", nodeService.exists(nodeArchiveService.getArchivedNode(pivot)));
assertFalse("The node " + trans2 + "must be restored", nodeService.exists(nodeArchiveService.getArchivedNode(trans2)));
assertFalse("The node " + trans3 + "must be restored", nodeService.exists(nodeArchiveService.getArchivedNode(trans3)));
// Ensure that the mlContainer is not restored
assertFalse("The mlContainer " + mlContainer + " must be deleted and can't be restored", nodeService.exists(mlContainer));
// 3. Delete space and remove it from the arhives
nodeService.deleteNode(space);
nodeService.deleteNode(nodeArchiveService.getArchivedNode(space));
assertFalse("The space " + space + "can't be archived", nodeService.exists(nodeArchiveService.getArchivedNode(space)));
assertFalse("The node " + pivot + "can't be archived", nodeService.exists(nodeArchiveService.getArchivedNode(pivot)));
assertFalse("The node " + trans2 + "can't be archived", nodeService.exists(nodeArchiveService.getArchivedNode(trans2)));
assertFalse("The node " + trans3 + "can't be archived", nodeService.exists(nodeArchiveService.getArchivedNode(trans3)));
assertFalse("The space " + space + "must be deleted", nodeService.exists(space));
assertFalse("The node " + pivot + "must be deleted", nodeService.exists(pivot));
assertFalse("The node " + trans2 + "must be deleted", nodeService.exists(trans2));
assertFalse("The node " + trans3 + "must be deleted", nodeService.exists(trans3));
}
}

View File

@@ -0,0 +1,268 @@
/*
* 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 java.util.ArrayList;
import java.util.Collections;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import org.alfresco.config.Config;
import org.alfresco.config.ConfigElement;
import org.alfresco.config.ConfigLookupContext;
import org.alfresco.config.ConfigService;
import org.alfresco.error.AlfrescoRuntimeException;
import org.alfresco.i18n.I18NUtil;
import org.alfresco.service.cmr.ml.ContentFilterLanguagesService;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
/**
* Provides a an implementation of the <b>Content Filter Languages Service</b>
*
* {@link org.alfresco.service.cmr.ml.ContentFilterLanguagesService Content Filter Languages Service}
*
* @author yanipig
*/
public class ContentFilterLanguagesMap implements ContentFilterLanguagesService
{
private static final String CONFIG_AREA = "content-filter-lang";
private static final String CONFIG_CONDITION = "Languages Filter Map";
private static final String USED_STANDARD_CONFIG_CONDITION = "Standard In Use";
private static final String USED_STANDARD_ELEMENT = "standard";
private static final String DEFAULT_LANGUAGE_LIST_STANDARD = "ISO 639-1";
private static final String ATTR_CODE = "code";
private static final String ATTR_ORDER = "order";
private static final String ATTR_DEFAULT = "default";
private static final Log logger = LogFactory.getLog(ContentFilterLanguagesMap.class);
private ConfigService configService;
private List<String> orderedLangCodes;
private Map<String, String> languagesByCode;
private String defaultLanguage = null;
/**
* @param configService the config service to use to read languages
*/
public ContentFilterLanguagesMap(ConfigService configService)
{
this.configService = configService;
}
/* (non-Javadoc)
* @see org.alfresco.service.cmr.ml.ContentFilterLanguagesService#getFilterLanguages()
*/
public List<String> getFilterLanguages()
{
return orderedLangCodes;
}
/* (non-Javadoc)
* @see org.alfresco.service.cmr.ml.ContentFilterLanguagesService#getMissingLanguages(java.util.List)
*/
public List<String> getMissingLanguages(List<String> availableLanguages)
{
if(availableLanguages == null || availableLanguages.size() == 0)
{
return orderedLangCodes;
}
List<String> returnList = new ArrayList<String>(orderedLangCodes.size() - availableLanguages.size());
int index = 0;
for(String lang : orderedLangCodes)
{
if(!availableLanguages.contains(lang))
{
returnList.add(index, lang);
index ++;
}
}
return returnList;
}
/* (non-Javadoc)
* @see org.alfresco.service.cmr.ml.ContentFilterLanguagesService#getLabelByCode(java.lang.String)
*/
public String getLabelByCode(String code)
{
// get the translated language label
String label;
label = I18NUtil.getMessage(MESSAGE_PREFIX + code);
// if not found, get the default name (found in content-filter-lang.xml)
if(label == null || label.length() == 0)
{
label = languagesByCode.get(code);
}
// if not found, return the language code
if(label == null || label.length() == 0)
{
label = code + " (label not found)";
}
return label;
}
/* (non-Javadoc)
* @see org.alfresco.service.cmr.ml.ContentFilterLanguagesService#getOrderByCode(java.lang.String)
*/
public int getOrderByCode(String code)
{
if (orderedLangCodes.contains(code))
{
return orderedLangCodes.indexOf(code);
}
else
{
throw new AlfrescoRuntimeException("Language code not found : " + code);
}
}
public String getDefaultLanguage()
{
return this.defaultLanguage ;
}
/**
* Initialises the map using the configuration service provided
*/
public void init()
{
ConfigLookupContext clContext = new ConfigLookupContext(CONFIG_AREA);
// get which standart is defined by the user (ISO 639-1 by default)
String standard = DEFAULT_LANGUAGE_LIST_STANDARD;
Config configStandard = configService.getConfig(USED_STANDARD_CONFIG_CONDITION, clContext);
if(configStandard != null
&& configStandard.getConfigElement(USED_STANDARD_ELEMENT) != null)
{
standard = configStandard.getConfigElement(USED_STANDARD_ELEMENT).getValue();
}
else
{
logger.warn("No standard configured, use by default : " + DEFAULT_LANGUAGE_LIST_STANDARD);
}
Config configConditions = configService.getConfig(CONFIG_CONDITION, clContext);
Map<String, ConfigElement> configElements = configConditions.getConfigElements();
ConfigElement configLanguages = null;
// get the list of languages of the matched standard
if(configElements.containsKey(standard))
{
configLanguages = configElements.get(standard);
}
// if the santard is not matched, get the first list
else
{
configLanguages = configElements.values().iterator().next();
logger.warn("Ignoring prefered standard doesn't found, choose : " + configLanguages.getName());
}
List<ConfigElement> languages = configLanguages.getChildren();
// get the size of the lists
int listSize = languages.size();
this.orderedLangCodes = new ArrayList<String>(listSize);
this.languagesByCode = new HashMap<String, String>(listSize);
// construct the languages map and list
for (ConfigElement langElem : languages)
{
String code = convertToOldISOCode(langElem.getAttribute(ATTR_CODE));
String order = langElem.getAttribute(ATTR_ORDER);
String value = langElem.getValue();
String def = langElem.getAttribute(ATTR_DEFAULT);
orderedLangCodes.add(Integer.parseInt(order) - 1, code);
languagesByCode.put(code, value);
if(def != null && Boolean.parseBoolean(def))
{
if(defaultLanguage != null)
{
logger.warn("Ignoring default attribute is not unique le last matched will be used");
}
this.defaultLanguage = code;
}
}
// make the collections read-only
this.orderedLangCodes = Collections.unmodifiableList(this.orderedLangCodes);
this.languagesByCode = Collections.unmodifiableMap(this.languagesByCode);
}
/* (non-Javadoc)
* @see org.alfresco.service.cmr.ml.ContentFilterLanguagesService#convertToOldISOCode(java.lang.String)
*/
public String convertToOldISOCode(String code)
{
if(code.equalsIgnoreCase("he"))
code = "iw";
else if(code.equalsIgnoreCase("id"))
code = "in";
else if(code.equalsIgnoreCase("yi"))
code = "ji";
return code;
}
/* (non-Javadoc)
* @see org.alfresco.service.cmr.ml.ContentFilterLanguagesService#convertToNewISOCode(java.lang.String)
*/
public String convertToNewISOCode(String code) {
if(code.equalsIgnoreCase("iw"))
code = "he";
else if(code.equalsIgnoreCase("in"))
code = "id";
else if(code.equalsIgnoreCase("ji"))
code = "yi";
return code;
}
}

View File

@@ -0,0 +1,160 @@
/*
* 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.repo.content.ContentServicePolicies;
import org.alfresco.repo.copy.CopyServicePolicies;
import org.alfresco.repo.node.NodeServicePolicies;
import org.alfresco.repo.policy.JavaBehaviour;
import org.alfresco.repo.policy.PolicyComponent;
import org.alfresco.repo.policy.PolicyScope;
import org.alfresco.service.cmr.repository.ContentData;
import org.alfresco.service.cmr.repository.NodeRef;
import org.alfresco.service.cmr.repository.NodeService;
import org.alfresco.service.cmr.repository.StoreRef;
import org.alfresco.service.namespace.NamespaceService;
import org.alfresco.service.namespace.QName;
/**
* Class containing behaviour for the multilingual empty translation aspect.
* An empty translation is a document's properties translation. This kind of node
* doesn't have a content.
*
* {@link ContentModel#ASPECT_MULTILINGUAL_EMPTY_TRANSLATION ml empty document aspect}
*
* @author yanipig
*/
public class EmptyTranslationAspect implements
CopyServicePolicies.OnCopyNodePolicy,
NodeServicePolicies.BeforeDeleteNodePolicy,
NodeServicePolicies.OnRemoveAspectPolicy,
ContentServicePolicies.OnContentUpdatePolicy
{
// Dependencies
private PolicyComponent policyComponent;
private NodeService nodeService;
/**
* Initialise the Multilingual Empty Translation Aspect
* <p>
* Ensures that the {@link ContentModel#ASPECT_MULTILINGUAL_EMPTY_TRANSLATION ml empty document aspect}
*/
public void init()
{
this.policyComponent.bindClassBehaviour(
QName.createQName(NamespaceService.ALFRESCO_URI, "onCopyNode"),
ContentModel.ASPECT_MULTILINGUAL_EMPTY_TRANSLATION,
new JavaBehaviour(this, "onCopyNode"));
this.policyComponent.bindClassBehaviour(
QName.createQName(NamespaceService.ALFRESCO_URI, "onContentUpdate"),
ContentModel.ASPECT_MULTILINGUAL_EMPTY_TRANSLATION,
new JavaBehaviour(this, "onContentUpdate"));
this.policyComponent.bindClassBehaviour(
QName.createQName(NamespaceService.ALFRESCO_URI, "beforeDeleteNode"),
ContentModel.ASPECT_MULTILINGUAL_EMPTY_TRANSLATION,
new JavaBehaviour(this, "beforeDeleteNode"));
this.policyComponent.bindClassBehaviour(
QName.createQName(NamespaceService.ALFRESCO_URI, "onRemoveAspect"),
ContentModel.ASPECT_MULTILINGUAL_EMPTY_TRANSLATION,
new JavaBehaviour(this, "onRemoveAspect"));
}
/**
* @param policyComponent the policy component to register behaviour with
*/
public void setPolicyComponent(PolicyComponent policyComponent)
{
this.policyComponent = policyComponent;
}
/**
* @param nodeService the Node Service to set
*/
public void setNodeService(NodeService nodeService)
{
this.nodeService = nodeService;
}
/**
* Copy a <b>cm:mlEmptyTranslation<b> is not permit.
*
* @see org.alfresco.repo.copy.CopyServicePolicies.OnCopyNodePolicy#onCopyNode(org.alfresco.service.namespace.QName, org.alfresco.service.cmr.repository.NodeRef, org.alfresco.service.cmr.repository.StoreRef, boolean, org.alfresco.repo.policy.PolicyScope)
*/
public void onCopyNode(QName classRef, NodeRef sourceNodeRef, StoreRef destinationStoreRef, boolean copyToNewNode, PolicyScope copyDetails)
{
throw new IllegalStateException("It's impossible to copy an empty translation");
}
/**
* If a content is added to a <b>cm:mlEmptyTranslation<b>, remove this aspect.
*
* @see org.alfresco.repo.content.ContentServicePolicies.OnContentUpdatePolicy#onContentUpdate(org.alfresco.service.cmr.repository.NodeRef, boolean)
*/
public void onContentUpdate(NodeRef nodeRef, boolean newContent)
{
if(newContent)
{
nodeService.removeAspect(nodeRef, ContentModel.ASPECT_MULTILINGUAL_EMPTY_TRANSLATION);
}
}
/**
* If a <b>cm:mlEmptyTranslation<b> is deleted, it can't be archived.
*
* @see org.alfresco.repo.node.NodeServicePolicies.BeforeDeleteNodePolicy#beforeDeleteNode(org.alfresco.service.cmr.repository.NodeRef)
*/
public void beforeDeleteNode(NodeRef nodeRef)
{
// add TEMPORARY ASPECT to force the deleteNode
nodeService.addAspect(nodeRef, ContentModel.ASPECT_TEMPORARY, null);
}
/**
* If the aspect <b>cm:mlEmptyTranslation<b> is removed <b>and the content url property is null</b>, the node can't be store much time.
*
* @see org.alfresco.repo.node.NodeServicePolicies.OnRemoveAspectPolicy#onRemoveAspect(org.alfresco.service.cmr.repository.NodeRef, org.alfresco.service.namespace.QName) *
*/
public void onRemoveAspect(NodeRef nodeRef, QName aspectTypeQName)
{
// if the node is updated, the URL will not be null and the rome aspect don't delete
// the translation. It will be a simple mlDocument.
if(aspectTypeQName.equals(ContentModel.ASPECT_MULTILINGUAL_EMPTY_TRANSLATION)
&& ((ContentData) nodeService.getProperty(nodeRef, ContentModel.PROP_CONTENT)).getContentUrl() == null)
{
// add TEMPORARY ASPECT to force the deleteNode
nodeService.addAspect(nodeRef, ContentModel.ASPECT_TEMPORARY, null);
nodeService.deleteNode(nodeRef);
}
}
}

View File

@@ -0,0 +1,172 @@
/*
* 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 java.io.Serializable;
import java.util.Locale;
import java.util.Map;
import org.alfresco.model.ContentModel;
import org.alfresco.repo.node.NodeServicePolicies;
import org.alfresco.repo.policy.JavaBehaviour;
import org.alfresco.repo.policy.PolicyComponent;
import org.alfresco.service.cmr.ml.MultilingualContentService;
import org.alfresco.service.cmr.repository.NodeRef;
import org.alfresco.service.cmr.repository.NodeService;
import org.alfresco.service.namespace.NamespaceService;
import org.alfresco.service.namespace.QName;
/**
* Class containing behaviour for the multilingual multilingual container type.
* A multilingual container type is fonctionally named '<b>Logical Document</b>'.
* It links each translation of a semantical message together
*
* {@link ContentModel#TYPE_MULTILINGUAL_CONTAINER multilingual container type}
*
* @author yanipig
*/
public class MLContainerType implements
NodeServicePolicies.BeforeDeleteNodePolicy,
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 NodeService nodeService;
private MultilingualContentService multilingualContentService;
/**
* Initialise the Multilingual Container Type
* <p>
* Ensures that the {@link ContentModel#ASPECT_MULTILINGUAL_EMPTY_TRANSLATION ml empty document aspect}
*/
public void init()
{
this.policyComponent.bindClassBehaviour(
QName.createQName(NamespaceService.ALFRESCO_URI, "onUpdateProperties"),
ContentModel.TYPE_MULTILINGUAL_CONTAINER,
new JavaBehaviour(this, "onUpdateProperties"));
this.policyComponent.bindClassBehaviour(
QName.createQName(NamespaceService.ALFRESCO_URI, "beforeDeleteNode"),
ContentModel.TYPE_MULTILINGUAL_CONTAINER,
new JavaBehaviour(this, "beforeDeleteNode"));
}
/**
* @param policyComponent the policy component to register behaviour with
*/
public void setPolicyComponent(PolicyComponent policyComponent)
{
this.policyComponent = policyComponent;
}
/**
* @param multilingualContentService the Multilingual Content Service to set
*/
public void setMultilingualContentService(
MultilingualContentService multilingualContentService)
{
this.multilingualContentService = multilingualContentService;
}
/**
* @param nodeService the Node Service to set
*/
public void setNodeService(NodeService nodeService)
{
this.nodeService = nodeService;
}
/**
* If a <b>cm:mlContainer<b> is deleted, it can't be archived.
*
* @see org.alfresco.repo.node.NodeServicePolicies.BeforeDeleteNodePolicy#beforeDeleteNode(org.alfresco.service.cmr.repository.NodeRef)
*/
public void beforeDeleteNode(NodeRef nodeRef)
{
Map<Locale, NodeRef> translations = multilingualContentService.getTranslations(nodeRef);
// add the DELETION_RUNNING property
nodeService.setProperty(nodeRef, PROP_NAME_DELETION_RUNNING, new Boolean(true));
for(Map.Entry<Locale, NodeRef> entry : translations.entrySet())
{
nodeService.removeAspect(entry.getValue(), ContentModel.ASPECT_MULTILINGUAL_DOCUMENT);
}
// remove the DELETION_RUNNING property
Map<QName, Serializable> prop = nodeService.getProperties(nodeRef);
prop.remove(PROP_NAME_DELETION_RUNNING);
nodeService.setProperties(nodeRef, prop);
}
/**
* The property <b>locale</b> of a <b>cm:mlContainer</b> represents the locale of the pivot translation.
*
* Since the pivot must be an existing translation and the pivot can t be empty, some tests must be performed when
* the locale of the mlContainer is updated.
*
* @see org.alfresco.repo.node.NodeServicePolicies.OnUpdatePropertiesPolicy#onUpdateProperties(org.alfresco.service.cmr.repository.NodeRef, java.util.Map, java.util.Map)
*/
public void onUpdateProperties(NodeRef nodeRef, Map<QName, Serializable> before, Map<QName, Serializable> after)
{
Locale localeAfter = (Locale) after.get(ContentModel.PROP_LOCALE);
Locale localeBefore = (Locale) before.get(ContentModel.PROP_LOCALE);
// The locale can be set as null if the container have no children.
// Normaly, it's ONLY the case at the creation of the container.
if(localeAfter == null && nodeService.getChildAssocs(nodeRef).size() != 0)
{
throw new IllegalArgumentException("A Locale property must be defined for a Multilingual Container and can't be null");
}
if(localeAfter != null && !localeAfter.equals(localeBefore))
{
Map<Locale, NodeRef> translations = multilingualContentService.getTranslations(nodeRef);
//get the new pivot translation
NodeRef pivot = translations.get(localeAfter);
if(pivot == null)
{
throw new IllegalArgumentException("The pivot translation must be an existing translation");
}
else if(nodeService.hasAspect(pivot, ContentModel.ASPECT_MULTILINGUAL_EMPTY_TRANSLATION))
{
throw new IllegalArgumentException("The pivot translation can't be an empty translation");
}
}
}
}

View File

@@ -15,15 +15,17 @@
* 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:
* 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 java.io.Serializable;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Locale;
@@ -33,8 +35,12 @@ import java.util.Set;
import org.alfresco.error.AlfrescoRuntimeException;
import org.alfresco.i18n.I18NUtil;
import org.alfresco.model.ContentModel;
import org.alfresco.repo.version.VersionModel;
import org.alfresco.service.cmr.ml.ContentFilterLanguagesService;
import org.alfresco.service.cmr.ml.MultilingualContentService;
import org.alfresco.service.cmr.model.FileFolderService;
import org.alfresco.service.cmr.repository.ChildAssociationRef;
import org.alfresco.service.cmr.repository.ContentData;
import org.alfresco.service.cmr.repository.NodeRef;
import org.alfresco.service.cmr.repository.NodeService;
import org.alfresco.service.cmr.repository.StoreRef;
@@ -52,19 +58,22 @@ import org.apache.commons.logging.LogFactory;
/**
* Multilingual support implementation
*
*
* @author Derek Hulley
* @author Philippe Dubois
* @author yanipig
*/
public class MultilingualContentServiceImpl implements MultilingualContentService
{
private static Log logger = LogFactory.getLog(MultilingualContentServiceImpl.class);
private NodeService nodeService;
private SearchService searchService;
private VersionService versionService;
private SearchParameters searchParametersMLRoot;
private ContentFilterLanguagesService contentFilterLanguagesService;
private FileFolderService fileFolderService;
public MultilingualContentServiceImpl()
{
searchParametersMLRoot = new SearchParameters();
@@ -73,27 +82,7 @@ public class MultilingualContentServiceImpl implements MultilingualContentServic
searchParametersMLRoot.addStore(new StoreRef(StoreRef.PROTOCOL_WORKSPACE, "SpacesStore"));
searchParametersMLRoot.setQuery("/cm:multilingualRoot");
}
public void setNodeService(NodeService nodeService)
{
this.nodeService = nodeService;
}
public void setSearchService(SearchService searchService)
{
this.searchService = searchService;
}
public void setVersionService(VersionService versionService)
{
this.versionService = versionService;
}
public void renameWithMLExtension(NodeRef translationNodeRef)
{
throw new UnsupportedOperationException();
}
/**
* @return Returns a reference to the node that will hold all the <b>cm:mlContainer</b> nodes.
*/
@@ -119,7 +108,7 @@ public class MultilingualContentServiceImpl implements MultilingualContentServic
rs.close();
}
}
private static final QName QNAME_ML_CONTAINER = QName.createQName(NamespaceService.CONTENT_MODEL_1_0_URI, "mlContainer");
private static final QName QNAME_ML_TRANSLATION = QName.createQName(NamespaceService.CONTENT_MODEL_1_0_URI, "mlTranslation");
/**
@@ -137,11 +126,11 @@ public class MultilingualContentServiceImpl implements MultilingualContentServic
// done
return assocRef.getChildRef();
}
/**
* Retrieve or create a <b>cm:mlDocument</b> container for the given node, which must have the
* <b>cm:mlDocument</b> already applied.
*
*
* @param mlDocumentNodeRef an existing <b>cm:mlDocument</b>
* @param allowCreate <tt>true</tt> if a <b>cm:mlContainer</b> must be created if on doesn't exist,
* otherwise <tt>false</tt> if a parent <b>cm:mlContainer</b> is expected to exist.
@@ -225,12 +214,15 @@ public class MultilingualContentServiceImpl implements MultilingualContentServic
// The aspect is present, so just ensure that the locale is correct
nodeService.setProperty(contentNodeRef, ContentModel.PROP_LOCALE, locale);
}
// Do we make use of an existing container?
if (mlContainerNodeRef == null)
{
// Make one
mlContainerNodeRef = getOrCreateMLContainer(contentNodeRef, true);
// set the pivot language
nodeService.setProperty(mlContainerNodeRef, ContentModel.PROP_LOCALE, locale);
}
else
{
@@ -240,7 +232,7 @@ public class MultilingualContentServiceImpl implements MultilingualContentServic
{
throw new AlfrescoRuntimeException("Duplicate locale in document pool: " + locale);
}
// Use the existing container
nodeService.addChild(
mlContainerNodeRef,
@@ -248,6 +240,7 @@ public class MultilingualContentServiceImpl implements MultilingualContentServic
ContentModel.ASSOC_MULTILINGUAL_CHILD,
QNAME_ML_TRANSLATION);
}
// done
return mlContainerNodeRef;
}
@@ -266,7 +259,7 @@ public class MultilingualContentServiceImpl implements MultilingualContentServic
}
return mlContainerNodeRef;
}
/** @inheritDoc */
public NodeRef addTranslation(NodeRef newTranslationNodeRef, NodeRef translationOfNodeRef, Locale locale)
{
@@ -307,7 +300,7 @@ public class MultilingualContentServiceImpl implements MultilingualContentServic
/** @inheritDoc */
public void createEdition( NodeRef translationNodeRef)
{
NodeRef mlContainerNodeRef = getOrCreateMLContainer(translationNodeRef, false);
NodeRef mlContainerNodeRef = getOrCreateMLContainer(translationNodeRef, false);
// Ensure that the translation given is one of the children
getOrCreateMLContainer(translationNodeRef, false);
// Get all the container's children
@@ -315,8 +308,25 @@ public class MultilingualContentServiceImpl implements MultilingualContentServic
mlContainerNodeRef,
ContentModel.ASSOC_MULTILINGUAL_CHILD,
RegexQNamePattern.MATCH_ALL);
// Version the container and all its children
versionService.createVersion(mlContainerNodeRef, null, true);
// Get and store the translation verions associated to the mlContainer
List<Version> versions = new ArrayList<Version>(childAssocRefs.size());
for (ChildAssociationRef childAssoc : childAssocRefs)
{
versions.add(versionService.getCurrentVersion(childAssoc.getChildRef()));
}
Map<String, Serializable> editionProperties = new HashMap<String, Serializable>();
editionProperties.put(
VersionModel.PROP_QNAME_TRANSLATION_VERIONS.toString(),
(Serializable) versions
);
// Version the container and all its children
versionService.createVersion(mlContainerNodeRef, editionProperties, true);
// Remove all the child documents apart from the given node
boolean found = false;
for (ChildAssociationRef childAssoc : childAssocRefs)
@@ -416,4 +426,173 @@ public class MultilingualContentServiceImpl implements MultilingualContentServic
}
return nearestNodeRef;
}
}
/** @inheritDoc */
public List<Locale> getMissingTranslations(NodeRef localizedNodeRef, boolean addThisNodeLocale)
{
List<Locale> foundLocales = new ArrayList<Locale>(getTranslations(localizedNodeRef).keySet());
List<String> foundLanguages = new ArrayList<String>();
// transform locales into languages codes
for(Locale locale : foundLocales)
{
foundLanguages.add(locale.getLanguage());
}
// add the locale of the given node if required
if(addThisNodeLocale)
{
Locale localeNode = (Locale) nodeService.getProperty(localizedNodeRef, ContentModel.PROP_LOCALE);
if(localeNode != null)
{
foundLanguages.remove(localeNode.toString());
}
else
{
logger.warn("No locale found for the node " + localizedNodeRef);
}
}
List<String> missingLanguages = null;
if(foundLanguages.size() == 0)
{
// The given node is the only one available translation and it must
// be return.
// MissingLanguages become the entire list pf languages.
missingLanguages = contentFilterLanguagesService.getFilterLanguages();
}
else
{
// get the missing languages form the list of content filter languages
missingLanguages = contentFilterLanguagesService.getMissingLanguages(foundLanguages);
}
// construct a list of locales
List<Locale> missingLocales = new ArrayList<Locale>(missingLanguages.size() + 1);
for(String lang : missingLanguages)
{
missingLocales.add(I18NUtil.parseLocale(lang));
}
return missingLocales;
}
/** @inheritDoc */
public NodeRef getPivotTranslation(NodeRef nodeRef)
{
if(nodeService.hasAspect(nodeRef, ContentModel.ASPECT_MULTILINGUAL_DOCUMENT))
{
NodeRef container = getTranslationContainer(nodeRef);
Locale containerLocale = (Locale) nodeService.getProperty(container, ContentModel.PROP_LOCALE);
return getTranslationForLocale(nodeRef, containerLocale);
}
else if(ContentModel.TYPE_MULTILINGUAL_CONTAINER.equals(nodeService.getType(nodeRef)))
{
Locale containerLocale = (Locale) nodeService.getProperty(nodeRef, ContentModel.PROP_LOCALE);
return getTranslationForLocale(getTranslations(nodeRef).get(containerLocale), containerLocale);
}
else
{
logger.warn("The node is not multilingual " + nodeRef);
return null;
}
}
/**
* @inheritDoc */
public NodeRef addEmptyTranslation(NodeRef translationOfNodeRef, String name, Locale locale)
{
// any node used as reference
NodeRef anyTranslation;
// the empty document to create
NodeRef newTranslationNodeRef = null;
QName typeQName = nodeService.getType(translationOfNodeRef);
if (typeQName.equals(ContentModel.TYPE_MULTILINGUAL_CONTAINER))
{
// Set the ml container ans get the pivot
anyTranslation = getPivotTranslation(translationOfNodeRef);
}
else if(nodeService.hasAspect(translationOfNodeRef, ContentModel.ASPECT_MULTILINGUAL_DOCUMENT))
{
anyTranslation = translationOfNodeRef;
}
else
{
throw new IllegalArgumentException(
"Node must have aspect " + ContentModel.ASPECT_MULTILINGUAL_DOCUMENT + " applied or be a " + ContentModel.TYPE_MULTILINGUAL_CONTAINER);
}
// Create the document in the space of the node of reference
NodeRef parentNodeRef = nodeService.getPrimaryParent(anyTranslation).getParentRef();
newTranslationNodeRef = fileFolderService.create(
parentNodeRef,
name,
ContentModel.TYPE_CONTENT).getNodeRef();
// add the translation to the container
addTranslation(newTranslationNodeRef, translationOfNodeRef, locale);
// set it empty
nodeService.addAspect(newTranslationNodeRef, ContentModel.ASPECT_MULTILINGUAL_EMPTY_TRANSLATION, null);
// get the extension and set the ContentData property with an null URL.
String extension = "";
int dotIdx;
if((dotIdx = name.lastIndexOf(".")) > -1 )
{
extension = name.substring(dotIdx);
}
nodeService.setProperty(newTranslationNodeRef, ContentModel.PROP_CONTENT,
new ContentData(null, extension, 0, "UTF-8", locale));
if (logger.isDebugEnabled())
{
logger.debug("Added an empty translation: \n" +
" Translation of: " + translationOfNodeRef + " of type " + typeQName + "\n" +
" New translation: " + newTranslationNodeRef + "\n" +
" Locale: " + locale);
}
return newTranslationNodeRef;
}
public void setNodeService(NodeService nodeService)
{
this.nodeService = nodeService;
}
public void setSearchService(SearchService searchService)
{
this.searchService = searchService;
}
public void setVersionService(VersionService versionService)
{
this.versionService = versionService;
}
public void setContentFilterLanguagesService(ContentFilterLanguagesService contentFilterLanguagesService)
{
this.contentFilterLanguagesService = contentFilterLanguagesService;
}
public void setFileFolderService(FileFolderService fileFolderService)
{
this.fileFolderService = fileFolderService;
}
public void renameWithMLExtension(NodeRef translationNodeRef)
{
throw new UnsupportedOperationException();
}
}

View File

@@ -0,0 +1,305 @@
/*
* 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 java.io.Serializable;
import java.util.Locale;
import java.util.Map;
import org.alfresco.i18n.I18NUtil;
import org.alfresco.model.ContentModel;
import org.alfresco.repo.copy.CopyServicePolicies;
import org.alfresco.repo.node.NodeServicePolicies;
import org.alfresco.repo.policy.JavaBehaviour;
import org.alfresco.repo.policy.PolicyComponent;
import org.alfresco.repo.policy.PolicyScope;
import org.alfresco.service.cmr.ml.MultilingualContentService;
import org.alfresco.service.cmr.repository.NodeRef;
import org.alfresco.service.cmr.repository.NodeService;
import org.alfresco.service.cmr.repository.StoreRef;
import org.alfresco.service.namespace.NamespaceService;
import org.alfresco.service.namespace.QName;
import org.alfresco.service.namespace.RegexQNamePattern;
/**
* Class containing behaviour for the multilingual document aspect.
*
* {@link ContentModel#ASPECT_MULTILINGUAL_DOCUMENT ml document aspect}
*
* @author yanipig
*/
public class MultilingualDocumentAspect implements
CopyServicePolicies.OnCopyNodePolicy,
CopyServicePolicies.OnCopyCompletePolicy,
NodeServicePolicies.BeforeDeleteNodePolicy,
NodeServicePolicies.BeforeRemoveAspectPolicy,
NodeServicePolicies.OnRemoveAspectPolicy,
NodeServicePolicies.OnUpdatePropertiesPolicy
{
// Dependencies
private PolicyComponent policyComponent;
private MultilingualContentService multilingualContentService;
private NodeService nodeService;
/**
* Initialise the Multilingual Aspect
*
* Ensures that the {@link ContentModel#ASPECT_MULTILINGUAL_DOCUMENT ml document aspect}
*/
public void init()
{
this.policyComponent.bindClassBehaviour(
QName.createQName(NamespaceService.ALFRESCO_URI, "onCopyNode"),
ContentModel.ASPECT_MULTILINGUAL_DOCUMENT,
new JavaBehaviour(this, "onCopyNode"));
this.policyComponent.bindClassBehaviour(
QName.createQName(NamespaceService.ALFRESCO_URI, "beforeDeleteNode"),
ContentModel.ASPECT_MULTILINGUAL_DOCUMENT,
new JavaBehaviour(this, "beforeDeleteNode"));
this.policyComponent.bindClassBehaviour(
QName.createQName(NamespaceService.ALFRESCO_URI, "beforeRemoveAspect"),
ContentModel.ASPECT_MULTILINGUAL_DOCUMENT,
new JavaBehaviour(this, "beforeRemoveAspect"));
this.policyComponent.bindClassBehaviour(
QName.createQName(NamespaceService.ALFRESCO_URI, "onUpdateProperties"),
ContentModel.ASPECT_MULTILINGUAL_DOCUMENT,
new JavaBehaviour(this, "onUpdateProperties"));
this.policyComponent.bindClassBehaviour(
QName.createQName(NamespaceService.ALFRESCO_URI, "onCopyComplete"),
ContentModel.ASPECT_MULTILINGUAL_DOCUMENT,
new JavaBehaviour(this, "onCopyComplete"));
this.policyComponent.bindClassBehaviour(
QName.createQName(NamespaceService.ALFRESCO_URI, "onRemoveAspect"),
ContentModel.ASPECT_MULTILINGUAL_DOCUMENT,
new JavaBehaviour(this, "onRemoveAspect"));
}
/**
* @param policyComponent the policy component to register behaviour with
*/
public void setPolicyComponent(PolicyComponent policyComponent)
{
this.policyComponent = policyComponent;
}
/**
* @param multilingualContentService the Multilingual Content Service to set
*/
public void setMultilingualContentService(
MultilingualContentService multilingualContentService)
{
this.multilingualContentService = multilingualContentService;
}
/**
* @param nodeService the Node Service to set
*/
public void setNodeService(NodeService nodeService)
{
this.nodeService = nodeService;
}
/**
* The copy of a <b>cm:mlDocument</b> can't keep the Multilingual aspect.
*
* @see org.alfresco.repo.copy.CopyServicePolicies.OnCopyNodePolicy#onCopyNode(org.alfresco.service.namespace.QName, org.alfresco.service.cmr.repository.NodeRef, org.alfresco.service.cmr.repository.StoreRef, boolean, org.alfresco.repo.policy.PolicyScope)
*/
public void onCopyNode(QName classRef, NodeRef sourceNodeRef, StoreRef destinationStoreRef, boolean copyToNewNode, PolicyScope copyDetails)
{
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)
{
Map<QName, Serializable> copiedProp = nodeService.getProperties(destinationRef);
copiedProp.remove(ContentModel.PROP_LOCALE);
nodeService.setProperties(destinationRef, copiedProp);
}
/**
* A <b>cm:mlDocument</b> is pivot translation it is a multilingual document (non empty) if it's language matches the language
* of its <b>cm:mlDocument</b>. And a pivot translation can't be removed if it's not the last translation of the <b>cm:mlContainer</b>.
*
* If a translation is deleted, it's multilingual aspect is lost.
*
* @see org.alfresco.repo.node.NodeServicePolicies.BeforeDeleteNodePolicy#beforeDeleteNode(org.alfresco.service.cmr.repository.NodeRef)
*/
public void beforeDeleteNode(NodeRef nodeRef)
{
nodeService.removeAspect(nodeRef, ContentModel.ASPECT_MULTILINGUAL_DOCUMENT);
}
/**
* When a pivot translation is deleted, it's <b>cm:mlContainer is deleted too.</b>
*
* <i>Note: When the pivot translation and the mlContainer are deleted, the mlDocument apsect is removed from
* the other translations. It will be better to don't allow the deletion of the pivot if other translation is
* available at the client side level.</i>
*
* @see org.alfresco.repo.node.NodeServicePolicies.BeforeRemoveAspectPolicy#beforeRemoveAspect(org.alfresco.service.cmr.repository.NodeRef, org.alfresco.service.namespace.QName)
*/
public void beforeRemoveAspect(NodeRef nodeRef, QName aspectTypeQName)
{
if(aspectTypeQName.equals(ContentModel.ASPECT_MULTILINGUAL_DOCUMENT))
{
NodeRef mlContainer = multilingualContentService.getTranslationContainer(nodeRef);
// nothing to do if the mlContainer is in a deletion process
Boolean inDeleteProcess = (Boolean) nodeService.getProperty(mlContainer, MLContainerType.PROP_NAME_DELETION_RUNNING);
if(inDeleteProcess != null && inDeleteProcess == true)
{
return;
}
Locale mlContainerLocale = (Locale) nodeService.getProperty(mlContainer, ContentModel.PROP_LOCALE);
Locale nodeRefLocale = (Locale) nodeService.getProperty(nodeRef, ContentModel.PROP_LOCALE);
nodeService.removeChild(mlContainer, nodeRef);
// if last translation or if nodeRef is pivot translation
if(multilingualContentService.getTranslations(mlContainer).size() == 0
|| mlContainerLocale.equals(nodeRefLocale))
{
// delete the mlContainer
nodeService.deleteNode(mlContainer);
}
}
}
/**
* After removing the <b>cm:mlDocument</b> aspect :
* - the node is removed is it's a <b>cm:mlEmptyTranslation</b>
* - if not, only the locale property is removed
*
* @see org.alfresco.repo.node.NodeServicePolicies.OnRemoveAspectPolicy#onRemoveAspect(org.alfresco.service.cmr.repository.NodeRef, org.alfresco.service.namespace.QName)
*/
public void onRemoveAspect(NodeRef nodeRef, QName aspectTypeQName)
{
if(aspectTypeQName.equals(ContentModel.ASPECT_MULTILINGUAL_DOCUMENT))
{
if(nodeService.hasAspect(nodeRef, ContentModel.ASPECT_MULTILINGUAL_EMPTY_TRANSLATION))
{
// note: if the node has the temporary aspect and the mlEmptyTranslation in a same
// time, it means that the node is being deleted by another process...
if(!nodeService.hasAspect(nodeRef, ContentModel.ASPECT_TEMPORARY))
{
nodeService.deleteNode(nodeRef);
}
}
else
{
Map<QName, Serializable> props = nodeService.getProperties(nodeRef);
props.remove(ContentModel.PROP_LOCALE);
nodeService.setProperties(nodeRef, props);
}
}
}
/**
* Ensure that the locale is unique inside the <b>mlContainer</b>.
*
* If the locale of a pivot translation is modified, the pivot locale reference of the mlContainer
* must be modified too.
*
* @see org.alfresco.repo.node.NodeServicePolicies.OnUpdatePropertiesPolicy#onUpdateProperties(org.alfresco.service.cmr.repository.NodeRef, java.util.Map, java.util.Map)
*/
public void onUpdateProperties(NodeRef nodeRef, Map<QName, Serializable> before, Map<QName, Serializable> after)
{
Locale localeBefore = (Locale) before.get(ContentModel.PROP_LOCALE);
Locale localeAfter;
// the after local property type can be either Locale or String
Serializable objLocaleAfter = after.get(ContentModel.PROP_LOCALE);
if (objLocaleAfter instanceof Locale )
{
localeAfter = (Locale) objLocaleAfter;
}
else
{
localeAfter = I18NUtil.parseLocale(objLocaleAfter.toString());
}
// if the local has been modified
if(!localeBefore.equals(localeAfter))
{
NodeRef mlContainer = multilingualContentService.getTranslationContainer(nodeRef);
// Since the map returned by the getTranslations doesn't duplicate keys, the size of this map will be
// different of the size of the number of children of the mlContainer if a duplicate locale is found.
int transSize = multilingualContentService.getTranslations(mlContainer).size();
int childSize = nodeService.getChildAssocs(mlContainer, ContentModel.ASSOC_MULTILINGUAL_CHILD, RegexQNamePattern.MATCH_ALL).size();
// if duplicate locale found
if(transSize != childSize)
{
// throw an exception and the current transaction will be rolled back. The properties will not be
// longer in an illegal state.
throw new IllegalArgumentException("The locale " + localeAfter +
" can't be changed for the node " + nodeRef +
" because this locale is already in use in an other translation of the same " +
ContentModel.TYPE_MULTILINGUAL_CONTAINER + ".");
}
// get the locale of ML Container
Locale localMlContainer = (Locale) nodeService.getProperty(
mlContainer,
ContentModel.PROP_LOCALE);
// if locale of the container is equals to the locale of
// the node (before update). The nodeRef is the pivot language
// and the locale of the mlContainer must be modified
if(localeBefore.equals(localMlContainer))
{
nodeService.setProperty(
mlContainer,
ContentModel.PROP_LOCALE,
localeAfter);
}
}
// else no action to perform
}
}

View File

@@ -0,0 +1,63 @@
/*
* 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 junit.framework.Test;
import junit.framework.TestSuite;
import org.alfresco.repo.model.filefolder.FolderTypeTest;
import org.alfresco.repo.model.ml.tools.ContentFilterLanguagesMapTest;
import org.alfresco.repo.model.ml.tools.EmptyTranslationAspectTest;
import org.alfresco.repo.model.ml.tools.MLContainerTypeTest;
import org.alfresco.repo.model.ml.tools.MultilingualContentServiceImplTest;
import org.alfresco.repo.model.ml.tools.MultilingualDocumentAspectTest;
/**
* Multilingual test suite
*
* @author yanipig
*/
public class MultilingualTestSuite extends TestSuite
{
/**
* Creates the test suite
*
* @return the test suite
*/
public static Test suite()
{
TestSuite suite = new TestSuite();
suite.addTestSuite(EmptyTranslationAspectTest.class);
suite.addTestSuite(ContentFilterLanguagesMapTest.class);
suite.addTestSuite(MultilingualContentServiceImplTest.class);
suite.addTestSuite(MultilingualDocumentAspectTest.class);
suite.addTestSuite(MLContainerTypeTest.class);
suite.addTestSuite(FolderTypeTest.class);
return suite;
}
}

View File

@@ -0,0 +1,138 @@
/*
* 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.tools;
import junit.framework.TestCase;
import org.alfresco.model.ContentModel;
import org.alfresco.repo.node.archive.NodeArchiveService;
import org.alfresco.repo.security.authentication.AuthenticationComponent;
import org.alfresco.repo.transaction.TransactionUtil;
import org.alfresco.repo.transaction.TransactionUtil.TransactionWork;
import org.alfresco.service.ServiceRegistry;
import org.alfresco.service.cmr.ml.ContentFilterLanguagesService;
import org.alfresco.service.cmr.ml.MultilingualContentService;
import org.alfresco.service.cmr.model.FileFolderService;
import org.alfresco.service.cmr.repository.ContentWriter;
import org.alfresco.service.cmr.repository.NodeRef;
import org.alfresco.service.cmr.repository.NodeService;
import org.alfresco.service.cmr.repository.StoreRef;
import org.alfresco.service.cmr.version.VersionService;
import org.alfresco.service.namespace.NamespaceService;
import org.alfresco.service.namespace.QName;
import org.alfresco.service.transaction.TransactionService;
import org.alfresco.util.ApplicationContextHelper;
import org.springframework.context.ApplicationContext;
/**
* Base multilingual test cases
*
* @author yanipig
*/
public abstract class AbstractMultilingualTestCases extends TestCase
{
protected static ApplicationContext ctx = ApplicationContextHelper.getApplicationContext();
protected ServiceRegistry serviceRegistry;
protected AuthenticationComponent authenticationComponent;
protected TransactionService transactionService;
protected NodeService nodeService;
protected FileFolderService fileFolderService;
protected VersionService versionService;
protected MultilingualContentService multilingualContentService;
protected NodeRef folderNodeRef;
protected ContentFilterLanguagesService contentFilterLanguagesService;
protected NodeArchiveService nodeArchiveService;
@Override
protected void setUp() throws Exception
{
nodeArchiveService = (NodeArchiveService) ctx.getBean("nodeArchiveService");
serviceRegistry = (ServiceRegistry) ctx.getBean(ServiceRegistry.SERVICE_REGISTRY);
authenticationComponent = (AuthenticationComponent) ctx.getBean("AuthenticationComponent");
transactionService = serviceRegistry.getTransactionService();
nodeService = serviceRegistry.getNodeService();
fileFolderService = serviceRegistry.getFileFolderService();
versionService = serviceRegistry.getVersionService();
multilingualContentService = (MultilingualContentService) ctx.getBean("MultilingualContentService");
contentFilterLanguagesService = (ContentFilterLanguagesService) ctx.getBean("ContentFilterLanguagesService");
// Run as admin
authenticationComponent.setCurrentUser("admin");
// Create a folder to work in
TransactionWork<NodeRef> createFolderWork = new TransactionWork<NodeRef>()
{
public NodeRef doWork() throws Exception
{
StoreRef storeRef = new StoreRef(StoreRef.PROTOCOL_WORKSPACE, "SpacesStore");
NodeRef rootNodeRef = nodeService.getRootNode(storeRef);
// Create the folder
NodeRef folderNodeRef = nodeService.createNode(
rootNodeRef,
ContentModel.ASSOC_CHILDREN,
QName.createQName(NamespaceService.CONTENT_MODEL_1_0_URI, "testFolder"),
ContentModel.TYPE_FOLDER).getChildRef();
// done
return folderNodeRef;
}
};
folderNodeRef = TransactionUtil.executeInUserTransaction(transactionService, createFolderWork);
}
@Override
protected void tearDown() throws Exception
{
// Clear authentication
try
{
authenticationComponent.clearCurrentSecurityContext();
}
catch (Throwable e)
{
e.printStackTrace();
}
}
protected NodeRef createContent()
{
NodeRef contentNodeRef = fileFolderService.create(
folderNodeRef,
"" + System.currentTimeMillis(),
ContentModel.TYPE_CONTENT).getNodeRef();
// add some content
ContentWriter contentWriter = fileFolderService.getWriter(contentNodeRef);
contentWriter.putContent("ABC");
// done
return contentNodeRef;
}
public void testSetup() throws Exception
{
// Ensure that content can be created
createContent();
}
}

View File

@@ -0,0 +1,146 @@
/*
* 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.tools;
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
import java.util.Locale;
/**
* Content filter language service test cases
*
* @see org.alfresco.service.cmr.ml.ContentFilterLanguagesService
* @see org.alfresco.repo.model.ml.ContentFilterLanguagesMap
*
* @author yanipig
*/
public class ContentFilterLanguagesMapTest extends AbstractMultilingualTestCases
{
public void testGetFilterLanguages() throws Exception
{
// get the list of content filter languages
List<String> lggs = contentFilterLanguagesService.getFilterLanguages();
// Ensure that the list is not null
assertNotNull("Language list is null", lggs);
// Ensure that the list is read-only
try
{
lggs.add("NEW LOCALE");
assertTrue("Add a value to the content filter language list is not permit, this list would be read only", false);
}
catch (Exception e)
{
// test case ok
}
try
{
lggs.remove(0);
assertTrue("Remove a value to the content filter language list is not permit, this list would be read only", false);
}
catch (Exception e)
{
// test case ok
}
}
@SuppressWarnings("unchecked")
public void testGetMissingLanguages() throws Exception
{
List<String> lggs = contentFilterLanguagesService.getFilterLanguages();
// get missing languages with null parameter
List<String> missingLggsNull = contentFilterLanguagesService.getMissingLanguages(null);
// Ensure that the returned list is not null
assertNotNull("Language list returned with the null parameter is null", missingLggsNull);
// Ensure that the returned list is entire
assertEquals("Language list returned with the null parameter corrupted", missingLggsNull.size(), lggs.size());
// get missing languages with empty collection parameter
List<String> missingLggsEmpty = contentFilterLanguagesService.getMissingLanguages(Collections.EMPTY_LIST);
// Ensure that the returned list is not null
assertNotNull("Language list returned with the empty parameter is null", missingLggsEmpty);
// Ensure that the returned list is entire
assertEquals("Language list returned with the empty parameter corrupted", missingLggsEmpty.size(), lggs.size());
// get missing languages with a two locale list
List<String> param = new ArrayList<String>();
param.add(0, lggs.get(0));
param.add(1, lggs.get(1));
List<String> missingLggsOk = contentFilterLanguagesService.getMissingLanguages(param);
// Ensure that the returned list is not null
assertNotNull("Language list returned with the correct parameter is null", missingLggsOk);
// Ensure that the returned list size is correct
assertEquals("Language list size returned with the correct parameter is not correct", missingLggsOk.size(), (lggs.size() - 2));
// Ensure that the returned list don't content the preceding locales
assertFalse("Language found : " + param.get(0), missingLggsOk.contains(param.get(0)));
assertFalse("Language found : " + param.get(1), missingLggsOk.contains(param.get(1)));
// get missing languages with a not found locale
param.add(2, "WRONG LOCALE CODE");
List<String> missingLggsWrong = contentFilterLanguagesService.getMissingLanguages(param);
// Ensure that the returned list is not null
assertNotNull("Language list returned with the wrong parameter is null", missingLggsWrong);
// Ensure that the returned list size is correct
assertEquals("Language list size returned with the correct parameter is not correct", missingLggsWrong.size(), (lggs.size() - 2));
// Ensure that the returned list don't content the wrong locale
assertFalse("Language found : " + param.get(0), missingLggsWrong.contains(param.get(0)));
assertFalse("Language found : " + param.get(1), missingLggsWrong.contains(param.get(1)));
assertFalse("Language found : " + param.get(2), missingLggsWrong.contains(param.get(2)));
}
public void testISOCodeConvertions() throws Exception
{
// New ISO code list
String[] newCode = {"he", "id", "yi"};
String[] oldCode = {"iw", "in", "ji"};
Locale loc0 = new Locale(newCode[0]);
Locale loc1 = new Locale(newCode[1]);
Locale loc2 = new Locale(newCode[2]);
// Ensure that java.util.Locale has converted the new ISO code into new iso code
assertEquals("java.util.Locale Convertion not correct for " + newCode[0], oldCode[0], loc0.getLanguage());
assertEquals("java.util.Locale Convertion not correct for " + newCode[1], oldCode[1], loc1.getLanguage());
assertEquals("java.util.Locale Convertion not correct for " + newCode[2], oldCode[2], loc2.getLanguage());
// Ensure that the convertion is correcte
assertEquals("Convertion of new ISO codes not correct for " + newCode[0], oldCode[0], contentFilterLanguagesService.convertToOldISOCode(newCode[0]));
assertEquals("Convertion of new ISO codes not correct for " + newCode[1], oldCode[1], contentFilterLanguagesService.convertToOldISOCode(newCode[1]));
assertEquals("Convertion of new ISO codes not correct for " + newCode[2], oldCode[2], contentFilterLanguagesService.convertToOldISOCode(newCode[2]));
assertEquals("Convertion of old ISO codes not correct for " + oldCode[0], newCode[0], contentFilterLanguagesService.convertToNewISOCode(oldCode[0]));
assertEquals("Convertion of old ISO codes not correct for " + oldCode[1], newCode[1], contentFilterLanguagesService.convertToNewISOCode(oldCode[1]));
assertEquals("Convertion of old ISO codes not correct for " + oldCode[2], newCode[2], contentFilterLanguagesService.convertToNewISOCode(oldCode[2]));
}
}

View File

@@ -0,0 +1,220 @@
/*
* 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.tools;
import java.io.Serializable;
import java.util.Locale;
import java.util.Map;
import org.alfresco.model.ContentModel;
import org.alfresco.service.cmr.repository.ContentData;
import org.alfresco.service.cmr.repository.ContentService;
import org.alfresco.service.cmr.repository.ContentWriter;
import org.alfresco.service.cmr.repository.NodeRef;
import org.alfresco.service.namespace.QName;
/**
* Empty translations aspect test cases
*
* @see org.alfresco.service.cmr.ml.EmptyTranslationAspect
*
* @author yanipig
*/
public class EmptyTranslationAspectTest extends AbstractMultilingualTestCases {
protected ContentService contentService;
protected void setUp() throws Exception
{
contentService = (ContentService) ctx.getBean("ContentService");
super.setUp();
}
public void testCopy() throws Exception
{
NodeRef pivot = createContent();
NodeRef empty = null;
multilingualContentService.makeTranslation(pivot, Locale.FRENCH);
empty = multilingualContentService.addEmptyTranslation(pivot, "empty_" + System.currentTimeMillis(), Locale.CHINESE);
boolean exceptionCatched = false;
NodeRef copy = null;
try
{
copy = fileFolderService.copy(
empty,
nodeService.getPrimaryParent(empty).getParentRef(),
"copyOfEmpty" + System.currentTimeMillis()).getNodeRef();
// test failed
}
catch (Exception ignore)
{
exceptionCatched = true;
}
// Ensure that the copy of an empty translation throws an exception
assertTrue("The copy of a translation must throws an exception", exceptionCatched);
// Ensure that the copy node is null
assertNull("The copy must fail ", copy);
}
public void testDeleteNode() throws Exception
{
NodeRef pivot = createContent();
NodeRef empty = null;
multilingualContentService.makeTranslation(pivot, Locale.FRENCH);
empty = multilingualContentService.addEmptyTranslation(pivot, "empty_" + System.currentTimeMillis(), Locale.CHINESE);
nodeService.deleteNode(empty);
// Ensure that the empty translation is removed from the workspace
assertFalse("The empty translation must be removed from the wokspace", nodeService.exists(empty));
// Ensure that the empty translation is not archived
assertFalse("The empty translation must be removed from the wokspace", nodeService.exists(nodeArchiveService.getArchivedNode(empty)));
}
public void testGetContent() throws Exception
{
NodeRef pivot = createContent();
NodeRef otherTranslation = createContent();
NodeRef empty = null;
NodeRef mlContainer = multilingualContentService.makeTranslation(pivot, Locale.FRENCH);
multilingualContentService.addTranslation(otherTranslation, pivot, Locale.KOREAN);
empty = multilingualContentService.addEmptyTranslation(pivot, "empty_" + System.currentTimeMillis(), Locale.CHINESE);
// Modify the content of the pivot
String contentString = fileFolderService.getReader(pivot).getContentString();
contentString += "_TEST_";
fileFolderService.getWriter(pivot).putContent(contentString);
// Ensure that the URL property of the empty translation content is null
assertNull("The URL property of an empty translation must be null", ((ContentData) nodeService.getProperty(empty, ContentModel.PROP_CONTENT)).getContentUrl());
// Ensure that the content retourned by a get reader of the empty document is the same as the pivot
assertEquals("The content retourned of the empty translation must be the same that the content of the pivot",
fileFolderService.getReader(pivot).getContentString(),
fileFolderService.getReader(empty).getContentString());
// Ensure that the content retourned by a get reader of the empty document is different to the non-pivot translation
assertNotSame("The content retourned of the empty translation must be different that the content of a non-pivot translation",
fileFolderService.getReader(otherTranslation).getContentString(),
fileFolderService.getReader(empty).getContentString());
// modify the pivot
Map<QName, Serializable> props = nodeService.getProperties(mlContainer);
props.put(ContentModel.PROP_LOCALE, Locale.KOREAN);
nodeService.setProperties(mlContainer, props);
// Ensure that the modicfication of the pivot is take in account
assertEquals("The modification of the pivot is not take in account",
fileFolderService.getReader(otherTranslation).getContentString(),
fileFolderService.getReader(empty).getContentString());
}
public void testUpdateContent() throws Exception
{
NodeRef pivot = createContent();
NodeRef empty = null;
multilingualContentService.makeTranslation(pivot, Locale.FRENCH);
empty = multilingualContentService.addEmptyTranslation(pivot, "empty_" + System.currentTimeMillis(), Locale.CHINESE);
// update the empty translation content
ContentWriter writer = contentService.getWriter(empty, ContentModel.PROP_CONTENT, true);
writer.setMimetype("text/plain");
writer.putContent("ANY_CONTENT");
// Ensure that the URL property of the empty translation content is not null
assertNotNull("The url of an updated (ex)empty transation can't be null", ((ContentData) nodeService.getProperty(empty, ContentModel.PROP_CONTENT)).getContentUrl());
// Ensure that the mlEmptyTranslation aspect is removed
assertFalse("The " + ContentModel.ASPECT_MULTILINGUAL_EMPTY_TRANSLATION + " aspect of an updated (ex)empty translation must be removed", nodeService.hasAspect(empty, ContentModel.ASPECT_MULTILINGUAL_EMPTY_TRANSLATION));
// Ensure that the mlDocument aspect is not removed
assertTrue("The " + ContentModel.ASPECT_MULTILINGUAL_DOCUMENT + " aspect of an updated (ex)empty translation must be keeped", nodeService.hasAspect(empty, ContentModel.ASPECT_MULTILINGUAL_DOCUMENT));
// Ensure that the content is written
assertEquals("The content of the (ex)empty translation is not correct",
fileFolderService.getReader(empty).getContentString(),
"ANY_CONTENT");
// Ensure that the content is different that the content of the pivot
assertNotSame("The content of the (ex)empty translation is not updated and is the same as the content of the pivot",
fileFolderService.getReader(empty).getContentString(),
fileFolderService.getReader(pivot).getContentString());
}
public void testRemoveAspect() throws Exception
{
NodeRef pivot = createContent();
NodeRef empty = null;
multilingualContentService.makeTranslation(pivot, Locale.FRENCH);
// 1. remove mlEmptyTranslation aspect with empty content
empty = multilingualContentService.addEmptyTranslation(pivot, "empty_" + System.currentTimeMillis(), Locale.CHINESE);
nodeService.removeAspect(empty, ContentModel.ASPECT_MULTILINGUAL_EMPTY_TRANSLATION);
// Ensure that the empty translation is deleted
assertFalse("After removed the " + ContentModel.ASPECT_MULTILINGUAL_EMPTY_TRANSLATION + " of an empty translation with no content the node must be deleted",
nodeService.exists(empty));
assertFalse("After removed the " + ContentModel.ASPECT_MULTILINGUAL_EMPTY_TRANSLATION + " of an empty translation with no content the node must be deleted and can't be archived",
nodeService.exists(nodeArchiveService.getArchivedNode(empty)));
// 2. remove mlDocument aspect with empty content
empty = multilingualContentService.addEmptyTranslation(pivot, "empty_" + System.currentTimeMillis(), Locale.CHINESE);
nodeService.removeAspect(empty, ContentModel.ASPECT_MULTILINGUAL_DOCUMENT);
// Ensure that the empty translation is deleted
assertFalse("After removed the " + ContentModel.ASPECT_MULTILINGUAL_DOCUMENT + " of an empty translation with no content the node must be deleted",
nodeService.exists(empty));
assertFalse("After removed the " + ContentModel.ASPECT_MULTILINGUAL_DOCUMENT + " of an empty translation with no content the node must be deleted and can't be archived",
nodeService.exists(nodeArchiveService.getArchivedNode(empty)));
// 3. remove mlEmptyTranslation aspect with not empty content
empty = multilingualContentService.addEmptyTranslation(pivot, "empty_" + System.currentTimeMillis(), Locale.CHINESE);
ContentWriter writer = contentService.getWriter(empty, ContentModel.PROP_CONTENT, true);
writer.setMimetype("text/plain");
writer.putContent("ANY_CONTENT");
nodeService.removeAspect(empty, ContentModel.ASPECT_MULTILINGUAL_EMPTY_TRANSLATION);
// Ensure that the empty translation is NOT deleted
assertTrue("After removed the " + ContentModel.ASPECT_MULTILINGUAL_EMPTY_TRANSLATION + " of an empty translation with content the node must NOT be deleted",
nodeService.exists(empty));
// Ensure that the mlEmptyTranslation aspect is removed
assertFalse("After removed the " + ContentModel.ASPECT_MULTILINGUAL_EMPTY_TRANSLATION + " of an empty translation with content this aspect must be removed",
nodeService.hasAspect(empty, ContentModel.ASPECT_MULTILINGUAL_EMPTY_TRANSLATION));
// Ensure that the mlEmptyDocument in NOT removed
assertTrue("After removed the " + ContentModel.ASPECT_MULTILINGUAL_EMPTY_TRANSLATION + " of an empty translation with content the " + ContentModel.ASPECT_MULTILINGUAL_DOCUMENT + " aspect must be keeped",
nodeService.hasAspect(empty, ContentModel.ASPECT_MULTILINGUAL_DOCUMENT));
}
}

View File

@@ -0,0 +1,148 @@
/*
* 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.tools;
import java.io.Serializable;
import java.util.Locale;
import java.util.Map;
import org.alfresco.model.ContentModel;
import org.alfresco.service.cmr.repository.NodeRef;
import org.alfresco.service.namespace.QName;
/**
* Multilingual container type test cases
*
* @see org.alfresco.service.cmr.ml.MLContainerType
*
* @author yanipig
*/
public class MLContainerTypeTest extends AbstractMultilingualTestCases {
public void testDeleteNode() throws Exception
{
NodeRef pivot = createContent();
NodeRef empty;
NodeRef mlContainer = multilingualContentService.makeTranslation(pivot, Locale.FRENCH);
empty = multilingualContentService.addEmptyTranslation(pivot, "Empty_" + System.currentTimeMillis(), Locale.ENGLISH);
nodeService.deleteNode(mlContainer);
// Ensure that the mlContainer is deleted
assertFalse("The mlContainer must be deleted", nodeService.exists(mlContainer));
// Ensure that the empty translation is deleted
assertFalse("The mlEmptyTranslation must be deleted", nodeService.exists(empty));
// Ensure that the non-empty document is not deleted
assertTrue("The mlDocument must not be deleted", nodeService.exists(pivot));
// Ensure that the mlDocument property of the non-empty document is removed
assertFalse("The " + ContentModel.ASPECT_MULTILINGUAL_DOCUMENT + " aspect of the mlDocument must be removed",
nodeService.hasAspect(pivot, ContentModel.ASPECT_MULTILINGUAL_DOCUMENT));
}
@SuppressWarnings("unused")
public void testEditLocale() throws Exception
{
NodeRef trans1 = createContent();
NodeRef trans2 = createContent();
NodeRef trans3 = createContent();
NodeRef empty = null;
NodeRef mlContainer = multilingualContentService.makeTranslation(trans1, Locale.FRENCH);
multilingualContentService.addTranslation(trans2, trans1, Locale.GERMAN);
multilingualContentService.addTranslation(trans3, trans1, Locale.ITALIAN);
empty = multilingualContentService.addEmptyTranslation(trans1, "EMPTY_" + System.currentTimeMillis(), Locale.JAPANESE);
// 1. Locale as null
// Ensure that the setting of the locale of the mlContainer as null throws an excpetion
assertTrue("The setting of the locale of a mlContainer must throws an exception",
setLocaleProp(mlContainer, null));
// Ensure that the locale of the mlContainer is not changed
assertEquals("The locale of the mlContainer would not be changed",
Locale.FRENCH,
nodeService.getProperty(mlContainer, ContentModel.PROP_LOCALE));
// 2. Set an non-existing locale
// Ensure that the setting of the locale of the mlContainer as a non-existing translation language throws an excpetion
assertTrue("The setting of the locale of a mlContainer as a non-existing translation language must throws an exception",
setLocaleProp(mlContainer, Locale.US));
// Ensure that the locale of the mlContainer is not changed
assertEquals("The locale of the mlContainer would not be changed",
Locale.FRENCH,
nodeService.getProperty(mlContainer, ContentModel.PROP_LOCALE));
// 3. Set the locale of a empty translation
// Ensure that the setting of the locale of the mlContainer as an empty translation language throws an excpetion
assertTrue("The setting of the locale of a mlContainer as an empty translation language must throws an exception",
setLocaleProp(mlContainer, Locale.JAPANESE));
// Ensure that the locale of the mlContainer is not changed
assertEquals("The locale of the mlContainer would not be changed",
Locale.FRENCH,
nodeService.getProperty(mlContainer, ContentModel.PROP_LOCALE));
// 4. Set an existing and valid locale
// Ensure that the setting of the locale of the mlContainer as an existing and a non-empty translation DOESN'T throw an excpetion
assertFalse("The setting of the locale of a mlContainer as an existing and a non-empty translation DOESN'T throw an excpetion",
setLocaleProp(mlContainer, Locale.ITALIAN));
// Ensure that the locale of the mlContainer is not changed
assertEquals("The locale of the mlContainer would be changed",
Locale.ITALIAN,
nodeService.getProperty(mlContainer, ContentModel.PROP_LOCALE));
}
private boolean setLocaleProp(NodeRef node, Locale locale) throws Exception
{
Map<QName, Serializable> props = nodeService.getProperties(node);
props.put(ContentModel.PROP_LOCALE, locale);
boolean exceptionCatched = false;
try
{
nodeService.setProperties(node, props);
}
catch (IllegalArgumentException ignore)
{
exceptionCatched = true;
}
catch(Exception ex)
{
throw new Exception(ex);
}
return exceptionCatched;
}
}

View File

@@ -0,0 +1,232 @@
/*
* 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.tools;
import java.util.ArrayList;
import java.util.Collection;
import java.util.List;
import java.util.Locale;
import java.util.Map;
import org.alfresco.i18n.I18NUtil;
import org.alfresco.model.ContentModel;
import org.alfresco.service.cmr.repository.NodeRef;
import org.alfresco.service.cmr.version.Version;
import org.alfresco.service.cmr.version.VersionHistory;
/**
* @see org.alfresco.repo.ml.MultilingualContentServiceImpl
*
* @author Derek Hulley
* @author Philippe Dubois
*/
public class MultilingualContentServiceImplTest extends AbstractMultilingualTestCases
{
public void testMakeTranslation() throws Exception
{
NodeRef contentNodeRef = createContent();
// Turn the content into a translation with the appropriate structures
NodeRef mlContainerNodeRef = multilingualContentService.makeTranslation(contentNodeRef, Locale.CHINESE);
// Check it
assertNotNull("Container not created", mlContainerNodeRef);
// Check the container child count
assertEquals("Incorrect number of child nodes", 1, nodeService.getChildAssocs(mlContainerNodeRef).size());
}
public void testAddTranslationUsingContainer() throws Exception
{
// Make a container with a single translation
NodeRef chineseContentNodeRef = createContent();
NodeRef mlContainerNodeRef = multilingualContentService.makeTranslation(chineseContentNodeRef, Locale.CHINESE);
// Create some more content
NodeRef frenchContentNodeRef = createContent();
// Make this a translation of the Chinese
NodeRef newMLContainerNodeRef = multilingualContentService.addTranslation(
frenchContentNodeRef,
mlContainerNodeRef,
Locale.FRENCH);
// Make sure that the original container was used
assertEquals("Existing container should have been used", mlContainerNodeRef, newMLContainerNodeRef);
// Check the container child count
assertEquals("Incorrect number of child nodes", 2, nodeService.getChildAssocs(mlContainerNodeRef).size());
}
public void testAddTranslationUsingContent() throws Exception
{
// Make a container with a single translation
NodeRef chineseContentNodeRef = createContent();
NodeRef mlContainerNodeRef = multilingualContentService.makeTranslation(chineseContentNodeRef, Locale.CHINESE);
// Create some more content
NodeRef frenchContentNodeRef = createContent();
// Make this a translation of the Chinese
NodeRef newMLContainerNodeRef = multilingualContentService.addTranslation(
frenchContentNodeRef,
chineseContentNodeRef,
Locale.FRENCH);
// Make sure that the original container was used
assertEquals("Existing container should have been used", mlContainerNodeRef, newMLContainerNodeRef);
// Check the container child count
assertEquals("Incorrect number of child nodes", 2, nodeService.getChildAssocs(mlContainerNodeRef).size());
}
@SuppressWarnings("unused")
public void testGetMissingTranslation() throws Exception
{
List<String> langList = contentFilterLanguagesService.getFilterLanguages();
int langListSize = langList.size();
// make sure that it exists at least tree language filter
assertFalse("The testGetMissingTranslation test case needs at least three language", langListSize < 3);
// get the first tree locale of the content filter language list
Locale loc1 = I18NUtil.parseLocale(langList.get(0));
Locale loc2 = I18NUtil.parseLocale(langList.get(1));
Locale loc3 = I18NUtil.parseLocale(langList.get(2));
// create three content
NodeRef nodeRef1 = createContent();
NodeRef nodeRef2 = createContent();
NodeRef nodeRef3 = createContent();
NodeRef mlContainerNodeRef = multilingualContentService.makeTranslation(nodeRef1, loc1);
List<Locale> missing = multilingualContentService.getMissingTranslations(mlContainerNodeRef, false);
// make sure that the missing language list size is correct
assertFalse("Missing Translation Size false. " +
"Real size : " + missing.size() + ". Normal Size " + (langListSize - 1), missing.size() != (langListSize - 1));
// make sure that the missing language list is correct
assertFalse("Missing Translation List false. Locale " + loc1 + " found", missing.contains(loc1.toString()));
multilingualContentService.addTranslation(nodeRef2, mlContainerNodeRef, loc2);
multilingualContentService.addTranslation(nodeRef3, mlContainerNodeRef, loc3);
missing = multilingualContentService.getMissingTranslations(mlContainerNodeRef, false);
// make sure that the missing language list size is correct
assertFalse("Missing Translation Size false. " +
"Real size : " + missing.size() + ". Normal Size " + (langListSize - 3), missing.size() != (langListSize - 3));
// make sure that the missing language list is correct
assertFalse("Missing Translation List false. Locale " + loc2 + " or " + loc3 + " found", missing.contains(loc2.toString()) || missing.contains(loc3.toString()));
}
@SuppressWarnings("unused")
public void testPivotTranslation() throws Exception
{
NodeRef chineseContentNodeRef = createContent();
NodeRef mlContainerNodeRef = multilingualContentService.makeTranslation(chineseContentNodeRef, Locale.CHINESE);
// make sure that the pivot language is set
assertNotNull("Pivot language not set", nodeService.getProperty(mlContainerNodeRef, ContentModel.PROP_LOCALE));
// make sure that the pivot language is correctly set
assertTrue("Pivot language not correctly set", nodeService.getProperty(mlContainerNodeRef, ContentModel.PROP_LOCALE).equals(Locale.CHINESE));
NodeRef frenchContentNodeRef = createContent();
multilingualContentService.addTranslation(frenchContentNodeRef, chineseContentNodeRef, Locale.FRENCH);
// make sure that the pivot noderef is correct
assertTrue("Pivot node ref not correct", multilingualContentService.getPivotTranslation(mlContainerNodeRef).equals(chineseContentNodeRef));
// modify the pivot language
nodeService.setProperty(mlContainerNodeRef, ContentModel.PROP_LOCALE, Locale.FRENCH);
// make sure that the modified pivot noderef is correct
assertTrue("Pivot node ref not correct", multilingualContentService.getPivotTranslation(mlContainerNodeRef).equals(frenchContentNodeRef));
}
@SuppressWarnings("unused")
public void testCreateEmptyTranslation() throws Exception
{
NodeRef chineseContentNodeRef = createContent();
NodeRef mlContainerNodeRef = multilingualContentService.makeTranslation(chineseContentNodeRef, Locale.CHINESE);
NodeRef empty = multilingualContentService.addEmptyTranslation(chineseContentNodeRef, "" + System.currentTimeMillis(), Locale.CANADA);
// Ensure that the empty translation is not null
assertNotNull("The creation of the empty document failed ", empty);
// Ensure that the empty translation has the mlDocument aspect
assertTrue("The empty document must have the mlDocument aspect", nodeService.hasAspect(empty, ContentModel.ASPECT_MULTILINGUAL_DOCUMENT));
// Ensure that the empty translation has the mlEmptyTranslation aspect
assertTrue("The empty document must have the mlEmptyTranslation aspect", nodeService.hasAspect(empty, ContentModel.ASPECT_MULTILINGUAL_EMPTY_TRANSLATION));
}
@SuppressWarnings("unused")
public void testCreateEdition() throws Exception
{
// Make some content
NodeRef chineseContentNodeRef = createContent();
NodeRef frenchContentNodeRef = createContent();
NodeRef japaneseContentNodeRef = createContent();
// Add to container
NodeRef mlContainerNodeRef = multilingualContentService.makeTranslation(chineseContentNodeRef, Locale.CHINESE);
multilingualContentService.addTranslation(frenchContentNodeRef, mlContainerNodeRef, Locale.FRENCH);
multilingualContentService.addTranslation(japaneseContentNodeRef, mlContainerNodeRef, Locale.JAPANESE);
// Check the container child count
assertEquals("Incorrect number of child nodes", 3, nodeService.getChildAssocs(mlContainerNodeRef).size());
// Version each of the documents
List<NodeRef> nodeRefs = new ArrayList<NodeRef>(3);
nodeRefs.add(chineseContentNodeRef);
nodeRefs.add(frenchContentNodeRef);
nodeRefs.add(japaneseContentNodeRef);
versionService.createVersion(nodeRefs, null);
// Get the current versions of each of the documents
Version chineseVersionPreEdition = versionService.getCurrentVersion(chineseContentNodeRef);
Version frenchVersionPreEdition = versionService.getCurrentVersion(frenchContentNodeRef);
Version japaneseVersionPreEdition = versionService.getCurrentVersion(japaneseContentNodeRef);
// Create the edition, keeping the Chinese translation as the basis
multilingualContentService.createEdition(chineseContentNodeRef);
// Check the container child count
assertEquals("Incorrect number of child nodes", 1, nodeService.getChildAssocs(mlContainerNodeRef).size());
// Get the document versions now
Version chineseVersionPostEdition = versionService.getCurrentVersion(chineseContentNodeRef);
assertFalse("Expected document to be gone", nodeService.exists(frenchContentNodeRef));
assertFalse("Expected document to be gone", nodeService.exists(japaneseContentNodeRef));
// Now be sure that we can get the required information using the version service
VersionHistory mlContainerVersionHistory = versionService.getVersionHistory(mlContainerNodeRef);
Collection<Version> mlContainerVersions = mlContainerVersionHistory.getAllVersions();
// Loop through and get all the children of each version
for (Version mlContainerVersion : mlContainerVersions)
{
NodeRef versionedMLContainerNodeRef = mlContainerVersion.getFrozenStateNodeRef();
// Get all the children
Map<Locale, NodeRef> translationsByLocale = multilingualContentService.getTranslations(
versionedMLContainerNodeRef);
// Count the children
int count = translationsByLocale.size();
}
}
}

View File

@@ -0,0 +1,220 @@
/*
* 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.tools;
import java.io.Serializable;
import java.util.Locale;
import java.util.Map;
import org.alfresco.model.ContentModel;
import org.alfresco.service.cmr.repository.NodeRef;
import org.alfresco.service.namespace.QName;
/**
* Multilingual document aspect test cases
*
* @see org.alfresco.service.cmr.ml.MultilingualDocumentAspect
*
* @author yanipig
*/
public class MultilingualDocumentAspectTest extends AbstractMultilingualTestCases
{
public void testCopy() throws Exception
{
NodeRef original = createContent();
NodeRef mlContainer = multilingualContentService.makeTranslation(original, Locale.FRENCH);
NodeRef copy =
fileFolderService.copy(original, nodeService.getPrimaryParent(original).getParentRef(), "COPY" + System.currentTimeMillis()).getNodeRef();
// Ensure that the copy removes the mlDocument aspect
assertFalse("The copy of a mlDocument can't have the multilingual aspect", nodeService.hasAspect(copy, ContentModel.ASPECT_MULTILINGUAL_DOCUMENT));
// 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());
// 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
{
NodeRef trad1 = createContent();
NodeRef trad2 = createContent();
NodeRef trad3 = createContent();
NodeRef parent = nodeService.getPrimaryParent(trad1).getParentRef();
NodeRef mlContainer = multilingualContentService.makeTranslation(trad1, Locale.FRENCH);
multilingualContentService.addTranslation(trad2, trad1, Locale.GERMAN);
multilingualContentService.addTranslation(trad3, trad1, Locale.ITALIAN);
nodeService.deleteNode(trad3);
// Ensure that the deleted node is romoved from its space
assertEquals("The deleted node must be removed to the space", 2, nodeService.getChildAssocs(parent).size());
// Ensure that the mlContainer doesn't keep an association to the deleted node
assertEquals("The deleted node must be removed to the child associations of the mlContainer", 2, multilingualContentService.getTranslations(mlContainer).size());
// retore the deleted node
NodeRef restoredNode = nodeArchiveService.restoreArchivedNode(nodeArchiveService.getArchivedNode(trad3)).getRestoredNodeRef();
// Ensure that the restored node is restored to it s original space
assertEquals("The restaured node must be restaured to the the space", 3, nodeService.getChildAssocs(parent).size());
// Ensure that the restored node is not linked to the mlContainer
assertEquals("The restaured node would not be restaured to the mlContainer", 2, multilingualContentService.getTranslations(mlContainer).size());
// Ensure that the restored node doesn't keep the mlDocument aspect
assertFalse("The restaured node can't keep the multilingual aspect", nodeService.hasAspect(restoredNode, ContentModel.ASPECT_MULTILINGUAL_DOCUMENT));
// Ensure that the restored node doesn't keep the locale property
assertNull("The restaured node can't keep the locale property", nodeService.getProperty(restoredNode, ContentModel.PROP_LOCALE));
}
public void testDeletePivot() throws Exception
{
NodeRef pivot = createContent();
NodeRef trans1 = createContent();
NodeRef mlContainer = multilingualContentService.makeTranslation(pivot, Locale.FRENCH);
multilingualContentService.addTranslation(trans1, pivot, Locale.KOREAN);
//nodeService.deleteNode(trans1);
nodeService.deleteNode(pivot);
// Ensure that pivot is removed
assertFalse("The pivot would be removed", nodeService.exists(pivot));
// Ensure that the mlContainer is removed
assertFalse("The mlContainer must be removed if the pivot is removed", nodeService.exists(mlContainer));
// Ensure that trans1 is NOT removed
assertTrue("The last translation would not be removed", nodeService.exists(trans1));
// Ensure that trans1 has no mlDocument aspect
assertFalse("The last translation can't keep the multilingual aspect", nodeService.hasAspect(trans1, ContentModel.ASPECT_MULTILINGUAL_DOCUMENT));
// Ensure that trans1 has no locale propety
assertNull("The last translation can't keep the locale property", nodeService.getProperty(trans1, ContentModel.PROP_LOCALE));
}
public void testDeleteLastNode() throws Exception
{
NodeRef pivot = createContent();
NodeRef mlContainer = multilingualContentService.makeTranslation(pivot, Locale.FRENCH);
nodeService.deleteNode(pivot);
// Ensure that the mlContainer is removed too
assertFalse("The mlContainer must be removed if the last translation is removed", nodeService.exists(mlContainer));
}
public void testRemoveAspect() throws Exception
{
// entierly covered by the delete tests
}
public void testUpdateLocale() throws Exception
{
NodeRef pivot = createContent();
NodeRef trans1 = createContent();
NodeRef mlContainer = multilingualContentService.makeTranslation(pivot, Locale.FRENCH);
multilingualContentService.addTranslation(trans1, pivot, Locale.KOREAN);
// modify the locale for the translation
Map<QName, Serializable> props = nodeService.getProperties(trans1);
props.put(ContentModel.PROP_LOCALE, Locale.GERMAN);
nodeService.setProperties(trans1, props);
// Ensure that the pivot reference is not changed for the mlContainer and the locale is changed for the translation
assertEquals("The locale for the pivot would be changed ",Locale.GERMAN, nodeService.getProperty(trans1, ContentModel.PROP_LOCALE));
assertEquals("The pivot reference would not be changed in the mlContainer", Locale.FRENCH, nodeService.getProperty(mlContainer, ContentModel.PROP_LOCALE));
// modify the locale for the pivot
props = nodeService.getProperties(pivot);
props.put(ContentModel.PROP_LOCALE, Locale.US);
nodeService.setProperties(pivot, props);
// Ensure that the pivot reference is changed (in the pivot and in the mlContainer)
assertEquals("The locale for the pivot would be changed ", Locale.US, nodeService.getProperty(pivot, ContentModel.PROP_LOCALE));
assertEquals("The pivot reference would be changes in the mlContainer", Locale.US, nodeService.getProperty(mlContainer, ContentModel.PROP_LOCALE));
}
public void testUpdateRedundantLocale() throws Exception
{
NodeRef pivot = createContent();
NodeRef trans1 = createContent();
NodeRef trans2 = createContent();
multilingualContentService.makeTranslation(pivot, Locale.FRENCH);
multilingualContentService.addTranslation(trans1, pivot, Locale.KOREAN);
multilingualContentService.addTranslation(trans2, pivot, Locale.JAPANESE);
// 1. Try with redundant locale
// modify the locale for the translation 2
Map<QName, Serializable> props = nodeService.getProperties(trans2);
props.put(ContentModel.PROP_LOCALE, Locale.KOREAN);
boolean exceptionCatched = false;
try
{
nodeService.setProperties(trans2, props);
// test failed
} catch (Exception ignore)
{
exceptionCatched = true;
}
// Ensure that the the exception was catched.
assertTrue("The modification of this locale must catch an exception because it is already in use in another translation", exceptionCatched);
// Ensure that the locale of the trans2 is unchanged
assertEquals("The locale must not be changed",
Locale.JAPANESE,
(Locale) nodeService.getProperty(trans2, ContentModel.PROP_LOCALE));
// 2. Try with a non-redundant locale
props = nodeService.getProperties(trans2);
props.put(ContentModel.PROP_LOCALE, Locale.ITALIAN);
exceptionCatched = false;
try
{
nodeService.setProperties(trans2, props);
} catch (Exception ignore)
{
// test failed
exceptionCatched = true;
}
// Ensure that the exception was not catched
assertFalse("The modification of the locale would not throws an exception", exceptionCatched);
// Ensure that the locale is modified
assertEquals("The locale must be changed",
Locale.ITALIAN,
(Locale) nodeService.getProperty(trans2, ContentModel.PROP_LOCALE));
}
}

View File

@@ -0,0 +1,181 @@
/*
* 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 nodeService;
private MultilingualContentService multilingualContentService;
@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
&& nodeService.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 = nodeService.getType(child);
if(type.equals(ContentModel.TYPE_CONTENT) &&
nodeService.hasAspect(child, ContentModel.ASPECT_MULTILINGUAL_DOCUMENT))
{
NodeRef container = multilingualContentService.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 = multilingualContentService.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 = multilingualContentService.getPivotTranslation(container);
}
else
{
// get the matched translation
matchedTranslation = multilingualContentService.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 MultilingualContentService getMultilingualContentService()
{
return multilingualContentService;
}
public void setMultilingualContentService(
MultilingualContentService multilingualContentService)
{
this.multilingualContentService = multilingualContentService;
}
public NodeService getNodeService()
{
return nodeService;
}
public void setNodeService(NodeService nodeService)
{
this.nodeService = nodeService;
}
}

View File

@@ -37,6 +37,7 @@ import org.alfresco.service.cmr.avmsync.AVMSyncService;
import org.alfresco.service.cmr.coci.CheckOutCheckInService;
import org.alfresco.service.cmr.dictionary.DictionaryService;
import org.alfresco.service.cmr.lock.LockService;
import org.alfresco.service.cmr.ml.ContentFilterLanguagesService;
import org.alfresco.service.cmr.model.FileFolderService;
import org.alfresco.service.cmr.repository.ContentService;
import org.alfresco.service.cmr.repository.CopyService;
@@ -255,7 +256,7 @@ public class ServiceDescriptorRegistry
*/
public ActionService getActionService()
{
return (ActionService)getService(ACTION_SERVICE);
return (ActionService)getService(ACTION_SERVICE);
}
/* (non-Javadoc)
@@ -364,6 +365,14 @@ public class ServiceDescriptorRegistry
return (AttributeService)getService(ATTRIBUTE_SERVICE);
}
/* (non-Javadoc)
* @see org.alfresco.service.ServiceRegistry#getContentFilterLanguagesService()
*/
public ContentFilterLanguagesService getContentFilterLanguagesService()
{
return (ContentFilterLanguagesService) getService(CONTENT_FILTER_LANGUAGES_SERVICE);
}
/* (non-Javadoc)
* @see org.alfresco.service.ServiceRegistry#getAVMLockingService()
*/

View File

@@ -15,11 +15,11 @@
* 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:
* 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;
@@ -29,9 +29,9 @@ import org.alfresco.service.cmr.version.VersionService;
import org.alfresco.service.namespace.QName;
/**
* interface conating the constants used by the light weight
* interface conating the constants used by the light weight
* version store implementation
*
*
* @author Roy Wetherall
*/
public interface VersionModel
@@ -40,20 +40,20 @@ public interface VersionModel
* Namespace
*/
public static final String NAMESPACE_URI = "http://www.alfresco.org/model/versionstore/1.0";
/**
/**
* The store protocol
*/
public static final String STORE_PROTOCOL = VersionService.VERSION_STORE_PROTOCOL;
/**
* The store id
*/
public static final String STORE_ID = "lightWeightVersionStore";
public static final String PROP_VERSION_LABEL = "versionLabel";
public static final String PROP_CREATED_DATE = ContentModel.PROP_CREATED.getLocalName();
public static final String PROP_CREATED_DATE = ContentModel.PROP_CREATED.getLocalName();
public static final String PROP_CREATOR = ContentModel.PROP_CREATOR.getLocalName();
public static final String PROP_VERSION_TYPE = "versionType";
public static final String PROP_VERSION_NUMBER = "versionNumber";
@@ -62,29 +62,29 @@ public interface VersionModel
public static final String PROP_FROZEN_NODE_STORE_PROTOCOL = "frozenNodeStoreProtocol";
public static final String PROP_FROZEN_NODE_STORE_ID = "frozenNodeStoreId";
public static final String PROP_FROZEN_ASPECTS = "frozenAspects";
/** The version store root aspect */
public static final QName ASPECT_VERSION_STORE_ROOT = QName.createQName(NAMESPACE_URI, "versionStoreRoot");
/**
* Version history type
*/
public static final String TYPE_VERSION_HISTORY = "versionHistory";
public static final QName TYPE_QNAME_VERSION_HISTORY = QName.createQName(NAMESPACE_URI, TYPE_VERSION_HISTORY);
/**
* Version history properties and associations
*/
public static final String PROP_VERSIONED_NODE_ID = "versionedNodeId";
public static final QName PROP_QNAME_VERSIONED_NODE_ID = QName.createQName(NAMESPACE_URI, PROP_VERSIONED_NODE_ID);
public static final QName PROP_QNAME_VERSIONED_NODE_ID = QName.createQName(NAMESPACE_URI, PROP_VERSIONED_NODE_ID);
public static final QName ASSOC_ROOT_VERSION = QName.createQName(NAMESPACE_URI, "rootVersion");
/**
* Verison type
*/
public static final String TYPE_VERSION = "version";
public static final QName TYPE_QNAME_VERSION = QName.createQName(NAMESPACE_URI, TYPE_VERSION);
/**
* Version type properties and associations
*/
@@ -95,14 +95,14 @@ public interface VersionModel
public static final QName PROP_QNAME_FROZEN_NODE_STORE_PROTOCOL = QName.createQName(NAMESPACE_URI, PROP_FROZEN_NODE_STORE_PROTOCOL);
public static final QName PROP_QNAME_FROZEN_NODE_STORE_ID = QName.createQName(NAMESPACE_URI, PROP_FROZEN_NODE_STORE_ID);
public static final QName PROP_QNAME_FROZEN_ASPECTS = QName.createQName(NAMESPACE_URI, PROP_FROZEN_ASPECTS);
public static final QName ASSOC_SUCCESSOR = QName.createQName(NAMESPACE_URI, "successor");
public static final QName ASSOC_SUCCESSOR = QName.createQName(NAMESPACE_URI, "successor");
/**
* Version Meta Data Value type
*/
public static final String TYPE_VERSION_META_DATA_VALUE = "versionMetaDataValue";
public static final QName TYPE_QNAME_VERSION_META_DATA_VALUE = QName.createQName(NAMESPACE_URI, TYPE_VERSION_META_DATA_VALUE);
/**
* Version Meta Data Value attributes
*/
@@ -110,13 +110,13 @@ public interface VersionModel
public static final QName PROP_QNAME_META_DATA_NAME = QName.createQName(NAMESPACE_URI, PROP_META_DATA_NAME);
public static final String PROP_META_DATA_VALUE = "metaDataValue";
public static final QName PROP_QNAME_META_DATA_VALUE = QName.createQName(NAMESPACE_URI, PROP_META_DATA_VALUE);
/**
* Versioned attribute type
*/
public static final String TYPE_VERSIONED_PROPERTY = "versionedProperty";
public static final QName TYPE_QNAME_VERSIONED_PROPERTY = QName.createQName(NAMESPACE_URI, TYPE_VERSIONED_PROPERTY);
/**
* Versioned attribute properties
*/
@@ -128,13 +128,13 @@ public interface VersionModel
public static final QName PROP_QNAME_VALUE = QName.createQName(NAMESPACE_URI, PROP_VALUE);
public static final QName PROP_QNAME_MULTI_VALUE = QName.createQName(NAMESPACE_URI, PROP_MULTI_VALUE);
public static final QName PROP_QNAME_IS_MULTI_VALUE = QName.createQName(NAMESPACE_URI, PROP_IS_MULTI_VALUE);
/**
* Versioned child assoc type
*/
public static final String TYPE_VERSIONED_CHILD_ASSOC = "versionedChildAssoc";
public static final QName TYPE_QNAME_VERSIONED_CHILD_ASSOC = QName.createQName(NAMESPACE_URI, TYPE_VERSIONED_CHILD_ASSOC);
/**
* Versioned child assoc properties
*/
@@ -146,13 +146,13 @@ public interface VersionModel
public static final QName PROP_QNAME_ASSOC_TYPE_QNAME = QName.createQName(NAMESPACE_URI, PROP_ASSOC_TYPE_QNAME);
public static final QName PROP_QNAME_IS_PRIMARY = QName.createQName(NAMESPACE_URI, PROP_IS_PRIMARY);
public static final QName PROP_QNAME_NTH_SIBLING = QName.createQName(NAMESPACE_URI, PROP_NTH_SIBLING);
/**
* Versioned assoc type
*/
public static final String TYPE_VERSIONED_ASSOC = "versionedAssoc";
public static final QName TYPE_QNAME_VERSIONED_ASSOC = QName.createQName(NAMESPACE_URI, TYPE_VERSIONED_ASSOC);
/**
* Child relationship names
*/
@@ -162,11 +162,18 @@ public interface VersionModel
public static final String CHILD_VERSIONED_CHILD_ASSOCS = "versionedChildAssocs";
public static final String CHILD_VERSIONED_ASSOCS = "versionedAssocs";
public static final String CHILD_VERSION_META_DATA = "versionMetaData";
public static final QName CHILD_QNAME_VERSION_HISTORIES = QName.createQName(NAMESPACE_URI, CHILD_VERSION_HISTORIES);
public static final QName CHILD_QNAME_VERSIONS = QName.createQName(NAMESPACE_URI, CHILD_VERSIONS);
public static final QName CHILD_QNAME_VERSIONED_ATTRIBUTES = QName.createQName(NAMESPACE_URI, CHILD_VERSIONED_ATTRIBUTES);
public static final QName CHILD_QNAME_VERSIONED_CHILD_ASSOCS = QName.createQName(NAMESPACE_URI, CHILD_VERSIONED_CHILD_ASSOCS);
public static final QName CHILD_QNAME_VERSIONED_ASSOCS = QName.createQName(NAMESPACE_URI, CHILD_VERSIONED_ASSOCS);
public static final QName CHILD_QNAME_VERSION_META_DATA = QName.createQName(NAMESPACE_URI, CHILD_VERSION_META_DATA);
/**
* Created version associated to the deleted translations of an mlContainer
*/
public static final String PROP_TRANSLATION_VERIONS = "translationVersions";
public static final QName PROP_QNAME_TRANSLATION_VERIONS = QName.createQName(VersionModel.NAMESPACE_URI, PROP_TRANSLATION_VERIONS);
}

View File

@@ -36,6 +36,7 @@ import org.alfresco.service.cmr.avmsync.AVMSyncService;
import org.alfresco.service.cmr.coci.CheckOutCheckInService;
import org.alfresco.service.cmr.dictionary.DictionaryService;
import org.alfresco.service.cmr.lock.LockService;
import org.alfresco.service.cmr.ml.ContentFilterLanguagesService;
import org.alfresco.service.cmr.model.FileFolderService;
import org.alfresco.service.cmr.repository.ContentService;
import org.alfresco.service.cmr.repository.CopyService;
@@ -85,6 +86,7 @@ public interface ServiceRegistry
static final QName NODE_SERVICE = QName.createQName(NamespaceService.ALFRESCO_URI, "NodeService");
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 CONTENT_FILTER_LANGUAGES_SERVICE = QName.createQName(NamespaceService.ALFRESCO_URI, "ContentFilterLanguagesService");
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 COPY_SERVICE = QName.createQName(NamespaceService.ALFRESCO_URI, "CopyService");
@@ -179,6 +181,12 @@ public interface ServiceRegistry
@NotAuditable
MimetypeService getMimetypeService();
/**
* @return the content filter languages service (or null, if one is not provided)
*/
@NotAuditable
ContentFilterLanguagesService getContentFilterLanguagesService();
/**
* @return the search service (or null, if one is not provided)
*/

View File

@@ -0,0 +1,115 @@
/*
* 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.service.cmr.ml;
import java.util.List;
import org.alfresco.error.AlfrescoRuntimeException;
import org.alfresco.service.Auditable;
import org.alfresco.service.NotAuditable;
import org.alfresco.service.PublicService;
/**
* This service interface provides support for content filter languages .
*
* @author yanipig
*
*/
@PublicService
public interface ContentFilterLanguagesService
{
/**
* I18N message prefix to found the translation of a language label with a
* given lang code.
*/
public static final String MESSAGE_PREFIX = "content_filter_lang.";
/**
* Get the order of the specified language code
*
* @param code
* @return
* @throws AlfrescoRuntimeException if the code doesn't exist
*/
@NotAuditable
public int getOrderByCode(String code);
/**
* Get the language of the specified language code
*
* @param code
* @return
* @throws AlfrescoRuntimeException if the code doesn't exist
*/
@NotAuditable
public String getLabelByCode(String code);
/**
* Get ordered list of languages code
*
* @return the map of displays indexed by extension
*/
@Auditable
public List<String> getFilterLanguages();
/**
* Get the the odered filter which results form an extract of availableLanguages on the filterLanguages
*
* @param availableLanguages the languages list whose will be removed from the filterLanguages
* @return
*/
@Auditable
public List<String> getMissingLanguages(List<String> availableLanguages);
/**
* @return the default content filter language, null if it's not set.
*/
@Auditable
public String getDefaultLanguage();
/**
* Since <code>java.util.Locale</code> uses and returns <b>old</b> ISO code and the content-filter-lang.xml
* respects the <b>new ones</b>. This method convert new codes into old codes:
* <p>(he, yi, and id) new codes to (iw, ji, and in) old codes </p>
*
* @param code the ISO language code to convert
* @return the convertion of the codes he, yi, and id or the given code
*/
@NotAuditable
public String convertToOldISOCode(String code);
/**
* Since <code>java.util.Locale</code> uses and returns <b>old</b> ISO code and the content-filter-lang.xml
* respects the <b>new ones</b>. This method convert old codes into new codes:
* <p>(iw, ji, and in) old codes to (he, yi, and id) new codes </p>
*
* @param code the ISO language code to convert
* @return the convertion of the codes iw, ji, and in or the given code
*/
@NotAuditable
public String convertToNewISOCode(String code);
}

View File

@@ -24,6 +24,7 @@
*/
package org.alfresco.service.cmr.ml;
import java.util.List;
import java.util.Locale;
import java.util.Map;
import java.util.Set;
@@ -117,4 +118,38 @@ public interface MultilingualContentService
*/
@Auditable(key = Auditable.Key.ARG_0, parameters = {"translationNodeRef", "locale"})
NodeRef getTranslationForLocale(NodeRef translationNodeRef, Locale locale);
/**
* Given <b>cm:mlDocument</b> or a <b>cm:mlContainer</b>, this node returns each
* locale that the node hasn't a translation yet.
*
* @param localizedNodeRef the <b>cm:mlDocument</b> or the <b>cm:mlContainer</b>
* @param addThisNodeLocale if true, add the locale of the given <b>cm:mlDocument</b> in the list.
* @return
*/
@Auditable(key = Auditable.Key.ARG_0, parameters = {"localizedNodeRef", "addThisNodeLocale"})
List<Locale> getMissingTranslations(NodeRef localizedNodeRef, boolean addThisNodeLocale);
/**
* Given any node, this returns the pivot translation. The pivot translation is the translation
* that its locale is referenced by the locale of the MLContainer. The translation can't be an
* empty translation.
*
* @param nodeRef the node to test
* @return the pivot translation
*/
@Auditable(key = Auditable.Key.ARG_0, parameters = {"nodeRef"})
NodeRef getPivotTranslation(NodeRef nodeRef);
/**
* Make a empty translation out of an existing document. The necessary translation structures will be created
* as necessary.
*
* @param translationOfNodeRef An existing <b>cm:mlDocument</b> or <b>cm:mlContainer</b>
* @param name The name of the translation to create
* @return Returns the new created <b>cm:mlEmptyTranslation</b>
*/
@Auditable(key = Auditable.Key.ARG_0, parameters = {"translationOfNodeRef", "name", "locale"})
NodeRef addEmptyTranslation(NodeRef translationOfNodeRef, String name, Locale locale);
}