org.springframework.flex.http.AmfHttpMessageConverter.java Source code

Java tutorial

Introduction

Here is the source code for org.springframework.flex.http.AmfHttpMessageConverter.java

Source

/*
 * Copyright 2002-2011 the original author or authors.
 * 
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 * 
 *   http://www.apache.org/licenses/LICENSE-2.0
 * 
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

package org.springframework.flex.http;

import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.util.List;

import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.springframework.http.HttpInputMessage;
import org.springframework.http.HttpOutputMessage;
import org.springframework.http.MediaType;
import org.springframework.http.converter.AbstractHttpMessageConverter;
import org.springframework.http.converter.HttpMessageNotReadableException;
import org.springframework.http.converter.HttpMessageNotWritableException;

import flex.messaging.FlexContext;
import flex.messaging.MessageException;
import flex.messaging.io.MessageIOConstants;
import flex.messaging.io.SerializationContext;
import flex.messaging.io.SerializationException;
import flex.messaging.io.amf.ActionContext;
import flex.messaging.io.amf.ActionMessage;
import flex.messaging.io.amf.Amf3Input;
import flex.messaging.io.amf.Amf3Output;
import flex.messaging.io.amf.AmfMessageDeserializer;
import flex.messaging.io.amf.AmfMessageSerializer;
import flex.messaging.io.amf.AmfTrace;

/**
 * Implementation of {@link org.springframework.http.converter.HttpMessageConverter HttpMessageConverter}
 * that can read and write AMF using BlazeDS's AMF serialization/deserialization APIs. 
 *
 * <p>This converter can be used to bind to typed beans, or untyped {@link java.util.HashMap HashMap} instances.
 *
 * <p>By default, this converter supports {@code application/x-amf}. This can be overridden by setting the
 * {@link #setSupportedMediaTypes(List) supportedMediaTypes} property.
 *
 * @author Jeremy Grelle
 */
public class AmfHttpMessageConverter extends AbstractHttpMessageConverter<Object> {

    private static final String AMF_ERROR = "Could not read input message body as AMF";
    private static final String ACTION_MSG_ERROR = "Could not read input message body as "
            + ActionMessage.class.getName();
    private static final Log log = LogFactory.getLog(AmfHttpMessageConverter.class);

    public AmfHttpMessageConverter() {
        super(MediaType.parseMediaType(MessageIOConstants.AMF_CONTENT_TYPE));
    }

    /**
     * {@inheritDoc}
     */
    @Override
    protected boolean supports(Class<?> clazz) {
        return true;
    }

    /**
     * {@inheritDoc}
     */
    @Override
    protected Object readInternal(Class<? extends Object> clazz, HttpInputMessage inputMessage)
            throws IOException, HttpMessageNotReadableException {

        try {
            AmfTrace trace = null;
            if (log.isDebugEnabled()) {
                trace = new AmfTrace();
            }

            Object result = null;

            if (clazz.equals(ActionMessage.class)) {
                result = readActionMessage(inputMessage, trace);
            } else {
                result = readObject(inputMessage, trace);
            }

            if (log.isDebugEnabled()) {
                log.debug("Read AMF message:\n" + trace);
            }
            return result;
        } finally {
            FlexContext.clearThreadLocalObjects();
            SerializationContext.clearThreadLocalObjects();
        }
    }

    /**
     * {@inheritDoc}
     */
    @Override
    protected void writeInternal(Object data, HttpOutputMessage outputMessage)
            throws IOException, HttpMessageNotWritableException {

        try {
            AmfTrace trace = null;
            if (log.isDebugEnabled()) {
                trace = new AmfTrace();
            }

            outputMessage.getHeaders().setPragma("no-cache");
            outputMessage.getHeaders().setCacheControl("no-cache, no-store, max-age=0");
            outputMessage.getHeaders().setExpires(1L);

            if (data instanceof ActionMessage) {
                writeActionMessage((ActionMessage) data, outputMessage, trace);
            } else {
                writeObject(data, outputMessage, trace);
            }

            if (log.isDebugEnabled()) {
                log.debug("Wrote AMF message:\n" + trace);
            }
        } finally {
            FlexContext.clearThreadLocalObjects();
            SerializationContext.clearThreadLocalObjects();
        }
    }

    private Object readObject(HttpInputMessage inputMessage, AmfTrace trace) throws IOException {
        Amf3Input deserializer = new Amf3Input(new SerializationContext());
        deserializer.setInputStream(inputMessage.getBody());
        deserializer.setDebugTrace(trace);
        try {
            return deserializer.readObject();
        } catch (ClassNotFoundException cnfe) {
            throw new HttpMessageNotReadableException(AMF_ERROR, cnfe);
        } catch (MessageException se) {
            throw new HttpMessageNotReadableException(AMF_ERROR, se);
        }
    }

    private ActionMessage readActionMessage(HttpInputMessage inputMessage, AmfTrace trace) throws IOException {
        AmfMessageDeserializer deserializer = new AmfMessageDeserializer();
        deserializer.initialize(new SerializationContext(), inputMessage.getBody(), trace);

        try {
            ActionContext context = new ActionContext();
            ActionMessage message = new ActionMessage();
            context.setRequestMessage(message);
            deserializer.readMessage(message, context);
            return message;
        } catch (ClassNotFoundException cnfe) {
            throw new HttpMessageNotReadableException(ACTION_MSG_ERROR, cnfe);
        } catch (MessageException me) {
            throw new HttpMessageNotReadableException(ACTION_MSG_ERROR, me);
        }
    }

    private void writeActionMessage(ActionMessage message, HttpOutputMessage outputMessage, AmfTrace trace)
            throws IOException {
        AmfMessageSerializer serializer = new AmfMessageSerializer();
        ByteArrayOutputStream outBuffer = new ByteArrayOutputStream();
        serializer.setVersion(message.getVersion());
        serializer.initialize(new SerializationContext(), outBuffer, trace);

        try {
            ActionContext context = new ActionContext();
            context.setVersion(message.getVersion());
            context.setResponseMessage(message);
            serializer.writeMessage(message);
            outBuffer.flush();
            outBuffer.close();
            outputMessage.getHeaders().setContentLength(outBuffer.size());
            outBuffer.writeTo(outputMessage.getBody());
        } catch (SerializationException se) {
            throw new HttpMessageNotWritableException("Could not write " + message + " as AMF message.", se);
        }
    }

    private void writeObject(Object data, HttpOutputMessage outputMessage, AmfTrace trace) throws IOException {
        ByteArrayOutputStream outBuffer = new ByteArrayOutputStream();
        Amf3Output serializer = new Amf3Output(new SerializationContext());
        serializer.setOutputStream(outBuffer);
        serializer.setDebugTrace(trace);
        try {
            serializer.writeObject(data);
            outBuffer.flush();
            outBuffer.close();
            outputMessage.getHeaders().setContentLength(outBuffer.size());
            outBuffer.writeTo(outputMessage.getBody());
        } catch (SerializationException se) {
            throw new HttpMessageNotWritableException("Could not write " + data + " as AMF message.", se);
        }
    }
}