Merged BRANCHES/DEV/RGAUSS/4.2-CORE-CHANGES-43298 to HEAD:

43309: Merged BRANCHES/DEV/RGAUSS/V4.1-BUG-FIX-TAG-MAPPING to BRANCHES/DEV/RGAUSS/4.2-CORE-CHANGES-43298:
        39447: Merged BRANCHES/DEV/RGAUSS/V4.1-BUG-FIX-38527 to BRANCHES/DEV/RGAUSS/V4.1-BUG-FIX-TAG-MAPPING:
             38719: ALF-14965: Ability to Map Extracted Metadata to Standard Tags
                  - Added more specific MalformedNodeRefException
                  - Changed NodeRef to throw MalformedNodeRefException on a bad string constructor rather than generic AlfrescoRunTimeException
                  - ContentMetadataExtracter: Added enableStringTagging boolean field
                  - ContentMetadataExtracter: Added taggingService
                  - ContentMetadataExtracter: Added addTags method responsible for iterating the raw value from the metadata extracter and creating either string tags or NodeRef links
                  - ContentMetadataExtracter: Added check for instanceof AbstractMappingMetadataExtracter and if so set its enableStringTagging field
                  - ContentMetadataExtracter: Added check for enableStringTagging in executeImpl and if enabled call addTags
                  - AbstractMappingMetadataExtracter: Added enableStringTagging boolean field
                  - AbstractMappingMetadataExtracter: Added catch of MalformedNodeRefException and if string tagging enabled leave the raw properties for processing by ContentMetadataExtracter
        39448: ALF-14965: Ability to Map Extracted Metadata to Standard Tags
             - Added fix for single valued raw properties
             - Added tag mapping unit test and test resource
        39449: ALF-14965: Ability to Map Extracted Metadata to Standard Tags
             - Added better class javadoc
        39479: ALF-14965: Ability to Map Extracted Metadata to Standard Tags
             - Changed behavior of addition of tags by NodeRef
             - Changed where some items were setup in the unit test
             - Added manual test keywords to those extracted from file in unit test
             - Added testing of addition of tag by NodeRef
   43324: ALF-14965: Ability to Map Extracted Metadata to Standard Tags
        - Added Javadoc to AbstractMappingMetadataExtracter.setEnableStringTagging
        - Changed check of enableStringTagging in AbstractMappingMetadataExtracter.convertSystemPropertyValues to allow graceful failure if mappings to cm:taggable are present but enableStringTagging is false


git-svn-id: https://svn.alfresco.com/repos/alfresco-enterprise/alfresco/HEAD/root@43335 c4b6b30b-aa2e-2d43-bbcb-ca4b014f7261
This commit is contained in:
Ray Gauss
2012-11-02 11:53:52 +00:00
parent 7c67a013ee
commit be1a9f5d17
4 changed files with 552 additions and 5 deletions

View File

