ALF-17897: Should be able to Override or Augment Metadata Extractor Mappings via Global Properties

- Changed AbstractMappingMetadataExtracter to implement ApplicationContextAware
   - Added AbstractMappingMetadataExtracter.getRelevantGlobalProperties responsible for fetching the global properties relevant to the bean and component ('extract' or 'embed')
   - Separated AbstractMappingMetadataExtracter readMappingProperties and readEmbedMappingProperties into separate methods with arguments for entry set or Properties
   - Added AbstractMappingMetadataExtracter readGlobalExtractMappingProperties and readGlobalEmbedMappingProperties which get the relevant property entries from getRelevantGlobalProperties
   - Changed AbstractMappingMetadataExtracter init to call readGlobalExtractMappingProperties and readGlobalEmbedMappingProperties
   - Added testPropertyMappingGlobalOverride to MappingMetadataExtracterTest

git-svn-id: https://svn.alfresco.com/repos/alfresco-enterprise/alfresco/HEAD/root@47008 c4b6b30b-aa2e-2d43-bbcb-ca4b014f7261
This commit is contained in:
Ray Gauss
2013-02-22 18:57:17 +00:00
parent 6b4cd73f22
commit 5921570ac1
2 changed files with 180 additions and 5 deletions

View File

@@ -33,6 +33,7 @@ import java.util.HashSet;
import java.util.List; import java.util.List;
import java.util.Locale; import java.util.Locale;
import java.util.Map; import java.util.Map;
import java.util.Map.Entry;
import java.util.Properties; import java.util.Properties;
import java.util.Set; import java.util.Set;
import java.util.StringTokenizer; import java.util.StringTokenizer;
@@ -55,6 +56,8 @@ import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory; import org.apache.commons.logging.LogFactory;
import org.apache.xmlbeans.impl.xb.xsdschema.All; import org.apache.xmlbeans.impl.xb.xsdschema.All;
import org.springframework.beans.factory.BeanNameAware; import org.springframework.beans.factory.BeanNameAware;
import org.springframework.context.ApplicationContext;
import org.springframework.context.ApplicationContextAware;
import org.springframework.extensions.surf.util.ISO8601DateFormat; import org.springframework.extensions.surf.util.ISO8601DateFormat;
/** /**
@@ -97,10 +100,13 @@ import org.springframework.extensions.surf.util.ISO8601DateFormat;
* @author Jesper Steen Møller * @author Jesper Steen Møller
* @author Derek Hulley * @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."; public static final String NAMESPACE_PROPERTY_PREFIX = "namespace.prefix.";
private static final String ERR_TYPE_CONVERSION = "metadata.extraction.err.type_conversion"; 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); protected static Log logger = LogFactory.getLog(AbstractMappingMetadataExtracter.class);
@@ -120,6 +126,7 @@ abstract public class AbstractMappingMetadataExtracter implements MetadataExtrac
private boolean inheritDefaultEmbedMapping; private boolean inheritDefaultEmbedMapping;
private boolean enableStringTagging; private boolean enableStringTagging;
private String beanName; private String beanName;
private ApplicationContext applicationContext;
private Properties properties; private Properties properties;
/** /**
@@ -390,6 +397,11 @@ abstract public class AbstractMappingMetadataExtracter implements MetadataExtrac
return beanName; return beanName;
} }
public void setApplicationContext(ApplicationContext applicationContext)
{
this.applicationContext = applicationContext;
}
/** /**
* The Alfresco global properties. * 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.
* <p>
* Mappings can be specified using the same method defined for
* normal mapping properties files but with a prefix of
* <code>metadata.extracter</code>, 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<Object, Object> 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<Object, Object> relevantGlobalPropertiesMap =
new HashMap<Object, Object>();
String propertyPrefix = PROPERTY_PREFIX_METADATA + beanName + propertyComponent;
for (Entry<Object, Object> 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.
* <p>
* Mappings can be specified using the same method defined for
* normal mapping properties files but with a prefix of
* <code>metadata.extracter</code>, 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<String, Set<QName>> readGlobalExtractMappingProperties()
{
Map<Object, Object> 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. * A utility method to convert mapping properties to the Map form.
* *
* @see #setMappingProperties(Properties) * @see #setMappingProperties(Properties)
*/ */
protected Map<String, Set<QName>> readMappingProperties(Properties mappingProperties) protected Map<String, Set<QName>> readMappingProperties(Properties mappingProperties)
{
return readMappingProperties(mappingProperties.entrySet());
}
/**
* A utility method to convert mapping properties entries to the Map form.
*
* @see #setMappingProperties(Properties)
*/
private Map<String, Set<QName>> readMappingProperties(Set<Entry<Object, Object>> mappingPropertiesEntries)
{ {
Map<String, String> namespacesByPrefix = new HashMap<String, String>(5); Map<String, String> namespacesByPrefix = new HashMap<String, String>(5);
// Get the namespaces // Get the namespaces
for (Map.Entry<Object, Object> entry : mappingProperties.entrySet()) for (Map.Entry<Object, Object> entry : mappingPropertiesEntries)
{ {
String propertyName = (String) entry.getKey(); String propertyName = (String) entry.getKey();
if (propertyName.startsWith(NAMESPACE_PROPERTY_PREFIX)) if (propertyName.startsWith(NAMESPACE_PROPERTY_PREFIX))
@@ -622,7 +710,7 @@ abstract public class AbstractMappingMetadataExtracter implements MetadataExtrac
} }
// Create the mapping // Create the mapping
Map<String, Set<QName>> convertedMapping = new HashMap<String, Set<QName>>(17); Map<String, Set<QName>> convertedMapping = new HashMap<String, Set<QName>>(17);
for (Map.Entry<Object, Object> entry : mappingProperties.entrySet()) for (Map.Entry<Object, Object> entry : mappingPropertiesEntries)
{ {
String documentProperty = (String) entry.getKey(); String documentProperty = (String) entry.getKey();
String qnamesStr = (String) entry.getValue(); String qnamesStr = (String) entry.getValue();
@@ -724,6 +812,32 @@ abstract public class AbstractMappingMetadataExtracter implements MetadataExtrac
} }
} }
/**
* A utility method to convert global mapping properties to the Map form.
* <p>
* Different from readGlobalExtractMappingProperties in that keys are the Alfresco QNames
* and values are file metadata properties.
* <p>
* Mappings can be specified using the same method defined for
* normal embed mapping properties files but with a prefix of
* <code>metadata.extracter</code>, 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<QName, Set<String>> readGlobalEmbedMappingProperties()
{
Map<Object, Object> 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. * A utility method to convert mapping properties to the Map form.
* <p> * <p>
@@ -733,10 +847,23 @@ abstract public class AbstractMappingMetadataExtracter implements MetadataExtrac
* @see #setMappingProperties(Properties) * @see #setMappingProperties(Properties)
*/ */
protected Map<QName, Set<String>> readEmbedMappingProperties(Properties mappingProperties) protected Map<QName, Set<String>> readEmbedMappingProperties(Properties mappingProperties)
{
return readEmbedMappingProperties(mappingProperties.entrySet());
}
/**
* A utility method to convert mapping properties entries to the Map form.
* <p>
* Different from readMappingProperties in that keys are the Alfresco QNames
* and values are file metadata properties.
*
* @see #setMappingProperties(Properties)
*/
private Map<QName, Set<String>> readEmbedMappingProperties(Set<Entry<Object, Object>> mappingPropertiesEntries)
{ {
Map<String, String> namespacesByPrefix = new HashMap<String, String>(5); Map<String, String> namespacesByPrefix = new HashMap<String, String>(5);
// Get the namespaces // Get the namespaces
for (Map.Entry<Object, Object> entry : mappingProperties.entrySet()) for (Map.Entry<Object, Object> entry : mappingPropertiesEntries)
{ {
String propertyName = (String) entry.getKey(); String propertyName = (String) entry.getKey();
if (propertyName.startsWith(NAMESPACE_PROPERTY_PREFIX)) if (propertyName.startsWith(NAMESPACE_PROPERTY_PREFIX))
@@ -748,7 +875,7 @@ abstract public class AbstractMappingMetadataExtracter implements MetadataExtrac
} }
// Create the mapping // Create the mapping
Map<QName, Set<String>> convertedMapping = new HashMap<QName, Set<String>>(17); Map<QName, Set<String>> convertedMapping = new HashMap<QName, Set<String>>(17);
for (Map.Entry<Object, Object> entry : mappingProperties.entrySet()) for (Map.Entry<Object, Object> entry : mappingPropertiesEntries)
{ {
String modelProperty = (String) entry.getKey(); String modelProperty = (String) entry.getKey();
String metadataKeysString = (String) entry.getValue(); 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<String, Set<QName>> 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 // The configured mappings are empty, but there were default mappings
if (mapping.size() == 0 && defaultMapping.size() > 0) if (mapping.size() == 0 && defaultMapping.size() > 0)
{ {
@@ -887,6 +1024,16 @@ abstract public class AbstractMappingMetadataExtracter implements MetadataExtrac
} }
} }
// Override with any embed mappings specified in global properties
Map<QName, Set<String>> globalEmbedMapping = readGlobalEmbedMappingProperties();
if (globalEmbedMapping != null && globalEmbedMapping.size() > 0)
{
for (QName modelProperty : globalEmbedMapping.keySet())
{
embedMapping.put(modelProperty, globalEmbedMapping.get(modelProperty));
}
}
// Done // Done
initialized = true; initialized = true;
} }

