BlazeDSのCore/Commonだけでさくっと通信する。


世の中若干のBlazeDSブームですが、それにのっかって1ネタ紹介。

(ちょい追記)
BlazeDSのRemotingを使わず、AMF通信のライブラリとしてCore/Commonだけを使って通信する方法です。

それなりに簡単。



BlazeDSは実はCoreとCommonは依存関係がそんなにありません。

backport-util-concurrentとか、xalanとかなくても動く。

というわけで、その2つだけで実は楽に通信できます。

以下サンプル。エラー処理とかちょっと適当だけど^^;

肝は上のエントリでも書きましたが、1回目のリクエストは単なるPINGでそれに

きちんとResponseしてやることと、実データのResponseにヘッダーできちんとバージョンを埋め込むところかな。

RemotingMessageで送られてくるdestinationやoperationに規約をあたえてあげれば

いろいろごにょごにょできますよ、と。わずらわしい設定ファイルも全然いらないのです。

(追記)

あ。言い忘れたけど、これはRemotingだけです。

pushとかできないし、HTTP Proxyとかもないです。

でも擬似pushどれだけ使うのかは若干の疑問だなあー^^;


package amftest.filter;

import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.lang.reflect.Array;
import java.util.ArrayList;
import java.util.List;

import javax.servlet.Filter;
import javax.servlet.FilterChain;
import javax.servlet.FilterConfig;
import javax.servlet.ServletException;
import javax.servlet.ServletRequest;
import javax.servlet.ServletResponse;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

import amftest2.Person;
import flex.messaging.MessageException;
import flex.messaging.io.MessageDeserializer;
import flex.messaging.io.MessageIOConstants;
import flex.messaging.io.MessageSerializer;
import flex.messaging.io.SerializationContext;
import flex.messaging.io.TypeMarshallingContext;
import flex.messaging.io.amf.ActionContext;
import flex.messaging.io.amf.ActionMessage;
import flex.messaging.io.amf.AmfMessageDeserializer;
import flex.messaging.io.amf.AmfMessageSerializer;
import flex.messaging.io.amf.AmfTrace;
import flex.messaging.io.amf.MessageBody;
import flex.messaging.messages.AcknowledgeMessage;
import flex.messaging.messages.CommandMessage;
import flex.messaging.messages.ErrorMessage;
import flex.messaging.messages.Message;
import flex.messaging.messages.RemotingMessage;

public class AMFFilter implements Filter {

	public void init(FilterConfig filterConfig) throws ServletException {
		TypeMarshallingContext
				.setTypeMarshallingContext(new TypeMarshallingContext() {

					@Override
					public void setClassLoader(ClassLoader loader) {
						super.setClassLoader(Thread.currentThread()
								.getContextClassLoader());
					}

				});
	}

	public void doFilter(ServletRequest request, ServletResponse response,
			FilterChain chain) throws IOException, ServletException {
		final ActionContext actionContext = new ActionContext();
		final HttpServletRequest req = (HttpServletRequest) request;
		final HttpServletResponse res = (HttpServletResponse) response;
		String contentType = req.getHeader("content-type");
		String flashVer = req.getHeader("x-flash-version");
		if (contentType.equals("application/x-amf")
				&& (flashVer == null || "".equals(flashVer))) {
			chain.doFilter(req, res);
			return;
		}
		try {
			processRequestMessage(req, actionContext);
			createResponseMessage(actionContext);
			processOutputMessage(res, actionContext);
		} catch (Throwable t) {
			t.printStackTrace();
			String errorStr = t.getMessage();
			if (errorStr == null)
				errorStr = t.getClass().getName();
			MessageException e = new MessageException();
			e.setMessage(10000, new Object[] { errorStr });
			Object data = actionContext.getRequestMessageBody().getData();
			Message inMessage = null;
			if (data instanceof List) {
				inMessage = (Message) ((List<?>) data).get(0);
			} else if (data.getClass().isArray()) {
				inMessage = (Message) Array.get(data, 0);
			}
			final ErrorMessage errorMessage = createErrorMessage(e, inMessage);

			actionContext.setStatus(MessageIOConstants.STATUS_ERR);
			final MessageBody responseMessageBody = actionContext
					.getResponseMessageBody();
			responseMessageBody
					.setReplyMethod(MessageIOConstants.STATUS_METHOD);
			responseMessageBody.setData(errorMessage);
		}
	}

