View Javadoc
1   /**
2    * Copyright 2005-2015 The Kuali Foundation
3    *
4    * Licensed under the Educational Community License, Version 2.0 (the "License");
5    * you may not use this file except in compliance with the License.
6    * You may obtain a copy of the License at
7    *
8    * http://www.opensource.org/licenses/ecl2.php
9    *
10   * Unless required by applicable law or agreed to in writing, software
11   * distributed under the License is distributed on an "AS IS" BASIS,
12   * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13   * See the License for the specific language governing permissions and
14   * limitations under the License.
15   */
16  package org.kuali.rice.kew.impl.support.krms;
17  
18  import org.apache.commons.lang.StringUtils;
19  import org.apache.log4j.Logger;
20  import org.kuali.rice.core.api.config.ConfigurationException;
21  import org.kuali.rice.core.api.reflect.ObjectDefinition;
22  import org.kuali.rice.core.api.resourceloader.GlobalResourceLoader;
23  import org.kuali.rice.kew.actionrequest.ActionRequestValue;
24  import org.kuali.rice.kew.api.exception.WorkflowException;
25  import org.kuali.rice.kew.api.extension.ExtensionDefinition;
26  import org.kuali.rice.kew.api.extension.ExtensionRepositoryService;
27  import org.kuali.rice.kew.api.extension.ExtensionUtils;
28  import org.kuali.rice.kew.engine.RouteContext;
29  import org.kuali.rice.kew.engine.node.NodeState;
30  import org.kuali.rice.kew.engine.node.RouteNode;
31  import org.kuali.rice.kew.engine.node.RouteNodeUtils;
32  import org.kuali.rice.kew.engine.node.service.RouteNodeService;
33  import org.kuali.rice.kew.framework.support.krms.RulesEngineExecutor;
34  import org.kuali.rice.kew.impl.peopleflow.PeopleFlowRouteModule;
35  import org.kuali.rice.kew.routemodule.RouteModule;
36  import org.kuali.rice.kew.util.ResponsibleParty;
37  import org.kuali.rice.krms.api.KrmsApiServiceLocator;
38  import org.kuali.rice.krms.api.engine.Engine;
39  import org.kuali.rice.krms.api.engine.EngineResults;
40  import org.w3c.dom.Element;
41  
42  import java.util.List;
43  
44  /**
45   * An implementation of a {@link RouteModule} which executes the KRMS rules engine using the configured
46   * {@link RulesEngineExecutor}.  It then interprets those results and processes them, which may include instantiating
47   * and delegating to another RouteModule.  Currently, this implementation only supports PeopleFlow results returned from
48   * KRMS and passes those off to the {@link org.kuali.rice.kew.impl.peopleflow.PeopleFlowRouteModule}.
49   *
50   * @author Kuali Rice Team (rice.collab@kuali.org)
51   */
52  public class RulesEngineRouteModule implements RouteModule {
53  
54      private static final Logger LOG = Logger.getLogger(RulesEngineRouteModule.class);
55  
56      private static final String RULES_ENGINE_ELEMENT = "rulesEngine";
57      private static final String EXECUTOR_NAME_ATTRIBUTE = "executorName";
58      private static final String EXECUTOR_CLASS_ATTRIBUTE = "executorClass";
59      private static final String PEOPLE_FLOWS_SELECTED_ATTRIBUTE = "peopleFlowsSelected";
60  
61      private volatile Engine rulesEngine;
62  
63      private PeopleFlowRouteModule peopleFlowRouteModule;
64      private ExtensionRepositoryService extensionRepositoryService;
65      private RouteNodeService routeNodeService;
66  
67      @Override
68      public List<ActionRequestValue> findActionRequests(RouteContext context) throws Exception {
69          EngineResults engineResults = executeRulesEngine(context, getRulesEngine());
70          if (engineResults != null) {
71              processEngineResults(context, engineResults);
72          }
73          return peopleFlowRouteModule.findActionRequests(context);
74      }
75  
76      @Override
77      public ResponsibleParty resolveResponsibilityId(String responsibilityId) throws WorkflowException {
78          return null;
79      }
80  
81      @Override
82      public boolean isMoreRequestsAvailable(RouteContext context) {
83          return peopleFlowRouteModule.isMoreRequestsAvailable(context);
84      }
85  
86      protected EngineResults executeRulesEngine(RouteContext context, Engine rulesEngine) {
87          RulesEngineExecutor executor = loadRulesEngineExecutor(context);
88          return executor.execute(context, rulesEngine);
89      }
90  
91      protected void processEngineResults(RouteContext context, EngineResults engineResults) {
92          String peopleFlowsSelected = (String)engineResults.getAttribute(PEOPLE_FLOWS_SELECTED_ATTRIBUTE);
93          if (StringUtils.isBlank(peopleFlowsSelected)) {
94              LOG.info("No PeopleFlows returned from KRMS execution.");
95          } else {
96              LOG.info("PeopleFlows returned from KRMS execution: " + peopleFlowsSelected);
97          }
98          NodeState nodeState = context.getNodeInstance().getNodeState(PeopleFlowRouteModule.PEOPLE_FLOW_SEQUENCE);
99          if (nodeState == null) {
100             nodeState = new NodeState();
101             nodeState.setNodeInstance(context.getNodeInstance());
102             nodeState.setKey(PeopleFlowRouteModule.PEOPLE_FLOW_SEQUENCE);
103             context.getNodeInstance().addNodeState(nodeState);
104         }
105         nodeState.setValue(peopleFlowsSelected);
106         if (!context.isSimulation()) {
107             routeNodeService.save(nodeState);
108         }
109     }
110 
111     protected RulesEngineExecutor loadRulesEngineExecutor(RouteContext context) {
112         RouteNode routeNode = context.getNodeInstance().getRouteNode();
113         Element rulesEngineElement = RouteNodeUtils.getCustomRouteNodeElement(
114                 context.getNodeInstance().getRouteNode(), RULES_ENGINE_ELEMENT);
115         if (rulesEngineElement == null) {
116             throw new ConfigurationException("Failed to located rules engine configuration for route node: " + routeNode.getName());
117         }
118         String executorName = rulesEngineElement.getAttribute(EXECUTOR_NAME_ATTRIBUTE);
119         String executorClassName = rulesEngineElement.getAttribute(EXECUTOR_CLASS_ATTRIBUTE);
120         if (StringUtils.isBlank(executorName) && StringUtils.isBlank(executorClassName)) {
121             throw new ConfigurationException("Failed to resolve a valid executor name or class name from rules engine configuration, was null or blank.");
122         }
123         RulesEngineExecutor rulesEngineExecutor = null;
124         if (StringUtils.isNotBlank(executorClassName)) {
125             rulesEngineExecutor = GlobalResourceLoader.getObject(new ObjectDefinition(executorClassName));
126         } else if (StringUtils.isNotBlank(executorName)) {
127             ExtensionDefinition extensionDefinition = getExtensionRepositoryService().getExtensionByName(executorName);
128             if (extensionDefinition != null) {
129                 rulesEngineExecutor = ExtensionUtils.loadExtension(extensionDefinition);
130             }
131         }
132         if (rulesEngineExecutor == null) {
133             throw new ConfigurationException("Failed to load RulesEngineExecutor for either executorName=" + executorName + " or executorClass=" + executorClassName);
134         }
135         return rulesEngineExecutor;
136     }
137 
138     protected Engine getRulesEngine() {
139         if (rulesEngine == null) {
140             rulesEngine = KrmsApiServiceLocator.getEngine();
141         }
142         return rulesEngine;
143     }
144 
145     public PeopleFlowRouteModule getPeopleFlowRouteModule() {
146         return peopleFlowRouteModule;
147     }
148 
149     public void setPeopleFlowRouteModule(PeopleFlowRouteModule peopleFlowRouteModule) {
150         this.peopleFlowRouteModule = peopleFlowRouteModule;
151     }
152 
153     public ExtensionRepositoryService getExtensionRepositoryService() {
154         return extensionRepositoryService;
155     }
156 
157     public void setExtensionRepositoryService(ExtensionRepositoryService extensionRepositoryService) {
158         this.extensionRepositoryService = extensionRepositoryService;
159     }
160 
161     public RouteNodeService getRouteNodeService() {
162         return routeNodeService;
163     }
164 
165     public void setRouteNodeService(RouteNodeService routeNodeService) {
166         this.routeNodeService = routeNodeService;
167     }
168     
169 }