001 /**
002 * Copyright 2005-2012 The Kuali Foundation
003 *
004 * Licensed under the Educational Community License, Version 2.0 (the "License");
005 * you may not use this file except in compliance with the License.
006 * You may obtain a copy of the License at
007 *
008 * http://www.opensource.org/licenses/ecl2.php
009 *
010 * Unless required by applicable law or agreed to in writing, software
011 * distributed under the License is distributed on an "AS IS" BASIS,
012 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
013 * See the License for the specific language governing permissions and
014 * limitations under the License.
015 */
016 package org.kuali.rice.kew.rule.web;
017
018 import org.apache.log4j.Logger;
019 import org.apache.struts.action.ActionForm;
020 import org.apache.struts.action.ActionForward;
021 import org.apache.struts.action.ActionMapping;
022 import org.apache.struts.action.ActionMessages;
023 import org.kuali.rice.core.api.config.property.ConfigContext;
024 import org.kuali.rice.core.api.criteria.Predicate;
025 import org.kuali.rice.core.api.criteria.QueryByCriteria;
026 import org.kuali.rice.kew.doctype.bo.DocumentType;
027 import org.kuali.rice.kew.doctype.service.DocumentTypeService;
028 import org.kuali.rice.kew.engine.node.BranchPrototype;
029 import org.kuali.rice.kew.engine.node.RouteNode;
030 import org.kuali.rice.kew.engine.node.RouteNodeConfigParam;
031 import org.kuali.rice.kew.rule.RuleBaseValues;
032 import org.kuali.rice.kew.rule.bo.RuleTemplateBo;
033 import org.kuali.rice.kew.rule.service.RuleServiceInternal;
034 import org.kuali.rice.kew.service.KEWServiceLocator;
035 import org.kuali.rice.kew.api.KewApiConstants;
036 import org.kuali.rice.kew.web.KewKualiAction;
037 import org.kuali.rice.kim.api.KimConstants;
038 import org.kuali.rice.kim.api.group.Group;
039 import org.kuali.rice.kim.api.permission.Permission;
040 import org.kuali.rice.kim.api.responsibility.Responsibility;
041 import org.kuali.rice.kim.api.services.KimApiServiceLocator;
042 import org.kuali.rice.kns.service.DocumentHelperService;
043 import org.kuali.rice.kns.service.KNSServiceLocator;
044 import org.kuali.rice.kns.service.MaintenanceDocumentDictionaryService;
045 import org.kuali.rice.krad.service.KRADServiceLocatorWeb;
046 import org.kuali.rice.krad.util.GlobalVariables;
047 import org.kuali.rice.krad.util.KRADConstants;
048
049 import javax.servlet.http.HttpServletRequest;
050 import javax.servlet.http.HttpServletResponse;
051 import java.util.ArrayList;
052 import java.util.Collections;
053 import java.util.Comparator;
054 import java.util.HashMap;
055 import java.util.Iterator;
056 import java.util.List;
057
058 import static org.kuali.rice.core.api.criteria.PredicateFactory.and;
059 import static org.kuali.rice.core.api.criteria.PredicateFactory.equal;
060
061
062 /**
063 * A Struts Action for building and interacting with the Rule Quick Links.
064 *
065 * @author Kuali Rice Team (rice.collab@kuali.org)
066 */
067 public class RuleQuickLinksAction extends KewKualiAction {
068
069 private static final Logger LOG = Logger.getLogger(RuleQuickLinksAction.class);
070
071 private MaintenanceDocumentDictionaryService maintenanceDocumentDictionaryService;
072 private DocumentHelperService documentHelperService;
073
074 public ActionForward start(ActionMapping mapping, ActionForm form, HttpServletRequest request, HttpServletResponse response) throws Exception {
075 makeLookupPathParam(mapping, request);
076 establishRequiredState(request, form);
077 return mapping.findForward("basic");
078 }
079
080 @SuppressWarnings("unchecked")
081 public ActionMessages establishRequiredState(HttpServletRequest request, ActionForm form) throws Exception {
082 RuleQuickLinksForm qlForm = (RuleQuickLinksForm) form;
083 List<DocumentType> documentTypes;
084 if (qlForm.getRootDocTypeName() != null) {
085 documentTypes = new ArrayList<DocumentType>();
086 DocumentType docType = getDocumentTypeService().findByName(qlForm.getRootDocTypeName());
087 documentTypes.add(docType);
088 request.setAttribute("renderOpened", Boolean.TRUE);
089 } else {
090 documentTypes = getDocumentTypeService().findAllCurrentRootDocuments();
091 }
092 qlForm.setDocumentTypeQuickLinksStructures(getDocumentTypeDataStructure(documentTypes));
093 int shouldDisplayCount = 0;
094 for ( DocumentTypeQuickLinksStructure dt : qlForm.getDocumentTypeQuickLinksStructures() ) {
095 if ( dt.isShouldDisplay() ) {
096 shouldDisplayCount++;
097 }
098 }
099 if ( shouldDisplayCount == 1 ) {
100 request.setAttribute("renderOpened", Boolean.TRUE);
101 }
102 String documentTypeName = getMaintenanceDocumentDictionaryService().getDocumentTypeName(DocumentType.class);
103 try {
104 if ((documentTypeName != null) && getDocumentHelperService().getDocumentAuthorizer(documentTypeName).canInitiate(documentTypeName, GlobalVariables.getUserSession().getPerson())) {
105 qlForm.setCanInitiateDocumentTypeDocument( true );
106 }
107 } catch (Exception ex) {
108 // just skip - and don't display links
109 LOG.error( "Unable to check initiation permission for "+ documentTypeName, ex );
110 }
111
112 return null;
113 }
114
115 public ActionForward addDelegationRule(ActionMapping mapping, ActionForm form, HttpServletRequest request, HttpServletResponse response) throws Exception {
116 ActionForward result = null;
117
118 String ruleTemplateId = request.getParameter("delegationRule.ruleTemplate.id");
119 String docTypeName = request.getParameter("delegationRule.documentType.name");
120 List rules = getRuleService().search(docTypeName, null, ruleTemplateId, "", null, null, Boolean.FALSE, Boolean.TRUE, new HashMap(), null);
121
122 if (rules.size() == 1) {
123 RuleBaseValues rule = (RuleBaseValues)rules.get(0);
124 String url = ConfigContext.getCurrentContextConfig().getKEWBaseURL() +
125 "/DelegateRule.do?methodToCall=start" +
126 "&parentRuleId=" + rule.getId();
127 result = new ActionForward(url, true);
128 } else {
129 makeLookupPathParam(mapping, request);
130 result = new ActionForward(ConfigContext.getCurrentContextConfig().getKRBaseURL() +
131 "/lookup.do?methodToCall=start&"+ stripMethodToCall(request.getQueryString()), true);
132 }
133
134 return result;
135 }
136
137 private List getDocumentTypeDataStructure(List rootDocuments) {
138 List documentTypeQuickLinksStructures = new ArrayList();
139 for (Iterator iter = rootDocuments.iterator(); iter.hasNext();) {
140 DocumentTypeQuickLinksStructure quickLinkStruct =new DocumentTypeQuickLinksStructure((DocumentType) iter.next());
141 if (! quickLinkStruct.getFlattenedNodes().isEmpty() || ! quickLinkStruct.getChildrenDocumentTypes().isEmpty()) {
142 documentTypeQuickLinksStructures.add(quickLinkStruct);
143 }
144
145 }
146
147 return documentTypeQuickLinksStructures;
148 }
149
150
151 /**
152 * A bean to hold a DocumentType with its flattened nodes for rendering purposes
153 * on the quick links.
154 *
155 * @author Kuali Rice Team (rice.collab@kuali.org)
156 */
157 public static class DocumentTypeQuickLinksStructure {
158 private DocumentType documentType;
159 private List<RouteNode> flattenedNodes = new ArrayList<RouteNode>();
160 private List<DocumentTypeQuickLinksStructure> childrenDocumentTypes = new ArrayList<DocumentTypeQuickLinksStructure>();
161 private List<Permission> permissions = null;
162
163 private DocumentTypeQuickLinksStructure(DocumentType documentType) {
164 this.documentType = documentType;
165 if ( documentType != null ) {
166 List<RouteNode> tempFlattenedNodes = KEWServiceLocator.getRouteNodeService()
167 .getFlattenedNodes( documentType, true );
168 for ( RouteNode routeNode : tempFlattenedNodes ) {
169 if ( routeNode.isFlexRM() || routeNode.isRoleNode() ) {
170 flattenedNodes.add( new RouteNodeForDisplay( routeNode ) );
171 }
172 }
173 Collections.sort(flattenedNodes,new Comparator() {
174 public int compare(Object o1, Object o2) {
175 return ( ((RouteNode)o1).getRouteNodeName().compareTo(((RouteNode)o2).getRouteNodeName()));
176 }
177 });
178 for ( Iterator<DocumentType> iter = documentType.getChildrenDocTypes().iterator(); iter.hasNext(); ) {
179 childrenDocumentTypes.add( new DocumentTypeQuickLinksStructure( iter.next() ) );
180 }
181 Collections.sort(childrenDocumentTypes,new Comparator() {
182 public int compare(Object o1, Object o2) {
183 return ( ((DocumentTypeQuickLinksStructure)o1).documentType.getLabel().compareTo(((DocumentTypeQuickLinksStructure)o2).documentType.getLabel()));
184 }
185 });
186 }
187 }
188
189 public List getChildrenDocumentTypes() {
190 return childrenDocumentTypes;
191 }
192 public void setChildrenDocumentTypes(List<DocumentTypeQuickLinksStructure> childrenDocumentTypes) {
193 this.childrenDocumentTypes = childrenDocumentTypes;
194 }
195 public DocumentType getDocumentType() {
196 return documentType;
197 }
198 public void setDocumentType(DocumentType documentType) {
199 this.documentType = documentType;
200 }
201 public List getFlattenedNodes() {
202 return flattenedNodes;
203 }
204 public void setFlattenedNodes(List<RouteNode> flattenedNodes) {
205 this.flattenedNodes = flattenedNodes;
206 }
207 public boolean isShouldDisplay() {
208 // if (flattenedNodes.isEmpty()) {
209 // for (DocumentTypeQuickLinksStructure docType : childrenDocumentTypes) {
210 // if (docType.isShouldDisplay()) {
211 // return true;
212 // }
213 // }
214 // return false;
215 // }
216 return true;
217 }
218
219 public List<Permission> getPermissions() {
220 if ( permissions == null ) {
221 Predicate p = and(
222 equal("attributeName", "documentTypeName"),
223 equal("active", "Y"),
224 equal("detailCriteria",
225 KimConstants.AttributeConstants.DOCUMENT_TYPE_NAME+"="+getDocumentType().getName()));
226 permissions = KimApiServiceLocator.getPermissionService().findPermissions( QueryByCriteria.Builder.fromPredicates(p)).getResults();
227 // sqlLogger.setLevel( Level.INFO );
228 }
229 return permissions;
230 }
231
232 public boolean isHasRelatedPermissions() {
233 return !getPermissions().isEmpty();
234 }
235
236 public int getRelatedPermissionCount() {
237 return getPermissions().size();
238 }
239 }
240
241 public static class RouteNodeForDisplay extends RouteNode {
242 private static final long serialVersionUID = 1L;
243 private RouteNode baseNode;
244
245 public RouteNodeForDisplay( RouteNode baseNode ) {
246 this.baseNode = baseNode;
247 }
248
249 public boolean equals(Object obj) {
250 return this.baseNode.equals(obj);
251 }
252
253 public String getActivationType() {
254 return this.baseNode.getActivationType();
255 }
256
257 public BranchPrototype getBranch() {
258 return this.baseNode.getBranch();
259 }
260
261 public List<RouteNodeConfigParam> getConfigParams() {
262 return this.baseNode.getConfigParams();
263 }
264
265 public String getContentFragment() {
266 return this.baseNode.getContentFragment();
267 }
268
269 public DocumentType getDocumentType() {
270 return this.baseNode.getDocumentType();
271 }
272
273 public String getDocumentTypeId() {
274 return this.baseNode.getDocumentTypeId();
275 }
276 public Group getExceptionWorkgroup() {
277 return this.baseNode.getExceptionWorkgroup();
278 }
279 public String getExceptionWorkgroupId() {
280 return this.baseNode.getExceptionWorkgroupId();
281 }
282 public String getExceptionWorkgroupName() {
283 return this.baseNode.getExceptionWorkgroupName();
284 }
285 public Boolean getFinalApprovalInd() {
286 return this.baseNode.getFinalApprovalInd();
287 }
288 public Integer getLockVerNbr() {
289 return this.baseNode.getLockVerNbr();
290 }
291 public Boolean getMandatoryRouteInd() {
292 return this.baseNode.getMandatoryRouteInd();
293 }
294 public List<RouteNode> getNextNodes() {
295 return this.baseNode.getNextNodes();
296 }
297 public String getNodeType() {
298 return this.baseNode.getNodeType();
299 }
300 public List<RouteNode> getPreviousNodes() {
301 return this.baseNode.getPreviousNodes();
302 }
303 public String getRouteMethodCode() {
304 return this.baseNode.getRouteMethodCode();
305 }
306 public String getRouteMethodName() {
307 return this.baseNode.getRouteMethodName();
308 }
309 public String getRouteNodeId() {
310 return this.baseNode.getRouteNodeId();
311 }
312 public String getRouteNodeName() {
313 return this.baseNode.getRouteNodeName();
314 }
315 public RuleTemplateBo getRuleTemplate() {
316 return this.baseNode.getRuleTemplate();
317 }
318 public int hashCode() {
319 return this.baseNode.hashCode();
320 }
321 public boolean isExceptionGroupDefined() {
322 return this.baseNode.isExceptionGroupDefined();
323 }
324 public boolean isFlexRM() {
325 return this.baseNode.isFlexRM();
326 }
327 public boolean isRoleNode() {
328 return this.baseNode.isRoleNode();
329 }
330 public String toString() {
331 return this.baseNode.toString();
332 }
333
334 private List<Responsibility> responsibilities = null;
335
336 public List<Responsibility> getResponsibilities() {
337 if ( responsibilities == null ) {
338 QueryByCriteria.Builder builder = QueryByCriteria.Builder.create();
339 Predicate p = and(
340 equal("template.namespaceCode", KRADConstants.KUALI_RICE_WORKFLOW_NAMESPACE),
341 equal("template.name", KewApiConstants.DEFAULT_RESPONSIBILITY_TEMPLATE_NAME),
342 equal("active", "Y"),
343 equal("attributes[documentTypeName]", getDocumentType().getName()),
344 equal("attributes[routeNodeName]", getRouteNodeName())
345 );
346 builder.setPredicates(p);
347 responsibilities = KimApiServiceLocator.getResponsibilityService().findResponsibilities(builder.build()).getResults();
348 }
349 return responsibilities;
350 }
351
352 public int getResponsibilityCount() {
353 return getResponsibilities().size();
354 }
355
356 public boolean isHasResponsibility() {
357 return !getResponsibilities().isEmpty();
358 }
359 }
360
361 private void makeLookupPathParam(ActionMapping mapping, HttpServletRequest request) {
362 String basePath = request.getScheme() + "://" + request.getServerName() + ":" + request.getServerPort() + request.getContextPath() + mapping.getModuleConfig().getPrefix();
363 request.setAttribute("basePath", basePath);
364 }
365
366 private String stripMethodToCall(String queryString) {
367 return queryString.replaceAll("methodToCall=addDelegationRule&", "");
368 }
369
370 private DocumentTypeService getDocumentTypeService() {
371 return KEWServiceLocator.getDocumentTypeService();
372 }
373
374 private RuleServiceInternal getRuleService() {
375 return KEWServiceLocator.getRuleService();
376 }
377
378 public DocumentHelperService getDocumentHelperService() {
379 if(documentHelperService == null){
380 documentHelperService = KNSServiceLocator.getDocumentHelperService();
381 }
382 return documentHelperService;
383 }
384
385 public MaintenanceDocumentDictionaryService getMaintenanceDocumentDictionaryService() {
386 if(maintenanceDocumentDictionaryService == null){
387 maintenanceDocumentDictionaryService = KNSServiceLocator.getMaintenanceDocumentDictionaryService();
388 }
389 return maintenanceDocumentDictionaryService;
390 }
391
392 @Override
393 public ActionForward toggleTab(ActionMapping mapping, ActionForm form,
394 HttpServletRequest request, HttpServletResponse response)
395 throws Exception {
396
397 establishRequiredState(request, form);
398 return super.toggleTab(mapping, form, request, response);
399 }
400
401 }