diff --git a/source/java/org/alfresco/repo/action/executer/ContentMetadataExtracter.java b/source/java/org/alfresco/repo/action/executer/ContentMetadataExtracter.java
index 023501108b..615f8dc9dd 100644
--- a/source/java/org/alfresco/repo/action/executer/ContentMetadataExtracter.java
+++ b/source/java/org/alfresco/repo/action/executer/ContentMetadataExtracter.java
@@ -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.
*/
@@ -110,7 +125,92 @@ public class ContentMetadataExtracter extends ActionExecuterAbstractBase
{
this.carryAspectProperties = carryAspectProperties;
}
+
+ /**
+ * Whether or not to enable mapping of simple strings to cm:taggable tags
+ *
+ * @param enableStringTagging true find or create tags for each string
+ * mapped to cm:taggable. false (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.
+ *
+ * If conversion by the metadata extracter failed due to a MalformedNodeRefException
+ * the taggable property should still contain raw string values.
+ *
+ * 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 tags = new ArrayList();
+ 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 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 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 aspectProperties = propertyContainerDef.getProperties().keySet();
+ aspectPropertyQNames.addAll(aspectProperties);
+ }
}
}
diff --git a/source/java/org/alfresco/repo/action/executer/ContentMetadataExtracterTagMappingTest.java b/source/java/org/alfresco/repo/action/executer/ContentMetadataExtracterTagMappingTest.java
new file mode 100644
index 0000000000..7e86ba72b4
--- /dev/null
+++ b/source/java/org/alfresco/repo/action/executer/ContentMetadataExtracterTagMappingTest.java
@@ -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 .
+ */
+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(){
+
+ @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(){
+
+ @Override
+ public Void execute() throws Throwable
+ {
+
+ // Authenticate as the system user
+ authenticationComponent.setSystemUserAsCurrentUser();
+
+ String guid = GUID.generate();
+
+ // Create a folder
+ Map folderProps = new HashMap(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 docProps = new HashMap(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(){
+ @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> getDefaultMapping()
+ {
+ // No need to give anything back as we have explicitly set the mapping already
+ return new HashMap>(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 extractRaw(ContentReader reader) throws Throwable
+ {
+ Map rawMap = super.extractRaw(reader);
+
+ // Add some test keywords to those actually extracted from the file including a nodeRef
+ List keywords = new ArrayList(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(){
+
+ @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;
+ }
+ });
+ }
+
+}
diff --git a/source/java/org/alfresco/repo/content/metadata/AbstractMappingMetadataExtracter.java b/source/java/org/alfresco/repo/content/metadata/AbstractMappingMetadataExtracter.java
index 959524e234..e829e19e9f 100644
--- a/source/java/org/alfresco/repo/content/metadata/AbstractMappingMetadataExtracter.java
+++ b/source/java/org/alfresco/repo/content/metadata/AbstractMappingMetadataExtracter.java
@@ -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> 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 true find or create tags for each string
+ * mapped to cm:taggable. false (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 false, 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