View Javadoc

1   /**
2    * Copyright 2005-2012 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          processEngineResults(context, engineResults);
71          return peopleFlowRouteModule.findActionRequests(context);
72      }
73  
74      @Override
75      public ResponsibleParty resolveResponsibilityId(String responsibilityId) throws WorkflowException {
76          return null;
77      }
78  
79      @Override
80      public boolean isMoreRequestsAvailable(RouteContext context) {
81          return peopleFlowRouteModule.isMoreRequestsAvailable(context);
82      }
83  
84      protected EngineResults executeRulesEngine(RouteContext context, Engine rulesEngine) {
85          RulesEngineExecutor executor = loadRulesEngineExecutor(context);
86          return executor.execute(context, rulesEngine);
87      }
88  
89      protected void processEngineResults(RouteContext context, EngineResults engineResults) {
90          String peopleFlowsSelected = (String)engineResults.getAttribute(PEOPLE_FLOWS_SELECTED_ATTRIBUTE);
91          if (StringUtils.isBlank(peopleFlowsSelected)) {
92              LOG.info("No PeopleFlows returned from KRMS execution.");
93          } else {
94              LOG.info("PeopleFlows returned from KRMS execution: " + peopleFlowsSelected);
95          }
96          NodeState nodeState = context.getNodeInstance().getNodeState(PeopleFlowRouteModule.PEOPLE_FLOW_SEQUENCE);
97          if (nodeState == null) {
98              nodeState = new NodeState();
99              nodeState.setNodeInstance(context.getNodeInstance());
100             nodeState.setKey(PeopleFlowRouteModule.PEOPLE_FLOW_SEQUENCE);
101             context.getNodeInstance().addNodeState(nodeState);
102         }
103         nodeState.setValue(peopleFlowsSelected);
104         if (!context.isSimulation()) {
105             routeNodeService.save(nodeState);
106         }
107     }
108 
109     protected RulesEngineExecutor loadRulesEngineExecutor(RouteContext context) {
110         RouteNode routeNode = context.getNodeInstance().getRouteNode();
111         Element rulesEngineElement = RouteNodeUtils.getCustomRouteNodeElement(
112                 context.getNodeInstance().getRouteNode(), RULES_ENGINE_ELEMENT);
113         if (rulesEngineElement == null) {
114             throw new ConfigurationException("Failed to located rules engine configuration for route node: " + routeNode.getName());
115         }
116         String executorName = rulesEngineElement.getAttribute(EXECUTOR_NAME_ATTRIBUTE);
117         String executorClassName = rulesEngineElement.getAttribute(EXECUTOR_CLASS_ATTRIBUTE);
118         if (StringUtils.isBlank(executorName) && StringUtils.isBlank(executorClassName)) {
119             throw new ConfigurationException("Failed to resolve a valid executor name or class name from rules engine configuration, was null or blank.");
120         }
121         RulesEngineExecutor rulesEngineExecutor = null;
122         if (StringUtils.isNotBlank(executorClassName)) {
123             rulesEngineExecutor = GlobalResourceLoader.getObject(new ObjectDefinition(executorClassName));
124         } else if (StringUtils.isNotBlank(executorName)) {
125             ExtensionDefinition extensionDefinition = getExtensionRepositoryService().getExtensionByName(executorName);
126             if (extensionDefinition != null) {
127                 rulesEngineExecutor = ExtensionUtils.loadExtension(extensionDefinition);
128             }
129         }
130         if (rulesEngineExecutor == null) {
131             throw new ConfigurationException("Failed to load RulesEngineExecutor for either executorName=" + executorName + " or executorClass=" + executorClassName);
132         }
133         return rulesEngineExecutor;
134     }
135 
136     protected Engine getRulesEngine() {
137         if (rulesEngine == null) {
138             rulesEngine = KrmsApiServiceLocator.getEngine();
139         }
140         return rulesEngine;
141     }
142 
143     public PeopleFlowRouteModule getPeopleFlowRouteModule() {
144         return peopleFlowRouteModule;
145     }
146 
147     public void setPeopleFlowRouteModule(PeopleFlowRouteModule peopleFlowRouteModule) {
148         this.peopleFlowRouteModule = peopleFlowRouteModule;
149     }
150 
151     public ExtensionRepositoryService getExtensionRepositoryService() {
152         return extensionRepositoryService;
153     }
154 
155     public void setExtensionRepositoryService(ExtensionRepositoryService extensionRepositoryService) {
156         this.extensionRepositoryService = extensionRepositoryService;
157     }
158 
159     public RouteNodeService getRouteNodeService() {
160         return routeNodeService;
161     }
162 
163     public void setRouteNodeService(RouteNodeService routeNodeService) {
164         this.routeNodeService = routeNodeService;
165     }
166     
167 }