001: /*
002: * Copyright 2005-2007 The Kuali Foundation.
003: *
004: *
005: * Licensed under the Educational Community License, Version 1.0 (the "License");
006: * you may not use this file except in compliance with the License.
007: * You may obtain a copy of the License at
008: *
009: * http://www.opensource.org/licenses/ecl1.php
010: *
011: * Unless required by applicable law or agreed to in writing, software
012: * distributed under the License is distributed on an "AS IS" BASIS,
013: * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
014: * See the License for the specific language governing permissions and
015: * limitations under the License.
016: */
017: package org.kuali.workflow.role;
018:
019: import java.sql.Timestamp;
020: import java.util.ArrayList;
021: import java.util.Collection;
022: import java.util.HashSet;
023: import java.util.Iterator;
024: import java.util.List;
025: import java.util.Set;
026:
027: import javax.xml.namespace.QName;
028:
029: import org.kuali.bus.services.KSBServiceLocator;
030: import org.kuali.rice.definition.ObjectDefinition;
031: import org.kuali.rice.resourceloader.GlobalResourceLoader;
032: import org.kuali.workflow.role.dao.RoleDAO;
033:
034: import edu.iu.uis.eden.KEWServiceLocator;
035: import edu.iu.uis.eden.actionrequests.ActionRequestValue;
036: import edu.iu.uis.eden.doctype.DocumentType;
037: import edu.iu.uis.eden.engine.RouteContext;
038: import edu.iu.uis.eden.engine.node.RouteNodeInstance;
039: import edu.iu.uis.eden.exception.WorkflowException;
040: import edu.iu.uis.eden.exception.WorkflowRuntimeException;
041: import edu.iu.uis.eden.messaging.KEWXMLService;
042: import edu.iu.uis.eden.messaging.MessageServiceNames;
043: import edu.iu.uis.eden.plugin.attributes.RoleAttribute;
044: import edu.iu.uis.eden.routeheader.DocumentRouteHeaderValue;
045: import edu.iu.uis.eden.routetemplate.FlexRM;
046: import edu.iu.uis.eden.routetemplate.RolePoker;
047: import edu.iu.uis.eden.routetemplate.RuleAttribute;
048: import edu.iu.uis.eden.routetemplate.RuleTemplate;
049: import edu.iu.uis.eden.routetemplate.RuleTemplateAttribute;
050: import edu.iu.uis.eden.util.Utilities;
051:
052: /**
053: *
054: * @author ewestfal
055: */
056: public class RoleServiceImpl implements RoleService {
057:
058: private static final org.apache.log4j.Logger LOG = org.apache.log4j.Logger
059: .getLogger(RoleServiceImpl.class);
060:
061: private RoleDAO dao;
062:
063: public QualifiedRole findQualifiedRoleById(Long qualifiedRoleId) {
064: return dao.findQualifiedRoleById(qualifiedRoleId);
065: }
066:
067: public Role findRoleById(Long roleId) {
068: return dao.findRoleById(roleId);
069: }
070:
071: public Role findRoleByName(String roleName) {
072: return dao.findRoleByName(roleName);
073: }
074:
075: public List<QualifiedRole> findQualifiedRolesForRole(
076: String roleName, Timestamp effectiveDate) {
077: Collection qualifiedRoles = dao
078: .findQualifiedRolesForRole(roleName);
079: List<QualifiedRole> filteredQualifiedRoles = new ArrayList<QualifiedRole>(
080: qualifiedRoles.size());
081: if (effectiveDate != null) {
082: for (Iterator iterator = qualifiedRoles.iterator(); iterator
083: .hasNext();) {
084: QualifiedRole qualifiedRole = (QualifiedRole) iterator
085: .next();
086: boolean withinEffectiveDate = false;
087: // TODO this logic is crazy, there's got to be an easier way to do this
088: if (qualifiedRole.getActivationDate() == null
089: || qualifiedRole.getActivationDate().compareTo(
090: effectiveDate) <= 0) {
091: withinEffectiveDate = true;
092: }
093: if (qualifiedRole.getDeactivationDate() == null
094: || qualifiedRole.getDeactivationDate()
095: .compareTo(effectiveDate) >= 0) {
096: withinEffectiveDate = withinEffectiveDate && true;
097: } else {
098: withinEffectiveDate = false;
099: }
100: if (withinEffectiveDate) {
101: filteredQualifiedRoles.add(qualifiedRole);
102: }
103: }
104: } else {
105: filteredQualifiedRoles.addAll(qualifiedRoles);
106: }
107: return filteredQualifiedRoles;
108: }
109:
110: public void save(Role role) {
111: dao.save(role);
112: }
113:
114: public void save(QualifiedRole qualifiedRole) {
115: dao.save(qualifiedRole);
116: updateResponsibilityIds(qualifiedRole);
117: }
118:
119: protected void updateResponsibilityIds(QualifiedRole qualifiedRole) {
120: boolean updated = false;
121: for (QualifiedRoleMember member : qualifiedRole.getMembers()) {
122: if (member.getResponsibilityId() == null) {
123: member.setResponsibilityId(member
124: .getQualifiedRoleMemberId());
125: updated = true;
126: }
127: }
128: if (updated) {
129: dao.save(qualifiedRole);
130: }
131: }
132:
133: public void reResolveRole(DocumentType documentType, String roleName)
134: throws WorkflowException {
135: String infoString = "documentType="
136: + (documentType == null ? null : documentType.getName())
137: + ", role=" + roleName;
138: if (documentType == null || Utilities.isEmpty(roleName)) {
139: throw new IllegalArgumentException(
140: "Cannot pass null or empty arguments to reResolveRole: "
141: + infoString);
142: }
143: LOG.debug("Re-resolving role asynchronously for " + infoString);
144: Set routeHeaderIds = new HashSet();
145: findAffectedDocuments(documentType, roleName, null,
146: routeHeaderIds);
147: LOG
148: .debug(routeHeaderIds.size()
149: + " documents were affected by this re-resolution, requeueing with the RolePokerProcessor");
150: for (Iterator iterator = routeHeaderIds.iterator(); iterator
151: .hasNext();) {
152: Long documentId = (Long) iterator.next();
153: QName rolePokerName = new QName(documentType
154: .getMessageEntity(), MessageServiceNames.ROLE_POKER);
155: RolePoker rolePoker = (RolePoker) KSBServiceLocator
156: .getMessageHelper().getServiceAsynchronously(
157: rolePokerName);
158: rolePoker.reResolveRole(documentId, roleName);
159:
160: // String parameters = generateProcessorParameters(roleName, null);
161: // SpringServiceLocator.getRouteQueueService().requeueDocument(routeHeaderId, EdenConstants.ROUTE_QUEUE_RERESOLVE_PRIORITY, new Long(0), RolePokerProcessor.class.getName(), parameters);
162: }
163: }
164:
165: public void reResolveQualifiedRole(DocumentType documentType,
166: String roleName, String qualifiedRoleNameLabel)
167: throws WorkflowException {
168: String infoString = "documentType="
169: + (documentType == null ? null : documentType.getName())
170: + ", role=" + roleName + ", qualifiedRole="
171: + qualifiedRoleNameLabel;
172: if (documentType == null || Utilities.isEmpty(roleName)
173: || Utilities.isEmpty(qualifiedRoleNameLabel)) {
174: throw new IllegalArgumentException(
175: "Cannot pass null or empty arguments to reResolveQualifiedRole: "
176: + infoString);
177: }
178: LOG.debug("Re-resolving qualified role asynchronously for "
179: + infoString);
180: Set routeHeaderIds = new HashSet();
181: findAffectedDocuments(documentType, roleName,
182: qualifiedRoleNameLabel, routeHeaderIds);
183: LOG
184: .debug(routeHeaderIds.size()
185: + " documents were affected by this re-resolution, requeueing with the RolePokerProcessor");
186: for (Iterator iterator = routeHeaderIds.iterator(); iterator
187: .hasNext();) {
188: Long documentId = (Long) iterator.next();
189:
190: QName rolePokerName = new QName(documentType
191: .getMessageEntity(), MessageServiceNames.ROLE_POKER);
192: RolePoker rolePoker = (RolePoker) KSBServiceLocator
193: .getMessageHelper().getServiceAsynchronously(
194: rolePokerName);
195: rolePoker.reResolveRole(documentId, roleName,
196: qualifiedRoleNameLabel);
197: }
198: }
199:
200: /**
201: *
202: * route level and then filters in the approriate ones.
203: */
204: public void reResolveQualifiedRole(
205: DocumentRouteHeaderValue routeHeader, String roleName,
206: String qualifiedRoleNameLabel) throws WorkflowException {
207: String infoString = "routeHeader="
208: + (routeHeader == null ? null : routeHeader
209: .getRouteHeaderId()) + ", role=" + roleName
210: + ", qualifiedRole=" + qualifiedRoleNameLabel;
211: if (routeHeader == null || Utilities.isEmpty(roleName)
212: || Utilities.isEmpty(qualifiedRoleNameLabel)) {
213: throw new IllegalArgumentException(
214: "Cannot pass null arguments to reResolveQualifiedRole: "
215: + infoString);
216: }
217: LOG.debug("Re-resolving qualified role synchronously for "
218: + infoString);
219: List nodeInstances = findNodeInstances(routeHeader, roleName);
220: int requestsGenerated = 0;
221: if (!nodeInstances.isEmpty()) {
222: deletePendingRoleRequests(routeHeader.getRouteHeaderId(),
223: roleName, qualifiedRoleNameLabel);
224: for (Iterator nodeIt = nodeInstances.iterator(); nodeIt
225: .hasNext();) {
226: RouteNodeInstance nodeInstance = (RouteNodeInstance) nodeIt
227: .next();
228: RuleTemplate ruleTemplate = nodeInstance.getRouteNode()
229: .getRuleTemplate();
230: FlexRM flexRM = new FlexRM();
231: RouteContext context = RouteContext
232: .getCurrentRouteContext();
233: context.setDocument(routeHeader);
234: context.setNodeInstance(nodeInstance);
235: try {
236: List actionRequests = flexRM.getActionRequests(
237: routeHeader, ruleTemplate.getName());
238: for (Iterator iterator = actionRequests.iterator(); iterator
239: .hasNext();) {
240: ActionRequestValue actionRequest = (ActionRequestValue) iterator
241: .next();
242: if (roleName
243: .equals(actionRequest.getRoleName())
244: && qualifiedRoleNameLabel
245: .equals(actionRequest
246: .getQualifiedRoleNameLabel())) {
247: actionRequest = KEWServiceLocator
248: .getActionRequestService()
249: .initializeActionRequestGraph(
250: actionRequest, routeHeader,
251: nodeInstance);
252: KEWServiceLocator.getActionRequestService()
253: .saveActionRequest(actionRequest);
254: requestsGenerated++;
255: }
256: }
257: } catch (Exception e) {
258: RouteContext.clearCurrentRouteContext();
259: }
260:
261: }
262: }
263: LOG.debug("Generated " + requestsGenerated
264: + " action requests after re-resolve: " + infoString);
265: requeueDocument(routeHeader);
266: }
267:
268: public void reResolveRole(DocumentRouteHeaderValue routeHeader,
269: String roleName) throws WorkflowException {
270: String infoString = "routeHeader="
271: + (routeHeader == null ? null : routeHeader
272: .getRouteHeaderId()) + ", role=" + roleName;
273: if (routeHeader == null || Utilities.isEmpty(roleName)) {
274: throw new IllegalArgumentException(
275: "Cannot pass null arguments to reResolveRole: "
276: + infoString);
277: }
278: LOG.debug("Re-resolving role synchronously for " + infoString);
279: List nodeInstances = findNodeInstances(routeHeader, roleName);
280: int requestsGenerated = 0;
281: if (!nodeInstances.isEmpty()) {
282: deletePendingRoleRequests(routeHeader.getRouteHeaderId(),
283: roleName, null);
284: for (Iterator nodeIt = nodeInstances.iterator(); nodeIt
285: .hasNext();) {
286: RouteNodeInstance nodeInstance = (RouteNodeInstance) nodeIt
287: .next();
288: RuleTemplate ruleTemplate = nodeInstance.getRouteNode()
289: .getRuleTemplate();
290: FlexRM flexRM = new FlexRM();
291: RouteContext context = RouteContext
292: .getCurrentRouteContext();
293: context.setDocument(routeHeader);
294: context.setNodeInstance(nodeInstance);
295: try {
296: List actionRequests = flexRM.getActionRequests(
297: routeHeader, ruleTemplate.getName());
298: for (Iterator iterator = actionRequests.iterator(); iterator
299: .hasNext();) {
300: ActionRequestValue actionRequest = (ActionRequestValue) iterator
301: .next();
302: if (roleName
303: .equals(actionRequest.getRoleName())) {
304: actionRequest = KEWServiceLocator
305: .getActionRequestService()
306: .initializeActionRequestGraph(
307: actionRequest, routeHeader,
308: nodeInstance);
309: KEWServiceLocator.getActionRequestService()
310: .saveActionRequest(actionRequest);
311: requestsGenerated++;
312: }
313: }
314: } finally {
315: RouteContext.clearCurrentRouteContext();
316: }
317: }
318: }
319: LOG.debug("Generated " + requestsGenerated
320: + " action requests after re-resolve: " + infoString);
321: requeueDocument(routeHeader);
322: }
323:
324: // search the document type and all its children
325: private void findAffectedDocuments(DocumentType documentType,
326: String roleName, String qualifiedRoleNameLabel,
327: Set routeHeaderIds) {
328: List pendingRequests = KEWServiceLocator
329: .getActionRequestService()
330: .findPendingRootRequestsByDocumentType(
331: documentType.getDocumentTypeId());
332: for (Iterator iterator = pendingRequests.iterator(); iterator
333: .hasNext();) {
334: ActionRequestValue actionRequest = (ActionRequestValue) iterator
335: .next();
336: if (roleName.equals(actionRequest.getRoleName())
337: && (qualifiedRoleNameLabel == null || qualifiedRoleNameLabel
338: .equals(actionRequest
339: .getQualifiedRoleNameLabel()))) {
340: routeHeaderIds.add(actionRequest.getRouteHeaderId());
341: }
342: }
343: for (Iterator iterator = documentType.getChildrenDocTypes()
344: .iterator(); iterator.hasNext();) {
345: DocumentType childDocumentType = (DocumentType) iterator
346: .next();
347: findAffectedDocuments(childDocumentType, roleName,
348: qualifiedRoleNameLabel, routeHeaderIds);
349: }
350: }
351:
352: private void deletePendingRoleRequests(Long routeHeaderId,
353: String roleName, String qualifiedRoleNameLabel) {
354: List pendingRequests = KEWServiceLocator
355: .getActionRequestService().findPendingByDoc(
356: routeHeaderId);
357: pendingRequests = KEWServiceLocator.getActionRequestService()
358: .getRootRequests(pendingRequests);
359: List requestsToDelete = new ArrayList();
360: for (Iterator iterator = pendingRequests.iterator(); iterator
361: .hasNext();) {
362: ActionRequestValue actionRequest = (ActionRequestValue) iterator
363: .next();
364: if (roleName.equals(actionRequest.getRoleName())
365: && (qualifiedRoleNameLabel == null || qualifiedRoleNameLabel
366: .equals(actionRequest
367: .getQualifiedRoleNameLabel()))) {
368: requestsToDelete.add(actionRequest);
369: }
370: }
371: LOG.debug("Deleting " + requestsToDelete.size()
372: + " action requests for roleName=" + roleName
373: + ", qualifiedRoleNameLabel=" + qualifiedRoleNameLabel);
374: for (Iterator iterator = requestsToDelete.iterator(); iterator
375: .hasNext();) {
376: KEWServiceLocator.getActionRequestService()
377: .deleteActionRequestGraph(
378: (ActionRequestValue) iterator.next());
379: }
380: }
381:
382: private List findNodeInstances(
383: DocumentRouteHeaderValue routeHeader, String roleName)
384: throws WorkflowException {
385: List nodeInstances = new ArrayList();
386: Collection activeNodeInstances = KEWServiceLocator
387: .getRouteNodeService().getActiveNodeInstances(
388: routeHeader.getRouteHeaderId());
389: if (Utilities.isEmpty(activeNodeInstances)) {
390: throw new WorkflowException(
391: "Document does not currently have any active nodes so re-resolving is not legal.");
392: }
393: for (Iterator iterator = activeNodeInstances.iterator(); iterator
394: .hasNext();) {
395: RouteNodeInstance activeNodeInstance = (RouteNodeInstance) iterator
396: .next();
397: RuleTemplate template = activeNodeInstance.getRouteNode()
398: .getRuleTemplate();
399: if (templateHasRole(template, roleName)) {
400: nodeInstances.add(activeNodeInstance);
401: }
402: }
403: if (nodeInstances.isEmpty()) {
404: throw new WorkflowException(
405: "Could not locate given role to re-resolve: "
406: + roleName);
407: }
408: return nodeInstances;
409: }
410:
411: private boolean templateHasRole(RuleTemplate template,
412: String roleName) throws WorkflowException {
413: List templateAttributes = template.getRuleTemplateAttributes();
414: for (Iterator iterator = templateAttributes.iterator(); iterator
415: .hasNext();) {
416: RuleTemplateAttribute templateAttribute = (RuleTemplateAttribute) iterator
417: .next();
418: RuleAttribute ruleAttribute = templateAttribute
419: .getRuleAttribute();
420: Object workflowAttribute = GlobalResourceLoader
421: .getResourceLoader().getObject(
422: new ObjectDefinition(ruleAttribute
423: .getClassName()));//SpringServiceLocator.getExtensionService().getWorkflowAttribute(ruleAttribute.getClassName());
424: if (workflowAttribute instanceof RoleAttribute) {
425: List roleNames = ((RoleAttribute) workflowAttribute)
426: .getRoleNames();
427: for (Iterator roleIt = roleNames.iterator(); roleIt
428: .hasNext();) {
429: edu.iu.uis.eden.routetemplate.Role role = (edu.iu.uis.eden.routetemplate.Role) roleIt
430: .next();
431: if (role.getLabel().equals(roleName)) {
432: return true;
433: }
434: }
435: }
436: }
437: return false;
438: }
439:
440: protected void requeueDocument(DocumentRouteHeaderValue document) {
441: QName documentServiceName = new QName(document
442: .getDocumentType().getMessageEntity(),
443: MessageServiceNames.DOCUMENT_ROUTING_SERVICE);
444: KEWXMLService documentRoutingService = (KEWXMLService) MessageServiceNames
445: .getServiceAsynchronously(documentServiceName, document);
446: try {
447: documentRoutingService.invoke(String.valueOf(document
448: .getRouteHeaderId()));
449: } catch (Exception e) {
450: throw new WorkflowRuntimeException(e);
451: }
452: }
453:
454: public void setRoleDAO(RoleDAO dao) {
455: this.dao = dao;
456: }
457:
458: }
|