package de.dpa.oss.metadata.mapper;
import de.dpa.oss.common.ResourceUtil;
import de.dpa.oss.metadata.mapper.imaging.configuration.generated.ConfigType;
import de.dpa.oss.metadata.mapper.imaging.configuration.generated.CustomizedMappingType;
import de.dpa.oss.metadata.mapper.imaging.configuration.generated.MappingType;
import de.dpa.oss.metadata.mapper.imaging.configuration.generated.MappingType.Metadata;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import javax.xml.bind.JAXBContext;
import javax.xml.bind.JAXBElement;
import javax.xml.bind.JAXBException;
import javax.xml.bind.Unmarshaller;
import javax.xml.transform.stream.StreamSource;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.InputStream;
import java.util.ArrayList;
import java.util.HashSet;
import java.util.List;
import java.util.Set;
/**
* @author oliver langer
*/
public class MetadataMapperConfigReader
{
private static Logger logger = LoggerFactory.getLogger(MetadataMapperConfigReader.class);
public static MappingType defaultConfig = null;
public static final String DEFAULT_MAPPING = "/image-metadata-mapping/default-mapping.xml";
/**
* @deprecated
*/
public static MappingType getDefaultConfigOverridenBy(final String resourcePath, Object caller)
throws FileNotFoundException, JAXBException
{
return getDefaultConfigOverridenBy(ResourceUtil.resourceAsStream(resourcePath, caller.getClass()));
}
/**
* @deprecated
*/
public static MappingType getDefaultConfigOverridenBy(final String path) throws FileNotFoundException, JAXBException
{
return getDefaultConfigOverridenBy(new FileInputStream(path));
}
/**
* Reads the default configuration and overrides it with the specified one
* @deprectated
*/
public static MappingType getDefaultConfigOverridenBy(final InputStream is) throws JAXBException
{
return new MetadataMapperConfigReader().readCustomConfigOverridingDefault(is);
}
public static MappingType getDefaultMapping() throws JAXBException
{
return new MetadataMapperConfigReader().getDefaultConfig();
}
public static MappingType readCustomConfig( final InputStream is ) throws JAXBException
{
return new MetadataMapperConfigReader().readConfig(is);
}
/**
* Reads a configuration file without inheriting from the default mapping.
*/
public CustomizedMappingType readConfig( final InputStream customizationsIS ) throws JAXBException
{
return readConfig(customizationsIS, CustomizedMappingType.class);
}
/**
* Reads a customized mapping. This mapping is merged with the default mapping:
* <ul>
* <li>
* New metadata mappings are added
* </li>
* <li>
* Metadata mapping which already exist in the default mapping override the default mapping
* </li>
* <li>
* timezone and charset definition for iim and xmp are taken from the override mapping
* </li>
* <li>
* Dateparser are merged in the same way metadata mappings are merged.
* </li>
* </ul>
*/
public CustomizedMappingType readCustomConfigOverridingDefault(final InputStream customizationsIS) throws JAXBException
{
final CustomizedMappingType customizations = readConfig(customizationsIS, CustomizedMappingType.class);
final MappingType defaultMapping = getDefaultConfig();
mergeMetadataMappings(customizations, defaultMapping );
mergeConfigs(customizations, defaultMapping);
return customizations;
}
private void mergeConfigs(final CustomizedMappingType customizations, final MappingType defaultMapping)
{
if( customizations.getConfig() == null )
{
customizations.setConfig(defaultMapping.getConfig());
}
else
{
/* merge date parsers: */
List<ConfigType.DateParser> customizedDateParser = customizations.getConfig().getDateParser();
List<ConfigType.DateParser> defaultDateParser = defaultMapping.getConfig().getDateParser();
Set<String> mergedParserNames = new HashSet<>();
List<ConfigType.DateParser> mergedList = customizations.getConfig().getDateParser();
for (ConfigType.DateParser dateParser : customizedDateParser)
{
mergedParserNames.add(dateParser.getId());
}
for (ConfigType.DateParser defaultParser : defaultDateParser)
{
if( !mergedParserNames.contains(defaultParser.getId()))
{
mergedList.add( defaultParser);
mergedParserNames.add(defaultParser.getId());
}
}
}
}
private void mergeMetadataMappings(final CustomizedMappingType customizations, final MappingType defaultMapping)
{
final List<Metadata> mergedMappings = new ArrayList<>();
final Set<String> customizedMappings = new HashSet<>();
for (Metadata customeMetadata : customizations.getMetadata())
{
mergedMappings.add( customeMetadata );
customizedMappings.add(customeMetadata.getName().trim().toLowerCase());
}
// now add all default mappings which are not found in the customizedMappings
for (Metadata mapping : defaultMapping.getMetadata() )
{
if( !customizedMappings.contains(mapping.getName().trim().toLowerCase()))
{
mergedMappings.add( mapping );
}
}
customizations.getMetadata().clear();
customizations.getMetadata().addAll( mergedMappings );
}
public MappingType getDefaultConfig() throws JAXBException
{
return readDefaultConfig();
}
private synchronized MappingType readDefaultConfig() throws JAXBException
{
if( defaultConfig != null )
{
return defaultConfig;
}
return readConfig( this.getClass().getResourceAsStream( DEFAULT_MAPPING),
MappingType.class);
}
private <T> T readConfig( final InputStream is, Class<T> clazz ) throws JAXBException
{
final JAXBContext jaxbContext = JAXBContext
.newInstance(clazz);
Unmarshaller unmarshaller = jaxbContext.createUnmarshaller();
JAXBElement<T> root = unmarshaller.unmarshal( new StreamSource(is), clazz);
if (root== null)
{
logger.info("Mapping configuration for given type not found. Type:" + clazz );
return null;
}
else
{
return root.getValue();
}
}
}