*
* @param o The stream to write the object contents to
* @throws IOException
*/
public void writeExternal(ObjectOutput o) throws IOException {
SafeObjectOutputStream out = SafeObjectOutputStream.install(o);
String logCorrelationIDString = getLogIDString();
if (DEBUG_ENABLED && log.isTraceEnabled()) {
log.trace(logCorrelationIDString + ":writeExternal(): writing to output stream");
}
//---------------------------------------------------------
// in order to handle future changes to the message
// context definition, be sure to maintain the
// object level identifiers
//---------------------------------------------------------
// serialization version ID
out.writeLong(serialVersionUID);
// revision ID
out.writeInt(revisionID);
//---------------------------------------------------------
// various simple fields
//---------------------------------------------------------
// the type of execution flow for the message context
out.writeInt(FLOW);
// various flags
out.writeBoolean(processingFault);
out.writeBoolean(paused);
out.writeBoolean(outputWritten);
out.writeBoolean(newThreadRequired);
out.writeBoolean(isSOAP11);
out.writeBoolean(doingREST);
out.writeBoolean(doingMTOM);
out.writeBoolean(doingSwA);
out.writeBoolean(responseWritten);
out.writeBoolean(serverSide);
out.writeLong(getLastTouchedTime());
out.writeObject(getLogCorrelationID());
//-----------------------------------------------------------------------
// Create and initialize the OMOutputFormat for Message Externalization
//-----------------------------------------------------------------------
OMOutputFormat outputFormat= new OMOutputFormat();
outputFormat.setSOAP11(isSOAP11);
boolean persistOptimized = getPersistOptimized();
if (persistOptimized) {
outputFormat.setDoOptimize(true);
}
String charSetEnc = (String) getProperty(MessageContext.CHARACTER_SET_ENCODING);
if (charSetEnc == null) {
OperationContext opContext = getOperationContext();
if (opContext != null) {
charSetEnc =
(String) opContext.getProperty(MessageContext.CHARACTER_SET_ENCODING);
}
}
if (charSetEnc == null) {
charSetEnc = MessageContext.DEFAULT_CHAR_SET_ENCODING;
}
outputFormat.setCharSetEncoding(charSetEnc);
// ----------------------------------------------------------
// Externalize the Message
// ----------------------------------------------------------
MessageExternalizeUtils.writeExternal(out, this, logCorrelationIDString, outputFormat);
// ---------------------------------------------------------
// ArrayList executionChain
// handler and phase related data
//---------------------------------------------------------
// The strategy is to save some metadata about each
// member of the list and the order of the list.
// Then when the message context is re-constituted,
// try to match up with phases and handlers on the
// engine.
//
// Non-null list:
// UTF - description string
// boolean - active flag
// int - current handler index
// int - current phase index
// int - expected number of entries in the list
// objects - MetaDataEntry object per list entry
// last entry will be empty MetaDataEntry
// with MetaDataEntry.LAST_ENTRY marker
// int - adjusted number of entries in the list
// includes the last empty entry
//
// Empty list:
// UTF - description string
// boolean - empty flag
//---------------------------------------------------------
out.writeUTF("executionChain");
if (executionChain != null && executionChain.size() > 0) {
// start writing data to the output stream
out.writeBoolean(ExternalizeConstants.ACTIVE_OBJECT);
out.writeInt(currentHandlerIndex);
out.writeInt(currentPhaseIndex);
out.writeInt(executionChain.size());
// put the metadata on each member of the list into a buffer
// match the current index with the actual saved list
int nextIndex = 0;
Iterator<Handler> i = executionChain.iterator();
while (i.hasNext()) {
Object obj = i.next();
String objClass = obj.getClass().getName();
// start the meta data entry for this object
MetaDataEntry mdEntry = new MetaDataEntry();
mdEntry.setClassName(objClass);
// get the correct object-specific name
String qnameAsString;
if (obj instanceof Phase) {
Phase phaseObj = (Phase) obj;
qnameAsString = phaseObj.getName();
// add the list of handlers to the meta data
setupPhaseList(phaseObj, mdEntry);
} else if (obj instanceof Handler) {
Handler handlerObj = (Handler) obj;
qnameAsString = handlerObj.getName();
} else {
// TODO: will there be any other kinds of objects in the execution Chain?
qnameAsString = "NULL";
}
mdEntry.setQName(qnameAsString);
// update the index for the entry in the chain
if (DEBUG_ENABLED && log.isTraceEnabled()) {
log.trace(logCorrelationIDString +
":writeExternal(): ***BEFORE OBJ WRITE*** executionChain entry class [" +
objClass + "] qname [" + qnameAsString + "]");
}
out.writeObject(mdEntry);
// update the index so that the index
// now indicates the next entry that
// will be attempted
nextIndex++;
if (DEBUG_ENABLED && log.isTraceEnabled()) {
log.trace(logCorrelationIDString +
":writeExternal(): ***AFTER OBJ WRITE*** executionChain entry class [" +
objClass + "] qname [" + qnameAsString + "]");
}
} // end while entries in execution chain
// done with the entries in the execution chain
// add the end-of-list marker
MetaDataEntry lastEntry = new MetaDataEntry();
lastEntry.setClassName(MetaDataEntry.END_OF_LIST);
out.writeObject(lastEntry);
nextIndex++;
// nextIndex also gives us the number of entries
// that were actually saved as opposed to the
// number of entries in the executionChain
out.writeInt(nextIndex);
} else {
// general case: handle "null" or "empty"
out.writeBoolean(ExternalizeConstants.EMPTY_OBJECT);
if (DEBUG_ENABLED && log.isTraceEnabled()) {
log.trace(logCorrelationIDString + ":writeExternal(): executionChain is NULL");
}
}
//---------------------------------------------------------
// LinkedList executedPhases
//---------------------------------------------------------
// The strategy is to save some metadata about each
// member of the list and the order of the list.
// Then when the message context is re-constituted,
// try to match up with phases and handlers on the
// engine.
//
// Non-null list:
// UTF - description string
// boolean - active flag
// int - expected number of entries in the list
// objects - MetaDataEntry object per list entry
// last entry will be empty MetaDataEntry
// with MetaDataEntry.LAST_ENTRY marker
// int - adjusted number of entries in the list
// includes the last empty entry
//
// Empty list:
// UTF - description string
// boolean - empty flag
//---------------------------------------------------------
out.writeUTF("executedPhases");
if (executedPhases != null && executedPhases.size() > 0) {
// start writing data to the output stream
out.writeBoolean(ExternalizeConstants.ACTIVE_OBJECT);
out.writeInt(executedPhases.size());
// put the metadata on each member of the list into a buffer
int execNextIndex = 0;
Iterator<Handler> iterator = executedPhases.iterator();
while (iterator.hasNext()) {
Object obj = iterator.next();
String objClass = obj.getClass().getName();
// start the meta data entry for this object
MetaDataEntry mdEntry = new MetaDataEntry();
mdEntry.setClassName(objClass);
// get the correct object-specific name
String qnameAsString;
if (obj instanceof Phase) {
Phase inPhaseObj = (Phase) obj;
qnameAsString = inPhaseObj.getName();
// add the list of handlers to the meta data
setupPhaseList(inPhaseObj, mdEntry);
} else if (obj instanceof Handler) {
Handler inHandlerObj = (Handler) obj;
qnameAsString = inHandlerObj.getName();
} else {
// TODO: will there be any other kinds of objects in the list
qnameAsString = "NULL";
}
mdEntry.setQName(qnameAsString);
if (DEBUG_ENABLED && log.isTraceEnabled()) {
log.trace(logCorrelationIDString +
":writeExternal(): ***BEFORE Executed List OBJ WRITE*** executedPhases entry class [" +
objClass + "] qname [" + qnameAsString + "]");
}
out.writeObject(mdEntry);
// update the index so that the index
// now indicates the next entry that
// will be attempted
execNextIndex++;
if (DEBUG_ENABLED && log.isTraceEnabled()) {
log.trace(logCorrelationIDString + ":writeExternal(): " +
"***AFTER Executed List OBJ WRITE*** " +
"executedPhases entry class [" + objClass + "] " +
"qname [" + qnameAsString + "]");
}
} // end while entries in execution chain
// done with the entries in the execution chain
// add the end-of-list marker
MetaDataEntry lastEntry = new MetaDataEntry();
lastEntry.setClassName(MetaDataEntry.END_OF_LIST);
out.writeObject(lastEntry);
execNextIndex++;
// execNextIndex also gives us the number of entries
// that were actually saved as opposed to the
// number of entries in the executedPhases
out.writeInt(execNextIndex);
} else {
// general case: handle "null" or "empty"
out.writeBoolean(ExternalizeConstants.EMPTY_OBJECT);
if (DEBUG_ENABLED && log.isTraceEnabled()) {
log.trace(
logCorrelationIDString + ":writeExternal(): executedPhases is NULL");
}
}
//---------------------------------------------------------
// options
//---------------------------------------------------------
// before saving the Options, make sure there is a message ID
String tmpID = getMessageID();
if (tmpID == null) {
// get an id to use when restoring this object
tmpID = UIDGenerator.generateUID();
setMessageID(tmpID);
}
if (DEBUG_ENABLED && log.isTraceEnabled()) {
log.trace(logCorrelationIDString + ":writeExternal(): message ID [" + tmpID + "]");
}
out.writeUTF("options");
out.writeObject(options);
//---------------------------------------------------------
// operation
//---------------------------------------------------------
// axis operation
//---------------------------------------------------------
out.writeUTF("axisOperation");
metaAxisOperation = null;
if (axisOperation != null) {
// TODO: may need to include the meta data for the axis service that is
// the parent of the axis operation
// make sure the axis operation has a name associated with it
QName aoTmpQName = axisOperation.getName();
if (aoTmpQName == null) {
aoTmpQName = new QName(ExternalizeConstants.EMPTY_MARKER);
axisOperation.setName(aoTmpQName);
}
metaAxisOperation = new MetaDataEntry(axisOperation.getClass().getName(),
axisOperation.getName().toString());
}
out.writeObject(metaAxisOperation);
//---------------------------------------------------------
// operation context
//---------------------------------------------------------
// The OperationContext has pointers to MessageContext objects.
// In order to avoid having multiple copies of the object graph
// being saved at different points in the serialization,
// it is important to isolate this message context object.
out.writeUTF("operationContext");
if (operationContext != null) {
operationContext.isolateMessageContext(this);
}
out.writeObject(operationContext);
//---------------------------------------------------------
// service
//---------------------------------------------------------
// axis service
//-------------------------
// this is expected to be the parent of the axis operation object
out.writeUTF("axisService");
metaAxisService = null;
if (axisService != null) {
String serviceAndPortNames = ActivateUtils.getAxisServiceExternalizeExtraName(axisService);
// If there is a service & port QName stored on the AxisService then write it out so
// it can be used during deserialization to hook up the message context to the
// correct AxisService.
metaAxisService = new MetaDataEntry(axisService.getClass().getName(),
axisService.getName(), serviceAndPortNames);
}
out.writeObject(metaAxisService);
//-------------------------
// serviceContextID string
//-------------------------
out.writeObject(serviceContextID);
//-------------------------
// serviceContext
//-------------------------
// is this the same as the parent of the OperationContext?
boolean isParent = false;
out.writeUTF("serviceContext");
if (operationContext != null) {
ServiceContext opctxParent = operationContext.getServiceContext();
if (serviceContext != null) {
if (serviceContext.equals(opctxParent)) {
// the ServiceContext is the parent of the OperationContext
isParent = true;
}
}
}
if (serviceContext == null) {
out.writeBoolean(ExternalizeConstants.EMPTY_OBJECT);
} else {
out.writeBoolean(ExternalizeConstants.ACTIVE_OBJECT);
out.writeBoolean(isParent);
// only write out the object if it is not the parent
if (!isParent) {
out.writeObject(serviceContext);
}
}
//---------------------------------------------------------
// axisServiceGroup
//---------------------------------------------------------
out.writeUTF("axisServiceGroup");
metaAxisServiceGroup = null;
if (axisServiceGroup != null) {
metaAxisServiceGroup = new MetaDataEntry(axisServiceGroup.getClass().getName(),
axisServiceGroup.getServiceGroupName());
}
out.writeObject(metaAxisServiceGroup);
//-----------------------------
// serviceGroupContextId string
//-----------------------------
out.writeObject(serviceGroupContextId);
//-------------------------
// serviceGroupContext
//-------------------------
// is this the same as the parent of the ServiceContext?
isParent = false;
out.writeUTF("serviceGroupContext");
if (serviceContext != null) {
ServiceGroupContext srvgrpctxParent = (ServiceGroupContext) serviceContext.getParent();
if (serviceGroupContext != null) {
if (serviceGroupContext.equals(srvgrpctxParent)) {
// the ServiceGroupContext is the parent of the ServiceContext
isParent = true;
}
}
}
if (serviceGroupContext == null) {
out.writeBoolean(ExternalizeConstants.EMPTY_OBJECT);
} else {
out.writeBoolean(ExternalizeConstants.ACTIVE_OBJECT);
out.writeBoolean(isParent);
// only write out the object if it is not the parent
if (!isParent) {
out.writeObject(serviceGroupContext);
}
}
//---------------------------------------------------------
// axis message
//---------------------------------------------------------
out.writeUTF("axisMessage");
metaAxisMessage = null;
if (axisMessage != null) {
// This AxisMessage is expected to belong to the AxisOperation
// that has already been recorded for this MessageContext.
// If an AxisMessage associated with this Messagecontext is
// associated with a different AxisOperation, then more
// meta information would need to be saved
// make sure the axis message has a name associated with it
String amTmpName = axisMessage.getName();
if (amTmpName == null) {
amTmpName = ExternalizeConstants.EMPTY_MARKER;
axisMessage.setName(amTmpName);
}
// get the element name if there is one
QName amTmpElementQName = axisMessage.getElementQName();
String amTmpElemQNameString = null;
if (amTmpElementQName != null) {
amTmpElemQNameString = amTmpElementQName.toString();
}
metaAxisMessage = new MetaDataEntry(axisMessage.getClass().getName(),
axisMessage.getName(), amTmpElemQNameString);
}
out.writeObject(metaAxisMessage);
//---------------------------------------------------------
// configuration context
//---------------------------------------------------------
// NOTE: Currently, there does not seem to be any
// runtime data important to this message context
// in the configuration context.
// if so, then need to save that runtime data and reconcile
// it with the configuration context on the system when
// this message context object is restored
//---------------------------------------------------------
// session context
//---------------------------------------------------------
out.writeObject(sessionContext);
//---------------------------------------------------------
// transport
//---------------------------------------------------------
//------------------------------
// incomingTransportName string
//------------------------------
out.writeObject(incomingTransportName);
// TransportInDescription transportIn
metaTransportIn = null;
if (transportIn != null) {
metaTransportIn = new MetaDataEntry(null, transportIn.getName());
}
out.writeObject(metaTransportIn);
// TransportOutDescription transportOut
metaTransportOut = null;
if (transportOut != null) {
metaTransportOut = new MetaDataEntry(null, transportOut.getName());
}
out.writeObject(metaTransportOut);
//---------------------------------------------------------
// properties
//---------------------------------------------------------
// Write out the local properties on the MessageContext
// Don't write out the properties from other hierarchical layers.
// (i.e. don't use getProperties())
out.writeUTF("properties"); // write marker
out.writeMap(properties);
//---------------------------------------------------------
// special data
//---------------------------------------------------------
out.writeUTF("selfManagedData");
serializeSelfManagedData(out);
//---------------------------------------------------------
// done
//---------------------------------------------------------