001: /*
002: * Copyright 2005-2006 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 edu.iu.uis.eden.actions;
018:
019: import java.util.List;
020:
021: import javax.xml.namespace.QName;
022:
023: import edu.iu.uis.eden.DocumentRouteStatusChange;
024: import edu.iu.uis.eden.KEWServiceLocator;
025: import edu.iu.uis.eden.actionrequests.ActionRequestService;
026: import edu.iu.uis.eden.actiontaken.ActionTakenService;
027: import edu.iu.uis.eden.actiontaken.ActionTakenValue;
028: import edu.iu.uis.eden.docsearch.SearchableAttributeProcessingService;
029: import edu.iu.uis.eden.doctype.DocumentTypeService;
030: import edu.iu.uis.eden.exception.EdenUserNotFoundException;
031: import edu.iu.uis.eden.exception.InvalidActionTakenException;
032: import edu.iu.uis.eden.exception.WorkflowRuntimeException;
033: import edu.iu.uis.eden.messaging.KEWXMLService;
034: import edu.iu.uis.eden.messaging.MessageQueueService;
035: import edu.iu.uis.eden.messaging.MessageServiceNames;
036: import edu.iu.uis.eden.postprocessor.PostProcessor;
037: import edu.iu.uis.eden.postprocessor.ProcessDocReport;
038: import edu.iu.uis.eden.routeheader.DocumentRouteHeaderValue;
039: import edu.iu.uis.eden.routeheader.RouteHeaderService;
040: import edu.iu.uis.eden.user.Recipient;
041: import edu.iu.uis.eden.user.WorkflowUser;
042: import edu.iu.uis.eden.util.Utilities;
043: import edu.iu.uis.eden.workgroup.Workgroup;
044: import edu.iu.uis.eden.workgroup.WorkgroupService;
045:
046: /**
047: * Super class containing mostly often used methods by all actions. Holds common
048: * state as well, {@link DocumentRouteHeaderValue} document,
049: * {@link ActionTakenValue} action taken (once saved), {@link WorkflowUser} user
050: * that has taken the action
051: *
052: * @author rkirkend
053: * @author ewestfal
054: */
055: public abstract class ActionTakenEvent {
056:
057: private static final org.apache.log4j.Logger LOG = org.apache.log4j.Logger
058: .getLogger(ActionTakenEvent.class);
059:
060: private String actionTakenCode;
061:
062: protected String annotation;
063:
064: protected ActionTakenValue actionTaken;
065:
066: protected DocumentRouteHeaderValue routeHeader;
067:
068: protected Long routeHeaderId;
069:
070: protected Boolean currentInd = new Boolean(true);
071:
072: private WorkflowUser user;
073:
074: public ActionTakenEvent(DocumentRouteHeaderValue routeHeader,
075: WorkflowUser user) {
076: this .routeHeader = routeHeader;
077: this .user = user;
078: this .routeHeaderId = routeHeader.getRouteHeaderId();
079: }
080:
081: public ActionTakenEvent(DocumentRouteHeaderValue routeHeader,
082: WorkflowUser user, String annotation) {
083: this .routeHeader = routeHeader;
084: this .user = user;
085: this .annotation = annotation;
086: this .routeHeaderId = routeHeader.getRouteHeaderId();
087: }
088:
089: public ActionRequestService getActionRequestService() {
090: return (ActionRequestService) KEWServiceLocator
091: .getService(KEWServiceLocator.ACTION_REQUEST_SRV);
092: }
093:
094: public DocumentRouteHeaderValue getRouteHeader() {
095: return routeHeader;
096: }
097:
098: public void setRouteHeader(DocumentRouteHeaderValue routeHeader) {
099: this .routeHeader = routeHeader;
100: }
101:
102: public WorkflowUser getUser() {
103: return user;
104: }
105:
106: /**
107: * Code of the action performed by the user
108: *
109: * Method may be overriden is action performed will be different than action
110: * taken
111: */
112: public String getActionPerformedCode() {
113: return getActionTakenCode();
114: }
115:
116: /**
117: * Validates whether or not this action is valid for the given WorkflowUser
118: * and DocumentRouteHeaderValue.
119: */
120: public boolean isActionValid() throws EdenUserNotFoundException {
121: return Utilities.isEmpty(validateActionRules());
122: }
123:
124: /**
125: * Placeholder for validation rules for each action
126: *
127: * @return error message string of specific error message
128: * @throws EdenUserNotFoundException
129: */
130: public abstract String validateActionRules()
131: throws EdenUserNotFoundException;
132:
133: /**
134: * Method to indicate that this action may require initiator execution only
135: *
136: * @return false if action can be performed by users outside the initiator
137: */
138: protected boolean requireInitiatorCheck() {
139: LOG
140: .debug("requireInitiatorCheck() Default method = returning true");
141: return true;
142: }
143:
144: protected boolean isActionCompatibleRequest(List requests)
145: throws EdenUserNotFoundException {
146: LOG
147: .debug("isActionCompatibleRequest() Default method = returning true");
148: return true;
149: }
150:
151: protected String validateActionTakenRules() {
152: if (requireInitiatorCheck()
153: && (!user.getWorkflowUserId().getWorkflowId().equals(
154: routeHeader.getInitiatorWorkflowId()) && (routeHeader
155: .isStateSaved() || routeHeader
156: .isStateInitiated()))) {
157: return "Only the initiator can take action on an initiated or saved document of this type";
158: }
159: return "";
160: }
161:
162: public abstract void recordAction()
163: throws InvalidActionTakenException,
164: EdenUserNotFoundException;
165:
166: public void checkLocking() throws InvalidActionTakenException {
167: if (routeHeader.isLocked()) {
168: throw new InvalidActionTakenException("The document "
169: + routeHeader.getRouteHeaderId()
170: + " is locked. Action cannot be taken.");
171: }
172: }
173:
174: public void updateSearchableAttributesIfPossible() {
175: // queue the document up so that it can be indexed for searching if it
176: // has searchable attributes
177: if (routeHeader.getDocumentType().hasSearchableAttributes()) {
178: SearchableAttributeProcessingService searchableAttService = (SearchableAttributeProcessingService) MessageServiceNames
179: .getSearchableAttributeService(routeHeader);
180: searchableAttService.indexDocument(routeHeaderId);
181: }
182: }
183:
184: protected void notifyActionTaken(ActionTakenValue actionTaken) {
185: if (actionTaken == null) {
186: return;
187: }
188: try {
189: LOG.debug("Notifying post processor of action taken");
190: PostProcessor postProcessor = routeHeader.getDocumentType()
191: .getPostProcessor();
192: ProcessDocReport report = postProcessor
193: .doActionTaken(new edu.iu.uis.eden.ActionTakenEvent(
194: routeHeader.getRouteHeaderId(), routeHeader
195: .getAppDocId(), actionTaken));
196: if (!report.isSuccess()) {
197: LOG.warn(report.getMessage(), report
198: .getProcessException());
199: throw new InvalidActionTakenException(report
200: .getMessage());
201: }
202: } catch (Exception ex) {
203: LOG.warn(ex, ex);
204: throw new WorkflowRuntimeException(ex.getMessage());
205: }
206: }
207:
208: protected void notifyStatusChange(String newStatusCode,
209: String oldStatusCode) throws InvalidActionTakenException {
210: DocumentRouteStatusChange statusChangeEvent = new DocumentRouteStatusChange(
211: routeHeader.getRouteHeaderId(), routeHeader
212: .getAppDocId(), oldStatusCode, newStatusCode);
213: try {
214: LOG.debug("Notifying post processor of status change "
215: + oldStatusCode + "->" + newStatusCode);
216: PostProcessor postProcessor = routeHeader.getDocumentType()
217: .getPostProcessor();
218: ProcessDocReport report = postProcessor
219: .doRouteStatusChange(statusChangeEvent);
220: if (!report.isSuccess()) {
221: LOG.warn(report.getMessage(), report
222: .getProcessException());
223: throw new InvalidActionTakenException(report
224: .getMessage());
225: }
226: } catch (Exception ex) {
227: throw new WorkflowRuntimeException(ex);
228: }
229: }
230:
231: public void queueDocument() {
232: QName documentServiceName = new QName(getRouteHeader()
233: .getDocumentType().getMessageEntity(),
234: MessageServiceNames.DOCUMENT_ROUTING_SERVICE);
235: KEWXMLService documentRoutingService = (KEWXMLService) MessageServiceNames
236: .getServiceAsynchronously(documentServiceName,
237: getRouteHeader());
238: try {
239: documentRoutingService.invoke(String
240: .valueOf(getRouteHeaderId()));
241: } catch (Exception e) {
242: throw new WorkflowRuntimeException(e);
243: }
244: }
245:
246: protected ActionTakenValue saveActionTaken() {
247: return saveActionTaken(null);
248: }
249:
250: protected ActionTakenValue saveActionTaken(Recipient delegator) {
251: ActionTakenValue val = new ActionTakenValue();
252: val.setActionTaken(actionTakenCode);
253: val.setAnnotation(annotation);
254: val.setDocVersion(routeHeader.getDocVersion());
255: val.setRouteHeaderId(routeHeaderId);
256: val.setWorkflowId(user.getWorkflowUserId().getWorkflowId());
257: if (delegator instanceof WorkflowUser) {
258: val.setDelegatorWorkflowId(((WorkflowUser) delegator)
259: .getWorkflowUserId().getWorkflowId());
260: } else if (delegator instanceof Workgroup) {
261: val.setDelegatorWorkgroupId(((Workgroup) delegator)
262: .getWorkflowGroupId().getGroupId());
263: }
264: val.setRouteHeader(routeHeader);
265: val.setCurrentIndicator(currentInd);
266: getActionTakenService().saveActionTaken(val);
267: this .actionTaken = val;
268: // notifyActionTaken(this.actionTaken);
269: return val;
270: }
271:
272: /**
273: * Returns the highest priority delegator in the list of action requests.
274: */
275: protected Recipient findDelegatorForActionRequests(
276: List actionRequests) throws EdenUserNotFoundException {
277: return getActionRequestService().findDelegator(actionRequests);
278: }
279:
280: public void setUser(WorkflowUser user) {
281: this .user = user;
282: }
283:
284: public String getActionTakenCode() {
285: return actionTakenCode;
286: }
287:
288: public void setActionTakenCode(String string) {
289: actionTakenCode = string;
290: }
291:
292: public Long getRouteHeaderId() {
293: return this .routeHeader.getRouteHeaderId();
294: }
295:
296: public Long getActionTakenId() {
297: return actionTaken.getActionTakenId();
298: }
299:
300: public ActionTakenValue getActionTaken() {
301: return actionTaken;
302: }
303:
304: public void delete() {
305: getActionTakenService().delete(actionTaken);
306: }
307:
308: public ActionTakenService getActionTakenService() {
309: return (ActionTakenService) KEWServiceLocator
310: .getService(KEWServiceLocator.ACTION_TAKEN_SRV);
311: }
312:
313: public DocumentTypeService getDocumentTypeService() {
314: return (DocumentTypeService) KEWServiceLocator
315: .getService(KEWServiceLocator.DOCUMENT_TYPE_SERVICE);
316: }
317:
318: public MessageQueueService getRouteQueueService() {
319: return (MessageQueueService) KEWServiceLocator
320: .getService(KEWServiceLocator.ROUTE_QUEUE_SRV);
321: }
322:
323: public RouteHeaderService getRouteHeaderService() {
324: return (RouteHeaderService) KEWServiceLocator
325: .getService(KEWServiceLocator.DOC_ROUTE_HEADER_SRV);
326: }
327:
328: public WorkgroupService getWorkgroupService() {
329: return (WorkgroupService) KEWServiceLocator
330: .getService(KEWServiceLocator.WORKGROUP_SRV);
331: }
332:
333: public Boolean getCurrentInd() {
334: return currentInd;
335: }
336:
337: public void setCurrentInd(Boolean currentInd) {
338: this.currentInd = currentInd;
339: }
340: }
|