	protected ErrorMessage createErrorMessage(MessageException lme,
			Message inMessage) {
		ErrorMessage outMessage = new ErrorMessage();
		lme.createErrorMessage();
		outMessage.setCorrelationId(inMessage.getMessageId());
		outMessage.setDestination(inMessage.getDestination());
		outMessage.setClientId(inMessage.getClientId());
		return outMessage;
	}

	protected void processRequestMessage(HttpServletRequest req,
			ActionContext actionContext) throws Exception {
		SerializationContext serializationContext = SerializationContext
				.getSerializationContext();

		MessageDeserializer deserializer = new AmfMessageDeserializer();
		InputStream inputStream = req.getInputStream();
		deserializer.initialize(serializationContext, inputStream,
				new AmfTrace());
		int contentLength = req.getContentLength();
		actionContext.setDeserializedBytes(contentLength);
		actionContext.setRequestMessage(new ActionMessage());
		deserializer.readMessage(actionContext.getRequestMessage(),
				actionContext);
	}

	protected void createResponseMessage(ActionContext actionContext)
			throws Exception {
		MessageBody requestBody = actionContext.getRequestMessageBody();
		MessageBody responseBody = new MessageBody();
		responseBody.setTargetURI(requestBody.getResponseURI());
		Object bodyCandidate = requestBody.getData();
		if (bodyCandidate.getClass().isArray()) {
			Object[] bodyObjects = (Object[]) bodyCandidate;
			for (int i = 0; i < bodyObjects.length; i++) {
				Object body = bodyObjects[i];
				handleBody(responseBody, body);
			}
		} else {
			handleBody(responseBody, bodyCandidate);
		}
		ActionMessage responseMessage = new ActionMessage();
		responseMessage.setVersion(actionContext.getVersion());
		responseMessage.addBody(responseBody);
		actionContext.setResponseMessage(responseMessage);
	}

	protected void handleBody(MessageBody responseBody, Object body) {
		if (body instanceof CommandMessage) {
			CommandMessage command = (CommandMessage) body;
			if (command.getOperation() == CommandMessage.CLIENT_PING_OPERATION) {
				responseBody.setReplyMethod(MessageIOConstants.RESULT_METHOD);
			}
		} else if (body instanceof RemotingMessage) {
			RemotingMessage remoting = (RemotingMessage) body;
			System.out.println("destination:" + remoting.getDestination());
			System.out.println("operation:" + remoting.getOperation());
			Person person = (Person) remoting.getParameters().get(0);
			System.out.println("Person:name=" + person.getStr());
			responseBody.setReplyMethod(MessageIOConstants.RESULT_METHOD);
			AcknowledgeMessage resultMessage = new AcknowledgeMessage();
			resultMessage.setClientId(remoting.getClientId());
			resultMessage.setCorrelationId(remoting.getMessageId());
			resultMessage.setDestination(remoting.getDestination());
			Person p = new Person();
			p.setStr("100年後の" + person.getNum());
			p.setNum(person.getNum() + 100);

			Person p2 = new Person();
			p2.setStr("101年後の" + person.getNum());
			p2.setNum(person.getNum() + 101);

			List<Person> list = new ArrayList<Person>();
			list.add(p);
			list.add(p2);

			resultMessage.setBody(list);
			resultMessage.setHeader(CommandMessage.MESSAGING_VERSION,
					new Double(3));
			responseBody.setData(resultMessage);
		}
	}

	protected void processOutputMessage(HttpServletResponse res,
			ActionContext actionContext) throws Exception {
		SerializationContext dsContext = SerializationContext
				.getSerializationContext();
		MessageSerializer serializer = new AmfMessageSerializer();
		OutputStream outputStream = res.getOutputStream();
		serializer.initialize(dsContext, outputStream, new AmfTrace());
		serializer.writeMessage(actionContext.getResponseMessage());
	}

	public void destroy() {
	}

}