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

Fri, 04 Oct 2013 16:21:34 +0100

author
mkos
date
Fri, 04 Oct 2013 16:21:34 +0100
changeset 408
b0610cd08440
parent 368
0989ad8c0860
child 637
9c07ef4934dd
permissions
-rw-r--r--

8025054: Update JAX-WS RI integration to 2.2.9-b130926.1035
Reviewed-by: chegar

ohair@286 1 /*
alanb@368 2 * Copyright (c) 1997, 2012, 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;
alanb@368 39 import java.util.logging.Level;
alanb@368 40 import java.util.logging.Logger;
ohair@286 41
ohair@286 42 // for testing method
ohair@286 43 //import com.sun.xml.internal.stream.writers.XMLStreamWriterImpl;
ohair@286 44 //import java.io.FileNotFoundException;
alanb@368 45 //import java.io.FileWriter;
ohair@286 46 //import javax.activation.FileDataSource;
ohair@286 47
ohair@286 48 /**
ohair@286 49 * Binary data represented as base64-encoded string
ohair@286 50 * in XML.
ohair@286 51 *
ohair@286 52 * <p>
ohair@286 53 * Used in conjunction with {@link XMLStreamReaderEx}
ohair@286 54 * and {@link XMLStreamWriterEx}.
ohair@286 55 *
ohair@286 56 * @author Kohsuke Kawaguchi, Martin Grebac
ohair@286 57 */
ohair@286 58 public class Base64Data implements CharSequence, Cloneable {
ohair@286 59
ohair@286 60 // either dataHandler or (data,dataLen,mimeType?) must be present
ohair@286 61 // (note that having both is allowed)
ohair@286 62
ohair@286 63 private DataHandler dataHandler;
alanb@368 64 private byte[] data;
ohair@286 65
ohair@286 66 /**
ohair@286 67 * Length of the valid data in {@link #data}.
ohair@286 68 */
ohair@286 69 private int dataLen;
ohair@286 70 /**
ohair@286 71 * True if {@link #data} can be cloned by reference
ohair@286 72 * if Base64Data instance is cloned.
ohair@286 73 */
ohair@286 74 private boolean dataCloneByRef;
ohair@286 75 /**
ohair@286 76 * Optional MIME type of {@link #data}.
ohair@286 77 *
ohair@286 78 * Unused when {@link #dataHandler} is set.
ohair@286 79 * Use {@link DataHandler#getContentType()} in that case.
ohair@286 80 */
ohair@286 81 private String mimeType;
ohair@286 82
ohair@286 83 /**
ohair@286 84 * Default constructor
ohair@286 85 */
ohair@286 86 public Base64Data() {
ohair@286 87 }
ohair@286 88
alanb@368 89 private static final Logger logger = Logger.getLogger(Base64Data.class.getName());
alanb@368 90
ohair@286 91 /**
ohair@286 92 * Clone constructor
ohair@286 93 * @param that needs to be cloned
ohair@286 94 */
ohair@286 95 public Base64Data(Base64Data that) {
ohair@286 96 that.get();
ohair@286 97 if (that.dataCloneByRef) {
ohair@286 98 this.data = that.data;
ohair@286 99 } else {
ohair@286 100 this.data = new byte[that.dataLen];
ohair@286 101 System.arraycopy(that.data, 0, this.data, 0, that.dataLen);
ohair@286 102 }
ohair@286 103
ohair@286 104 this.dataCloneByRef = true;
ohair@286 105 this.dataLen = that.dataLen;
ohair@286 106 this.dataHandler = null;
ohair@286 107 this.mimeType = that.mimeType;
ohair@286 108 }
ohair@286 109
ohair@286 110 /**
ohair@286 111 * Fills in the data object by a portion of the byte[].
ohair@286 112 *
ohair@286 113 * @param data actual data
ohair@286 114 * @param len
ohair@286 115 * data[0] to data[len-1] are treated as the data.
ohair@286 116 * @param mimeType MIME type
ohair@286 117 * @param cloneByRef
ohair@286 118 * true if data[] can be cloned by reference
ohair@286 119 */
ohair@286 120 public void set(byte[] data, int len, String mimeType, boolean cloneByRef) {
ohair@286 121 this.data = data;
ohair@286 122 this.dataLen = len;
ohair@286 123 this.dataCloneByRef = cloneByRef;
ohair@286 124 this.dataHandler = null;
ohair@286 125 this.mimeType = mimeType;
ohair@286 126 }
ohair@286 127
ohair@286 128 /**
ohair@286 129 * Fills in the data object by a portion of the byte[].
ohair@286 130 *
ohair@286 131 * @param data actual data bytes
ohair@286 132 * @param len
ohair@286 133 * data[0] to data[len-1] are treated as the data.
ohair@286 134 * @param mimeType MIME type
ohair@286 135 */
ohair@286 136 public void set(byte[] data, int len, String mimeType) {
ohair@286 137 set(data,len,mimeType,false);
ohair@286 138 }
ohair@286 139
ohair@286 140 /**
ohair@286 141 * Fills in the data object by the byte[] of the exact length.
ohair@286 142 *
ohair@286 143 * @param data
ohair@286 144 * this buffer may be owned directly by the unmarshaleld JAXB object.
ohair@286 145 * @param mimeType MIME type
ohair@286 146 */
ohair@286 147 public void set(byte[] data,String mimeType) {
ohair@286 148 set(data,data.length,mimeType,false);
ohair@286 149 }
ohair@286 150
ohair@286 151 /**
ohair@286 152 * Fills in the data object by a {@link DataHandler}.
ohair@286 153 *
ohair@286 154 * @param data DataHandler for the data
ohair@286 155 */
ohair@286 156 public void set(DataHandler data) {
ohair@286 157 assert data!=null;
ohair@286 158 this.dataHandler = data;
ohair@286 159 this.data = null;
ohair@286 160 }
ohair@286 161
ohair@286 162 /**
ohair@286 163 * Gets the raw data. If the returned DataHandler is {@link StreamingDataHandler},
ohair@286 164 * callees may need to downcast to take advantage of its capabilities.
ohair@286 165 *
ohair@286 166 * @see StreamingDataHandler
ohair@286 167 * @return DataHandler for the data
ohair@286 168 */
ohair@286 169 public DataHandler getDataHandler() {
ohair@286 170 if(dataHandler==null){
ohair@286 171 dataHandler = new Base64StreamingDataHandler(new Base64DataSource());
ohair@286 172 } else if (!(dataHandler instanceof StreamingDataHandler)) {
ohair@286 173 dataHandler = new FilterDataHandler(dataHandler);
ohair@286 174 }
ohair@286 175 return dataHandler;
ohair@286 176 }
ohair@286 177
ohair@286 178 private final class Base64DataSource implements DataSource {
ohair@286 179 public String getContentType() {
ohair@286 180 return getMimeType();
ohair@286 181 }
ohair@286 182
ohair@286 183 public InputStream getInputStream() {
ohair@286 184 return new ByteArrayInputStream(data,0,dataLen);
ohair@286 185 }
ohair@286 186
ohair@286 187 public String getName() {
ohair@286 188 return null;
ohair@286 189 }
ohair@286 190
ohair@286 191 public OutputStream getOutputStream() {
ohair@286 192 throw new UnsupportedOperationException();
ohair@286 193 }
ohair@286 194
ohair@286 195 }
ohair@286 196
ohair@286 197 private final class Base64StreamingDataHandler extends StreamingDataHandler {
ohair@286 198
ohair@286 199 Base64StreamingDataHandler(DataSource source) {
ohair@286 200 super(source);
ohair@286 201 }
ohair@286 202
ohair@286 203 public InputStream readOnce() throws IOException {
ohair@286 204 return getDataSource().getInputStream();
ohair@286 205 }
ohair@286 206
ohair@286 207 public void moveTo(File dst) throws IOException {
ohair@286 208 FileOutputStream fout = new FileOutputStream(dst);
ohair@286 209 try {
ohair@286 210 fout.write(data, 0, dataLen);
ohair@286 211 } finally {
ohair@286 212 fout.close();
ohair@286 213 }
ohair@286 214 }
ohair@286 215
ohair@286 216 public void close() throws IOException {
ohair@286 217 // nothing to do
ohair@286 218 }
ohair@286 219 }
ohair@286 220
ohair@286 221 private static final class FilterDataHandler extends StreamingDataHandler {
ohair@286 222
ohair@286 223 FilterDataHandler(DataHandler dh) {
ohair@286 224 super(dh.getDataSource());
ohair@286 225 }
ohair@286 226
ohair@286 227 public InputStream readOnce() throws IOException {
ohair@286 228 return getDataSource().getInputStream();
ohair@286 229 }
ohair@286 230
ohair@286 231 public void moveTo(File dst) throws IOException {
ohair@286 232 byte[] buf = new byte[8192];
ohair@286 233 InputStream in = null;
ohair@286 234 OutputStream out = null;
ohair@286 235 try {
ohair@286 236 in = getDataSource().getInputStream();
ohair@286 237 out = new FileOutputStream(dst);
ohair@286 238 while (true) {
ohair@286 239 int amountRead = in.read(buf);
ohair@286 240 if (amountRead == -1) {
ohair@286 241 break;
ohair@286 242 }
ohair@286 243 out.write(buf, 0, amountRead);
ohair@286 244 }
ohair@286 245 } finally {
ohair@286 246 if (in != null) {
ohair@286 247 try {
ohair@286 248 in.close();
ohair@286 249 } catch(IOException ioe) {
ohair@286 250 // nothing to do
ohair@286 251 }
ohair@286 252 }
ohair@286 253 if (out != null) {
ohair@286 254 try {
ohair@286 255 out.close();
ohair@286 256 } catch(IOException ioe) {
ohair@286 257 // nothing to do
ohair@286 258 }
ohair@286 259 }
ohair@286 260 }
ohair@286 261 }
ohair@286 262
ohair@286 263 public void close() throws IOException {
ohair@286 264 // nothing to do
ohair@286 265 }
ohair@286 266 }
ohair@286 267
ohair@286 268 /**
ohair@286 269 * Gets the byte[] of the exact length.
ohair@286 270 *
ohair@286 271 * @return byte[] for data
ohair@286 272 */
ohair@286 273 public byte[] getExact() {
ohair@286 274 get();
ohair@286 275 if(dataLen!=data.length) {
ohair@286 276 byte[] buf = new byte[dataLen];
ohair@286 277 System.arraycopy(data,0,buf,0,dataLen);
ohair@286 278 data = buf;
ohair@286 279 }
ohair@286 280 return data;
ohair@286 281 }
ohair@286 282
ohair@286 283 /**
ohair@286 284 * Gets the data as an {@link InputStream}.
ohair@286 285 *
ohair@286 286 * @return data as InputStream
ohair@286 287 * @throws IOException if i/o error occurs
ohair@286 288 */
ohair@286 289 public InputStream getInputStream() throws IOException {
mkos@408 290 if(dataHandler!=null) {
ohair@286 291 return dataHandler.getInputStream();
mkos@408 292 } else {
ohair@286 293 return new ByteArrayInputStream(data,0,dataLen);
mkos@408 294 }
ohair@286 295 }
ohair@286 296
ohair@286 297 /**
ohair@286 298 * Returns false if this object only has {@link DataHandler} and therefore
ohair@286 299 * {@link #get()} operation is likely going to be expensive.
ohair@286 300 *
ohair@286 301 * @return false if it has only DataHandler
ohair@286 302 */
ohair@286 303 public boolean hasData() {
ohair@286 304 return data!=null;
ohair@286 305 }
ohair@286 306
ohair@286 307 /**
ohair@286 308 * Gets the raw data. The size of the byte array maybe larger than the actual length.
ohair@286 309 *
ohair@286 310 * @return data as byte[], the array may be larger
ohair@286 311 */
ohair@286 312 public byte[] get() {
ohair@286 313 if(data==null) {
ohair@286 314 try {
ohair@286 315 ByteArrayOutputStreamEx baos = new ByteArrayOutputStreamEx(1024);
ohair@286 316 InputStream is = dataHandler.getDataSource().getInputStream();
ohair@286 317 baos.readFrom(is);
ohair@286 318 is.close();
ohair@286 319 data = baos.getBuffer();
ohair@286 320 dataLen = baos.size();
ohair@286 321 dataCloneByRef = true;
ohair@286 322 } catch (IOException e) {
ohair@286 323 // TODO: report the error to the unmarshaller
ohair@286 324 dataLen = 0; // recover by assuming length-0 data
ohair@286 325 }
ohair@286 326 }
ohair@286 327 return data;
ohair@286 328 }
ohair@286 329
ohair@286 330 /**
ohair@286 331 * Gets the length of the binary data counted in bytes.
ohair@286 332 *
ohair@286 333 * Note that if this object encapsulates {@link DataHandler},
ohair@286 334 * this method would have to read the whole thing into {@code byte[]}
ohair@286 335 * just to count the length, because {@link DataHandler}
ohair@286 336 * doesn't easily expose the length.
ohair@286 337 *
ohair@286 338 * @return no of bytes
ohair@286 339 */
ohair@286 340 public int getDataLen() {
ohair@286 341 get();
ohair@286 342 return dataLen;
ohair@286 343 }
ohair@286 344
ohair@286 345 public String getMimeType() {
mkos@408 346 if (mimeType==null) {
ohair@286 347 return "application/octet-stream";
mkos@408 348 }
ohair@286 349 return mimeType;
ohair@286 350 }
ohair@286 351
ohair@286 352 /**
ohair@286 353 * Gets the number of characters needed to represent
ohair@286 354 * this binary data in the base64 encoding.
ohair@286 355 */
ohair@286 356 public int length() {
ohair@286 357 // for each 3 bytes you use 4 chars
ohair@286 358 // if the remainder is 1 or 2 there will be 4 more
ohair@286 359 get(); // fill in the buffer if necessary
ohair@286 360 return ((dataLen+2)/3)*4;
ohair@286 361 }
ohair@286 362
ohair@286 363 /**
ohair@286 364 * Encode this binary data in the base64 encoding
ohair@286 365 * and returns the character at the specified position.
ohair@286 366 */
ohair@286 367 public char charAt(int index) {
ohair@286 368 // we assume that the length() method is called before this method
ohair@286 369 // (otherwise how would the caller know that the index is valid?)
ohair@286 370 // so we assume that the byte[] is already populated
ohair@286 371
ohair@286 372 int offset = index%4;
ohair@286 373 int base = (index/4)*3;
ohair@286 374
ohair@286 375 byte b1,b2;
ohair@286 376
ohair@286 377 switch(offset) {
ohair@286 378 case 0:
ohair@286 379 return Base64Encoder.encode(data[base]>>2);
ohair@286 380 case 1:
mkos@408 381 if (base+1<dataLen) {
ohair@286 382 b1 = data[base+1];
mkos@408 383 } else {
ohair@286 384 b1 = 0;
mkos@408 385 }
ohair@286 386 return Base64Encoder.encode(
ohair@286 387 ((data[base]&0x3)<<4) |
ohair@286 388 ((b1>>4)&0xF));
ohair@286 389 case 2:
mkos@408 390 if (base+1<dataLen) {
ohair@286 391 b1 = data[base+1];
mkos@408 392 if (base+2<dataLen) {
ohair@286 393 b2 = data[base+2];
mkos@408 394 } else {
ohair@286 395 b2 = 0;
mkos@408 396 }
ohair@286 397
ohair@286 398 return Base64Encoder.encode(
ohair@286 399 ((b1&0xF)<<2)|
ohair@286 400 ((b2>>6)&0x3));
mkos@408 401 } else {
ohair@286 402 return '=';
mkos@408 403 }
ohair@286 404 case 3:
mkos@408 405 if(base+2<dataLen) {
ohair@286 406 return Base64Encoder.encode(data[base+2]&0x3F);
mkos@408 407 } else {
ohair@286 408 return '=';
mkos@408 409 }
ohair@286 410 }
ohair@286 411
ohair@286 412 throw new IllegalStateException();
ohair@286 413 }
ohair@286 414
ohair@286 415 /**
ohair@286 416 * Internally this is only used to split a text to a list,
ohair@286 417 * which doesn't happen that much for base64.
ohair@286 418 * So this method should be smaller than faster.
ohair@286 419 */
ohair@286 420 public CharSequence subSequence(int start, int end) {
ohair@286 421 StringBuilder buf = new StringBuilder();
ohair@286 422 get(); // fill in the buffer if we haven't done so
mkos@408 423 for (int i=start; i<end; i++ ) {
ohair@286 424 buf.append(charAt(i));
mkos@408 425 }
ohair@286 426 return buf;
ohair@286 427 }
ohair@286 428
ohair@286 429 /**
ohair@286 430 * Returns the base64 encoded string of this data.
ohair@286 431 */
ohair@286 432 @Override
ohair@286 433 public String toString() {
ohair@286 434 get(); // fill in the buffer
ohair@286 435 return Base64Encoder.print(data, 0, dataLen);
ohair@286 436 }
ohair@286 437
ohair@286 438 public void writeTo(char[] buf, int start) {
ohair@286 439 get();
ohair@286 440 Base64Encoder.print(data, 0, dataLen, buf, start);
ohair@286 441 }
ohair@286 442
alanb@368 443 private static final int CHUNK_SIZE;
alanb@368 444 static {
alanb@368 445 int bufSize = 1024;
alanb@368 446 try {
alanb@368 447 String bufSizeStr = getProperty("com.sun.xml.internal.org.jvnet.staxex.Base64DataStreamWriteBufferSize");
alanb@368 448 if (bufSizeStr != null) {
alanb@368 449 bufSize = Integer.parseInt(bufSizeStr);
alanb@368 450 }
alanb@368 451 } catch (Exception e) {
alanb@368 452 logger.log(Level.INFO, "Error reading com.sun.xml.internal.org.jvnet.staxex.Base64DataStreamWriteBufferSize property", e);
alanb@368 453 }
alanb@368 454 CHUNK_SIZE = bufSize;
alanb@368 455 }
alanb@368 456
ohair@286 457 public void writeTo(XMLStreamWriter output) throws IOException, XMLStreamException {
ohair@286 458 if (data==null) {
ohair@286 459 try {
ohair@286 460 InputStream is = dataHandler.getDataSource().getInputStream();
ohair@286 461 ByteArrayOutputStream outStream = new ByteArrayOutputStream(); // dev-null stream
ohair@286 462 Base64EncoderStream encWriter = new Base64EncoderStream(output, outStream);
alanb@368 463 int b;
alanb@368 464 byte[] buffer = new byte[CHUNK_SIZE];
alanb@368 465 while ((b = is.read(buffer)) != -1) {
alanb@368 466 encWriter.write(buffer, 0, b);
ohair@286 467 }
ohair@286 468 outStream.close();
ohair@286 469 encWriter.close();
ohair@286 470 } catch (IOException e) {
ohair@286 471 dataLen = 0; // recover by assuming length-0 data
ohair@286 472 throw e;
ohair@286 473 }
ohair@286 474 } else {
ohair@286 475 // the data is already in memory and not streamed
ohair@286 476 String s = Base64Encoder.print(data, 0, dataLen);
ohair@286 477 output.writeCharacters(s);
ohair@286 478 }
ohair@286 479 }
ohair@286 480
ohair@286 481 @Override
ohair@286 482 public Base64Data clone() {
mkos@408 483 try {
mkos@408 484 Base64Data clone = (Base64Data) super.clone();
mkos@408 485 clone.get();
mkos@408 486 if (clone.dataCloneByRef) {
mkos@408 487 this.data = clone.data;
mkos@408 488 } else {
mkos@408 489 this.data = new byte[clone.dataLen];
mkos@408 490 System.arraycopy(clone.data, 0, this.data, 0, clone.dataLen);
mkos@408 491 }
mkos@408 492
mkos@408 493 this.dataCloneByRef = true;
mkos@408 494 this.dataLen = clone.dataLen;
mkos@408 495 this.dataHandler = null;
mkos@408 496 this.mimeType = clone.mimeType;
mkos@408 497 return clone;
mkos@408 498 } catch (CloneNotSupportedException ex) {
mkos@408 499 Logger.getLogger(Base64Data.class.getName()).log(Level.SEVERE, null, ex);
mkos@408 500 return null;
mkos@408 501 }
ohair@286 502 }
ohair@286 503
alanb@368 504 static String getProperty(final String propName) {
alanb@368 505 if (System.getSecurityManager() == null) {
alanb@368 506 return System.getProperty(propName);
alanb@368 507 } else {
alanb@368 508 return (String) java.security.AccessController.doPrivileged(
alanb@368 509 new java.security.PrivilegedAction() {
alanb@368 510 public java.lang.Object run() {
alanb@368 511 return System.getProperty(propName);
alanb@368 512 }
alanb@368 513 });
alanb@368 514 }
alanb@368 515 }
alanb@368 516
ohair@286 517 // public static void main(String[] args) throws FileNotFoundException, IOException, XMLStreamException {
ohair@286 518 // Base64Data data = new Base64Data();
ohair@286 519 //
alanb@368 520 // File f = new File("/Users/snajper/work/builds/weblogic/wls1211_dev.zip");
alanb@368 521 // FileDataSource fds = new FileDataSource(f);
alanb@368 522 // DataHandler dh = new DataHandler(fds);
alanb@368 523 // data.set(dh);
ohair@286 524 //
alanb@368 525 // FileWriter fw = new FileWriter(new File("/Users/snajper/Desktop/b.txt"));
alanb@368 526 // XMLStreamWriterImpl wi = new XMLStreamWriterImpl(fw, null);
ohair@286 527 //
ohair@286 528 // data.writeTo(wi);
alanb@368 529 // wi.flush();fw.flush();
alanb@368 530 // //System.out.println("SW: " + sw.toString());
ohair@286 531 //
ohair@286 532 // }
ohair@286 533
ohair@286 534 }

mercurial