@@ -19,6 +19,8 @@
package org.alfresco.repo.action.executer;
import java.io.Serializable;
import java.util.ArrayList;
import java.util.Collection;
import java.util.HashMap;
import java.util.HashSet;
import java.util.List;
@@ -26,6 +28,7 @@ import java.util.Map;
import java.util.Set;
import org.alfresco.model.ContentModel;
import org.alfresco.repo.content.metadata.AbstractMappingMetadataExtracter;
import org.alfresco.repo.content.metadata.MetadataExtracter;
import org.alfresco.repo.content.metadata.MetadataExtracterRegistry;
import org.alfresco.service.cmr.action.Action;
@@ -37,6 +40,8 @@ import org.alfresco.service.cmr.repository.ContentReader;
import org.alfresco.service.cmr.repository.ContentService;
import org.alfresco.service.cmr.repository.NodeRef;
import org.alfresco.service.cmr.repository.NodeService;
import org.alfresco.service.cmr.repository.datatype.DefaultTypeConverter;
import org.alfresco.service.cmr.tagging.TaggingService;
import org.alfresco.service.namespace.QName;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
@@ -60,8 +65,10 @@ public class ContentMetadataExtracter extends ActionExecuterAbstractBase
private NodeService nodeService;
private ContentService contentService;
private DictionaryService dictionaryService;
private TaggingService taggingService;
private MetadataExtracterRegistry metadataExtracterRegistry;
private boolean carryAspectProperties = true;
private boolean enableStringTagging = false;
public ContentMetadataExtracter()
{
@@ -91,6 +98,14 @@ public class ContentMetadataExtracter extends ActionExecuterAbstractBase
this.dictionaryService = dictService;
}
/**
* @param taggingService The TaggingService to set.
*/
public void setTaggingService(TaggingService taggingService)
{
this.taggingService = taggingService;
}
/**
* @param metadataExtracterRegistry The metadataExtracterRegistry to set.
*/
@@ -111,6 +126,91 @@ public class ContentMetadataExtracter extends ActionExecuterAbstractBase
this.carryAspectProperties = carryAspectProperties;
}
/**
* Whether or not to enable mapping of simple strings to cm:taggable tags
*
* @param enableStringTagging <tt>true</tt> find or create tags for each string
* mapped to cm:taggable. <tt>false</tt> (default)
* ignore mapping strings to tags.
*/
public void setEnableStringTagging(boolean enableStringTagging)
{
this.enableStringTagging = enableStringTagging;
}
/**
* Iterates the values of the taggable property which the metadata
* extractor should have already attempted to convert values to {@link NodeRef}s.
* <p>
* If conversion by the metadata extracter failed due to a MalformedNodeRefException
* the taggable property should still contain raw string values.
* <p>
* Mixing of NodeRefs and string values is permitted so each raw value is
* checked for a valid NodeRef representation and if so, converts to a NodeRef,
* if not, adds as a tag via the {@link TaggingService}.
*
* @param actionedUponNodeRef The NodeRef being actioned upon
* @param propertyDef the PropertyDefinition of the taggable property
* @param rawValue the raw value from the metadata extracter
*/
@SuppressWarnings("unchecked")
protected void addTags(NodeRef actionedUponNodeRef, PropertyDefinition propertyDef, Serializable rawValue)
{
List<String> tags = new ArrayList<String>();
if (logger.isDebugEnabled())
{
logger.debug("converting " + rawValue.toString() + " of type " +
rawValue.getClass().getCanonicalName() + " to tags");
}
if (rawValue instanceof Collection<?>)
{
for (Object singleValue : (Collection<?>) rawValue)
{
if (singleValue instanceof String)
{
if (NodeRef.isNodeRef((String) singleValue))
{
// Convert to a NodeRef
Serializable convertedPropertyValue = (Serializable) DefaultTypeConverter.INSTANCE.convert(
propertyDef.getDataType(),
(String) singleValue);
String tagName = (String) nodeService.getProperty((NodeRef) convertedPropertyValue, ContentModel.PROP_NAME);
if (logger.isTraceEnabled())
{
logger.trace("found tag '" + tagName + "' from tag nodeRef '" + (String) singleValue + "', " +
"adding to " + actionedUponNodeRef.toString());
}
tags.add(tagName);
}
else
{
// Must be a simple string
if (logger.isTraceEnabled())
{
logger.trace("adding string tag '" + (String) singleValue + "' to " + actionedUponNodeRef.toString());
}
tags.add((String) singleValue);
}
}
else if (singleValue instanceof NodeRef)
{
String tagName = (String) nodeService.getProperty((NodeRef) singleValue, ContentModel.PROP_NAME);
tags.add(tagName);
}
}
}
else if (rawValue instanceof String)
{
if (logger.isTraceEnabled())
{
logger.trace("adding tag '" + (String) rawValue + "' to " + actionedUponNodeRef.toString());
}
tags.add((String) rawValue);
}
taggingService.addTags(actionedUponNodeRef, tags);
}
/**
* @see org.alfresco.repo.action.executer.ActionExecuter#execute(org.alfresco.service.cmr.repository.NodeRef,
* NodeRef)
@@ -144,6 +244,10 @@ public class ContentMetadataExtracter extends ActionExecuterAbstractBase
// There is no extracter to use
return;
}
if (enableStringTagging && (extracter instanceof AbstractMappingMetadataExtracter))
{
((AbstractMappingMetadataExtracter) extracter).setEnableStringTagging(enableStringTagging);
}
// Get all the node's properties
Map<QName, Serializable> nodeProperties = nodeService.getProperties(actionedUponNodeRef);
@@ -212,11 +316,22 @@ public class ContentMetadataExtracter extends ActionExecuterAbstractBase
ClassDefinition propertyContainerDef = propertyDef.getContainerClass();
if (propertyContainerDef.isAspect())
{
QName aspectQName = propertyContainerDef.getName();
requiredAspectQNames.add(aspectQName);
// Get all properties associated with the aspect
Set<QName> aspectProperties = propertyContainerDef.getProperties().keySet();
aspectPropertyQNames.addAll(aspectProperties);
if (enableStringTagging && propertyContainerDef.getName().equals(ContentModel.ASPECT_TAGGABLE))
{
Serializable oldValue = nodeProperties.get(propertyQName);
addTags(actionedUponNodeRef, propertyDef, oldValue);
// Replace the raw value with the created tag NodeRefs
nodeProperties.put(ContentModel.PROP_TAGS,
nodeService.getProperty(actionedUponNodeRef, ContentModel.PROP_TAGS));
}
else
{
QName aspectQName = propertyContainerDef.getName();
requiredAspectQNames.add(aspectQName);
// Get all properties associated with the aspect
Set<QName> aspectProperties = propertyContainerDef.getProperties().keySet();
aspectPropertyQNames.addAll(aspectProperties);
}
}
}

View File

@@ -0,0 +1,385 @@
/*
* Copyright (C) 2005-2012 Alfresco Software Limited.
*
* This file is part of Alfresco
*
* Alfresco is free software: you can redistribute it and/or modify
* it under the terms of the GNU Lesser General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* Alfresco 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 Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public License
* along with Alfresco. If not, see <http://www.gnu.org/licenses/>.
*/
package org.alfresco.repo.action.executer;
import java.io.Serializable;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collection;
import java.util.Date;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Properties;
import java.util.Set;
import junit.framework.TestCase;
import org.alfresco.model.ContentModel;
import org.alfresco.repo.action.ActionImpl;
import org.alfresco.repo.action.ActionModel;
import org.alfresco.repo.action.AsynchronousActionExecutionQueuePolicies;
import org.alfresco.repo.content.MimetypeMap;
import org.alfresco.repo.content.metadata.MetadataExtracterRegistry;
import org.alfresco.repo.content.metadata.TikaPoweredMetadataExtracter;
import org.alfresco.repo.content.transform.AbstractContentTransformerTest;
import org.alfresco.repo.policy.Behaviour.NotificationFrequency;
import org.alfresco.repo.policy.JavaBehaviour;
import org.alfresco.repo.policy.PolicyComponent;
import org.alfresco.repo.security.authentication.AuthenticationComponent;
import org.alfresco.repo.tagging.TaggingServiceImplTest;
import org.alfresco.repo.tagging.TaggingServiceImplTest.AsyncOccurs;
import org.alfresco.repo.tagging.UpdateTagScopesActionExecuter;
import org.alfresco.repo.transaction.AlfrescoTransactionSupport;
import org.alfresco.repo.transaction.AlfrescoTransactionSupport.TxnReadState;
import org.alfresco.repo.transaction.RetryingTransactionHelper.RetryingTransactionCallback;
import org.alfresco.service.cmr.audit.AuditService;
import org.alfresco.service.cmr.repository.ContentReader;
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.cmr.repository.NodeService;
import org.alfresco.service.cmr.repository.StoreRef;
import org.alfresco.service.cmr.tagging.TaggingService;
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.alfresco.util.GUID;
import org.apache.tika.metadata.Metadata;
import org.apache.tika.parser.Parser;
import org.apache.tika.parser.jpeg.JpegParser;
import org.springframework.context.ConfigurableApplicationContext;
import com.google.common.collect.Sets;
/**
* Test of the ActionExecuter for extracting metadata, specifically for
* the mapping to cm:taggable tags which requires different transaction
* mechanisms than the existing {@link ContentMetadataExtracterTest}.
*
* @author Roy Wetherall
* @author Nick Burch
* @author Ray Gauss II
*/
public class ContentMetadataExtracterTagMappingTest extends TestCase
{
private static ConfigurableApplicationContext ctx =
(ConfigurableApplicationContext)ApplicationContextHelper.getApplicationContext();
protected static final String TAGGING_AUDIT_APPLICATION_NAME = "Alfresco Tagging Service";
protected static final String QUICK_FILENAME = "quickIPTC.jpg";
protected static final String QUICK_KEYWORD = "fox";
protected static final String TAG_1 = "tag one";
protected static final String TAG_2 = "tag two";
protected static final String TAG_3 = "Tag Three";
/** Services */
private TaggingService taggingService;
private NodeService nodeService;
private ContentService contentService;
private AuditService auditService;
private TransactionService transactionService;
private AuthenticationComponent authenticationComponent;
private AsyncOccurs asyncOccurs;
private static StoreRef storeRef;
private static NodeRef rootNode;
private NodeRef folder;
private NodeRef document;
private ContentMetadataExtracter executer;
private TagMappingMetadataExtracter extractor;
private static boolean init = false;
private final static String ID = GUID.generate();
@Override
protected void setUp() throws Exception
{
// Detect any dangling transactions as there is a lot of direct UserTransaction manipulation
if (AlfrescoTransactionSupport.getTransactionReadState() != TxnReadState.TXN_NONE)
{
throw new IllegalStateException(
"There should not be any transactions when starting test: " +
AlfrescoTransactionSupport.getTransactionId() + " started at " +
new Date(AlfrescoTransactionSupport.getTransactionStartTime()));
}
// Get services
this.taggingService = (TaggingService)ctx.getBean("TaggingService");
this.nodeService = (NodeService) ctx.getBean("NodeService");
this.contentService = (ContentService) ctx.getBean("ContentService");
this.transactionService = (TransactionService)ctx.getBean("transactionComponent");
this.auditService = (AuditService)ctx.getBean("auditService");
this.authenticationComponent = (AuthenticationComponent)ctx.getBean("authenticationComponent");
this.executer = (ContentMetadataExtracter) ctx.getBean("extract-metadata");
executer.setEnableStringTagging(true);
executer.setTaggingService(taggingService);
if (init == false)
{
this.transactionService.getRetryingTransactionHelper().doInTransaction(new RetryingTransactionCallback<Void>(){
@Override
public Void execute() throws Throwable
{
// Authenticate as the system user
authenticationComponent.setSystemUserAsCurrentUser();
// Create the store and get the root node
ContentMetadataExtracterTagMappingTest.storeRef = nodeService.createStore(StoreRef.PROTOCOL_WORKSPACE, "Test_" + System.currentTimeMillis());
ContentMetadataExtracterTagMappingTest.rootNode = nodeService.getRootNode(ContentMetadataExtracterTagMappingTest.storeRef);
// Create the required tagging category
NodeRef catContainer = nodeService.createNode(ContentMetadataExtracterTagMappingTest.rootNode, ContentModel.ASSOC_CHILDREN, QName.createQName(NamespaceService.CONTENT_MODEL_1_0_URI, "categoryContainer"), ContentModel.TYPE_CONTAINER).getChildRef();
NodeRef catRoot = nodeService.createNode(
catContainer,
ContentModel.ASSOC_CHILDREN,
QName.createQName(NamespaceService.CONTENT_MODEL_1_0_URI, "categoryRoot"),
ContentModel.TYPE_CATEGORYROOT).getChildRef();
nodeService.createNode(
catRoot,
ContentModel.ASSOC_CATEGORIES,
ContentModel.ASPECT_TAGGABLE,
ContentModel.TYPE_CATEGORY).getChildRef();
MetadataExtracterRegistry registry = (MetadataExtracterRegistry) ctx.getBean("metadataExtracterRegistry");
extractor = new TagMappingMetadataExtracter();
extractor.setRegistry(registry);
extractor.register();
init = true;
return null;
}});
}
// We want to know when tagging actions have finished running
asyncOccurs = (new TaggingServiceImplTest()).new AsyncOccurs();
((PolicyComponent)ctx.getBean("policyComponent")).bindClassBehaviour(
AsynchronousActionExecutionQueuePolicies.OnAsyncActionExecute.QNAME,
ActionModel.TYPE_ACTION,
new JavaBehaviour(asyncOccurs, "onAsyncActionExecute", NotificationFrequency.EVERY_EVENT)
);
// We do want action tracking whenever the tag scope updater runs
UpdateTagScopesActionExecuter updateTagsAction =
(UpdateTagScopesActionExecuter)ctx.getBean("update-tagscope");
updateTagsAction.setTrackStatus(true);
// Create the folders and documents to be tagged
createTestDocumentsAndFolders();
}
@Override
protected void tearDown() throws Exception
{
removeTestDocumentsAndFolders();
if (AlfrescoTransactionSupport.getTransactionReadState() != TxnReadState.TXN_NONE)
{
fail("Test is not transaction-safe. Fix up transaction handling and re-test.");
}
}
private void createTestDocumentsAndFolders() throws Exception
{
this.transactionService.getRetryingTransactionHelper().doInTransaction(new RetryingTransactionCallback<Void>(){
@Override
public Void execute() throws Throwable
{
// Authenticate as the system user
authenticationComponent.setSystemUserAsCurrentUser();
String guid = GUID.generate();
// Create a folder
Map<QName, Serializable> folderProps = new HashMap<QName, Serializable>(1);
folderProps.put(ContentModel.PROP_NAME, "testFolder" + guid);
folder = nodeService.createNode(
ContentMetadataExtracterTagMappingTest.rootNode,
ContentModel.ASSOC_CHILDREN,
QName.createQName(NamespaceService.CONTENT_MODEL_1_0_URI, "testFolder" + guid),
ContentModel.TYPE_FOLDER,
folderProps).getChildRef();
// Create a node
Map<QName, Serializable> docProps = new HashMap<QName, Serializable>(1);
docProps.put(ContentModel.PROP_NAME, "testDocument" + guid + ".jpg");
document = nodeService.createNode(
folder,
ContentModel.ASSOC_CONTAINS,
QName.createQName(NamespaceService.CONTENT_MODEL_1_0_URI, "testDocument" + guid + ".jpg"),
ContentModel.TYPE_CONTENT,
docProps).getChildRef();
try
{
ContentWriter cw = contentService.getWriter(document, ContentModel.PROP_CONTENT, true);
cw.setMimetype(MimetypeMap.MIMETYPE_IMAGE_JPEG);
cw.putContent(AbstractContentTransformerTest.loadNamedQuickTestFile(QUICK_FILENAME));
}
catch (Exception e)
{
fail(e.getMessage());
}
return null;
}
});
}
private void removeTestDocumentsAndFolders() throws Exception
{
this.transactionService.getRetryingTransactionHelper().doInTransaction(new RetryingTransactionCallback<Void>(){
@Override
public Void execute() throws Throwable
{
// Authenticate as the system user
authenticationComponent.setSystemUserAsCurrentUser();
// If anything is a tag scope, stop it being
NodeRef[] nodes = new NodeRef[] { document, folder };
for(NodeRef nodeRef : nodes)
{
if(taggingService.isTagScope(nodeRef))
{
taggingService.removeTagScope(nodeRef);
}
}
// Remove the sample nodes
for(NodeRef nodeRef : nodes)
{
nodeService.deleteNode(nodeRef);
}
// Tidy up the audit component, now all the nodes have gone
auditService.clearAudit(
TAGGING_AUDIT_APPLICATION_NAME,
0l, System.currentTimeMillis()+1
);
return null;
}
});
}
private static class TagMappingMetadataExtracter extends TikaPoweredMetadataExtracter
{
private String existingTagNodeRef;
public TagMappingMetadataExtracter()
{
super(Sets.newHashSet(MimetypeMap.MIMETYPE_IMAGE_JPEG));
Properties mappingProperties = new Properties();
// TODO move to new keyword once tika is upgraded
mappingProperties.put(Metadata.KEYWORDS, ContentModel.PROP_TAGS.toString());
mappingProperties.put(Metadata.DESCRIPTION, ContentModel.PROP_DESCRIPTION.toString());
setMappingProperties(mappingProperties);
}
public void setExistingTagNodeRef(String existingTagNodeRef)
{
this.existingTagNodeRef = existingTagNodeRef;
}
@Override
protected Map<String, Set<QName>> getDefaultMapping()
{
// No need to give anything back as we have explicitly set the mapping already
return new HashMap<String, Set<QName>>(0);
}
@Override
public boolean isSupported(String sourceMimetype)
{
return sourceMimetype.equals(MimetypeMap.MIMETYPE_IMAGE_JPEG);
}
@Override
protected Parser getParser()
{
return new JpegParser();
}
@SuppressWarnings("unchecked")
public Map<String, Serializable> extractRaw(ContentReader reader) throws Throwable
{
Map<String, Serializable> rawMap = super.extractRaw(reader);
// Add some test keywords to those actually extracted from the file including a nodeRef
List<String> keywords = new ArrayList<String>(Arrays.asList(new String[] { existingTagNodeRef, TAG_2, TAG_3 }));
Serializable extractedKeywords = rawMap.get(Metadata.KEYWORDS);
if (extractedKeywords != null && extractedKeywords instanceof String)
{
keywords.add((String) extractedKeywords);
}
else if (extractedKeywords != null && extractedKeywords instanceof Collection<?>)
{
keywords.addAll((Collection<? extends String>) extractedKeywords);
}
putRawValue(Metadata.KEYWORDS, (Serializable) keywords, rawMap);
return rawMap;
}
}
/**
* Test execution of mapping strings to tags
*/
public void testTagMapping()
{
this.transactionService.getRetryingTransactionHelper().doInTransaction(new RetryingTransactionCallback<Void>(){
@Override
public Void execute() throws Throwable
{
NodeRef existingTagNodeRef = taggingService.createTag(storeRef, TAG_1);
extractor.setExistingTagNodeRef(existingTagNodeRef.toString());
ActionImpl action = new ActionImpl(document, ID, ContentMetadataExtracter.EXECUTOR_NAME, null);
executer.execute(action, document);
// Test extracted properties
assertEquals(ContentMetadataExtracterTest.QUICK_DESCRIPTION,
nodeService.getProperty(document, ContentModel.PROP_DESCRIPTION));
assertTrue("storeRef tags should contain '" + QUICK_KEYWORD + "'",
taggingService.getTags(storeRef).contains(QUICK_KEYWORD));
assertTrue("document's tags should contain '" + QUICK_KEYWORD + "'",
taggingService.getTags(document).contains(QUICK_KEYWORD));
// Test manually added keyword
assertTrue("tags should contain '" + TAG_2 + "'",
taggingService.getTags(document).contains(TAG_2));
// Test manually added nodeRef keyword
assertTrue("tags should contain '" + TAG_1 + "'",
taggingService.getTags(document).contains(TAG_1));
return null;
}
});
}
}

