diff --git a/source/java/org/alfresco/repo/content/metadata/AbstractMappingMetadataExtracter.java b/source/java/org/alfresco/repo/content/metadata/AbstractMappingMetadataExtracter.java index 5c9eca043a..d8a3f75a57 100644 --- a/source/java/org/alfresco/repo/content/metadata/AbstractMappingMetadataExtracter.java +++ b/source/java/org/alfresco/repo/content/metadata/AbstractMappingMetadataExtracter.java @@ -33,6 +33,7 @@ import java.util.HashSet; import java.util.List; import java.util.Locale; import java.util.Map; +import java.util.Map.Entry; import java.util.Properties; import java.util.Set; import java.util.StringTokenizer; @@ -55,6 +56,8 @@ import org.apache.commons.logging.Log; import org.apache.commons.logging.LogFactory; import org.apache.xmlbeans.impl.xb.xsdschema.All; import org.springframework.beans.factory.BeanNameAware; +import org.springframework.context.ApplicationContext; +import org.springframework.context.ApplicationContextAware; import org.springframework.extensions.surf.util.ISO8601DateFormat; /** @@ -97,10 +100,13 @@ import org.springframework.extensions.surf.util.ISO8601DateFormat; * @author Jesper Steen Møller * @author Derek Hulley */ -abstract public class AbstractMappingMetadataExtracter implements MetadataExtracter, MetadataEmbedder, BeanNameAware +abstract public class AbstractMappingMetadataExtracter implements MetadataExtracter, MetadataEmbedder, BeanNameAware, ApplicationContextAware { public static final String NAMESPACE_PROPERTY_PREFIX = "namespace.prefix."; private static final String ERR_TYPE_CONVERSION = "metadata.extraction.err.type_conversion"; + public static final String PROPERTY_PREFIX_METADATA = "metadata."; + public static final String PROPERTY_COMPONENT_EXTRACT = ".extract."; + public static final String PROPERTY_COMPONENT_EMBED = ".extract."; protected static Log logger = LogFactory.getLog(AbstractMappingMetadataExtracter.class); @@ -120,6 +126,7 @@ abstract public class AbstractMappingMetadataExtracter implements MetadataExtrac private boolean inheritDefaultEmbedMapping; private boolean enableStringTagging; private String beanName; + private ApplicationContext applicationContext; private Properties properties; /** @@ -390,6 +397,11 @@ abstract public class AbstractMappingMetadataExtracter implements MetadataExtrac return beanName; } + public void setApplicationContext(ApplicationContext applicationContext) + { + this.applicationContext = applicationContext; + } + /** * The Alfresco global properties. */ @@ -601,16 +613,92 @@ abstract public class AbstractMappingMetadataExtracter implements MetadataExtrac } } + /** + * A utility method to convert global properties to the Map form for the given + * propertyComponent. + *

+ * Mappings can be specified using the same method defined for + * normal mapping properties files but with a prefix of + * metadata.extracter, the extracter bean name, and the propertyComponent. + * For example: + * + * metadata.extracter.TikaAuto.extract.namespace.prefix.my=http://DummyMappingMetadataExtracter + * metadata.extracter.TikaAuto.extract.namespace.prefix.cm=http://www.alfresco.org/model/content/1.0 + * metadata.extracter.TikaAuto.extract.dc\:description=cm:description, my:customDescription + * + */ + private Map getRelevantGlobalProperties(String propertyComponent) + { + if (applicationContext == null) + { + logger.info("ApplicationContext not set"); + return null; + } + Properties globalProperties = (Properties) applicationContext.getBean("global-properties"); + if (globalProperties == null) + { + logger.info("Could not get global-properties"); + return null; + } + Map relevantGlobalPropertiesMap = + new HashMap(); + String propertyPrefix = PROPERTY_PREFIX_METADATA + beanName + propertyComponent; + for (Entry globalEntry : globalProperties.entrySet()) + { + if (((String) globalEntry.getKey()).startsWith(propertyPrefix)) + { + relevantGlobalPropertiesMap.put( + ((String) globalEntry.getKey()).replace(propertyPrefix, ""), + globalEntry.getValue()); + } + } + return relevantGlobalPropertiesMap; + } + + /** + * A utility method to convert global properties to the Map form for the given + * propertyComponent. + *

+ * Mappings can be specified using the same method defined for + * normal mapping properties files but with a prefix of + * metadata.extracter, the extracter bean name, and the extract component. + * For example: + * + * metadata.extracter.TikaAuto.extract.namespace.prefix.my=http://DummyMappingMetadataExtracter + * metadata.extracter.TikaAuto.extract.namespace.prefix.cm=http://www.alfresco.org/model/content/1.0 + * metadata.extracter.TikaAuto.extract.dc\:description=cm:description, my:customDescription + * + */ + protected Map> readGlobalExtractMappingProperties() + { + Map relevantGlobalPropertiesMap = getRelevantGlobalProperties(PROPERTY_COMPONENT_EXTRACT); + if (relevantGlobalPropertiesMap == null) + { + return null; + } + return readMappingProperties(relevantGlobalPropertiesMap.entrySet()); + } + /** * A utility method to convert mapping properties to the Map form. * * @see #setMappingProperties(Properties) */ protected Map> readMappingProperties(Properties mappingProperties) + { + return readMappingProperties(mappingProperties.entrySet()); + } + + /** + * A utility method to convert mapping properties entries to the Map form. + * + * @see #setMappingProperties(Properties) + */ + private Map> readMappingProperties(Set> mappingPropertiesEntries) { Map namespacesByPrefix = new HashMap(5); // Get the namespaces - for (Map.Entry entry : mappingProperties.entrySet()) + for (Map.Entry entry : mappingPropertiesEntries) { String propertyName = (String) entry.getKey(); if (propertyName.startsWith(NAMESPACE_PROPERTY_PREFIX)) @@ -622,7 +710,7 @@ abstract public class AbstractMappingMetadataExtracter implements MetadataExtrac } // Create the mapping Map> convertedMapping = new HashMap>(17); - for (Map.Entry entry : mappingProperties.entrySet()) + for (Map.Entry entry : mappingPropertiesEntries) { String documentProperty = (String) entry.getKey(); String qnamesStr = (String) entry.getValue(); @@ -723,6 +811,32 @@ abstract public class AbstractMappingMetadataExtracter implements MetadataExtrac } } } + + /** + * A utility method to convert global mapping properties to the Map form. + *

+ * Different from readGlobalExtractMappingProperties in that keys are the Alfresco QNames + * and values are file metadata properties. + *

+ * Mappings can be specified using the same method defined for + * normal embed mapping properties files but with a prefix of + * metadata.extracter, the extracter bean name, and the embed component. + * For example: + * + * metadata.extracter.TikaAuto.embed.namespace.prefix.cm=http://www.alfresco.org/model/content/1.0 + * metadata.extracter.TikaAuto.embed.cm\:description=description + * + * @see #setMappingProperties(Properties) + */ + protected Map> readGlobalEmbedMappingProperties() + { + Map relevantGlobalPropertiesMap = getRelevantGlobalProperties(PROPERTY_COMPONENT_EMBED); + if (relevantGlobalPropertiesMap == null) + { + return null; + } + return readEmbedMappingProperties(relevantGlobalPropertiesMap.entrySet()); + } /** * A utility method to convert mapping properties to the Map form. @@ -733,10 +847,23 @@ abstract public class AbstractMappingMetadataExtracter implements MetadataExtrac * @see #setMappingProperties(Properties) */ protected Map> readEmbedMappingProperties(Properties mappingProperties) + { + return readEmbedMappingProperties(mappingProperties.entrySet()); + } + + /** + * A utility method to convert mapping properties entries to the Map form. + *

+ * Different from readMappingProperties in that keys are the Alfresco QNames + * and values are file metadata properties. + * + * @see #setMappingProperties(Properties) + */ + private Map> readEmbedMappingProperties(Set> mappingPropertiesEntries) { Map namespacesByPrefix = new HashMap(5); // Get the namespaces - for (Map.Entry entry : mappingProperties.entrySet()) + for (Map.Entry entry : mappingPropertiesEntries) { String propertyName = (String) entry.getKey(); if (propertyName.startsWith(NAMESPACE_PROPERTY_PREFIX)) @@ -748,7 +875,7 @@ abstract public class AbstractMappingMetadataExtracter implements MetadataExtrac } // Create the mapping Map> convertedMapping = new HashMap>(17); - for (Map.Entry entry : mappingProperties.entrySet()) + for (Map.Entry entry : mappingPropertiesEntries) { String modelProperty = (String) entry.getKey(); String metadataKeysString = (String) entry.getValue(); @@ -855,6 +982,16 @@ abstract public class AbstractMappingMetadataExtracter implements MetadataExtrac } } + // Override with any extract mappings specified in global properties + Map> globalExtractMapping = readGlobalExtractMappingProperties(); + if (globalExtractMapping != null && globalExtractMapping.size() > 0) + { + for (String documentKey : globalExtractMapping.keySet()) + { + mapping.put(documentKey, globalExtractMapping.get(documentKey)); + } + } + // The configured mappings are empty, but there were default mappings if (mapping.size() == 0 && defaultMapping.size() > 0) { @@ -886,6 +1023,16 @@ abstract public class AbstractMappingMetadataExtracter implements MetadataExtrac metadataKeys.addAll(defaultMetadataKeys); } } + + // Override with any embed mappings specified in global properties + Map> globalEmbedMapping = readGlobalEmbedMappingProperties(); + if (globalEmbedMapping != null && globalEmbedMapping.size() > 0) + { + for (QName modelProperty : globalEmbedMapping.keySet()) + { + embedMapping.put(modelProperty, globalEmbedMapping.get(modelProperty)); + } + } // Done initialized = true; diff --git a/source/java/org/alfresco/repo/content/metadata/MappingMetadataExtracterTest.java b/source/java/org/alfresco/repo/content/metadata/MappingMetadataExtracterTest.java index 040d6ee80f..194c33dffa 100644 --- a/source/java/org/alfresco/repo/content/metadata/MappingMetadataExtracterTest.java +++ b/source/java/org/alfresco/repo/content/metadata/MappingMetadataExtracterTest.java @@ -29,6 +29,7 @@ import java.util.Set; import junit.framework.TestCase; import org.alfresco.error.AlfrescoRuntimeException; +import org.alfresco.repo.content.ContentMinimalContextTestSuite; import org.alfresco.repo.content.MimetypeMap; import org.alfresco.repo.content.filestore.FileContentReader; import org.alfresco.repo.content.metadata.MetadataExtracter.OverwritePolicy; @@ -36,6 +37,7 @@ import org.alfresco.repo.content.transform.AbstractContentTransformerTest; import org.alfresco.service.cmr.repository.ContentReader; import org.alfresco.service.namespace.NamespaceService; import org.alfresco.service.namespace.QName; +import org.springframework.context.ApplicationContext; /** * @see org.alfresco.repo.content.metadata.AbstractMappingMetadataExtracter @@ -131,6 +133,30 @@ public class MappingMetadataExtracterTest extends TestCase assertTrue(destination.containsKey(DummyMappingMetadataExtracter.QNAME_A2)); } + public void testPropertyMappingGlobalOverride() throws Exception + { + String propertyPrefix = AbstractMappingMetadataExtracter.PROPERTY_PREFIX_METADATA + + DummyMappingMetadataExtracter.EXTRACTER_NAME + + AbstractMappingMetadataExtracter.PROPERTY_COMPONENT_EXTRACT; + + ApplicationContext ctx = ContentMinimalContextTestSuite.getContext(); + Properties globalProperties = (Properties) ctx.getBean("global-properties"); + globalProperties.setProperty( + propertyPrefix + "namespace.prefix.my", + DummyMappingMetadataExtracter.NAMESPACE_MY); + globalProperties.setProperty( + propertyPrefix + DummyMappingMetadataExtracter.PROP_A, + " my:a1, my:a2, my:c "); + + extracter.setApplicationContext(ctx); + + extracter.register(); + // Only mapped 'a' + destination.clear(); + extracter.extract(reader, destination); + assertEquals(DummyMappingMetadataExtracter.VALUE_A, destination.get(DummyMappingMetadataExtracter.QNAME_C)); + } + public void testPropertyMappingMerge() throws Exception { Properties props = new Properties(); @@ -254,6 +280,7 @@ public class MappingMetadataExtracterTest extends TestCase public static final String VALUE_D = "DDD"; public static final String VALUE_IMG = "IMAGE"; + public static final String EXTRACTER_NAME = "extracter.Dummy"; public static final String NAMESPACE_MY = "http://DummyMappingMetadataExtracter"; public static final QName QNAME_A1 = QName.createQName(NAMESPACE_MY, "a1"); public static final QName QNAME_A2 = QName.createQName(NAMESPACE_MY, "a2"); @@ -278,6 +305,7 @@ public class MappingMetadataExtracterTest extends TestCase { super(MIMETYPES); initCheck = false; + setBeanName(EXTRACTER_NAME); } @Override