Home | History | Annotate | Download | only in json
      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    */
     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    */
     74   public static JsonWireAdapter fromContext(PairingContext context) {
     75     return new JsonWireAdapter(context.getPeerInputStream(), context
     76         .getPeerOutputStream());
     77   }
     78 
     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 
     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 
     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 
    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 
    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    */
    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