View File

@@ -38,11 +38,13 @@ import java.util.Set;
import java.util.StringTokenizer;
import org.alfresco.error.AlfrescoRuntimeException;
import org.alfresco.model.ContentModel;
import org.alfresco.service.cmr.dictionary.DataTypeDefinition;
import org.alfresco.service.cmr.dictionary.DictionaryService;
import org.alfresco.service.cmr.dictionary.PropertyDefinition;
import org.alfresco.service.cmr.repository.ContentReader;
import org.alfresco.service.cmr.repository.ContentWriter;
import org.alfresco.service.cmr.repository.MalformedNodeRefException;
import org.alfresco.service.cmr.repository.MimetypeService;
import org.alfresco.service.cmr.repository.datatype.DefaultTypeConverter;
import org.alfresco.service.cmr.repository.datatype.TypeConversionException;
@@ -114,6 +116,7 @@ abstract public class AbstractMappingMetadataExtracter implements MetadataExtrac
private Map<QName, Set<String>> embedMapping;
private boolean inheritDefaultMapping;
private boolean inheritDefaultEmbedMapping;
private boolean enableStringTagging;
/**
* Default constructor. If this is called, then {@link #isSupported(String)} should
@@ -351,6 +354,18 @@ abstract public class AbstractMappingMetadataExtracter implements MetadataExtrac
this.inheritDefaultMapping = inheritDefaultMapping;
}
/**
* Whether or not to enable the pass through of simple strings to cm:taggable tags
*
* @param enableStringTagging <tt>true</tt> find or create tags for each string
* mapped to cm:taggable. <tt>false</tt> (default)
* ignore mapping strings to tags.
*/
public void setEnableStringTagging(boolean enableStringTagging)
{
this.enableStringTagging = enableStringTagging;
}
/**
* Set if the embed property mappings augment or override the mapping generically provided by the
* extracter implementation. The default is <tt>false</tt>, i.e. any mapping set completely
@@ -1298,6 +1313,38 @@ abstract public class AbstractMappingMetadataExtracter implements MetadataExtrac
propertyValue);
}
}
catch (MalformedNodeRefException e)
{
if (propertyQName.equals(ContentModel.PROP_TAGS))
{
if (enableStringTagging)
{
// We must want to map tag string values instead of nodeRefs
// ContentMetadataExtracter will take care of tagging by string
ArrayList<Object> list = new ArrayList<Object>(1);
for (Object value : (Object[]) propertyValue)
{
list.add(value);
}
convertedProperties.put(propertyQName, list);
}
else
{
if (logger.isInfoEnabled())
{
logger.info("enableStringTagging is false and could not convert " +
propertyQName.toString() + ": " + e.getMessage());
}
}
}
else
{
if (failOnTypeConversion)
{
throw e;
}
}
}
}
// Done
return convertedProperties;

Binary file not shown.

After

Width:  |  Height:  |  Size: 24 KiB