    001    package com.hammurapi.reasoning.impl;
    002
    003    import java.util.ArrayList;
    004    import java.util.Collection;
    005    import java.util.Iterator;
    006    import java.util.List;
    007    import java.util.concurrent.Future;
    008
    009    import com.hammurapi.flow.runtime.ProcessingPathElement;
    010    import com.hammurapi.flow.runtime.PropertySet;
    011    import com.hammurapi.flow.runtime.impl.Joiner.InputConsumer;
    012    import com.hammurapi.reasoning.ReasoningException;
    013    import com.hammurapi.util.Context;
    014
    015
    016    /**
    017     * Base class for condition nodes.
    018     *
    019     * @author Pavel Vlasov
    020     *
    021     */
    022    public abstract class ConditionNode<F> extends ReasoningNodeBase<F> {
    023
    024            /**
    025             * Dispatch inputs to outputs.
    026             */
    027            @SuppressWarnings("unchecked")
    028            @Override
    029            protected Collection<Future<?>> process(
    030                            KnowledgeBase<F> flowState,
    031                            List<InferenceToken<F>>[] inputs,
    032                            PropertySet properties,
    033                            Context context,
    034                            List<ProcessingPathElement> processingPath,
    035                            InputConsumer consumer,
    036                            int activator) throws Exception {
    037
    038                    Collection<Future<?>> ret = new ArrayList<Future<?>>();
    039
    040                    boolean dispatched = false;
    041                    Z: for (PinEntry<F> pin: pins) {
    042                            if (pin.getName().startsWith(Constants.OUTPUT)) {
    043                                    for (Object alt: pin.config) {
    044                                            List<TokenInfo> lti=(List<TokenInfo>) alt;
    045                                            InferenceToken<F>[] out = match(inputs, lti);
    046                                            if (out!=null) {
    047                                                    dispatched = true;
    048                                                    for (Output<F> output: pin.outputs) {
    049                                                            ret.addAll(output.invocable.invoke(flowState, out, properties, context, processingPath));
    050                                                    }
    051
    052                                                    continue Z;
    053                                            }
    054                                    }
    055                            }
    056                    }
    057                    if (!dispatched) {
    058                            throw new IllegalArgumentException("Condition output was not dispatched to any output pins");
    059                    }
    060                    return ret;
    061            }
    062
    063            /**
    064             * Matches input tokens with output config.
    065             * @param inputs
    066             * @param outputConfig
    067             * @return Filled out output array or null if there is no match.
    068             * @throws ReasoningException
    069             */
    070            @SuppressWarnings("unchecked")
    071            private InferenceToken<F>[] match(List<InferenceToken<F>>[] inputs, List<TokenInfo> outputConfig) throws ReasoningException {
    072                    InferenceToken<F>[] out = new InferenceToken[outputConfig.size()];
    073                    Iterator<TokenInfo> outputConfigIterator = outputConfig.iterator();
    074                    Z: for (int outputIdx=0; outputConfigIterator.hasNext(); ++outputIdx) {
    075                            TokenInfo outputTokenInfo = outputConfigIterator.next();
    076                            Iterator<PinEntry<F>> inputPinIterator = getInputPins().iterator();
    077                            for (int inputPinIndex=0; inputPinIterator.hasNext(); ++inputPinIndex) {
    078                                    PinEntry<F> inputPin = inputPinIterator.next();
    079                                    List<TokenInfo> pinConfig = (List<TokenInfo>) inputPin.config;
    080                                    Iterator<TokenInfo> inputTokenInfoIterator = pinConfig.iterator();
    081                                    for (int inputTokenIndex=0; inputTokenInfoIterator.hasNext(); ++inputTokenIndex) {
    082                                            TokenInfo inputTokenInfo = inputTokenInfoIterator.next();
    083                                            if (outputTokenInfo.getParameterIndex() == inputTokenInfo.getParameterIndex()) {
    084                                                    InferenceToken<F> it = inputs[inputPinIndex].get(inputTokenIndex);
    085                                                    if (it.isConsumed()) {
    086                                                            return null;
    087                                                    }
    088
    089                                                    if (!outputTokenInfo.getType().isInstance(knowledgeBase.get(it.getHandle()))) {
    090                                                            return null;
    091                                                    }
    092
    093                                                    out[outputIdx] = it;
    094                                                    continue Z;
    095                                            }
    096                                    }
    097                            }
    098                            throw new IllegalArgumentException("Could not find input for output index "+outputIdx);
    099                    }
    100                    return out;
    101            }
    102
    103    }