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.HashMap;
053 import java.util.Iterator;
054 import java.util.List;
055
056 import static org.kuali.rice.core.api.criteria.PredicateFactory.and;
057 import static org.kuali.rice.core.api.criteria.PredicateFactory.equal;
058
059
060 /**
061 * A Struts Action for building and interacting with the Rule Quick Links.
062 *
063 * @author Kuali Rice Team (rice.collab@kuali.org)
064 */
065 public class RuleQuickLinksAction extends KewKualiAction {
066
067 private static final Logger LOG = Logger.getLogger(RuleQuickLinksAction.class);
068
069 private MaintenanceDocumentDictionaryService maintenanceDocumentDictionaryService;
070 private DocumentHelperService documentHelperService;
071
072 public ActionForward start(ActionMapping mapping, ActionForm form, HttpServletRequest request, HttpServletResponse response) throws Exception {
073 makeLookupPathParam(mapping, request);
074 establishRequiredState(request, form);
075 return mapping.findForward("basic");
076 }
077
078 @SuppressWarnings("unchecked")
079 public ActionMessages establishRequiredState(HttpServletRequest request, ActionForm form) throws Exception {
080 RuleQuickLinksForm qlForm = (RuleQuickLinksForm) form;
081 List<DocumentType> documentTypes;
082 if (qlForm.getRootDocTypeName() != null) {
083 documentTypes = new ArrayList<DocumentType>();
084 DocumentType docType = getDocumentTypeService().findByName(qlForm.getRootDocTypeName());
085 documentTypes.add(docType);
086 request.setAttribute("renderOpened", Boolean.TRUE);
087 } else {
088 documentTypes = getDocumentTypeService().findAllCurrentRootDocuments();
089 }
090 qlForm.setDocumentTypeQuickLinksStructures(getDocumentTypeDataStructure(documentTypes));
091 int shouldDisplayCount = 0;
092 for ( DocumentTypeQuickLinksStructure dt : qlForm.getDocumentTypeQuickLinksStructures() ) {
093 if ( dt.isShouldDisplay() ) {
094 shouldDisplayCount++;
095 }
096 }
097 if ( shouldDisplayCount == 1 ) {
098 request.setAttribute("renderOpened", Boolean.TRUE);
099 }
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 }