mirror of
https://github.com/Alfresco/alfresco-community-repo.git
synced 2025-07-31 17:39:05 +00:00
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:
@@ -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;
|
||||||
}
|
}
|
||||||
|
@@ -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
|
||||||
|
Reference in New Issue
Block a user