001    /**
002     * Copyright 2005-2013 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     */
016    package org.kuali.rice.krms.framework.engine;
017    
018    import java.util.Map;
019    
020    import org.joda.time.DateTime;
021    import org.kuali.rice.krms.api.engine.Engine;
022    import org.kuali.rice.krms.api.engine.EngineResults;
023    import org.kuali.rice.krms.api.engine.ExecutionEnvironment;
024    import org.kuali.rice.krms.api.engine.ExecutionOptions;
025    import org.kuali.rice.krms.api.engine.Facts;
026    import org.kuali.rice.krms.api.engine.ResultEvent;
027    import org.kuali.rice.krms.api.engine.SelectionCriteria;
028    import org.kuali.rice.krms.api.engine.Term;
029    import 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     */
035    public 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    }