View File

@@ -29,6 +29,7 @@ import java.util.Set;
import junit.framework.TestCase; import junit.framework.TestCase;
import org.alfresco.error.AlfrescoRuntimeException; import org.alfresco.error.AlfrescoRuntimeException;
import org.alfresco.repo.content.ContentMinimalContextTestSuite;
import org.alfresco.repo.content.MimetypeMap; import org.alfresco.repo.content.MimetypeMap;
import org.alfresco.repo.content.filestore.FileContentReader; import org.alfresco.repo.content.filestore.FileContentReader;
import org.alfresco.repo.content.metadata.MetadataExtracter.OverwritePolicy; 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.cmr.repository.ContentReader;
import org.alfresco.service.namespace.NamespaceService; import org.alfresco.service.namespace.NamespaceService;
import org.alfresco.service.namespace.QName; import org.alfresco.service.namespace.QName;
import org.springframework.context.ApplicationContext;
/** /**
* @see org.alfresco.repo.content.metadata.AbstractMappingMetadataExtracter * @see org.alfresco.repo.content.metadata.AbstractMappingMetadataExtracter
@@ -131,6 +133,30 @@ public class MappingMetadataExtracterTest extends TestCase
assertTrue(destination.containsKey(DummyMappingMetadataExtracter.QNAME_A2)); 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 public void testPropertyMappingMerge() throws Exception
{ {
Properties props = new Properties(); 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_D = "DDD";
public static final String VALUE_IMG = "IMAGE"; 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 String NAMESPACE_MY = "http://DummyMappingMetadataExtracter";
public static final QName QNAME_A1 = QName.createQName(NAMESPACE_MY, "a1"); public static final QName QNAME_A1 = QName.createQName(NAMESPACE_MY, "a1");
public static final QName QNAME_A2 = QName.createQName(NAMESPACE_MY, "a2"); public static final QName QNAME_A2 = QName.createQName(NAMESPACE_MY, "a2");
@@ -278,6 +305,7 @@ public class MappingMetadataExtracterTest extends TestCase
{ {
super(MIMETYPES); super(MIMETYPES);
initCheck = false; initCheck = false;
setBeanName(EXTRACTER_NAME);
} }
@Override @Override