package org.jactr.core.slot; /* * default logging */ import java.util.Arrays; import java.util.List; import org.apache.commons.logging.Log; import org.apache.commons.logging.LogFactory; /** * Utility for building slots quickly with a builder pattern. Start with the * static accessor for the type of slot you need {@link #slot(String)}, * {@link #conditionalSlot(String)}, {@link #mutableSlot(String)}, * {@link #logicalSlot()}), then provide the conditional portion ( * {@link #eq(Object)}, {@link #gt(Object)}, {@link #gte(Object)}, * {@link #lt(Object)}, {@link #lte(Object)}, {@link #notEq(Object)} for * conditionals, {@link #eq(Object)} for basic slot, {@link #and(ISlot, ISlot)}, * {@link #or(ISlot, ISlot)}, {@link #not(ISlot)} for logical) and invoke * {@link #build()}. <br/> * There are no safe guards to verify that incorrect conditionals are not called * for the particular flavor of slot being generated. <br/> * builders for a given type can be recycled to generate more of that type * without generating additional garbage by calling {@link #reset()}. But be * sure to call {@link #slotName(String)} before use.<br/> * <code> * SlotBuilder<ISlot> sBuilder = SlotBuilder.slot("s1"); * ISlot slot1 = sBuilder.eq(value1).build(); * ISlot slot2 = sBuilder.reset().slotName("s2").eq(value2).build(); * </code> <br/> * But if you are attentive and aware of the internal states, the builder can be * reused. <br/> * <code> * SlotBuilder<IConditionalSlot> sBuilder = SlotBuilder.conditionalSlot("when"); * IConditionalSlot past = sBuilder.lte(referenceTime).build(); * IConditionalSlot future = sBuilder.gte(referenceTime).build(); * //both have the same slot name and reference times * </code> * * @author harrison * @param <T> */ public class SlotBuilder<T> { /** * Logger definition */ static private final transient Log LOGGER = LogFactory .getLog(SlotBuilder.class); private String _slotName; private int _condition = IConditionalSlot.EQUALS; // IConditionalSlot, // or // ILogicalSlot private Object _value = null; private List<ISlot> _children; private SlotBuilder(String slotName) { _slotName = slotName; } protected String getSlotName() { return _slotName; } protected int getCondition() { return _condition; } protected Object getValue() { return _value; } protected List<ISlot> getChildren() { return _children; } /** * reset the builder. * * @param slotName * @return */ public SlotBuilder<T> reset() { _children = null; _value = null; _slotName = null; _condition = IConditionalSlot.EQUALS; return this; } /** * start builder chain for conditional slot <code> * IConditionalSlot slot = SlotBuilder.conditionalSlot("slot1").lte(100.0).build(); * </code> * * @return */ static public SlotBuilder<IConditionalSlot> conditionalSlot(String slotName) { return new SlotBuilder<IConditionalSlot>(slotName) { @Override public IConditionalSlot build() { return new DefaultConditionalSlot(getSlotName(), getCondition(), getValue()); } }; } /** * start builder chain for logical slot <code> * SlotBuilder<ILogicalSlot> sBuilder = SlotBuilder.logicalSlot(); * ILogicalSlot notSlot = sBuilder.reset(null).not(oSlot).build(); * ILogicalSlot andSlot = sBuilder.reset(null).and(slot1, slot2).build(); * ILogicalSlot orSlotNested = sBuilder.reset(null).or(notSlot, andSlot).build(); * </code> * * @return */ static public SlotBuilder<ILogicalSlot> logicalSlot() { return new SlotBuilder<ILogicalSlot>(":logical") { @Override public ILogicalSlot build() { return new DefaultLogicalSlot(getCondition(), getChildren()); } }; } /** * start builder chain for mutable slot <code> * IMutableSlot slot = SlotBuilder.mutableSlot("slot1").eq(value).build(); * </code> * * @return */ static public SlotBuilder<IMutableSlot> mutableSlot(String slotName) { return new SlotBuilder<IMutableSlot>(slotName) { @Override public IMutableSlot build() { return new DefaultMutableSlot(getSlotName(), getValue()); } }; } /** * start builder chain for general equality slot <code> * ISlot slot = SlotBuilder.slot("slot1").eq(value).build(); * </code> * * @return */ static public SlotBuilder<ISlot> slot(String slotName) { return new SlotBuilder<ISlot>(slotName) { @Override public ISlot build() { return new BasicSlot(getSlotName(), getValue()); } }; } public T build() { return null; } /** * specify slotName * * @param slotName * @return */ public SlotBuilder<T> slotName(String slotName) { _slotName = slotName; return this; } private SlotBuilder<T> conditionAndValue(int condition, Object value) { _condition = condition; _value = value; return this; } /** * Conditional equality to value. <br/> * for conditional, mutable, or simple slots. * * @param value * @return */ public SlotBuilder<T> eq(Object value) { return conditionAndValue(IConditionalSlot.EQUALS, value); } /** * Conditional greater than value. <br/> * for conditional slots. * * @param value * @return */ public SlotBuilder<T> gt(Object value) { return conditionAndValue(IConditionalSlot.GREATER_THAN, value); } /** * Conditional greater than/equals value. <br/> * for conditional slots. * * @param value * @return */ public SlotBuilder<T> gte(Object value) { return conditionAndValue(IConditionalSlot.GREATER_THAN_EQUALS, value); } /** * Conditional less than value. <br/> * for conditional slots. * * @param value * @return */ public SlotBuilder<T> lt(Object value) { return conditionAndValue(IConditionalSlot.LESS_THAN, value); } /** * Conditional less than/equals value. <br/> * for conditional slots. * * @param value * @return */ public SlotBuilder<T> lte(Object value) { return conditionAndValue(IConditionalSlot.LESS_THAN_EQUALS, value); } /** * not equals (but not logical negation {@link #not(ISlot)} <br/> * for conditional slots. * * @param value * @return */ public SlotBuilder<T> notEq(Object value) { return conditionAndValue(IConditionalSlot.NOT_EQUALS, value); } private SlotBuilder<T> logicalAndValue(int condition, ISlot... slots) { _condition = condition; _children = Arrays.asList(slots); return this; } /** * logical not * * @param slot * @return */ public SlotBuilder<T> not(ISlot slot) { return logicalAndValue(ILogicalSlot.NOT, slot); } /** * logical and * * @param slot1 * @param slot2 * @return */ public SlotBuilder<T> and(ISlot slot1, ISlot slot2) { return logicalAndValue(ILogicalSlot.AND, slot1, slot2); } /** * logical or * * @param slot1 * @param slot2 * @return */ public SlotBuilder<T> or(ISlot slot1, ISlot slot2) { return logicalAndValue(ILogicalSlot.OR, slot1, slot2); } }