1 /* 2 * Copyright (c) 2000, 2016, Oracle and/or its affiliates. All rights reserved. 3 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. 4 * 5 * This code is free software; you can redistribute it and/or modify it 6 * under the terms of the GNU General Public License version 2 only, as 7 * published by the Free Software Foundation. Oracle designates this 8 * particular file as subject to the "Classpath" exception as provided 9 * by Oracle in the LICENSE file that accompanied this code. 10 * 11 * This code is distributed in the hope that it will be useful, but WITHOUT 12 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or 13 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License 14 * version 2 for more details (a copy is included in the LICENSE file that 15 * accompanied this code). 16 * 17 * You should have received a copy of the GNU General Public License version 18 * 2 along with this work; if not, write to the Free Software Foundation, 19 * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. 20 * 21 * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA 22 * or visit www.oracle.com if you need additional information or have any 23 * questions. 24 */ 25 26 package javax.xml.transform.stream; 27 28 import java.io.File; 29 import java.io.IOException; 30 import java.io.InputStream; 31 import java.io.Reader; 32 import javax.xml.transform.Result; 33 34 import javax.xml.transform.Source; 35 36 /** 37 * <p>Acts as an holder for a transformation Source in the form 38 * of a stream of XML markup.</p> 39 * 40 * <p><em>Note:</em> Due to their internal use of either a {@link Reader} or {@link InputStream} instance, 41 * <code>StreamSource</code> instances may only be used once.</p> 42 * 43 * @author <a href="Jeff.Suttor@Sun.com">Jeff Suttor</a> 44 * @since 1.4 45 */ 46 public class StreamSource implements Source { 47 48 /** If {@link javax.xml.transform.TransformerFactory#getFeature} 49 * returns true when passed this value as an argument, 50 * the Transformer supports Source input of this type. 51 */ 52 public static final String FEATURE = 53 "http://javax.xml.transform.stream.StreamSource/feature"; 54 55 /** 56 * <p>Zero-argument default constructor. If this constructor is used, and 57 * no Stream source is set using 58 * {@link #setInputStream(java.io.InputStream inputStream)} or 59 * {@link #setReader(java.io.Reader reader)}, then the 60 * <code>Transformer</code> will 61 * create an empty source {@link java.io.InputStream} using 62 * {@link java.io.InputStream#InputStream() new InputStream()}.</p> 63 * 64 * @see javax.xml.transform.Transformer#transform(Source xmlSource, Result outputTarget) 65 */ 66 public StreamSource() { } 67 68 /** 69 * Construct a StreamSource from a byte stream. Normally, 70 * a stream should be used rather than a reader, so 71 * the XML parser can resolve character encoding specified 72 * by the XML declaration. 73 * 74 * <p>If this constructor is used to process a stylesheet, normally 75 * setSystemId should also be called, so that relative URI references 76 * can be resolved.</p> 77 * 78 * @param inputStream A valid InputStream reference to an XML stream. 79 */ 80 public StreamSource(InputStream inputStream) { 81 setInputStream(inputStream); 82 } 83 84 /** 85 * Construct a StreamSource from a byte stream. Normally, 86 * a stream should be used rather than a reader, so that 87 * the XML parser can resolve character encoding specified 88 * by the XML declaration. 89 * 90 * <p>This constructor allows the systemID to be set in addition 91 * to the input stream, which allows relative URIs 92 * to be processed.</p> 93 * 94 * @param inputStream A valid InputStream reference to an XML stream. 95 * @param systemId Must be a String that conforms to the URI syntax. 96 */ 97 public StreamSource(InputStream inputStream, String systemId) { 98 setInputStream(inputStream); 99 setSystemId(systemId); 100 } 101 102 /** 103 * Construct a StreamSource from a character reader. Normally, 104 * a stream should be used rather than a reader, so that 105 * the XML parser can resolve character encoding specified 106 * by the XML declaration. However, in many cases the encoding 107 * of the input stream is already resolved, as in the case of 108 * reading XML from a StringReader. 109 * 110 * @param reader A valid Reader reference to an XML character stream. 111 */ 112 public StreamSource(Reader reader) { 113 setReader(reader); 114 } 115 116 /** 117 * Construct a StreamSource from a character reader. Normally, 118 * a stream should be used rather than a reader, so that 119 * the XML parser may resolve character encoding specified 120 * by the XML declaration. However, in many cases the encoding 121 * of the input stream is already resolved, as in the case of 122 * reading XML from a StringReader. 123 * 124 * @param reader A valid Reader reference to an XML character stream. 125 * @param systemId Must be a String that conforms to the URI syntax. 126 */ 127 public StreamSource(Reader reader, String systemId) { 128 setReader(reader); 129 setSystemId(systemId); 130 } 131 132 /** 133 * Construct a StreamSource from a URL. 134 * 135 * @param systemId Must be a String that conforms to the URI syntax. 136 */ 137 public StreamSource(String systemId) { 138 this.systemId = systemId; 139 } 140 141 /** 142 * Construct a StreamSource from a File. 143 * 144 * @param f Must a non-null File reference. 145 */ 146 public StreamSource(File f) { 147 //convert file to appropriate URI, f.toURI().toASCIIString() 148 //converts the URI to string as per rule specified in 149 //RFC 2396, 150 setSystemId(f.toURI().toASCIIString()); 151 } 152 153 /** 154 * Set the byte stream to be used as input. Normally, 155 * a stream should be used rather than a reader, so that 156 * the XML parser can resolve character encoding specified 157 * by the XML declaration. 158 * 159 * <p>If this Source object is used to process a stylesheet, normally 160 * setSystemId should also be called, so that relative URL references 161 * can be resolved.</p> 162 * 163 * @param inputStream A valid InputStream reference to an XML stream. 164 */ 165 public void setInputStream(InputStream inputStream) { 166 this.inputStream = inputStream; 167 } 168 169 /** 170 * Get the byte stream that was set with setByteStream. 171 * 172 * @return The byte stream that was set with setByteStream, or null 173 * if setByteStream or the ByteStream constructor was not called. 174 */ 175 public InputStream getInputStream() { 176 return inputStream; 177 } 178 179 /** 180 * Set the input to be a character reader. Normally, 181 * a stream should be used rather than a reader, so that 182 * the XML parser can resolve character encoding specified 183 * by the XML declaration. However, in many cases the encoding 184 * of the input stream is already resolved, as in the case of 185 * reading XML from a StringReader. 186 * 187 * @param reader A valid Reader reference to an XML CharacterStream. 188 */ 189 public void setReader(Reader reader) { 190 this.reader = reader; 191 } 192 193 /** 194 * Get the character stream that was set with setReader. 195 * 196 * @return The character stream that was set with setReader, or null 197 * if setReader or the Reader constructor was not called. 198 */ 199 public Reader getReader() { 200 return reader; 201 } 202 203 /** 204 * Set the public identifier for this Source. 205 * 206 * <p>The public identifier is always optional: if the application 207 * writer includes one, it will be provided as part of the 208 * location information.</p> 209 * 210 * @param publicId The public identifier as a string. 211 */ 212 public void setPublicId(String publicId) { 213 this.publicId = publicId; 214 } 215 216 /** 217 * Get the public identifier that was set with setPublicId. 218 * 219 * @return The public identifier that was set with setPublicId, or null 220 * if setPublicId was not called. 221 */ 222 public String getPublicId() { 223 return publicId; 224 } 225 226 /** 227 * Set the system identifier for this Source. 228 * 229 * <p>The system identifier is optional if there is a byte stream 230 * or a character stream, but it is still useful to provide one, 231 * since the application can use it to resolve relative URIs 232 * and can include it in error messages and warnings (the parser 233 * will attempt to open a connection to the URI only if 234 * there is no byte stream or character stream specified).</p> 235 * 236 * @param systemId The system identifier as a URL string. 237 */ 238 @Override 239 public void setSystemId(String systemId) { 240 this.systemId = systemId; 241 } 242 243 /** 244 * Get the system identifier that was set with setSystemId. 245 * 246 * @return The system identifier that was set with setSystemId, or null 247 * if setSystemId was not called. 248 */ 249 @Override 250 public String getSystemId() { 251 return systemId; 252 } 253 254 /** 255 * Set the system ID from a File reference. 256 * 257 * @param f Must a non-null File reference. 258 */ 259 public void setSystemId(File f) { 260 //convert file to appropriate URI, f.toURI().toASCIIString() 261 //converts the URI to string as per rule specified in 262 //RFC 2396, 263 this.systemId = f.toURI().toASCIIString(); 264 } 265 266 /** 267 * Indicates whether the {@code StreamSource} object is empty. Empty is 268 * defined as follows: 269 * <ul> 270 * <li>All of the input sources, including the public identifier, system 271 * identifier, byte stream, and character stream, are {@code null}. 272 * </li> 273 * <li>The public identifier and system identifier are {@code null}, and 274 * byte and character stream are either {@code null} or contain no byte or 275 * character. 276 * <p> 277 * Note that this method will reset the byte stream if it is provided, or 278 * the character stream if the byte stream is not provided. 279 * </li> 280 * </ul> 281 * <p> 282 * In case of error while checking the byte or character stream, the method 283 * will return false to allow the XML processor to handle the error. 284 * 285 * @return true if the {@code StreamSource} object is empty, false otherwise 286 */ 287 @Override 288 public boolean isEmpty() { 289 return (publicId == null && systemId == null && isStreamEmpty()); 290 } 291 292 private boolean isStreamEmpty() { 293 boolean empty = true; 294 try { 295 if (inputStream != null) { 296 inputStream.reset(); 297 int bytesRead = inputStream.available(); 298 if (bytesRead > 0) { 299 return false; 300 } 301 } 302 303 if (reader != null) { 304 reader.reset(); 305 int c = reader.read(); 306 reader.reset(); 307 if (c != -1) { 308 return false; 309 } 310 } 311 } catch (IOException ex) { 312 //in case of error, return false 313 return false; 314 } 315 316 return empty; 317 } 318 319 ////////////////////////////////////////////////////////////////////// 320 // Internal state. 321 ////////////////////////////////////////////////////////////////////// 322 323 /** 324 * The public identifier for this input source, or null. 325 */ 326 private String publicId; 327 328 /** 329 * The system identifier as a URL string, or null. 330 */ 331 private String systemId; 332 333 /** 334 * The byte stream for this Source, or null. 335 */ 336 private InputStream inputStream; 337 338 /** 339 * The character stream for this Source, or null. 340 */ 341 private Reader reader; 342 }