package org.hivedb.serialization; import org.hivedb.annotations.AnnotationHelper; import org.hivedb.util.classgen.GenerateInstance; import org.hivedb.util.classgen.GeneratedClassFactory; import org.hivedb.util.classgen.GeneratedImplementation; import org.hivedb.util.classgen.ReflectionTools; import org.hivedb.util.functional.Filter; import org.hivedb.util.functional.Pair; import org.hivedb.util.functional.Transform; import org.hivedb.util.functional.Transform.MapToValueFunction; import org.hivedb.util.functional.Unary; import org.hivedb.versioning.Modernizer; import org.hivedb.versioning.XmlModernizationPaver; import java.util.ArrayList; import java.util.Collection; import java.util.Map; import java.util.Map.Entry; public class ClassXmlTransformerImpl<T> implements ClassXmlTransformer<T> { private XmlModernizationPaver<T> xmlModernizationPaver; private Class<T> clazz; private Map<String,String> abbrevationMap; private String classAbbreviation; public ClassXmlTransformerImpl(Class<T> representedInterface, XmlModernizationPaver<T> xmlModernizationPaver) { this.clazz = representedInterface; this.xmlModernizationPaver = xmlModernizationPaver; this.abbrevationMap = createAbbreviationMap( representedInterface, Filter.grepUnique(ReflectionTools.getPropertiesOfGetters(representedInterface))); this.classAbbreviation = abbreviate( representedInterface, representedInterface.getSimpleName().toLowerCase()); } public Class<T> getRespresentedInterface() { return clazz; } public final String abbreviate(String propertyName) { return abbrevationMap.get(propertyName); } public final String getClassAbbreviation() { return classAbbreviation; } // Use a simple abbreviation strategy to abbreviate the collection of names. // If a conflict occurs an exception is thrown. This is purposely not a dynamic // abbreviator because we do not want existing abbreviations to change when a new // property is introduced. // TODO use annotations on the representedInterface to resolve abbreviation names. private Map<String,String> createAbbreviationMap(final Class<?> representedInterface, Collection<String> names) { Map<String,String> abbreviationMap = Transform.toMap(Filter.getUnique( Transform.map(new Unary<String,Entry<String,String>>() { public Entry<String, String> f(String name) { return new Pair<String,String>(name, abbreviate(representedInterface, name)); } }, names), new MapToValueFunction<String,String>())); if (abbreviationMap.size() != names.size()) throw new RuntimeException(String.format("Interface %s properties cannot be abbreviated. The following properties have abbreviations in use by another property %s", representedInterface.getSimpleName(), Filter.grepFalseAgainstList(abbreviationMap.keySet(),names))); return abbreviationMap; } private String abbreviate(Class<?> representedInterface, String name) { Abbreviation abbreviation = representedInterface.getSimpleName().toLowerCase().equals(name) ? representedInterface.getAnnotation(Abbreviation.class) : getAbbreviationOfMethod(representedInterface, name); if (abbreviation != null) return abbreviation.value(); String camelized = name.replaceAll("[^A-Z]",""); if (camelized.length() > 0) return name.substring(0,camelized.length() < 3 ? 4-camelized.length() : 1)+camelized; return name.length() > 4 ? name.substring(0,4) : name; } private Abbreviation getAbbreviationOfMethod(Class<?> representedInterface, String name) { return AnnotationHelper.getAnnotationDeeply(representedInterface, name, Abbreviation.class); } public T createInstance() { try { return clazz.isInterface() ? GeneratedClassFactory.newInstance(clazz) : clazz.getConstructor().newInstance(); } catch (Exception e) { throw new RuntimeException(e); } } public T wrapInSerializingImplementation(T instance) { ((Blobbable)instance).setBlobVersion(getCurrentXmlVersion()); if (instance instanceof GeneratedImplementation) return instance; return (T) new GenerateInstance<T>(clazz).generateAndCopyProperties(instance); } public Collection<ClassXmlTransformer> getRequiredTransformers() { Collection<ClassXmlTransformer> transformers = new ArrayList<ClassXmlTransformer>(); transformers.add(this); return transformers; } public Modernizer<T> getModernizer(Integer fromVersion, Integer toVersion) { return xmlModernizationPaver.getModernizer(fromVersion, toVersion); } public Integer getCurrentXmlVersion() { return xmlModernizationPaver.getCurrentXmlVersion(); } }