package org.jactr.core.production.request; import java.util.ArrayList; import java.util.Collection; import java.util.Collections; import java.util.HashSet; import java.util.Iterator; import java.util.Map; import java.util.Set; import org.jactr.core.model.IModel; import org.jactr.core.production.condition.CannotMatchException; import org.jactr.core.slot.DefaultConditionalSlot; import org.jactr.core.slot.DefaultVariableConditionalSlot; import org.jactr.core.slot.IConditionalSlot; import org.jactr.core.slot.IMutableVariableNameSlot; import org.jactr.core.slot.ISlot; import org.jactr.core.slot.ISlotContainer; import org.jactr.core.slot.IUniqueSlotContainer; import org.jactr.core.slot.IVariableNameSlot; /* * default logging */ /** * basic slot based request */ public class SlotBasedRequest implements IRequest, ISlotContainer { protected Collection<IConditionalSlot> _slots; protected Set<IConditionalSlot> _unresolved; private boolean _locked = false; @SuppressWarnings("unchecked") public SlotBasedRequest() { this(Collections.EMPTY_LIST); } public SlotBasedRequest(Collection<? extends ISlot> slots) { _slots = new ArrayList<IConditionalSlot>(Math.max(slots.size(), 5)); for (ISlot slot : slots) _slots.add(new DefaultConditionalSlot(slot)); } /** * bind the slot values in this request against those slots contained in the * container. This allows us to generally bind against anything that contains * a slot (chunk, chunktype, or buffer for queries) * * @param model * @param container * @param bindings * @param iterativeCall * @return * @throws CannotMatchException */ public int bind(IModel model, String containerName, IUniqueSlotContainer container, Map<String, Object> bindings, boolean iterativeCall) throws CannotMatchException { if (_unresolved == null) _unresolved = new HashSet<IConditionalSlot>(_slots); Iterator<IConditionalSlot> slotItr = _unresolved.iterator(); while (slotItr.hasNext()) { IConditionalSlot cSlot = slotItr.next(); /* * the name is a variable.. */ if (cSlot instanceof IMutableVariableNameSlot && ((IMutableVariableNameSlot) cSlot).isVariableName()) { String variableName = cSlot.getName().toLowerCase(); /* * if we can resolve, do so, otherwise skip until we can. */ if (bindings.containsKey(variableName)) ((IMutableVariableNameSlot) cSlot).setName(bindings.get(variableName) .toString()); else continue; } ISlot valueSlot = null; try { valueSlot = container.getSlot(cSlot.getName()); } catch (Exception e) { throw new CannotMatchException(String.format("%s.%s does not exist", containerName, cSlot.getName())); } if (!cSlot.isVariableValue()) { if (valueSlot == null) throw new CannotMatchException(String.format("%s.%s does not exist", containerName, cSlot.getName())); if (!cSlot.matchesCondition(valueSlot.getValue())) throw new CannotMatchException(String.format( "%s.%s=%s does not match condition %s.", containerName, valueSlot .getName(), valueSlot.getValue(), cSlot)); else slotItr.remove(); // did match, no longer unresolved } else { String variableName = ((String) cSlot.getValue()).toLowerCase(); /* * check to see if we can resolve */ if (bindings.containsKey(variableName)) { Object value = bindings.get(variableName); cSlot.setValue(value); // test if (!cSlot.matchesCondition(valueSlot.getValue())) throw new CannotMatchException(String.format( "%s.%s=%s does not match condition %s.", containerName, valueSlot.getName(), valueSlot.getValue(), cSlot)); } else /* * do we bind this variable? */ if (cSlot.getCondition() == IConditionalSlot.EQUALS && cSlot.matchesCondition(valueSlot.getValue())) { bindings.put(variableName, valueSlot.getValue()); slotItr.remove(); } } } if (_unresolved.size() > 0) if (!iterativeCall) throw new CannotMatchException("Unresolved variables for slots : " + _unresolved + ". available:" + bindings.keySet()); return _unresolved.size(); } @SuppressWarnings("unchecked") public int bind(IModel model, Map<String, Object> bindings, boolean iterativeCall) throws CannotMatchException { /* * this shouldn't be locked, nor should there be any other threads futzing * with it */ if (_unresolved == null) _unresolved = new HashSet<IConditionalSlot>(_slots); Iterator<IConditionalSlot> slotItr = _unresolved.iterator(); while (slotItr.hasNext()) { IConditionalSlot slot = slotItr.next(); /* * the name is a variable.. */ if (slot instanceof IMutableVariableNameSlot && ((IMutableVariableNameSlot) slot).isVariableName()) { /* * if we can resolve, do so, otherwise skip until we can. */ String variableName = slot.getName().toLowerCase(); if (bindings.containsKey(variableName)) ((IMutableVariableNameSlot) slot).setName(bindings.get(variableName) .toString()); else continue; } /* * if we can resolve, do so. */ if (slot.isVariableValue()) { String variableName = ((String) slot.getValue()).toLowerCase(); if (bindings.containsKey(variableName)) { slot.setValue(bindings.get(variableName)); slotItr.remove(); } } else slotItr.remove(); } if (_unresolved.size() > 0) if (!iterativeCall) throw new CannotMatchException("Unresolved variables for slots : " + _unresolved + ". available:" + bindings.keySet()); return _unresolved.size(); } @Override public SlotBasedRequest clone() { return new SlotBasedRequest(_slots); } protected void setLocked(boolean locked) { if (_locked != locked) { _locked = locked; if (_locked) _slots = Collections.unmodifiableCollection(_slots); else _slots = new ArrayList<IConditionalSlot>(_slots); } } public void addSlot(ISlot slot) { if (_locked) throw new RuntimeException("Cannot modify a locked slot container"); if (slot instanceof IVariableNameSlot) _slots.add(new DefaultVariableConditionalSlot(slot)); else _slots.add(new DefaultConditionalSlot(slot)); } public Collection<? extends IConditionalSlot> getConditionalSlots() { return Collections.unmodifiableCollection(_slots); } public Collection<? extends ISlot> getSlots() { if (!_locked) return _slots; return Collections.unmodifiableCollection(_slots); } public void removeSlot(ISlot slot) { if (_locked) throw new RuntimeException("Cannot modify a locked slot container"); _slots.remove(slot); } public Collection<ISlot> getSlots(Collection<ISlot> container) { if (container == null) if (_slots != null) container = new ArrayList<ISlot>(_slots.size() + 1); else container = new ArrayList<ISlot>(); container.addAll(_slots); return container; } }