src/share/jaxws_classes/com/sun/xml/internal/org/jvnet/staxex/Base64Data.java

Tue, 06 Mar 2012 16:09:35 -0800

author
ohair
date
Tue, 06 Mar 2012 16:09:35 -0800
changeset 286
f50545b5e2f1
child 368
0989ad8c0860
permissions
-rw-r--r--

7150322: Stop using drop source bundles in jaxws
Reviewed-by: darcy, ohrstrom

ohair@286 1 /*
ohair@286 2 * Copyright (c) 1997, 2010, Oracle and/or its affiliates. All rights reserved.
ohair@286 3 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
ohair@286 4 *
ohair@286 5 * This code is free software; you can redistribute it and/or modify it
ohair@286 6 * under the terms of the GNU General Public License version 2 only, as
ohair@286 7 * published by the Free Software Foundation. Oracle designates this
ohair@286 8 * particular file as subject to the "Classpath" exception as provided
ohair@286 9 * by Oracle in the LICENSE file that accompanied this code.
ohair@286 10 *
ohair@286 11 * This code is distributed in the hope that it will be useful, but WITHOUT
ohair@286 12 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
ohair@286 13 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
ohair@286 14 * version 2 for more details (a copy is included in the LICENSE file that
ohair@286 15 * accompanied this code).
ohair@286 16 *
ohair@286 17 * You should have received a copy of the GNU General Public License version
ohair@286 18 * 2 along with this work; if not, write to the Free Software Foundation,
ohair@286 19 * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
ohair@286 20 *
ohair@286 21 * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
ohair@286 22 * or visit www.oracle.com if you need additional information or have any
ohair@286 23 * questions.
ohair@286 24 */
ohair@286 25
ohair@286 26 package com.sun.xml.internal.org.jvnet.staxex;
ohair@286 27
ohair@286 28 import javax.activation.DataHandler;
ohair@286 29 import javax.activation.DataSource;
ohair@286 30 import java.io.ByteArrayInputStream;
ohair@286 31 import java.io.ByteArrayOutputStream;
ohair@286 32 import java.io.File;
ohair@286 33 import java.io.FileOutputStream;
ohair@286 34 import java.io.IOException;
ohair@286 35 import java.io.InputStream;
ohair@286 36 import java.io.OutputStream;
ohair@286 37 import javax.xml.stream.XMLStreamException;
ohair@286 38 import javax.xml.stream.XMLStreamWriter;
ohair@286 39
ohair@286 40 // for testing method
ohair@286 41 //import com.sun.xml.internal.stream.writers.XMLStreamWriterImpl;
ohair@286 42 //import java.io.FileNotFoundException;
ohair@286 43 //import java.io.StringWriter;
ohair@286 44 //import javax.activation.FileDataSource;
ohair@286 45
ohair@286 46 /**
ohair@286 47 * Binary data represented as base64-encoded string
ohair@286 48 * in XML.
ohair@286 49 *
ohair@286 50 * <p>
ohair@286 51 * Used in conjunction with {@link XMLStreamReaderEx}
ohair@286 52 * and {@link XMLStreamWriterEx}.
ohair@286 53 *
ohair@286 54 * @author Kohsuke Kawaguchi, Martin Grebac
ohair@286 55 */
ohair@286 56 public class Base64Data implements CharSequence, Cloneable {
ohair@286 57
ohair@286 58 // either dataHandler or (data,dataLen,mimeType?) must be present
ohair@286 59 // (note that having both is allowed)
ohair@286 60
ohair@286 61 private DataHandler dataHandler;
ohair@286 62
ohair@286 63 private byte[] data;
ohair@286 64 /**
ohair@286 65 * Length of the valid data in {@link #data}.
ohair@286 66 */
ohair@286 67 private int dataLen;
ohair@286 68 /**
ohair@286 69 * True if {@link #data} can be cloned by reference
ohair@286 70 * if Base64Data instance is cloned.
ohair@286 71 */
ohair@286 72 private boolean dataCloneByRef;
ohair@286 73 /**
ohair@286 74 * Optional MIME type of {@link #data}.
ohair@286 75 *
ohair@286 76 * Unused when {@link #dataHandler} is set.
ohair@286 77 * Use {@link DataHandler#getContentType()} in that case.
ohair@286 78 */
ohair@286 79 private String mimeType;
ohair@286 80
ohair@286 81 /**
ohair@286 82 * Default constructor
ohair@286 83 */
ohair@286 84 public Base64Data() {
ohair@286 85 }
ohair@286 86
ohair@286 87 /**
ohair@286 88 * Clone constructor
ohair@286 89 * @param that needs to be cloned
ohair@286 90 */
ohair@286 91 public Base64Data(Base64Data that) {
ohair@286 92 that.get();
ohair@286 93 if (that.dataCloneByRef) {
ohair@286 94 this.data = that.data;
ohair@286 95 } else {
ohair@286 96 this.data = new byte[that.dataLen];
ohair@286 97 System.arraycopy(that.data, 0, this.data, 0, that.dataLen);
ohair@286 98 }
ohair@286 99
ohair@286 100 this.dataCloneByRef = true;
ohair@286 101 this.dataLen = that.dataLen;
ohair@286 102 this.dataHandler = null;
ohair@286 103 this.mimeType = that.mimeType;
ohair@286 104 }
ohair@286 105
ohair@286 106 /**
ohair@286 107 * Fills in the data object by a portion of the byte[].
ohair@286 108 *
ohair@286 109 * @param data actual data
ohair@286 110 * @param len
ohair@286 111 * data[0] to data[len-1] are treated as the data.
ohair@286 112 * @param mimeType MIME type
ohair@286 113 * @param cloneByRef
ohair@286 114 * true if data[] can be cloned by reference
ohair@286 115 */
ohair@286 116 public void set(byte[] data, int len, String mimeType, boolean cloneByRef) {
ohair@286 117 this.data = data;
ohair@286 118 this.dataLen = len;
ohair@286 119 this.dataCloneByRef = cloneByRef;
ohair@286 120 this.dataHandler = null;
ohair@286 121 this.mimeType = mimeType;
ohair@286 122 }
ohair@286 123
ohair@286 124 /**
ohair@286 125 * Fills in the data object by a portion of the byte[].
ohair@286 126 *
ohair@286 127 * @param data actual data bytes
ohair@286 128 * @param len
ohair@286 129 * data[0] to data[len-1] are treated as the data.
ohair@286 130 * @param mimeType MIME type
ohair@286 131 */
ohair@286 132 public void set(byte[] data, int len, String mimeType) {
ohair@286 133 set(data,len,mimeType,false);
ohair@286 134 }
ohair@286 135
ohair@286 136 /**
ohair@286 137 * Fills in the data object by the byte[] of the exact length.
ohair@286 138 *
ohair@286 139 * @param data
ohair@286 140 * this buffer may be owned directly by the unmarshaleld JAXB object.
ohair@286 141 * @param mimeType MIME type
ohair@286 142 */
ohair@286 143 public void set(byte[] data,String mimeType) {
ohair@286 144 set(data,data.length,mimeType,false);
ohair@286 145 }
ohair@286 146
ohair@286 147 /**
ohair@286 148 * Fills in the data object by a {@link DataHandler}.
ohair@286 149 *
ohair@286 150 * @param data DataHandler for the data
ohair@286 151 */
ohair@286 152 public void set(DataHandler data) {
ohair@286 153 assert data!=null;
ohair@286 154 this.dataHandler = data;
ohair@286 155 this.data = null;
ohair@286 156 }
ohair@286 157
ohair@286 158 /**
ohair@286 159 * Gets the raw data. If the returned DataHandler is {@link StreamingDataHandler},
ohair@286 160 * callees may need to downcast to take advantage of its capabilities.
ohair@286 161 *
ohair@286 162 * @see StreamingDataHandler
ohair@286 163 * @return DataHandler for the data
ohair@286 164 */
ohair@286 165 public DataHandler getDataHandler() {
ohair@286 166 if(dataHandler==null){
ohair@286 167 dataHandler = new Base64StreamingDataHandler(new Base64DataSource());
ohair@286 168 } else if (!(dataHandler instanceof StreamingDataHandler)) {
ohair@286 169 dataHandler = new FilterDataHandler(dataHandler);
ohair@286 170 }
ohair@286 171 return dataHandler;
ohair@286 172 }
ohair@286 173
ohair@286 174 private final class Base64DataSource implements DataSource {
ohair@286 175 public String getContentType() {
ohair@286 176 return getMimeType();
ohair@286 177 }
ohair@286 178
ohair@286 179 public InputStream getInputStream() {
ohair@286 180 return new ByteArrayInputStream(data,0,dataLen);
ohair@286 181 }
ohair@286 182
ohair@286 183 public String getName() {
ohair@286 184 return null;
ohair@286 185 }
ohair@286 186
ohair@286 187 public OutputStream getOutputStream() {
ohair@286 188 throw new UnsupportedOperationException();
ohair@286 189 }
ohair@286 190
ohair@286 191 }
ohair@286 192
ohair@286 193 private final class Base64StreamingDataHandler extends StreamingDataHandler {
ohair@286 194
ohair@286 195 Base64StreamingDataHandler(DataSource source) {
ohair@286 196 super(source);
ohair@286 197 }
ohair@286 198
ohair@286 199 public InputStream readOnce() throws IOException {
ohair@286 200 return getDataSource().getInputStream();
ohair@286 201 }
ohair@286 202
ohair@286 203 public void moveTo(File dst) throws IOException {
ohair@286 204 FileOutputStream fout = new FileOutputStream(dst);
ohair@286 205 try {
ohair@286 206 fout.write(data, 0, dataLen);
ohair@286 207 } finally {
ohair@286 208 fout.close();
ohair@286 209 }
ohair@286 210 }
ohair@286 211
ohair@286 212 public void close() throws IOException {
ohair@286 213 // nothing to do
ohair@286 214 }
ohair@286 215 }
ohair@286 216
ohair@286 217 private static final class FilterDataHandler extends StreamingDataHandler {
ohair@286 218
ohair@286 219 FilterDataHandler(DataHandler dh) {
ohair@286 220 super(dh.getDataSource());
ohair@286 221 }
ohair@286 222
ohair@286 223 public InputStream readOnce() throws IOException {
ohair@286 224 return getDataSource().getInputStream();
ohair@286 225 }
ohair@286 226
ohair@286 227 public void moveTo(File dst) throws IOException {
ohair@286 228 byte[] buf = new byte[8192];
ohair@286 229 InputStream in = null;
ohair@286 230 OutputStream out = null;
ohair@286 231 try {
ohair@286 232 in = getDataSource().getInputStream();
ohair@286 233 out = new FileOutputStream(dst);
ohair@286 234 while (true) {
ohair@286 235 int amountRead = in.read(buf);
ohair@286 236 if (amountRead == -1) {
ohair@286 237 break;
ohair@286 238 }
ohair@286 239 out.write(buf, 0, amountRead);
ohair@286 240 }
ohair@286 241 } finally {
ohair@286 242 if (in != null) {
ohair@286 243 try {
ohair@286 244 in.close();
ohair@286 245 } catch(IOException ioe) {
ohair@286 246 // nothing to do
ohair@286 247 }
ohair@286 248 }
ohair@286 249 if (out != null) {
ohair@286 250 try {
ohair@286 251 out.close();
ohair@286 252 } catch(IOException ioe) {
ohair@286 253 // nothing to do
ohair@286 254 }
ohair@286 255 }
ohair@286 256 }
ohair@286 257 }
ohair@286 258
ohair@286 259 public void close() throws IOException {
ohair@286 260 // nothing to do
ohair@286 261 }
ohair@286 262 }
ohair@286 263
ohair@286 264 /**
ohair@286 265 * Gets the byte[] of the exact length.
ohair@286 266 *
ohair@286 267 * @return byte[] for data
ohair@286 268 */
ohair@286 269 public byte[] getExact() {
ohair@286 270 get();
ohair@286 271 if(dataLen!=data.length) {
ohair@286 272 byte[] buf = new byte[dataLen];
ohair@286 273 System.arraycopy(data,0,buf,0,dataLen);
ohair@286 274 data = buf;
ohair@286 275 }
ohair@286 276 return data;
ohair@286 277 }
ohair@286 278
ohair@286 279 /**
ohair@286 280 * Gets the data as an {@link InputStream}.
ohair@286 281 *
ohair@286 282 * @return data as InputStream
ohair@286 283 * @throws IOException if i/o error occurs
ohair@286 284 */
ohair@286 285 public InputStream getInputStream() throws IOException {
ohair@286 286 if(dataHandler!=null)
ohair@286 287 return dataHandler.getInputStream();
ohair@286 288 else
ohair@286 289 return new ByteArrayInputStream(data,0,dataLen);
ohair@286 290 }
ohair@286 291
ohair@286 292 /**
ohair@286 293 * Returns false if this object only has {@link DataHandler} and therefore
ohair@286 294 * {@link #get()} operation is likely going to be expensive.
ohair@286 295 *
ohair@286 296 * @return false if it has only DataHandler
ohair@286 297 */
ohair@286 298 public boolean hasData() {
ohair@286 299 return data!=null;
ohair@286 300 }
ohair@286 301
ohair@286 302 /**
ohair@286 303 * Gets the raw data. The size of the byte array maybe larger than the actual length.
ohair@286 304 *
ohair@286 305 * @return data as byte[], the array may be larger
ohair@286 306 */
ohair@286 307 public byte[] get() {
ohair@286 308 if(data==null) {
ohair@286 309 try {
ohair@286 310 ByteArrayOutputStreamEx baos = new ByteArrayOutputStreamEx(1024);
ohair@286 311 InputStream is = dataHandler.getDataSource().getInputStream();
ohair@286 312 baos.readFrom(is);
ohair@286 313 is.close();
ohair@286 314 data = baos.getBuffer();
ohair@286 315 dataLen = baos.size();
ohair@286 316 dataCloneByRef = true;
ohair@286 317 } catch (IOException e) {
ohair@286 318 // TODO: report the error to the unmarshaller
ohair@286 319 dataLen = 0; // recover by assuming length-0 data
ohair@286 320 }
ohair@286 321 }
ohair@286 322 return data;
ohair@286 323 }
ohair@286 324
ohair@286 325 /**
ohair@286 326 * Gets the length of the binary data counted in bytes.
ohair@286 327 *
ohair@286 328 * Note that if this object encapsulates {@link DataHandler},
ohair@286 329 * this method would have to read the whole thing into {@code byte[]}
ohair@286 330 * just to count the length, because {@link DataHandler}
ohair@286 331 * doesn't easily expose the length.
ohair@286 332 *
ohair@286 333 * @return no of bytes
ohair@286 334 */
ohair@286 335 public int getDataLen() {
ohair@286 336 get();
ohair@286 337 return dataLen;
ohair@286 338 }
ohair@286 339
ohair@286 340 public String getMimeType() {
ohair@286 341 if(mimeType==null)
ohair@286 342 return "application/octet-stream";
ohair@286 343 return mimeType;
ohair@286 344 }
ohair@286 345
ohair@286 346 /**
ohair@286 347 * Gets the number of characters needed to represent
ohair@286 348 * this binary data in the base64 encoding.
ohair@286 349 */
ohair@286 350 public int length() {
ohair@286 351 // for each 3 bytes you use 4 chars
ohair@286 352 // if the remainder is 1 or 2 there will be 4 more
ohair@286 353 get(); // fill in the buffer if necessary
ohair@286 354 return ((dataLen+2)/3)*4;
ohair@286 355 }
ohair@286 356
ohair@286 357 /**
ohair@286 358 * Encode this binary data in the base64 encoding
ohair@286 359 * and returns the character at the specified position.
ohair@286 360 */
ohair@286 361 public char charAt(int index) {
ohair@286 362 // we assume that the length() method is called before this method
ohair@286 363 // (otherwise how would the caller know that the index is valid?)
ohair@286 364 // so we assume that the byte[] is already populated
ohair@286 365
ohair@286 366 int offset = index%4;
ohair@286 367 int base = (index/4)*3;
ohair@286 368
ohair@286 369 byte b1,b2;
ohair@286 370
ohair@286 371 switch(offset) {
ohair@286 372 case 0:
ohair@286 373 return Base64Encoder.encode(data[base]>>2);
ohair@286 374 case 1:
ohair@286 375 if(base+1<dataLen)
ohair@286 376 b1 = data[base+1];
ohair@286 377 else
ohair@286 378 b1 = 0;
ohair@286 379 return Base64Encoder.encode(
ohair@286 380 ((data[base]&0x3)<<4) |
ohair@286 381 ((b1>>4)&0xF));
ohair@286 382 case 2:
ohair@286 383 if(base+1<dataLen) {
ohair@286 384 b1 = data[base+1];
ohair@286 385 if(base+2<dataLen)
ohair@286 386 b2 = data[base+2];
ohair@286 387 else
ohair@286 388 b2 = 0;
ohair@286 389
ohair@286 390 return Base64Encoder.encode(
ohair@286 391 ((b1&0xF)<<2)|
ohair@286 392 ((b2>>6)&0x3));
ohair@286 393 } else
ohair@286 394 return '=';
ohair@286 395 case 3:
ohair@286 396 if(base+2<dataLen)
ohair@286 397 return Base64Encoder.encode(data[base+2]&0x3F);
ohair@286 398 else
ohair@286 399 return '=';
ohair@286 400 }
ohair@286 401
ohair@286 402 throw new IllegalStateException();
ohair@286 403 }
ohair@286 404
ohair@286 405 /**
ohair@286 406 * Internally this is only used to split a text to a list,
ohair@286 407 * which doesn't happen that much for base64.
ohair@286 408 * So this method should be smaller than faster.
ohair@286 409 */
ohair@286 410 public CharSequence subSequence(int start, int end) {
ohair@286 411 StringBuilder buf = new StringBuilder();
ohair@286 412 get(); // fill in the buffer if we haven't done so
ohair@286 413 for( int i=start; i<end; i++ )
ohair@286 414 buf.append(charAt(i));
ohair@286 415 return buf;
ohair@286 416 }
ohair@286 417
ohair@286 418 /**
ohair@286 419 * Returns the base64 encoded string of this data.
ohair@286 420 */
ohair@286 421 @Override
ohair@286 422 public String toString() {
ohair@286 423 get(); // fill in the buffer
ohair@286 424 return Base64Encoder.print(data, 0, dataLen);
ohair@286 425 }
ohair@286 426
ohair@286 427 public void writeTo(char[] buf, int start) {
ohair@286 428 get();
ohair@286 429 Base64Encoder.print(data, 0, dataLen, buf, start);
ohair@286 430 }
ohair@286 431
ohair@286 432 public void writeTo(XMLStreamWriter output) throws IOException, XMLStreamException {
ohair@286 433 if (data==null) {
ohair@286 434 try {
ohair@286 435 InputStream is = dataHandler.getDataSource().getInputStream();
ohair@286 436 ByteArrayOutputStream outStream = new ByteArrayOutputStream(); // dev-null stream
ohair@286 437 Base64EncoderStream encWriter = new Base64EncoderStream(output, outStream);
ohair@286 438 int b = -1;
ohair@286 439 while ((b = is.read()) != -1) {
ohair@286 440 encWriter.write(b);
ohair@286 441 }
ohair@286 442 outStream.close();
ohair@286 443 encWriter.close();
ohair@286 444 } catch (IOException e) {
ohair@286 445 dataLen = 0; // recover by assuming length-0 data
ohair@286 446 throw e;
ohair@286 447 }
ohair@286 448 } else {
ohair@286 449 // the data is already in memory and not streamed
ohair@286 450 String s = Base64Encoder.print(data, 0, dataLen);
ohair@286 451 output.writeCharacters(s);
ohair@286 452 }
ohair@286 453 }
ohair@286 454
ohair@286 455 @Override
ohair@286 456 public Base64Data clone() {
ohair@286 457 return new Base64Data(this);
ohair@286 458 }
ohair@286 459
ohair@286 460 // public static void main(String[] args) throws FileNotFoundException, IOException, XMLStreamException {
ohair@286 461 // Base64Data data = new Base64Data();
ohair@286 462 //
ohair@286 463 // data.set(new DataHandler(new FileDataSource(new File("/home/snajper/Desktop/a.txt"))));
ohair@286 464 //
ohair@286 465 // StringWriter sw = new StringWriter();
ohair@286 466 // XMLStreamWriterImpl wi = new XMLStreamWriterImpl(sw, null);
ohair@286 467 //
ohair@286 468 // data.writeTo(wi);
ohair@286 469 // wi.flush();sw.flush();
ohair@286 470 // System.out.println("SW: " + sw.toString());
ohair@286 471 //
ohair@286 472 // }
ohair@286 473
ohair@286 474 }

mercurial