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
17package com.google.polo.wire.xml;
18
19import com.google.polo.exception.PoloException;
20import com.google.polo.pairing.HexDump;
21import com.google.polo.pairing.PairingContext;
22import com.google.polo.pairing.message.PoloMessage;
23import com.google.polo.pairing.message.PoloMessage.PoloMessageType;
24import com.google.polo.wire.PoloWireInterface;
25
26import java.io.IOException;
27import java.io.InputStream;
28import java.io.OutputStream;
29
30public class XmlWireAdapter implements PoloWireInterface {
31
32    /**
33     * Enables extra verbose debug logging.
34     */
35    private static final boolean DEBUG_VERBOSE = false;
36
37    private static final int STATUS_OK = 1;
38
39    /**
40     * The output coming from the peer.
41     */
42    private final InputStream mInputStream;
43
44    /**
45     * The input going to the peer.
46     */
47    private final OutputStream mOutputStream;
48
49    private final XmlMessageBuilder mBuilder;
50
51    /**
52     * Constructor.
53     *
54     * @param input  the {@link InputStream} from the peer
55     * @param output  the {@link OutputStream} to the peer
56     */
57    public XmlWireAdapter(InputStream input, OutputStream output) {
58      mInputStream = input;
59      mOutputStream = output;
60      mBuilder = new XmlMessageBuilder();
61    }
62
63    /**
64     * Generates a new instance from a {@link PairingContext}.
65     * @param context  the {@link PairingContext}
66     * @return  the new instance
67     */
68    public static XmlWireAdapter fromContext(PairingContext context) {
69      return new XmlWireAdapter(context.getPeerInputStream(),
70          context.getPeerOutputStream());
71    }
72
73    public PoloMessage getNextMessage() throws IOException, PoloException {
74        XmlMessageWrapper outerMessage =
75                XmlMessageWrapper.fromInputStream(mInputStream);
76        if (DEBUG_VERBOSE) {
77            debug(">>> Incoming Message:");
78            debug(HexDump.dumpHexString(outerMessage.serializeToByteArray()));
79        }
80
81        String outerXML = new String(outerMessage.getPayload());
82        return mBuilder.outerXMLToPoloMessage(outerXML);
83    }
84
85    public PoloMessage getNextMessage(PoloMessageType type) throws IOException, PoloException {
86        PoloMessage message = getNextMessage();
87        if (message.getType() != type) {
88            throw new PoloException("Wrong message type (wanted " + type +
89                ", got " + message.getType() + ")");
90          }
91          return message;
92    }
93
94    public void sendErrorMessage(Exception exception) throws IOException {
95        String errorXml;
96        try {
97          errorXml = mBuilder.getErrorXML(exception);
98        } catch (PoloException e) {
99          // just ignore it; nothing we can do
100          return;
101        }
102        byte[] outBytes = errorXml.getBytes();
103        XmlMessageWrapper message = new XmlMessageWrapper("client", 1,
104            (byte) 0, outBytes);
105        writeXML(message);
106    }
107
108    public void sendMessage(PoloMessage poloMessage) throws IOException {
109        String outString = mBuilder.getOuterXML(poloMessage, STATUS_OK);
110
111        // NOTE(mikey): A particular parser is very sensitive to newline
112        // placement. Strip all newlines, then add them to separate adjacent
113        // XML entities.
114        outString = outString.replace("\n", "");
115        outString = outString.replace("><", ">\n<");
116
117        byte[] outBytes = outString.getBytes();
118        XmlMessageWrapper message = new XmlMessageWrapper("client", 1,
119            (byte) 0, outBytes);
120        writeXML(message);
121    }
122
123    /**
124     * Writes a {@link XmlMessageWrapper} to the output stream as a
125     * {@link String}.
126     *
127     * @param message       the message to write
128     * @throws IOException  on error generating the serialized message
129     */
130    private void writeXML(XmlMessageWrapper message) throws IOException {
131      if (DEBUG_VERBOSE) {
132          debug("<<< Outgoing Message:");
133          debug(HexDump.dumpHexString(message.serializeToByteArray()));
134      }
135      mOutputStream.write(message.serializeToByteArray());
136    }
137
138    private void debug(String message) {
139      System.out.println(message);
140    }
141
142}
143