/*
* This file is part of the WfMOpen project.
* Copyright (C) 2001-2003 Danet GmbH (www.danet.de), GS-AN.
* All rights reserved.
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*
* $Id: DefaultAuditEvent.java 1607 2006-09-29 12:32:13Z drmlipp $
*
* $Log$
* Revision 1.4 2006/09/06 09:30:25 drmlipp
* Further improved serialization.
*
* Revision 1.3 2006/09/05 15:55:25 drmlipp
* Added deferred deserialization of source as a workaround for a
* classloader problem.
*
* Revision 1.2 2005/04/22 15:11:02 drmlipp
* Merged changes from 1.3 branch up to 1.3p15.
*
* Revision 1.1.1.2.6.2 2005/04/18 11:11:21 drmlipp
* More event handling optimization.
*
* Revision 1.1.1.2.6.1 2005/04/16 21:18:30 drmlipp
* Made audit event filtering more flexible and added possibility to turn
* off audit log.
*
* Revision 1.1.1.2 2004/08/18 15:17:38 drmlipp
* Update to 1.2
*
* Revision 1.18 2004/07/04 17:34:19 lipp
* Fixed problem with event source.
*
* Revision 1.17 2003/06/27 08:51:45 lipp
* Fixed copyright/license information.
*
* Revision 1.16 2003/05/28 15:11:03 lipp
* Updated toString.
*
* Revision 1.15 2003/05/07 10:46:06 lipp
* Renamed some classes/methods to imply both tool and sub-process
* implementations.
*
* Revision 1.14 2003/04/26 16:11:15 lipp
* Moved some classes to reduce package dependencies.
*
* Revision 1.13 2003/03/31 16:50:28 huaiyang
* Logging using common-logging.
*
* Revision 1.12 2003/02/11 08:49:55 lipp
* Shortened toString repr.
*
* Revision 1.11 2003/02/06 16:39:51 lipp
* Fixed a state handling bug (must not expose running state for manually
* started activity).
*
* Revision 1.10 2002/10/22 15:48:21 lipp
* Keep audit event base information as local info to avoid unnecessary
* container() calls.
*
* Revision 1.9 2002/10/16 08:40:19 barzik
* new constructors to allow recreation by history
*
* Revision 1.8 2002/10/07 12:04:38 barzik
* toString now displays the event type, too.
*
* Revision 1.7 2002/10/03 19:01:00 lipp
* New constructor.
*
* Revision 1.6 2002/10/02 20:54:40 lipp
* Event handling partially reorganized.
*
* Revision 1.5 2002/10/02 15:07:43 lipp
* Support eventType null.
*
* Revision 1.4 2002/10/02 11:27:07 barzik
* bug fixes and more ...
*
* Revision 1.3 2002/10/01 16:06:00 lipp
* Event queue activated.
*
* Revision 1.2 2002/10/01 11:03:14 barzik
* add toString()
*
* Revision 1.1 2002/10/01 09:10:38 lipp
* AuditEvent handling restructured.
*
* Revision 1.9 2002/10/01 06:45:23 barzik
* no message
*
* Revision 1.8 2002/09/30 15:04:46 lipp
* Added implements Serializable.
*
* Revision 1.7 2002/09/30 12:42:05 barzik
* audit event handling using base event information
*
* Revision 1.6 2002/09/26 09:53:00 huaiyang
* In readresolve method use text representation to compare.
*
* Revision 1.5 2002/09/26 08:02:31 barzik
* Moved EventType to WfAuditEvent.java
*
* Revision 1.4 2002/09/24 12:23:36 barzik
* Extended ...
*
* Revision 1.3 2002/07/24 08:04:42 huaiyang
* doccheck.
*
* Revision 1.2 2001/08/24 12:58:30 lipp
* CR/NL fixes
*
* Revision 1.1 2001/07/06 08:51:48 lipp
* Moved from domain to omgcore
*
* Revision 1.1 2001/07/05 14:15:09 lipp
* Rather complete version.
*
*/
package de.danet.an.workflow.domain;
import java.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.io.ObjectInputStream;
import java.io.ObjectOutputStream;
import java.io.Serializable;
import java.util.Date;
import java.util.EventObject;
import de.danet.an.workflow.omgcore.SourceNotAvailableException;
import de.danet.an.workflow.omgcore.WfActivity;
import de.danet.an.workflow.omgcore.WfAuditEvent;
import de.danet.an.workflow.omgcore.WfExecutionObject;
import de.danet.an.workflow.omgcore.WfProcess;
import de.danet.an.workflow.api.ProcessDefinition;
/**
* <P>A <code>DefaultAuditEvent</code> implements an audit record of
* workflow event information.</P>
*
* <P>It provides information on the source of the event and contains
* specific event data. Workflow events include state changes, change
* of a resource assignment, and data changes. Workflow events are
* persistent and can be accessed navigating the history relationship
* of a <code>WfExecutionObject</code>.</P>
*
* <P>Workflow audit event objects are not part of the persistent state of
* their source workflow object.</P>
*/
public class DefaultAuditEvent extends EventObject
implements WfAuditEvent, Serializable {
private static final org.apache.commons.logging.Log logger
= org.apache.commons.logging.LogFactory.getLog
(DefaultAuditEvent.class);
private byte[] marshalledSource = null;
/**
* The attribute <code>timeStamp</code>. It identifies
* the timestamp as supplied at trigger time of the event.
*/
private Date timeStamp = null;
/**
* The attribute <code>eventType</code>. It identifies
* the type of the event. The type is supplied either
* implicit in case of a unique definition or must be supplied at trigger
* time.
*/
private String eventType = null;
/**
* The attribute <code>activityKey</code>. It identifies
* the activity associated with the event.
*/
private String activityKey = null;
/**
* The attribute <code>processKey</code>. It identifies
* the name of the activity associated with the event.
* If the event is associated to a process, the attribute is expected
* being <code>null</code>.
*/
private String activityName = null;
/**
* The attribute <code><processKey/code>. It identifies
* the process associated with the event.
* If the event is associated to a process, the attribute is expected
* being <code>null</code>.
*/
private String processKey = null;
/**
* The attribute <code>processName</code>. It identifies
* the name of the process associated with the event.
*/
private String processName = null;
/**
* The attribute <code>processMgrName</code>. It identifies
* the name of the process manager associated with the event.
* If the event is associated to a process, this is the manager of the
* process. If the event is associated to an activity, it is the manager
* of the process that contains the activity.
*/
private String processMgrName = null;
/**
* The attribute <code>processMgrVersion</code>. It identifies
* the version of the process manager associated with the event.
* If the event is associated to a process, this is the manager of the
* process. If the event is associated to an activity, it is the manager
* of the process that contains the activity.
*/
private String processMgrVersion = null;
/**
* If <code>true</code> the event will not be processed
* (i.e. fed back to the engine) when retrieved from the event queue.
*/
private boolean skip = false;
/**
* The audit event selection of the event source.
*/
private int auditEventSelection
= ProcessDefinition.AUDIT_SELECTION_ALL_EVENTS;
/**
* If <code>true</code> the event will be stored.
*/
private boolean store = false;
/**
* Create a <code>DefaultAuditEvent</code> related to the given
* <code>WfExecutionObject</code>.
* @param source the related object.
*/
protected DefaultAuditEvent(Object source) {
super ((source == null) ? ((Object)"(no source)") : ((Object)source));
}
/**
* Create a <code>DefaultAuditEvent</code> triggered by a given
* <code>WfExecutionObject</code>.
* @param baseInfo a <code>WfAuditEvent</code> containing further
* information for the event.
*/
protected DefaultAuditEvent(WfAuditEvent baseInfo) {
this (baseInfo, false);
}
/**
* Create a <code>DefaultAuditEvent</code> triggered by a given
* <code>WfExecutionObject</code>.
* @param baseInfo a <code>WfAuditEvent</code> containing further
* information for the event.
* @param skip if <code>true</code> the event will not be processed
* (i.e. fed back to the engine) when retrieved from the event queue.
*/
protected DefaultAuditEvent
(WfAuditEvent baseInfo, boolean skip) {
this(((DefaultAuditEvent)baseInfo).source,
(DefaultAuditEvent)baseInfo);
this.skip = skip;
}
/**
* Create a <code>DefaultAuditEvent</code> with the given
* <code>WfExecutionObject</code> as source and all other
* attributes copied from the given event.
* @param source the value for the source attribute.
* @param baseInfo a <code>WfAuditEvent</code> containing further
* information for the event.
*/
protected DefaultAuditEvent (Object source, DefaultAuditEvent baseInfo) {
this(source);
// assign data not depending on event type
timeStamp = baseInfo.timeStamp;
auditEventSelection = baseInfo.auditEventSelection;
store = baseInfo.store;
skip = baseInfo.skip;
// assign attributes
eventType = baseInfo.eventType;
activityKey = baseInfo.activityKey;
activityName = baseInfo.activityName;
assignProcessRelatedAttributes
(baseInfo.processKey(), baseInfo.processName(),
baseInfo.processMgrName(), baseInfo.processMgrVersion());
}
/**
* Creates a new <code>DefaultAuditEvent</code> containing process-related
* and activity-related information, only.
* @param source the activity which is the originator of the audit event.
* @param eventType the event's type identifier.
* @param actKey the attribute <code>activityKey</code>.
* @param actName the attribute <code>activityName</code>.
* @param processInfo a <code>WfAuditEvent</code> containing
* process-related information about the process that contains the
* activity.
*/
public DefaultAuditEvent(WfActivity source, String eventType,
String actKey, String actName,
WfAuditEvent processInfo) {
this (source, eventType, new Date(), processInfo.processKey(),
processInfo.processName(), processInfo.processMgrName(),
processInfo.processMgrVersion(),
((DefaultAuditEvent)processInfo).auditEventSelection(),
((DefaultAuditEvent)processInfo).store(),
true);
// validate event type
if (eventType != null
&& (!eventType.equals(ACTIVITY_STATE_CHANGED))
&& (!eventType.equals(ACTIVITY_ASSIGNMENT_CHANGED))
&& (!eventType.equals(ACTIVITY_RESULT_CHANGED))
&& (!eventType.equals(ACTIVITY_CONTEXT_CHANGED))
&& (!eventType.equals(ImplCompleteAuditEvent.TOOL_COMPLETE))){
throw new IllegalArgumentException
("Invalid 'eventType' supplied.");
}
// assign attributes
activityKey = actKey;
activityName = actName;
}
/**
* Creates a new <code>DefaultAuditEvent</code> containing process-related
* and activity-related information.
* This descriptor's intention is for re-creation usage, only.
* @param source the activity which is the originator of the audit event.
* @param eventType the event's type identifier.
* @param timestamp the event time.
* @param actKey the attribute <code>activityKey</code>.
* @param actName the attribute <code>activityName</code>.
* @param processKey the attribute <code>processKey</code>.
* @param processName the attribute <code>processName</code>.
* @param processMgrName the attribute <code>processMgrName</code>.
* @param processMgrVersion the attribute <code>processMgrVersion</code>.
* @param auditEventSelection the audit event selection of source
* @param store if <code>true</code> the event will be stored in
* the database
*/
public DefaultAuditEvent
(WfActivity source, String eventType, Date timestamp,
String actKey, String actName,
String processKey, String processName,
String processMgrName, String processMgrVersion,
int auditEventSelection, boolean store) {
this (source, eventType, timestamp, processKey,
processName, processMgrName, processMgrVersion,
auditEventSelection, store, false);
// validate event type
if (eventType != null
&& (!eventType.equals(ACTIVITY_STATE_CHANGED))
&& (!eventType.equals(ACTIVITY_ASSIGNMENT_CHANGED))
&& (!eventType.equals(ACTIVITY_RESULT_CHANGED))
&& (!eventType.equals(ACTIVITY_CONTEXT_CHANGED))
&& (!eventType.equals(ImplCompleteAuditEvent.TOOL_COMPLETE))){
throw new IllegalArgumentException
("Invalid 'eventType' supplied.");
}
// assign attributes
activityKey = actKey;
activityName = actName;
}
/**
* Creates a new <code>DefaultAuditEvent</code> containing process-related
* information, only.
* @param source the process which is the originator of the audit event
* @param eventType the event's type identifier
* @param processKey the attribute <code>processKey</code>.
* @param processName the attribute <code>processName</code>.
* @param processMgrName the attribute <code>processMgrName</code>.
* @param processMgrVersion the attribute <code>processMgrVersion</code>.
* @param auditEventSelection the audit event selection of source
* @param store if <code>true</code> the event will be stored in
* the database
*/
public DefaultAuditEvent (WfProcess source, String eventType,
String processKey, String processName,
String processMgrName, String processMgrVersion,
int auditEventSelection, boolean store) {
this(source, eventType, new Date(), processKey, processName,
processMgrName, processMgrVersion, auditEventSelection, store);
}
/**
* Creates a new <code>DefaultAuditEvent</code> containing process-related
* information, only.
* @param source the process which is the originator of the audit event
* @param eventType the event's type identifier
* @param timestamp the event's timestamp
* @param processKey the attribute <code>processKey</code>.
* @param processName the attribute <code>processName</code>.
* @param processMgrName the attribute <code>processMgrName</code>.
* @param processMgrVersion the attribute <code>processMgrVersion</code>.
* @param auditEventSelection the audit event selection of source
* @param store if <code>true</code> the event will be stored in
* the database
*/
public DefaultAuditEvent (WfProcess source, String eventType,
Date timestamp,
String processKey, String processName,
String processMgrName, String processMgrVersion,
int auditEventSelection, boolean store) {
this(source, eventType, timestamp, processKey, processName,
processMgrName, processMgrVersion, auditEventSelection, store,
false);
// validate event type
if (eventType != null
&& (!eventType.equals(PROCESS_STATE_CHANGED))
&& (!eventType.equals(PROCESS_CREATED))
&& (!eventType.equals(PROCESS_CONTEXT_CHANGED))){
throw new IllegalArgumentException
("Invalid 'eventType' supplied.");
}
}
/**
* Create a <code>DefaultAuditEvent</code> triggered by a given
* <code>WfExecutionObject</code>.
* @param source the process which is the originator of the audit event
* @param et the event's type identifier
* @param ts the event's timestamp
* @param processKey the attribute <code>processKey</code>.
* @param processName the attribute <code>processName</code>.
* @param processMgrName the attribute <code>processMgrName</code>.
* @param processMgrVersion the attribute <code>processMgrVersion</code>.
* @param auditEventSelection the audit event selection of source
* @param store if <code>true</code> the event will be stored in
* the database
* @param verifySource if <code>true</code> <code>source</code> may not be
* <code>null</code>.
*/
private DefaultAuditEvent
(WfExecutionObject source, String et, Date ts, String processKey,
String processName, String processMgrName, String processMgrVersion,
int auditEventSelection, boolean store, boolean verifySource) {
this(source);
// check mandatory parameters
if (verifySource && source == null){
throw new IllegalArgumentException
("The argument 'source' MUST be supplied.");
}
// assign data not depending on event type
timeStamp = ts;
// assign attributes
eventType = et;
assignProcessRelatedAttributes
(processKey, processName, processMgrName, processMgrVersion);
this.auditEventSelection = auditEventSelection;
this.store = store;
}
private void writeObject(ObjectOutputStream stream)
throws IOException {
// "source" is transient. So we have to save it explicitly.
// The additional wrapper for deferred deserialization is a
// workaround for a classloader problem.
if (source != null) {
ByteArrayOutputStream bos = new ByteArrayOutputStream();
ObjectOutputStream oos = new ObjectOutputStream(bos);
oos.writeObject(source);
marshalledSource = bos.toByteArray();
}
stream.defaultWriteObject();
}
private void readObject(ObjectInputStream stream)
throws IOException, ClassNotFoundException {
stream.defaultReadObject();
}
/**
* Override <code>getSource</code> to do deferred unmarshalling
* if required.
*/
public Object getSource () {
if (source != null) {
return source;
}
if (marshalledSource != null) {
try {
ObjectInputStream ois = new ObjectInputStream
(new ByteArrayInputStream(marshalledSource));
source = ois.readObject();
marshalledSource = null;
return source;
} catch (IOException e) {
throw (IllegalStateException)
(new IllegalStateException
("Cannot deserialize source: "
+ e.getMessage()).initCause(e));
} catch (ClassNotFoundException e) {
throw (IllegalStateException)
(new IllegalStateException
("Cannot deserialize source: "
+ e.getMessage()).initCause(e));
}
}
return null;
}
/**
* Assigns the given attribute values.
* @param processKey the attribute <code>processKey</code>.
* @param processName the attribute <code>processName</code>.
* @param processMgrName the attribute <code>processMgrName</code>.
* @param processMgrVersion the attribute <code>processMgrVersion</code>.
*/
private void assignProcessRelatedAttributes(String processKey,
String processName,
String processMgrName,
String processMgrVersion){
this.processKey = processKey;
this.processName = processName;
this.processMgrName = processMgrName;
this.processMgrVersion = processMgrVersion;
}
/**
* Return a new audit event object with the source attribute
* replaced with the given object. Derived classes must override
* this method and return an object of the derived type.
* @param source the new source attribute.
* @return the new audit event.
*/
public DefaultAuditEvent replaceSource (Object source) {
return new DefaultAuditEvent (source, this);
}
/**
* Returns the current value of the attribute <code>source</code>.
* The source of the event is the <code>WfExceutionObject</code>
* associated to the event, i.e. that triggered the event.
* @return the current value of the attribute.
* @throws SourceNotAvailableException if the source is not available.
*/
public WfExecutionObject source() throws SourceNotAvailableException {
Object source = getSource();
if (source == null || !(source instanceof WfExecutionObject)) {
throw new SourceNotAvailableException();
}
return (WfExecutionObject)source;
}
/**
* Returns the audit event selection of the source of this event.
* @return the audit event selection
*/
public int auditEventSelection () {
return auditEventSelection;
}
/**
* Indicates if the event is to be stored in the database.
* @return <code>true</code> if the event is not to be processed.
*/
public boolean store () {
return store;
}
/**
* Indicates if the event is to be processed (i.e. fed back to the
* event queue).
* @return <code>true</code> if the event is not to be processed.
*/
public boolean skip () {
return skip;
}
/**
* Returns the current value of the attribute <code>timeStamp</code>.
* @return the current value of the attribute.
*/
public Date timeStamp () {
return timeStamp;
}
/**
* Returns the current value of the attribute <code>eventType</code>.
* @return the current value of the attribute.
*/
public String eventType(){
return eventType;
}
/**
* Returns the current value of the attribute <code>activityKey</code>.
* @return the current value of the attribute.
*/
public String activityKey(){
return activityKey;
}
/**
* Returns the current value of the attribute <code>activityName</code>.
* @return the current value of the attribute.
*/
public String activityName(){
return activityName;
}
/**
* Returns the current value of the attribute <code>processKey</code>.
* @return the current value of the attribute.
*/
public String processKey(){
return processKey;
}
/**
* Returns the current value of the attribute <code>processName</code>.
* @return the current value of the attribute.
*/
public String processName(){
return processName;
}
/**
* Returns the current value of the attribute
* <code>processMgrName</code>.
* @return the current value of the attribute.
*/
public String processMgrName(){
return processMgrName;
}
/**
* Returns the current value of the attribute
* <code>processMgrVersion</code>.
* @return the current value of the attribute.
*/
public String processMgrVersion(){
return processMgrVersion;
}
/**
* Returns a textual representation of the event.
* @return the textual representation
*/
public String toString() {
return "eventType=" + eventType
+ ", activityKey=" + activityKey
+ ", activityName=" + activityName
+ ", processKey=" + processKey
+ ", processName=" + processName
+ ", processManagerName=" + processMgrName
+ ", processManagerVersion=" + processMgrVersion
+ ", auditEventSelection=" + auditEventSelection
+ ", store=" + store
+ ", skip=" + skip;
}
}