package nl.ipo.cds.etl.theme;
import java.beans.PropertyDescriptor;
import java.lang.reflect.Method;
import java.util.ArrayList;
import java.util.Collections;
import java.util.HashMap;
import java.util.HashSet;
import java.util.List;
import java.util.Map;
import java.util.Set;
import javax.annotation.PostConstruct;
import nl.ipo.cds.admin.ba.controller.beans.mapping.Mapping;
import nl.ipo.cds.domain.EtlJob;
import nl.ipo.cds.etl.DatasetHandlersFactory;
import nl.ipo.cds.etl.PersistableFeature;
import nl.ipo.cds.etl.Validator;
import nl.ipo.cds.etl.theme.annotation.MappableAttribute;
import nl.ipo.cds.etl.theme.schema.SchemaHarvester;
import nl.ipo.cds.etl.theme.schema.WfsSchemaHarvester;
import org.springframework.beans.BeanUtils;
import org.springframework.context.MessageSource;
import org.springframework.context.support.ResourceBundleMessageSource;
public abstract class ThemeConfig<T extends PersistableFeature> implements DatasetHandlersFactory<T> {
private final Class<T> featureTypeClass;
private final Map<Class<?>, ObjectDescriptor<?>> objectDescriptors;
private final String themeName;
public ThemeConfig (final String themeName, final Class<T> featureTypeClass) {
this.themeName = themeName;
this.featureTypeClass = featureTypeClass;
this.objectDescriptors = new HashMap<Class<?>, ObjectDescriptor<?>> ();
}
@PostConstruct
public void initialize () {
final MessageSource messageSource = createMessageSource (featureTypeClass);
this.objectDescriptors.put (featureTypeClass, introspect (featureTypeClass, messageSource));
}
@Override
public boolean isJobSupported (final EtlJob job) {
return job.getDatasetType () != null
&& job.getDatasetType ().getThema () != null
&& getThemeName ().equals (job.getDatasetType ().getThema ().getNaam ());
}
public String getThemeName () {
return themeName;
}
public Class<T> getFeatureTypeClass () {
return featureTypeClass;
}
public Set<ObjectDescriptor<?>> getObjectDescriptors () {
return Collections.unmodifiableSet (new HashSet<ObjectDescriptor<?>> (objectDescriptors.values ()));
}
public Set<AttributeDescriptor<?>> getAttributeDescriptors () {
final Set<AttributeDescriptor<?>> attributeDescriptors = new HashSet<AttributeDescriptor<?>> ();
for (final Map.Entry<Class<?>, ObjectDescriptor<?>> entry: objectDescriptors.entrySet ()) {
final ObjectDescriptor<?> objectDescriptor = entry.getValue ();
attributeDescriptors.addAll (objectDescriptor.getAttributeDescriptors ());
}
return Collections.unmodifiableSet (attributeDescriptors);
}
public abstract Validator<T> getValidator () throws ThemeConfigException;
public SchemaHarvester getSchemaHarvester() {
return new WfsSchemaHarvester();
}
private MessageSource createMessageSource (final Class<T> cls) {
final List<String> baseNames = new ArrayList<String> ();
baseNames.add (String.format ("%s.messages", cls.getCanonicalName ()));
baseNames.add (String.format ("%s.messages", cls.getPackage ().getName ()));
final ResourceBundleMessageSource messageSource = new ResourceBundleMessageSource ();
messageSource.setBasenames (baseNames.toArray (new String[baseNames.size ()]));
return messageSource;
}
private ObjectDescriptor<T> introspect (final Class<T> cls, final MessageSource messageSource) {
return new ObjectDescriptor<T> (cls, messageSource, getCandidateProperties (cls));
}
private PropertyDescriptor[] getCandidateProperties (final Class<?> cls) {
final List<PropertyDescriptor> candidates = new ArrayList<PropertyDescriptor> ();
for (final PropertyDescriptor propertyDescriptor: BeanUtils.getPropertyDescriptors (cls)) {
final Method readerMethod = propertyDescriptor.getReadMethod ();
final Method writerMethod = propertyDescriptor.getWriteMethod ();
if (readerMethod == null || writerMethod == null) {
continue;
}
for (final Method method: (new Method[] { readerMethod, writerMethod })) {
if (method.getAnnotation (MappableAttribute.class) != null) {
candidates.add (propertyDescriptor);
break;
}
}
}
return candidates.toArray (new PropertyDescriptor[candidates.size ()]);
}
/**
* Return initial mapping for a specific attribute; default is null, but can be overridden by subclass.
*
* @param name
* @return
*/
public Mapping getDefaultMappingForAttributeType(AttributeDescriptor<?> attributeDescriptor) {
return null;
}
/**
* Whether or not the features in this theme are taggable.
*/
public boolean isTaggable() {
return false;
}
}