/****************************************************************************** * * Copyright 2011-2012 Tavendo GmbH * * 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.magnum.soda.transport.wamp; import java.io.IOException; import java.nio.channels.SocketChannel; import android.os.Handler; import android.os.Looper; import android.util.Log; import com.fasterxml.jackson.core.JsonFactory; import com.fasterxml.jackson.core.JsonGenerationException; import com.fasterxml.jackson.core.JsonGenerator; import com.fasterxml.jackson.databind.JsonMappingException; import com.fasterxml.jackson.databind.MappingJsonFactory; /** * Autobahn WAMP writer, the transmitting leg of a WAMP connection. * This writer serializes WAMP messages forwarded from the foreground thread * (the master) to this object running on the writer thread. WAMP messages are * serialized to JSON, and then sent via WebSockets. */ public class WampWriter extends WebSocketWriter { private static final boolean DEBUG = true; private static final String TAG = WampWriter.class.getName(); /** * This is the Jackson JSON factory we use to create JSON generators. */ private final JsonFactory mJsonFactory; /** * This is where we buffer the JSON serialization of WAMP messages. */ private final NoCopyByteArrayOutputStream mPayload; /** * A writer object is created in AutobahnConnection. * * @param looper The message looper associated with the thread running this object. * @param master The message handler associated with the master thread (running AutobahnConnection). * @param socket The TCP socket (channel) the WebSocket connection runs over. * @param options WebSockets options for the underlying WebSockets connection. */ public WampWriter(Looper looper, Handler master, SocketChannel socket, WebSocketOptions options) { super(looper, master, socket, options); mJsonFactory = new MappingJsonFactory(); mPayload = new NoCopyByteArrayOutputStream(); if (DEBUG) Log.d(TAG, "created"); } /** * Called from WebSocketWriter when it receives a message in it's * message loop it does not recognize. */ protected void processAppMessage(Object msg) throws WebSocketException, IOException { mPayload.reset(); // creating a JSON generator is supposed to be a light-weight operation JsonGenerator generator = mJsonFactory.createJsonGenerator(mPayload); try { // serialize WAMP messages to JSON: the code here needs to understand // any client-to-server WAMP messages forward from the foreground thread if (msg instanceof WampMessage.Call) { WampMessage.Call call = (WampMessage.Call) msg; generator.writeStartArray(); generator.writeNumber(WampMessage.MESSAGE_TYPE_CALL); generator.writeString(call.mCallId); generator.writeString(call.mProcUri); for (Object arg : call.mArgs) { generator.writeObject(arg); } generator.writeEndArray(); } else if (msg instanceof WampMessage.Prefix) { WampMessage.Prefix prefix = (WampMessage.Prefix) msg; generator.writeStartArray(); generator.writeNumber(WampMessage.MESSAGE_TYPE_PREFIX); generator.writeString(prefix.mPrefix); generator.writeString(prefix.mUri); generator.writeEndArray(); } else if (msg instanceof WampMessage.Subscribe) { WampMessage.Subscribe subscribe = (WampMessage.Subscribe) msg; generator.writeStartArray(); generator.writeNumber(WampMessage.MESSAGE_TYPE_SUBSCRIBE); generator.writeString(subscribe.mTopicUri); generator.writeEndArray(); } else if (msg instanceof WampMessage.Unsubscribe) { WampMessage.Unsubscribe unsubscribe = (WampMessage.Unsubscribe) msg; generator.writeStartArray(); generator.writeNumber(WampMessage.MESSAGE_TYPE_UNSUBSCRIBE); generator.writeString(unsubscribe.mTopicUri); generator.writeEndArray(); } else if (msg instanceof WampMessage.Publish) { WampMessage.Publish publish = (WampMessage.Publish) msg; generator.writeStartArray(); generator.writeNumber(WampMessage.MESSAGE_TYPE_PUBLISH); generator.writeString(publish.mTopicUri); generator.writeObject(publish.mEvent); generator.writeEndArray(); } else { // this should not happen, but to be sure throw new WebSocketException("invalid message received by AutobahnWriter"); } } catch (JsonGenerationException e) { // this may happen, and we need to wrap the error throw new WebSocketException("JSON serialization error (" + e.toString() + ")"); } catch (JsonMappingException e) { // this may happen, and we need to wrap the error throw new WebSocketException("JSON serialization error (" + e.toString() + ")"); } // make sure the JSON generator has spit out everything generator.flush(); // Jackson's JSON generator produces UTF-8 directly, so we send // a text message frame using the raw sendFrame() method sendFrame(1, true, mPayload.getByteArray(), 0, mPayload.size()); // cleanup generators resources generator.close(); } }