View Javadoc

1   /**
2    * Copyright 2005-2011 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.rule;
17  
18  import org.apache.commons.lang.StringUtils;
19  import org.jdom.Document;
20  import org.jdom.Element;
21  import org.kuali.rice.core.api.util.xml.XmlHelper;
22  import org.kuali.rice.kew.api.WorkflowRuntimeException;
23  import org.kuali.rice.kew.doctype.bo.DocumentType;
24  import org.kuali.rice.kew.doctype.service.DocumentTypeService;
25  import org.kuali.rice.kew.exception.WorkflowServiceErrorImpl;
26  import org.kuali.rice.kew.routeheader.DocumentContent;
27  import org.kuali.rice.kew.rule.xmlrouting.XPathHelper;
28  import org.kuali.rice.kew.service.KEWServiceLocator;
29  import org.kuali.rice.kns.web.ui.Field;
30  import org.kuali.rice.kns.web.ui.Row;
31  
32  import javax.xml.xpath.XPath;
33  import javax.xml.xpath.XPathExpressionException;
34  import java.io.StringReader;
35  import java.util.ArrayList;
36  import java.util.Collection;
37  import java.util.Iterator;
38  import java.util.List;
39  import java.util.Map;
40  
41  
42  /**
43   * A {@link WorkflowRuleAttribute} which is used to route a rule based on the
44   * {@link DocumentType} of the rule which is created.
45   *
46   * @author Kuali Rice Team (rice.collab@kuali.org)
47   */
48  public class RuleRoutingAttribute implements WorkflowRuleAttribute {
49  
50  	private static final long serialVersionUID = -8884711461398770563L;
51  
52  	private static final String DOC_TYPE_NAME_PROPERTY = "docTypeFullName";//doc_type_name
53      private static final String DOC_TYPE_NAME_KEY = "docTypeFullName";
54  
55      private static final String LOOKUPABLE_CLASS = "org.kuali.rice.kew.doctype.bo.DocumentType";//DocumentTypeLookupableImplService//org.kuali.rice.kew.doctype.bo.DocumentType
56      private static final String DOC_TYPE_NAME_LABEL = "Document type name";
57  
58      private static final String DOC_TYPE_NAME_XPATH = "//newMaintainableObject/businessObject/docTypeName";
59      private static final String DOC_TYPE_NAME_DEL_XPATH = "//newMaintainableObject/businessObject/delegationRuleBaseValues/docTypeName";
60  
61      private String doctypeName;
62      private List<Row> rows;
63      private boolean required;
64  
65      public RuleRoutingAttribute(String docTypeName) {
66          this();
67          setDoctypeName(docTypeName);
68      }
69  
70      public RuleRoutingAttribute() {
71          buildRows();
72      }
73  
74      private void buildRows() {
75          rows = new ArrayList<Row>();
76  
77          List<Field> fields = new ArrayList<Field>();
78          fields.add(new Field(DOC_TYPE_NAME_LABEL, "", Field.TEXT, false, DOC_TYPE_NAME_PROPERTY, "", false, false, null, LOOKUPABLE_CLASS));
79          //fields.add(new Field(DOC_TYPE_NAME_LABEL, "", Field.TEXT, false, DOC_TYPE_NAME_KEY, "", false, false, null, LOOKUPABLE_CLASS));
80          rows.add(new Row(fields));
81      }
82  
83      public boolean isMatch(DocumentContent docContent, List ruleExtensions) {
84  	setDoctypeName(getRuleDocumentTypeFromRuleExtensions(ruleExtensions));
85          DocumentTypeService service = (DocumentTypeService) KEWServiceLocator.getService(KEWServiceLocator.DOCUMENT_TYPE_SERVICE);
86          
87  		try {
88  			String docTypeName = getDocTypNameFromXML(docContent);
89              if (docTypeName.equals(getDoctypeName())) {
90                  return true;
91              }
92              DocumentType documentType = service.findByName(docTypeName);
93              while (documentType != null && documentType.getParentDocType() != null) {
94                  documentType = documentType.getParentDocType();
95                  if(documentType.getName().equals(getDoctypeName())){
96                      return true;
97                  }
98              }
99  		} catch (XPathExpressionException e) {
100 			throw new WorkflowRuntimeException(e);
101 		}
102 		
103 		
104         if (ruleExtensions.isEmpty()) {
105             return true;
106         }
107         return false;
108     }
109 
110     protected String getRuleDocumentTypeFromRuleExtensions(List ruleExtensions) {
111 	for (Iterator extensionsIterator = ruleExtensions.iterator(); extensionsIterator.hasNext();) {
112             RuleExtensionBo extension = (RuleExtensionBo) extensionsIterator.next();
113             if (extension.getRuleTemplateAttribute().getRuleAttribute().getResourceDescriptor().equals(getClass().getName())) {
114                 for (Iterator valuesIterator = extension.getExtensionValues().iterator(); valuesIterator.hasNext();) {
115                     RuleExtensionValue extensionValue = (RuleExtensionValue) valuesIterator.next();
116                     String key = extensionValue.getKey();
117                     String value = extensionValue.getValue();
118                     if (key.equals(DOC_TYPE_NAME_KEY)) {
119                         return value;
120                     }
121                 }
122             }
123         }
124 	return null;
125     }
126 
127     public List getRuleRows() {
128         return rows;
129     }
130 
131     public List getRoutingDataRows() {
132         return rows;
133     }
134 
135     public String getDocContent() {
136         if (!org.apache.commons.lang.StringUtils.isEmpty(getDoctypeName())) {
137             return "<ruleRouting><doctype>" + getDoctypeName() + "</doctype></ruleRouting>";
138         } else {
139             return "";
140         }
141     }
142   
143 
144 	private String getDocTypNameFromXML(DocumentContent docContent) throws XPathExpressionException {
145 		XPath xPath = XPathHelper.newXPath();
146 		String docTypeName = xPath.evaluate(DOC_TYPE_NAME_XPATH, docContent.getDocument());
147 				
148 		if (StringUtils.isBlank(docTypeName)) {
149 			docTypeName = xPath.evaluate(DOC_TYPE_NAME_DEL_XPATH, docContent.getDocument());
150 			
151 			if (StringUtils.isBlank(docTypeName)) {
152 				throw new WorkflowRuntimeException("Could not locate Document Type Name on the document: " + 
153 						docContent.getRouteContext().getDocument().getDocumentId());
154 			}
155 		} 
156 		return docTypeName;
157 	}
158 
159 
160     public List<RuleRoutingAttribute> parseDocContent(DocumentContent docContent) {
161         try {
162             Document doc2 = (Document) XmlHelper.buildJDocument(new StringReader(docContent.getDocContent()));
163             
164             List<RuleRoutingAttribute> doctypeAttributes = new ArrayList<RuleRoutingAttribute>();
165             Collection<Element> ruleRoutings = XmlHelper.findElements(doc2.getRootElement(), "docTypeName");
166             List<String> usedDTs = new ArrayList<String>();
167             for (Iterator<Element> iter = ruleRoutings.iterator(); iter.hasNext();) {
168                 Element ruleRoutingElement = (Element) iter.next();
169 
170                 //Element docTypeElement = ruleRoutingElement.getChild("doctype");
171                 Element docTypeElement = ruleRoutingElement;
172                 String elTxt = docTypeElement.getText();
173                 if (docTypeElement != null && !usedDTs.contains(elTxt)) {
174                 	usedDTs.add(elTxt);
175                     doctypeAttributes.add(new RuleRoutingAttribute(elTxt));
176                 }
177             }
178 
179             return doctypeAttributes;
180         } catch (Exception e) {
181             throw new RuntimeException(e);
182         }
183     }
184 
185     public List getRuleExtensionValues() {
186         List extensions = new ArrayList();
187 
188         if (!org.apache.commons.lang.StringUtils.isEmpty(getDoctypeName())) {
189             RuleExtensionValue extension = new RuleExtensionValue();
190             extension.setKey(DOC_TYPE_NAME_KEY);
191             extension.setValue(getDoctypeName());
192             extensions.add(extension);
193         }
194 
195         return extensions;
196     }
197 
198     public List validateRoutingData(Map paramMap) {
199         List errors = new ArrayList();
200         setDoctypeName((String) paramMap.get(DOC_TYPE_NAME_PROPERTY));
201         if (isRequired() && org.apache.commons.lang.StringUtils.isEmpty(getDoctypeName())) {
202             errors.add(new WorkflowServiceErrorImpl("doc type is not valid.", "routetemplate.ruleroutingattribute.doctype.invalid"));
203         }
204 
205         if (!org.apache.commons.lang.StringUtils.isEmpty(getDoctypeName())) {
206             DocumentTypeService service = (DocumentTypeService) KEWServiceLocator.getService(KEWServiceLocator.DOCUMENT_TYPE_SERVICE);
207             DocumentType documentType = service.findByName(getDoctypeName());
208             if (documentType == null) {
209                 errors.add(new WorkflowServiceErrorImpl("doc type is not valid", "routetemplate.ruleroutingattribute.doctype.invalid"));
210             }
211         }
212         return errors;
213     }
214 
215     public List validateRuleData(Map paramMap) {
216         return validateRoutingData(paramMap);
217     }
218 
219     public String getDoctypeName() {
220         return this.doctypeName;
221     }
222 
223     public void setDoctypeName(String docTypeName) {
224         this.doctypeName = docTypeName;
225     }
226 
227     public void setRequired(boolean required) {
228         this.required = required;
229     }
230 
231     public boolean isRequired() {
232         return required;
233     }
234 }