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.rule.web;
17  
18  import org.apache.log4j.Logger;
19  import org.apache.struts.action.ActionForm;
20  import org.apache.struts.action.ActionForward;
21  import org.apache.struts.action.ActionMapping;
22  import org.apache.struts.action.ActionMessages;
23  import org.kuali.rice.core.api.config.property.ConfigContext;
24  import org.kuali.rice.core.api.criteria.Predicate;
25  import org.kuali.rice.core.api.criteria.QueryByCriteria;
26  import org.kuali.rice.kew.doctype.bo.DocumentType;
27  import org.kuali.rice.kew.doctype.service.DocumentTypeService;
28  import org.kuali.rice.kew.engine.node.BranchPrototype;
29  import org.kuali.rice.kew.engine.node.RouteNode;
30  import org.kuali.rice.kew.engine.node.RouteNodeConfigParam;
31  import org.kuali.rice.kew.rule.RuleBaseValues;
32  import org.kuali.rice.kew.rule.bo.RuleTemplateBo;
33  import org.kuali.rice.kew.rule.service.RuleServiceInternal;
34  import org.kuali.rice.kew.service.KEWServiceLocator;
35  import org.kuali.rice.kew.api.KewApiConstants;
36  import org.kuali.rice.kew.web.KewKualiAction;
37  import org.kuali.rice.kim.api.KimConstants;
38  import org.kuali.rice.kim.api.group.Group;
39  import org.kuali.rice.kim.api.permission.Permission;
40  import org.kuali.rice.kim.api.responsibility.Responsibility;
41  import org.kuali.rice.kim.api.services.KimApiServiceLocator;
42  import org.kuali.rice.kns.service.DocumentHelperService;
43  import org.kuali.rice.kns.service.KNSServiceLocator;
44  import org.kuali.rice.kns.service.MaintenanceDocumentDictionaryService;
45  import org.kuali.rice.krad.service.KRADServiceLocatorWeb;
46  import org.kuali.rice.krad.util.GlobalVariables;
47  import org.kuali.rice.krad.util.KRADConstants;
48  
49  import javax.servlet.http.HttpServletRequest;
50  import javax.servlet.http.HttpServletResponse;
51  import java.util.ArrayList;
52  import java.util.HashMap;
53  import java.util.Iterator;
54  import java.util.List;
55  
56  import static org.kuali.rice.core.api.criteria.PredicateFactory.and;
57  import static org.kuali.rice.core.api.criteria.PredicateFactory.equal;
58  
59  
60  /**
61   * A Struts Action for building and interacting with the Rule Quick Links.
62   *
63   * @author Kuali Rice Team (rice.collab@kuali.org)
64   */
65  public class RuleQuickLinksAction extends KewKualiAction {
66  
67  	private static final Logger LOG = Logger.getLogger(RuleQuickLinksAction.class);
68  	
69  	private MaintenanceDocumentDictionaryService maintenanceDocumentDictionaryService;
70  	private DocumentHelperService documentHelperService;
71  
72      public ActionForward start(ActionMapping mapping, ActionForm form, HttpServletRequest request, HttpServletResponse response) throws Exception {
73      	makeLookupPathParam(mapping, request);
74      	establishRequiredState(request, form);
75          return mapping.findForward("basic");
76      }
77  
78      @SuppressWarnings("unchecked")
79  	public ActionMessages establishRequiredState(HttpServletRequest request, ActionForm form) throws Exception {
80          RuleQuickLinksForm qlForm = (RuleQuickLinksForm) form;
81          List<DocumentType> documentTypes;
82          if (qlForm.getRootDocTypeName() != null) {
83          	documentTypes = new ArrayList<DocumentType>();
84              DocumentType docType = getDocumentTypeService().findByName(qlForm.getRootDocTypeName());
85              documentTypes.add(docType);
86              request.setAttribute("renderOpened", Boolean.TRUE);
87          } else {
88          	documentTypes = getDocumentTypeService().findAllCurrentRootDocuments();
89          }
90          qlForm.setDocumentTypeQuickLinksStructures(getDocumentTypeDataStructure(documentTypes));
91      	int shouldDisplayCount = 0;
92          for ( DocumentTypeQuickLinksStructure dt : qlForm.getDocumentTypeQuickLinksStructures() ) {
93          	if ( dt.isShouldDisplay() ) {
94          		shouldDisplayCount++;
95          	}
96          }
97      	if ( shouldDisplayCount == 1 ) {
98              request.setAttribute("renderOpened", Boolean.TRUE);
99      	}
100         String documentTypeName = getMaintenanceDocumentDictionaryService().getDocumentTypeName(DocumentType.class);
101         try {
102             if ((documentTypeName != null) && getDocumentHelperService().getDocumentAuthorizer(documentTypeName).canInitiate(documentTypeName, GlobalVariables.getUserSession().getPerson())) {
103                 qlForm.setCanInitiateDocumentTypeDocument( true );
104             }
105         } catch (Exception ex) {
106 			// just skip - and don't display links
107         	LOG.error( "Unable to check initiation permission for "+ documentTypeName, ex );
108 		}
109 
110         return null;
111     }
112 
113     public ActionForward addDelegationRule(ActionMapping mapping, ActionForm form, HttpServletRequest request, HttpServletResponse response) throws Exception {
114     	ActionForward result = null;
115     	
116     	String ruleTemplateId = request.getParameter("delegationRuleBaseValues.ruleTemplate.ruleTemplateId");
117         String docTypeName = request.getParameter("delegationRuleBaseValues.documentType.name");
118         List rules = getRuleService().search(docTypeName, null, ruleTemplateId, "", null, null, Boolean.FALSE, Boolean.TRUE, new HashMap(), null);
119         
120         if (rules.size() == 1) {
121             RuleBaseValues rule = (RuleBaseValues)rules.get(0);
122             String url = ConfigContext.getCurrentContextConfig().getKEWBaseURL() +
123                 "/DelegateRule.do?methodToCall=start" +
124             	"&parentRuleId=" + rule.getId();
125             result = new ActionForward(url, true);
126         } else {
127         	makeLookupPathParam(mapping, request);
128         	result = new ActionForward(ConfigContext.getCurrentContextConfig().getKRBaseURL() + 
129         			"/lookup.do?methodToCall=start&"+ stripMethodToCall(request.getQueryString()), true);
130         }
131         
132         return result;
133     }
134 
135 	private List getDocumentTypeDataStructure(List rootDocuments) {
136 		List documentTypeQuickLinksStructures = new ArrayList();
137 		for (Iterator iter = rootDocuments.iterator(); iter.hasNext();) {
138 			DocumentTypeQuickLinksStructure quickLinkStruct =new DocumentTypeQuickLinksStructure((DocumentType) iter.next());
139 			if (! quickLinkStruct.getFlattenedNodes().isEmpty() || ! quickLinkStruct.getChildrenDocumentTypes().isEmpty()) {
140 				documentTypeQuickLinksStructures.add(quickLinkStruct);
141 			}
142 
143 		}
144 
145 		return documentTypeQuickLinksStructures;
146 	}
147 
148 
149 	/**
150      * A bean to hold a DocumentType with its flattened nodes for rendering purposes
151      * on the quick links.
152      *
153  * @author Kuali Rice Team (rice.collab@kuali.org)
154      */
155     public static class DocumentTypeQuickLinksStructure {
156         private DocumentType documentType;
157         private List<RouteNode> flattenedNodes = new ArrayList<RouteNode>();
158         private List<DocumentTypeQuickLinksStructure> childrenDocumentTypes = new ArrayList<DocumentTypeQuickLinksStructure>();
159         private List<Permission> permissions = null;
160         
161         private DocumentTypeQuickLinksStructure(DocumentType documentType) {
162 			this.documentType = documentType;
163 			if ( documentType != null ) {
164 				List<RouteNode> tempFlattenedNodes = KEWServiceLocator.getRouteNodeService()
165 						.getFlattenedNodes( documentType, true );
166 				for ( RouteNode routeNode : tempFlattenedNodes ) {
167 					if ( routeNode.isFlexRM() || routeNode.isRoleNode() ) {
168 						flattenedNodes.add( new RouteNodeForDisplay( routeNode ) );
169 					}
170 				}
171 				for ( Iterator<DocumentType> iter = documentType.getChildrenDocTypes().iterator(); iter.hasNext(); ) {
172 					childrenDocumentTypes.add( new DocumentTypeQuickLinksStructure( iter.next() ) );
173 				}
174 			}
175 		}
176 
177         public List getChildrenDocumentTypes() {
178             return childrenDocumentTypes;
179         }
180         public void setChildrenDocumentTypes(List<DocumentTypeQuickLinksStructure> childrenDocumentTypes) {
181             this.childrenDocumentTypes = childrenDocumentTypes;
182         }
183         public DocumentType getDocumentType() {
184             return documentType;
185         }
186         public void setDocumentType(DocumentType documentType) {
187             this.documentType = documentType;
188         }
189         public List getFlattenedNodes() {
190             return flattenedNodes;
191         }
192         public void setFlattenedNodes(List<RouteNode> flattenedNodes) {
193             this.flattenedNodes = flattenedNodes;
194         }
195         public boolean isShouldDisplay() {
196 //			if (flattenedNodes.isEmpty()) {
197 //				for (DocumentTypeQuickLinksStructure docType : childrenDocumentTypes) {
198 //					if (docType.isShouldDisplay()) {
199 //						return true;
200 //					}
201 //				}
202 //				return false;
203 //			}
204 			return true;
205 		}
206 
207 		public List<Permission> getPermissions() {
208 			if ( permissions == null ) {
209                 Predicate p = and(
210                         equal("attributeName", "documentTypeName"),
211                         equal("active", "Y"),
212                         equal("detailCriteria",
213 						KimConstants.AttributeConstants.DOCUMENT_TYPE_NAME+"="+getDocumentType().getName()));
214 				permissions = KimApiServiceLocator.getPermissionService().findPermissions( QueryByCriteria.Builder.fromPredicates(p)).getResults();
215 //				sqlLogger.setLevel( Level.INFO );
216 			}
217 			return permissions;
218 		}
219 		
220 		public boolean isHasRelatedPermissions() {
221 			return !getPermissions().isEmpty();
222 		}
223 		
224 		public int getRelatedPermissionCount() {
225 			return getPermissions().size();
226 		}
227     }
228 
229     public static class RouteNodeForDisplay extends RouteNode {
230     	private static final long serialVersionUID = 1L;
231 		private RouteNode baseNode;
232     	
233 		public RouteNodeForDisplay( RouteNode baseNode ) {
234 			this.baseNode = baseNode;
235 		}
236 
237 		public boolean equals(Object obj) {
238 			return this.baseNode.equals(obj);
239 		}
240 
241 		public String getActivationType() {
242 			return this.baseNode.getActivationType();
243 		}
244 
245 		public BranchPrototype getBranch() {
246 			return this.baseNode.getBranch();
247 		}
248 
249 		public List<RouteNodeConfigParam> getConfigParams() {
250 			return this.baseNode.getConfigParams();
251 		}
252 
253 		public String getContentFragment() {
254 			return this.baseNode.getContentFragment();
255 		}
256 
257 		public DocumentType getDocumentType() {
258 			return this.baseNode.getDocumentType();
259 		}
260 
261 		public String getDocumentTypeId() {
262 			return this.baseNode.getDocumentTypeId();
263 		}
264 		public Group getExceptionWorkgroup() {
265 			return this.baseNode.getExceptionWorkgroup();
266 		}
267 		public String getExceptionWorkgroupId() {
268 			return this.baseNode.getExceptionWorkgroupId();
269 		}
270 		public String getExceptionWorkgroupName() {
271 			return this.baseNode.getExceptionWorkgroupName();
272 		}
273 		public Boolean getFinalApprovalInd() {
274 			return this.baseNode.getFinalApprovalInd();
275 		}
276 		public Integer getLockVerNbr() {
277 			return this.baseNode.getLockVerNbr();
278 		}
279 		public Boolean getMandatoryRouteInd() {
280 			return this.baseNode.getMandatoryRouteInd();
281 		}
282 		public List<RouteNode> getNextNodes() {
283 			return this.baseNode.getNextNodes();
284 		}
285 		public String getNodeType() {
286 			return this.baseNode.getNodeType();
287 		}
288 		public List<RouteNode> getPreviousNodes() {
289 			return this.baseNode.getPreviousNodes();
290 		}
291 		public String getRouteMethodCode() {
292 			return this.baseNode.getRouteMethodCode();
293 		}
294 		public String getRouteMethodName() {
295 			return this.baseNode.getRouteMethodName();
296 		}
297 		public String getRouteNodeId() {
298 			return this.baseNode.getRouteNodeId();
299 		}
300 		public String getRouteNodeName() {
301 			return this.baseNode.getRouteNodeName();
302 		}
303 		public RuleTemplateBo getRuleTemplate() {
304 			return this.baseNode.getRuleTemplate();
305 		}
306 		public int hashCode() {
307 			return this.baseNode.hashCode();
308 		}
309 		public boolean isExceptionGroupDefined() {
310 			return this.baseNode.isExceptionGroupDefined();
311 		}
312 		public boolean isFlexRM() {
313 			return this.baseNode.isFlexRM();
314 		}
315 		public boolean isRoleNode() {
316 			return this.baseNode.isRoleNode();
317 		}
318 		public String toString() {
319 			return this.baseNode.toString();
320 		}
321 		
322 		private List<Responsibility> responsibilities = null;
323 		
324 		public List<Responsibility> getResponsibilities() {
325 			if ( responsibilities == null ) {
326 				QueryByCriteria.Builder builder = QueryByCriteria.Builder.create();
327                 Predicate p = and(
328                     equal("template.namespaceCode", KRADConstants.KUALI_RICE_WORKFLOW_NAMESPACE),
329                     equal("template.name", KewApiConstants.DEFAULT_RESPONSIBILITY_TEMPLATE_NAME),
330                     equal("active", "Y"),
331                     equal("attributes[documentTypeName]", getDocumentType().getName()),
332                     equal("attributes[routeNodeName]", getRouteNodeName())
333                 );
334                 builder.setPredicates(p);
335  				responsibilities = KimApiServiceLocator.getResponsibilityService().findResponsibilities(builder.build()).getResults();
336 			}
337 			return responsibilities;
338 		}
339 		
340 		public int getResponsibilityCount() {
341 			return getResponsibilities().size();
342 		}
343 		
344 		public boolean isHasResponsibility() {
345 			return !getResponsibilities().isEmpty();
346 		}
347     }
348     
349     private void makeLookupPathParam(ActionMapping mapping, HttpServletRequest request) {
350     	String basePath = request.getScheme() + "://" + request.getServerName() + ":" + request.getServerPort() + request.getContextPath() + mapping.getModuleConfig().getPrefix();
351     	request.setAttribute("basePath", basePath);
352     }
353 
354     private String stripMethodToCall(String queryString) {
355         return queryString.replaceAll("methodToCall=addDelegationRule&", "");
356     }
357 
358     private DocumentTypeService getDocumentTypeService() {
359         return KEWServiceLocator.getDocumentTypeService();
360     }
361 
362     private RuleServiceInternal getRuleService() {
363     	return KEWServiceLocator.getRuleService();
364     }
365     
366 	public DocumentHelperService getDocumentHelperService() {
367 		if(documentHelperService == null){
368 			documentHelperService = KNSServiceLocator.getDocumentHelperService();
369 		}
370 		return documentHelperService;
371 	}
372 
373 	public MaintenanceDocumentDictionaryService getMaintenanceDocumentDictionaryService() {
374 		if(maintenanceDocumentDictionaryService == null){
375 			maintenanceDocumentDictionaryService = KNSServiceLocator.getMaintenanceDocumentDictionaryService();
376 		}
377 		return maintenanceDocumentDictionaryService;
378 	}
379 
380 	@Override
381 	public ActionForward toggleTab(ActionMapping mapping, ActionForm form,
382 			HttpServletRequest request, HttpServletResponse response)
383 			throws Exception {
384 		
385 		establishRequiredState(request, form);
386 		return super.toggleTab(mapping, form, request, response);
387 	}
388 
389 }