package com.intrbiz.bergamot.config.model; import java.io.File; import java.util.Iterator; import java.util.LinkedHashSet; import java.util.LinkedList; import java.util.List; import java.util.Set; import javax.xml.bind.annotation.XmlAttribute; import javax.xml.bind.annotation.XmlTransient; import javax.xml.bind.annotation.adapters.XmlJavaTypeAdapter; import com.intrbiz.bergamot.config.adapter.CSVAdapter; import com.intrbiz.bergamot.config.adapter.ObjectStateAdapter; import com.intrbiz.bergamot.config.adapter.YesNoAdapter; import com.intrbiz.bergamot.config.resolver.BeanResolver; import com.intrbiz.bergamot.config.resolver.ObjectResolver; import com.intrbiz.configuration.Configuration; public abstract class TemplatedObjectCfg<P extends TemplatedObjectCfg<P>> extends Configuration { public enum ObjectState { PRESENT, ABSENT, REMOVED, /* Synonym for Absent */ CHANGED; public static boolean isRemove(ObjectState state) { return state == ABSENT || state == REMOVED; } public static boolean isChange(ObjectState state) { return state == PRESENT || state == CHANGED || state == null; } } private static final long serialVersionUID = 1L; private Set<String> inheritedTemplates = new LinkedHashSet<String>(); private Boolean template; private List<P> inherits = new LinkedList<P>(); private File loadedFrom; private ObjectState objectState; public TemplatedObjectCfg() { super(); } @XmlTransient public File getLoadedFrom() { return loadedFrom; } public void setLoadedFrom(File loadedFrom) { this.loadedFrom = loadedFrom; } @XmlJavaTypeAdapter(ObjectStateAdapter.class) @XmlAttribute(name = "state") public final ObjectState getObjectState() { return this.objectState; } public final void setObjectState(ObjectState objectState) { this.objectState = objectState; } @XmlJavaTypeAdapter(CSVAdapter.class) @XmlAttribute(name = "extends") public Set<String> getInheritedTemplates() { return inheritedTemplates; } public void setInheritedTemplates(Set<String> inheritedTemplates) { this.inheritedTemplates = inheritedTemplates; } public boolean isInheriting(String templateName) { return this.getInheritedTemplates().contains(templateName); } @XmlJavaTypeAdapter(YesNoAdapter.class) @XmlAttribute(name = "template") public Boolean getTemplate() { return template; } @XmlTransient public boolean getTemplateBooleanValue() { return this.template == null ? false : this.template.booleanValue(); } public void setTemplate(Boolean template) { this.template = template; } @XmlTransient public List<P> getInherits() { return inherits; } public void setInherits(List<P> inherits) { this.inherits = inherits; } public void addInheritedObject(P inheritedObject) { if (this.getClass() != inheritedObject.getClass()) throw new IllegalArgumentException("Cannot inheirt from an object of a different type"); this.inherits.add(inheritedObject); } public abstract List<TemplatedObjectCfg<?>> getTemplatedChildObjects(); /** * Process the inheritance hierarchy and produce a resolved configuration */ @SuppressWarnings("unchecked") protected P resolve(ObjectResolver<P> resolver) { // nothing to resolve if (this.inherits == null || this.inherits.isEmpty()) return (P) this; // process the inheritance graph P parent = null; // resolve the parents Iterator<P> i = this.inherits.iterator(); parent = i.next().resolve(resolver); while (i.hasNext()) { parent = resolver.resolve(parent, i.next()); } // resolve ourselves with the resolved state of our parents return resolver.resolve((P) this, parent); } /** * Process the inheritance hierarchy and produce a resolved configuration */ @SuppressWarnings("unchecked") public final P resolve() { return this.resolve(BeanResolver.fromClass((Class<P>) this.getClass())); } public final P resolveDeep() { P resolved = this.resolve(); this.resolveChildren(resolved); return resolved; } protected void resolveChildren(P resolved) { } }