1 /* 2 * Copyright (C) 2009 Google Inc. All rights reserved. 3 * 4 * Licensed under the Apache License, Version 2.0 (the "License"); 5 * you may not use this file except in compliance with the License. 6 * You may obtain a copy of the License at 7 * 8 * http://www.apache.org/licenses/LICENSE-2.0 9 * 10 * Unless required by applicable law or agreed to in writing, software 11 * distributed under the License is distributed on an "AS IS" BASIS, 12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 * See the License for the specific language governing permissions and 14 * limitations under the License. 15 */ 16 17 package com.google.polo.wire.json; 18 19 import com.google.polo.exception.PoloException; 20 import com.google.polo.json.JSONException; 21 import com.google.polo.json.JSONObject; 22 import com.google.polo.pairing.PairingContext; 23 import com.google.polo.pairing.PoloUtil; 24 import com.google.polo.pairing.message.PoloMessage; 25 import com.google.polo.pairing.message.PoloMessage.PoloMessageType; 26 import com.google.polo.wire.PoloWireInterface; 27 28 import java.io.DataInputStream; 29 import java.io.DataOutputStream; 30 import java.io.IOException; 31 import java.io.InputStream; 32 import java.io.OutputStream; 33 34 /** 35 * A {@link PoloWireInterface} which uses JavaScript Object Notation (JSON) for 36 * the message representation. 37 * <p> 38 * Messages are streamed over the wire prepended with an integer which indicates 39 * the total length, in bytes, of the message which follows. The format of the 40 * message is JSON. 41 * <p> 42 * See {@link JsonMessageBuilder} for the underlying message translation 43 * implementation. 44 */ 45 public class JsonWireAdapter implements PoloWireInterface { 46 47 /** 48 * The output coming from the peer. 49 */ 50 private final DataInputStream mInputStream; 51 52 /** 53 * The input going to the peer. 54 */ 55 private final DataOutputStream mOutputStream; 56 57 /** 58 * Constructor. 59 * 60 * @param input the {@link InputStream} from the peer 61 * @param output the {@link OutputStream} to the peer 62 */ JsonWireAdapter(InputStream input, OutputStream output)63 public JsonWireAdapter(InputStream input, OutputStream output) { 64 mInputStream = new DataInputStream(input); 65 mOutputStream = new DataOutputStream(output); 66 } 67 68 /** 69 * Generates a new instance from a {@link PairingContext}. 70 * 71 * @param context the {@link PairingContext} 72 * @return the new instance 73 */ fromContext(PairingContext context)74 public static JsonWireAdapter fromContext(PairingContext context) { 75 return new JsonWireAdapter(context.getPeerInputStream(), context 76 .getPeerOutputStream()); 77 } 78 getNextMessage()79 public PoloMessage getNextMessage() throws IOException, PoloException { 80 byte[] payloadLenBytes = new byte[4]; 81 mInputStream.readFully(payloadLenBytes); 82 long payloadLen = PoloUtil.intBigEndianBytesToLong(payloadLenBytes); 83 byte[] outerJsonBytes = new byte[(int) payloadLen]; 84 mInputStream.readFully(outerJsonBytes); 85 return parseOuterMessageString(new String(outerJsonBytes)); 86 } 87 parseOuterMessageString(String outerString)88 public PoloMessage parseOuterMessageString(String outerString) 89 throws PoloException { 90 JSONObject outerMessage; 91 try { 92 outerMessage = new JSONObject(outerString); 93 } catch (JSONException e) { 94 throw new PoloException("Error parsing incoming message", e); 95 } 96 return JsonMessageBuilder.outerJsonToPoloMessage(outerMessage); 97 } 98 getNextMessage(PoloMessageType type)99 public PoloMessage getNextMessage(PoloMessageType type) throws IOException, 100 PoloException { 101 PoloMessage message = getNextMessage(); 102 if (message.getType() != type) { 103 throw new PoloException("Wrong message type (wanted " + type + ", got " 104 + message.getType() + ")"); 105 } 106 return message; 107 } 108 sendErrorMessage(Exception exception)109 public void sendErrorMessage(Exception exception) throws IOException { 110 try { 111 writeJson(JsonMessageBuilder.getErrorJson(exception)); 112 } catch (PoloException e) { 113 throw new IOException("Error sending error message"); 114 } 115 } 116 sendMessage(PoloMessage message)117 public void sendMessage(PoloMessage message) throws IOException { 118 String outString; 119 JSONObject outerJson; 120 121 try { 122 outerJson = JsonMessageBuilder.getOuterJson(message); 123 } catch (PoloException e) { 124 throw new IOException("Error generating message"); 125 } 126 127 writeJson(outerJson); 128 } 129 130 /** 131 * Writes a {@link JSONObject} to the output stream as a {@link String}. 132 * 133 * @param message the message to write 134 * @throws IOException on error generating the serialized message 135 */ writeJson(JSONObject message)136 private void writeJson(JSONObject message) throws IOException { 137 byte[] outBytes = message.toString().getBytes(); 138 mOutputStream.write(PoloUtil.intToBigEndianIntBytes(outBytes.length)); 139 mOutputStream.write(outBytes); 140 } 141 142 } 143