View Javadoc

1   /*
2    * Copyright 2005-2007 The Kuali Foundation
3    * 
4    * 
5    * Licensed under the Educational Community License, Version 2.0 (the "License");
6    * you may not use this file except in compliance with the License.
7    * You may obtain a copy of the License at
8    * 
9    * http://www.opensource.org/licenses/ecl2.php
10   * 
11   * Unless required by applicable law or agreed to in writing, software
12   * distributed under the License is distributed on an "AS IS" BASIS,
13   * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14   * See the License for the specific language governing permissions and
15   * limitations under the License.
16   */
17  package org.kuali.rice.kew.routemodule;
18  
19  import org.apache.log4j.Logger;
20  import org.jdom.Document;
21  import org.jdom.Element;
22  import org.kuali.rice.core.api.impex.xml.XmlConstants;
23  import org.kuali.rice.core.api.reflect.ObjectDefinition;
24  import org.kuali.rice.core.api.reflect.ObjectDefinition;
25  import org.kuali.rice.core.api.resourceloader.GlobalResourceLoader;
26  import org.kuali.rice.core.util.xml.XmlHelper;
27  import org.kuali.rice.kew.actionrequest.ActionRequestFactory;
28  import org.kuali.rice.kew.actionrequest.ActionRequestValue;
29  import org.kuali.rice.kew.engine.RouteContext;
30  import org.kuali.rice.kew.engine.node.RouteNodeInstance;
31  import org.kuali.rice.kew.rule.RuleBaseValues;
32  import org.kuali.rice.kew.rule.RuleExtension;
33  import org.kuali.rice.kew.rule.RuleResponsibility;
34  import org.kuali.rice.kew.rule.WorkflowAttribute;
35  import org.kuali.rice.kew.rule.bo.RuleAttribute;
36  import org.kuali.rice.kew.rule.xmlrouting.GenericXMLRuleAttribute;
37  import org.kuali.rice.kew.rule.xmlrouting.XPathHelper;
38  import org.kuali.rice.kew.service.KEWServiceLocator;
39  import org.kuali.rice.kew.util.KEWConstants;
40  import org.kuali.rice.kew.xml.RuleXmlParser;
41  
42  import javax.xml.xpath.XPath;
43  import javax.xml.xpath.XPathConstants;
44  import java.io.ByteArrayInputStream;
45  import java.util.ArrayList;
46  import java.util.List;
47  
48  
49  /**
50   * A RouteModule that generates requests for responsibilities statically defined
51   * in the config block of the node.
52   * @author Kuali Rice Team (rice.collab@kuali.org)
53   */
54  public class InlineRequestsRouteModule extends FlexRMAdapter {
55      private static final Logger LOG = Logger.getLogger(InlineRequestsRouteModule.class);
56  
57      /**
58       * This overridden method is used to decipher the inline xpath and responsibilities of a route node definition and use
59       * them to create action reqeusts
60       * 
61       * @see org.kuali.rice.kew.routemodule.FlexRMAdapter#findActionRequests(org.kuali.rice.kew.engine.RouteContext)
62       */
63      @Override
64      public List<ActionRequestValue> findActionRequests(RouteContext context) throws Exception {
65          // comment this out while implementing the meta-rules stuff
66          // re-implement later
67          List<ActionRequestValue> actionRequests = new ArrayList<ActionRequestValue>();
68          RouteNodeInstance currentNode = context.getNodeInstance();
69          String contentFragment = currentNode.getRouteNode().getContentFragment();
70          // parse with JDOM to reuse RuleXmlParser
71          Document doc = XmlHelper.trimSAXXml(new ByteArrayInputStream(contentFragment.getBytes()));
72          Element root = doc.getRootElement();
73          List<String> ruleAttributeNames = new ArrayList<String>();
74          List<String> ruleAttributeClassNames = new ArrayList<String>();
75          List<String> xpathExpressions = new ArrayList<String>();
76          // get the list of ruleAttributes to use
77          Element ruleAttributes = root.getChild("ruleAttributes");
78          if (ruleAttributes != null) {
79              for (Object o : ruleAttributes.getChildren("name")) {
80                  Element e = (Element) o;
81                  ruleAttributeNames.add(e.getText());
82              }
83              for (Object o : ruleAttributes.getChildren("className")) {
84                  Element e = (Element) o;
85                  ruleAttributeClassNames.add(e.getText());
86              }
87          }
88          // get the list of xpath expressions to verify
89          for (Object o: root.getChildren("match")) {
90              Element e = (Element) o;
91              xpathExpressions.add(e.getText());
92          }
93          if ( (ruleAttributeNames.isEmpty()) && (ruleAttributeClassNames.isEmpty()) && (xpathExpressions.isEmpty()) ) {
94              throw new RuntimeException("Match xpath expression not specified (should be parse-time exception...)");
95          }
96  
97          List<WorkflowAttribute> attributes = new ArrayList<WorkflowAttribute>();
98          for (String attributeName : ruleAttributeNames) {
99              attributes.add(getRuleAttributeByName(attributeName));
100         }
101         for (String attributeClassName : ruleAttributeClassNames) {
102             attributes.add(getRuleAttributeByClassName(attributeClassName));
103         }
104         
105         // at this point if we have no xpath expressions or attributes we cannot match
106         if (attributes.isEmpty() && xpathExpressions.isEmpty()) {
107             return actionRequests;
108         }
109         
110         Boolean match = Boolean.TRUE;
111         if (!xpathExpressions.isEmpty()) {
112             XPath xpath = XPathHelper.newXPath();
113             for (String xpathExpression : xpathExpressions) {
114                 match &= (Boolean) xpath.evaluate(xpathExpression, context.getDocumentContent().getDocument(), XPathConstants.BOOLEAN);
115             }
116         }
117         for (WorkflowAttribute workflowAttribute : attributes) {
118             // no rule extensions to pass in below because we have no rule... simple attribute matching only
119             match &= workflowAttribute.isMatch(context.getDocumentContent(), new ArrayList<RuleExtension>());
120         }
121         
122         if (match.booleanValue()) {
123 //            LOG.debug("Expression '" + xpathExpression + "' matched document '" + context.getDocumentContent().getDocContent() + "'");
124         } else {
125             // return an empty list because we didn't find a match using the given xpath
126 //            LOG.debug("Expression '" + xpathExpression + "' did NOT match document '" + context.getDocumentContent().getDocContent() + "'");
127             return actionRequests;
128         }
129 
130         List<RuleResponsibility> responsibilities = new ArrayList<RuleResponsibility>();
131         RuleXmlParser parser = new RuleXmlParser();
132         ActionRequestFactory arf = new ActionRequestFactory(context.getDocument(), currentNode);
133         // this rule is only used to obtain description, forceAction flag, and the rulebasevalues id, which may be null
134         RuleBaseValues fakeRule = new RuleBaseValues();
135         fakeRule.setActiveInd(Boolean.TRUE);
136         fakeRule.setCurrentInd(Boolean.TRUE);
137         fakeRule.setDescription("a fake rule");
138         fakeRule.setForceAction(Boolean.TRUE);
139         fakeRule.setRuleBaseValuesId(null);
140 
141         for (Object o: root.getChildren("responsibility", XmlConstants.RULE_NAMESPACE)) {
142             Element e = (Element) o;
143             RuleResponsibility responsibility = parser.parseResponsibility(e, fakeRule);
144             responsibility.setResponsibilityId(KEWConstants.MACHINE_GENERATED_RESPONSIBILITY_ID);
145             responsibilities.add(responsibility);
146         }
147         if (responsibilities.size() == 0) {
148             throw new RuntimeException("No responsibilities found on node " + currentNode.getName());
149         }
150 
151         makeActionRequests(arf, responsibilities, context, fakeRule, context.getDocument(), null, null); 
152         actionRequests.addAll(arf.getRequestGraphs());
153         return actionRequests;
154     }
155     
156     @Override
157     public String toString() {
158         return "InlineRequestsRouteModule";
159     }
160 
161     private WorkflowAttribute getRuleAttributeByName(String ruleAttributeName) {
162         return materializeRuleAttribute(KEWServiceLocator.getRuleAttributeService().findByName(ruleAttributeName));
163     }
164     
165     private WorkflowAttribute getRuleAttributeByClassName(String ruleAttributeClassName) {
166         return materializeRuleAttribute(KEWServiceLocator.getRuleAttributeService().findByClassName(ruleAttributeClassName));
167     }
168     
169     private WorkflowAttribute materializeRuleAttribute(RuleAttribute ruleAttribute) {
170         if (ruleAttribute != null) {
171             if (KEWConstants.RULE_ATTRIBUTE_TYPE.equals(ruleAttribute.getType())) {
172                 ObjectDefinition objDef = new ObjectDefinition(ruleAttribute.getClassName(), ruleAttribute.getApplicationId());
173                 return (WorkflowAttribute) GlobalResourceLoader.getObject(objDef);
174             } else if (KEWConstants.RULE_XML_ATTRIBUTE_TYPE.equals(ruleAttribute.getType())) {
175                 ObjectDefinition objDef = new ObjectDefinition(ruleAttribute.getClassName(), ruleAttribute.getApplicationId());
176                 WorkflowAttribute workflowAttribute = (WorkflowAttribute) GlobalResourceLoader.getObject(objDef);
177                 //required to make it work because ruleAttribute XML is required to construct custom columns
178                 ((GenericXMLRuleAttribute) workflowAttribute).setRuleAttribute(ruleAttribute);
179                 return workflowAttribute;
180             }
181         }
182         return null;
183     }
184     
185 }