001/**
002 * Copyright 2005-2016 The Kuali Foundation
003 *
004 * Licensed under the Educational Community License, Version 2.0 (the "License");
005 * you may not use this file except in compliance with the License.
006 * You may obtain a copy of the License at
007 *
008 * http://www.opensource.org/licenses/ecl2.php
009 *
010 * Unless required by applicable law or agreed to in writing, software
011 * distributed under the License is distributed on an "AS IS" BASIS,
012 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
013 * See the License for the specific language governing permissions and
014 * limitations under the License.
015 */
016package org.kuali.rice.krms.framework.engine;
017
018import java.util.Map;
019
020import org.joda.time.DateTime;
021import org.kuali.rice.krms.api.engine.Engine;
022import org.kuali.rice.krms.api.engine.EngineResults;
023import org.kuali.rice.krms.api.engine.ExecutionEnvironment;
024import org.kuali.rice.krms.api.engine.ExecutionOptions;
025import org.kuali.rice.krms.api.engine.Facts;
026import org.kuali.rice.krms.api.engine.ResultEvent;
027import org.kuali.rice.krms.api.engine.SelectionCriteria;
028import org.kuali.rice.krms.api.engine.Term;
029import org.kuali.rice.krms.framework.engine.result.TimingResult;
030
031/**
032 * An implementation of {@link Engine}
033 * @author Kuali Rice Team (rice.collab@kuali.org)
034 */
035public class ProviderBasedEngine implements Engine {
036
037        private static final Term effectiveExecutionTimeTerm = new Term("effectiveExecutionTime", null);
038        
039        private static final org.apache.log4j.Logger LOG = org.apache.log4j.Logger.getLogger(ProviderBasedEngine.class);
040        private static final ResultLogger KLog = ResultLogger.getInstance();
041
042        private ContextProvider contextProvider;
043
044    @Override
045    public EngineResults execute(SelectionCriteria selectionCriteria, Map<String, Object> facts,
046            ExecutionOptions executionOptions) {
047        return execute(selectionCriteria,
048                Facts.Builder.create().addFactsByName(facts).build(),
049                executionOptions);
050    }
051
052    @Override
053        public EngineResults execute(SelectionCriteria selectionCriteria, Facts facts, ExecutionOptions executionOptions) {
054                DateTime start, end;
055                start = new DateTime();
056                ExecutionEnvironment environment = establishExecutionEnvironment(selectionCriteria, facts.getFactMap(), executionOptions);
057                
058                // set execution time
059                Long effectiveExecutionTime = environment.getSelectionCriteria().getEffectiveExecutionTime();
060                if (effectiveExecutionTime == null) { effectiveExecutionTime = System.currentTimeMillis(); }
061                environment.publishFact(effectiveExecutionTimeTerm, effectiveExecutionTime);
062
063                Context context = selectContext(selectionCriteria, facts.getFactMap(), executionOptions);
064                if (context == null) {
065                        LOG.info("Failed to locate a Context for the given qualifiers, skipping rule engine execution: " + selectionCriteria.getContextQualifiers());
066                        return null;
067                }
068                context.execute(environment);
069                end = new DateTime();
070                if (KLog.isEnabled(environment)){
071                        KLog.logResult(new TimingResult(ResultEvent.TIMING_EVENT, this, environment, start, end));
072                }
073                return environment.getEngineResults();
074        }
075
076    /**
077     * Return a {@link BasicExecutionEnvironment} using the given parameters
078     * @param selectionCriteria {@link SelectionCriteria}
079     * @param facts
080     * @param executionOptions {@link ExecutionOptions}
081     * @return {@link ExecutionEnvironment} created with the given parameters
082     */
083        protected ExecutionEnvironment establishExecutionEnvironment(SelectionCriteria selectionCriteria, Map<Term, Object> facts, ExecutionOptions executionOptions) {
084                return new BasicExecutionEnvironment(selectionCriteria, facts, executionOptions, new TermResolutionEngineImpl());
085        }
086
087    /**
088     * Load a Context from the contextProvider using the given parameters
089     * @see ContextProvider loadContext
090     * @param selectionCriteria
091     * @param facts
092     * @param executionOptions
093     * @return {@link Context}
094     * @throws IllegalStateException if the contextProvider is null;
095     */
096        protected Context selectContext(SelectionCriteria selectionCriteria, Map<Term, Object> facts, ExecutionOptions executionOptions) {
097                if (contextProvider == null) {
098                        throw new IllegalStateException("No ContextProvider was configured.");
099                }
100                return contextProvider.loadContext(selectionCriteria, facts, executionOptions);
101        }
102
103    /**
104     * Set the {@link ContextProvider}
105     * @param contextProvider to loadContext from.
106     */
107        public void setContextProvider(ContextProvider contextProvider) {
108                this.contextProvider = contextProvider;
109        }
110        
111}