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 17 package com.kenai.jbosh; 18 19 import java.io.ByteArrayOutputStream; 20 import java.io.IOException; 21 import java.io.InputStream; 22 import java.util.Collections; 23 import 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 */ 39 final 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