this.endpoint = endpoint;
}
public void invoke(final ActionContext context)
{
MessageBody request = context.getRequestMessageBody();
MessageBody response = context.getResponseMessageBody();
Object data = request.getData();
if (data instanceof List)
{
data = ((List)data).get(0);
}
else if (data.getClass().isArray())
{
data = Array.get(data, 0);
}
Message inMessage;
if (data instanceof Message)
{
inMessage = (Message)data;
}
else
{
throw new MessageException("Request was not of type flex.messaging.messages.Message");
}
Object outMessage = null;
String replyMethodName = MessageIOConstants.STATUS_METHOD;
try
{
// Lookup or create the correct FlexClient.
endpoint.setupFlexClient(inMessage);
// Assign a clientId if necessary.
// We don't need to assign clientIds to general poll requests.
if (inMessage.getClientId() == null &&
(!(inMessage instanceof CommandMessage) || ((CommandMessage)inMessage).getOperation() != CommandMessage.POLL_OPERATION))
{
Object clientId = UUIDUtils.createUUID();
inMessage.setClientId(clientId);
}
// Messages received via the AMF channel can be batched (by NetConnection on the client) and
// we must not put the handler thread into a poll-wait state if a poll command message is followed by
// or preceeded by other messages in the batch; the request-response loop must complete without waiting.
// If the poll command is the only message in the batch it's ok to wait.
// If it isn't ok to wait, tag the poll message with a header that short-circuits any potential poll-wait.
if (inMessage instanceof CommandMessage)
{
CommandMessage command = (CommandMessage)inMessage;
if ((command.getOperation() == CommandMessage.POLL_OPERATION) && (context.getRequestMessage().getBodyCount() != 1))
command.setHeader(CommandMessage.SUPPRESS_POLL_WAIT_HEADER, Boolean.TRUE);
}
// If MPI is enabled update the MPI metrics on the object referred to by the context
// and the messages
if (context.isMPIenabled())
MessagePerformanceUtils.setupMPII(context, inMessage);
// Service the message.
outMessage = endpoint.serviceMessage(inMessage);
// if processing of the message resulted in an error, set up context and reply method accordingly
if (outMessage instanceof ErrorMessage)
{
context.setStatus(MessageIOConstants.STATUS_ERR);
replyMethodName = MessageIOConstants.STATUS_METHOD;
}
else
{
replyMethodName = MessageIOConstants.RESULT_METHOD;
}
}
catch (MessageException e)
{
context.setStatus(MessageIOConstants.STATUS_ERR);
replyMethodName = MessageIOConstants.STATUS_METHOD;
outMessage = e.createErrorMessage();
((ErrorMessage)outMessage).setCorrelationId(inMessage.getMessageId());
((ErrorMessage)outMessage).setDestination(inMessage.getDestination());
((ErrorMessage)outMessage).setClientId(inMessage.getClientId());
if (e instanceof flex.messaging.security.SecurityException)
{
if (Log.isDebug())
Log.getLogger(LOG_CATEGORY).debug("Security error for message: " +
e.toString() + StringUtils.NEWLINE +
" incomingMessage: " + inMessage + StringUtils.NEWLINE +
" errorReply: " + outMessage);
}
else if (e.getCode() != null && e.getCode().equals(MessageService.NOT_SUBSCRIBED_CODE))
{
if (Log.isDebug())
Log.getLogger(LOG_CATEGORY).debug("Client not subscribed: " +
e.toString() + StringUtils.NEWLINE +
" incomingMessage: " + inMessage + StringUtils.NEWLINE +
" errorReply: " + outMessage);
}
else if (Log.isError())
Log.getLogger(LOG_CATEGORY).error("Error handling message: " +
e.toString() + StringUtils.NEWLINE +
" incomingMessage: " + inMessage + StringUtils.NEWLINE +
" errorReply: " + outMessage);
}
catch (Throwable t)
{
// Handle any uncaught failures. The normal exception path on the server
// is to throw MessageExceptions which are handled in the catch block above,
// so if that was skipped we have an overlooked or serious problem.
context.setStatus(MessageIOConstants.STATUS_ERR);
replyMethodName = MessageIOConstants.STATUS_METHOD;
String lmeMessage = t.getMessage();
if (lmeMessage == null)
lmeMessage = t.getClass().getName();
MessageException lme = new MessageException();
lme.setMessage(UNHANDLED_ERROR, new Object[] {lmeMessage});
outMessage = lme.createErrorMessage();
((ErrorMessage)outMessage).setCorrelationId(inMessage.getMessageId());
((ErrorMessage)outMessage).setDestination(inMessage.getDestination());
((ErrorMessage)outMessage).setClientId(inMessage.getClientId());
if (Log.isError())
{
StringBuffer sb = new StringBuffer();
StackTraceElement [] el = t.getStackTrace();
if (el != null)
{
for (int i = 0; i < el.length; i++)
{
sb.append(" ");
sb.append(el[i].toString());
sb.append(StringUtils.NEWLINE);
}
}
Log.getLogger(LOG_CATEGORY).error("Unhandled error when processing a message: " +
t.toString() + StringUtils.NEWLINE +
" incomingMessage: " + inMessage + StringUtils.NEWLINE +
" errorReply: " + outMessage + StringUtils.NEWLINE +
" stackTrace for: " + t.toString() +
StringUtils.NEWLINE + sb.toString());
}
}
finally
{
// If MPI is enabled update the MPI metrics on the object referred to by the context
// and the messages
if (context.isRecordMessageSizes() || context.isRecordMessageTimes())
{
MessagePerformanceUtils.updateOutgoingMPI(context, inMessage, outMessage);
}
// If our channel-endpoint combination supports small messages, and
// if we know the current protocol version supports small messages,
// try to replace the message...
FlexSession session = FlexContext.getFlexSession();
if (session != null && session.useSmallMessages()
&& !context.isLegacy()
&& context.getVersion() >= MessageIOConstants.AMF3
&& outMessage instanceof Message)
{
outMessage = endpoint.convertToSmallMessage((Message)outMessage);
}
response.setReplyMethod(replyMethodName);
response.setData(outMessage);
}
}