1/*
2 * Copyright 2009 Mike Cumings
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.kenai.jbosh;
18
19import java.io.ByteArrayOutputStream;
20import java.io.IOException;
21import java.io.InputStream;
22import java.util.Collections;
23import java.util.Map;
24
25/**
26 * Implementation of the {@code AbstractBody} class which allows for the
27 * definition of messages from pre-existing message content.  Instances of
28 * this class are based on the underlying data and therefore cannot be
29 * modified.  In order to obtain the wrapper element namespace and
30 * attribute information, the body content is partially parsed.
31 * <p/>
32 * This class does only minimal syntactic and semantic checking with respect
33 * to what the generated XML will look like.  It is up to the developer to
34 * protect against the definition of malformed XML messages when building
35 * instances of this class.
36 * <p/>
37 * Instances of this class are immutable and thread-safe.
38 */
39final class StaticBody extends AbstractBody {
40
41    /**
42     * Selected parser to be used to process raw XML messages.
43     */
44    private static final BodyParser PARSER =
45            new BodyParserXmlPull();
46
47    /**
48     * Size of the internal buffer when copying from a stream.
49     */
50    private static final int BUFFER_SIZE = 1024;
51
52    /**
53     * Map of all attributes to their values.
54     */
55    private final Map<BodyQName, String> attrs;
56
57    /**
58     * This body message in raw XML form.
59     */
60    private final String raw;
61
62    ///////////////////////////////////////////////////////////////////////////
63    // Constructors:
64
65    /**
66     * Prevent direct construction.
67     */
68    private StaticBody(
69            final Map<BodyQName, String> attrMap,
70            final String rawXML) {
71        attrs = attrMap;
72        raw = rawXML;
73    }
74
75    /**
76     * Creates an instance which is initialized by reading a body
77     * message from the provided stream.
78     *
79     * @param inStream stream to read message XML from
80     * @return body instance
81     * @throws BOSHException on parse error
82     */
83    public static StaticBody fromStream(
84            final InputStream inStream)
85            throws BOSHException {
86        ByteArrayOutputStream byteOut = new ByteArrayOutputStream();
87        try {
88            byte[] buffer = new byte[BUFFER_SIZE];
89            int read;
90            do {
91                read = inStream.read(buffer);
92                if (read > 0) {
93                    byteOut.write(buffer, 0, read);
94                }
95            } while (read >= 0);
96        } catch (IOException iox) {
97            throw(new BOSHException(
98                    "Could not read body data", iox));
99        }
100        return fromString(byteOut.toString());
101    }
102
103    /**
104     * Creates an instance which is initialized by reading a body
105     * message from the provided raw XML string.
106     *
107     * @param rawXML raw message XML in string form
108     * @return body instance
109     * @throws BOSHException on parse error
110     */
111    public static StaticBody fromString(
112            final String rawXML)
113            throws BOSHException {
114        BodyParserResults results = PARSER.parse(rawXML);
115        return new StaticBody(results.getAttributes(), rawXML);
116    }
117
118
119    /**
120     * {@inheritDoc}
121     */
122    public Map<BodyQName, String> getAttributes() {
123        return Collections.unmodifiableMap(attrs);
124    }
125
126    /**
127     * {@inheritDoc}
128     */
129    public String toXML() {
130        return raw;
131    }
132
133}
134