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

Tue, 09 Apr 2013 14:51:13 +0100

author
alanb
date
Tue, 09 Apr 2013 14:51:13 +0100
changeset 368
0989ad8c0860
parent 286
f50545b5e2f1
child 408
b0610cd08440
permissions
-rw-r--r--

8010393: Update JAX-WS RI to 2.2.9-b12941
Reviewed-by: alanb, erikj
Contributed-by: miroslav.kos@oracle.com, martin.grebac@oracle.com

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 {
ohair@286 290 if(dataHandler!=null)
ohair@286 291 return dataHandler.getInputStream();
ohair@286 292 else
ohair@286 293 return new ByteArrayInputStream(data,0,dataLen);
ohair@286 294 }
ohair@286 295
ohair@286 296 /**
ohair@286 297 * Returns false if this object only has {@link DataHandler} and therefore
ohair@286 298 * {@link #get()} operation is likely going to be expensive.
ohair@286 299 *
ohair@286 300 * @return false if it has only DataHandler
ohair@286 301 */
ohair@286 302 public boolean hasData() {
ohair@286 303 return data!=null;
ohair@286 304 }
ohair@286 305
ohair@286 306 /**
ohair@286 307 * Gets the raw data. The size of the byte array maybe larger than the actual length.
ohair@286 308 *
ohair@286 309 * @return data as byte[], the array may be larger
ohair@286 310 */
ohair@286 311 public byte[] get() {
ohair@286 312 if(data==null) {
ohair@286 313 try {
ohair@286 314 ByteArrayOutputStreamEx baos = new ByteArrayOutputStreamEx(1024);
ohair@286 315 InputStream is = dataHandler.getDataSource().getInputStream();
ohair@286 316 baos.readFrom(is);
ohair@286 317 is.close();
ohair@286 318 data = baos.getBuffer();
ohair@286 319 dataLen = baos.size();
ohair@286 320 dataCloneByRef = true;
ohair@286 321 } catch (IOException e) {
ohair@286 322 // TODO: report the error to the unmarshaller
ohair@286 323 dataLen = 0; // recover by assuming length-0 data
ohair@286 324 }
ohair@286 325 }
ohair@286 326 return data;
ohair@286 327 }
ohair@286 328
ohair@286 329 /**
ohair@286 330 * Gets the length of the binary data counted in bytes.
ohair@286 331 *
ohair@286 332 * Note that if this object encapsulates {@link DataHandler},
ohair@286 333 * this method would have to read the whole thing into {@code byte[]}
ohair@286 334 * just to count the length, because {@link DataHandler}
ohair@286 335 * doesn't easily expose the length.
ohair@286 336 *
ohair@286 337 * @return no of bytes
ohair@286 338 */
ohair@286 339 public int getDataLen() {
ohair@286 340 get();
ohair@286 341 return dataLen;
ohair@286 342 }
ohair@286 343
ohair@286 344 public String getMimeType() {
ohair@286 345 if(mimeType==null)
ohair@286 346 return "application/octet-stream";
ohair@286 347 return mimeType;
ohair@286 348 }
ohair@286 349
ohair@286 350 /**
ohair@286 351 * Gets the number of characters needed to represent
ohair@286 352 * this binary data in the base64 encoding.
ohair@286 353 */
ohair@286 354 public int length() {
ohair@286 355 // for each 3 bytes you use 4 chars
ohair@286 356 // if the remainder is 1 or 2 there will be 4 more
ohair@286 357 get(); // fill in the buffer if necessary
ohair@286 358 return ((dataLen+2)/3)*4;
ohair@286 359 }
ohair@286 360
ohair@286 361 /**
ohair@286 362 * Encode this binary data in the base64 encoding
ohair@286 363 * and returns the character at the specified position.
ohair@286 364 */
ohair@286 365 public char charAt(int index) {
ohair@286 366 // we assume that the length() method is called before this method
ohair@286 367 // (otherwise how would the caller know that the index is valid?)
ohair@286 368 // so we assume that the byte[] is already populated
ohair@286 369
ohair@286 370 int offset = index%4;
ohair@286 371 int base = (index/4)*3;
ohair@286 372
ohair@286 373 byte b1,b2;
ohair@286 374
ohair@286 375 switch(offset) {
ohair@286 376 case 0:
ohair@286 377 return Base64Encoder.encode(data[base]>>2);
ohair@286 378 case 1:
ohair@286 379 if(base+1<dataLen)
ohair@286 380 b1 = data[base+1];
ohair@286 381 else
ohair@286 382 b1 = 0;
ohair@286 383 return Base64Encoder.encode(
ohair@286 384 ((data[base]&0x3)<<4) |
ohair@286 385 ((b1>>4)&0xF));
ohair@286 386 case 2:
ohair@286 387 if(base+1<dataLen) {
ohair@286 388 b1 = data[base+1];
ohair@286 389 if(base+2<dataLen)
ohair@286 390 b2 = data[base+2];
ohair@286 391 else
ohair@286 392 b2 = 0;
ohair@286 393
ohair@286 394 return Base64Encoder.encode(
ohair@286 395 ((b1&0xF)<<2)|
ohair@286 396 ((b2>>6)&0x3));
ohair@286 397 } else
ohair@286 398 return '=';
ohair@286 399 case 3:
ohair@286 400 if(base+2<dataLen)
ohair@286 401 return Base64Encoder.encode(data[base+2]&0x3F);
ohair@286 402 else
ohair@286 403 return '=';
ohair@286 404 }
ohair@286 405
ohair@286 406 throw new IllegalStateException();
ohair@286 407 }
ohair@286 408
ohair@286 409 /**
ohair@286 410 * Internally this is only used to split a text to a list,
ohair@286 411 * which doesn't happen that much for base64.
ohair@286 412 * So this method should be smaller than faster.
ohair@286 413 */
ohair@286 414 public CharSequence subSequence(int start, int end) {
ohair@286 415 StringBuilder buf = new StringBuilder();
ohair@286 416 get(); // fill in the buffer if we haven't done so
ohair@286 417 for( int i=start; i<end; i++ )
ohair@286 418 buf.append(charAt(i));
ohair@286 419 return buf;
ohair@286 420 }
ohair@286 421
ohair@286 422 /**
ohair@286 423 * Returns the base64 encoded string of this data.
ohair@286 424 */
ohair@286 425 @Override
ohair@286 426 public String toString() {
ohair@286 427 get(); // fill in the buffer
ohair@286 428 return Base64Encoder.print(data, 0, dataLen);
ohair@286 429 }
ohair@286 430
ohair@286 431 public void writeTo(char[] buf, int start) {
ohair@286 432 get();
ohair@286 433 Base64Encoder.print(data, 0, dataLen, buf, start);
ohair@286 434 }
ohair@286 435
alanb@368 436 private static final int CHUNK_SIZE;
alanb@368 437 static {
alanb@368 438 int bufSize = 1024;
alanb@368 439 try {
alanb@368 440 String bufSizeStr = getProperty("com.sun.xml.internal.org.jvnet.staxex.Base64DataStreamWriteBufferSize");
alanb@368 441 if (bufSizeStr != null) {
alanb@368 442 bufSize = Integer.parseInt(bufSizeStr);
alanb@368 443 }
alanb@368 444 } catch (Exception e) {
alanb@368 445 logger.log(Level.INFO, "Error reading com.sun.xml.internal.org.jvnet.staxex.Base64DataStreamWriteBufferSize property", e);
alanb@368 446 }
alanb@368 447 CHUNK_SIZE = bufSize;
alanb@368 448 }
alanb@368 449
ohair@286 450 public void writeTo(XMLStreamWriter output) throws IOException, XMLStreamException {
ohair@286 451 if (data==null) {
ohair@286 452 try {
ohair@286 453 InputStream is = dataHandler.getDataSource().getInputStream();
ohair@286 454 ByteArrayOutputStream outStream = new ByteArrayOutputStream(); // dev-null stream
ohair@286 455 Base64EncoderStream encWriter = new Base64EncoderStream(output, outStream);
alanb@368 456 int b;
alanb@368 457 byte[] buffer = new byte[CHUNK_SIZE];
alanb@368 458 while ((b = is.read(buffer)) != -1) {
alanb@368 459 encWriter.write(buffer, 0, b);
ohair@286 460 }
ohair@286 461 outStream.close();
ohair@286 462 encWriter.close();
ohair@286 463 } catch (IOException e) {
ohair@286 464 dataLen = 0; // recover by assuming length-0 data
ohair@286 465 throw e;
ohair@286 466 }
ohair@286 467 } else {
ohair@286 468 // the data is already in memory and not streamed
ohair@286 469 String s = Base64Encoder.print(data, 0, dataLen);
ohair@286 470 output.writeCharacters(s);
ohair@286 471 }
ohair@286 472 }
ohair@286 473
ohair@286 474 @Override
ohair@286 475 public Base64Data clone() {
ohair@286 476 return new Base64Data(this);
ohair@286 477 }
ohair@286 478
alanb@368 479 static String getProperty(final String propName) {
alanb@368 480 if (System.getSecurityManager() == null) {
alanb@368 481 return System.getProperty(propName);
alanb@368 482 } else {
alanb@368 483 return (String) java.security.AccessController.doPrivileged(
alanb@368 484 new java.security.PrivilegedAction() {
alanb@368 485 public java.lang.Object run() {
alanb@368 486 return System.getProperty(propName);
alanb@368 487 }
alanb@368 488 });
alanb@368 489 }
alanb@368 490 }
alanb@368 491
ohair@286 492 // public static void main(String[] args) throws FileNotFoundException, IOException, XMLStreamException {
ohair@286 493 // Base64Data data = new Base64Data();
ohair@286 494 //
alanb@368 495 // File f = new File("/Users/snajper/work/builds/weblogic/wls1211_dev.zip");
alanb@368 496 // FileDataSource fds = new FileDataSource(f);
alanb@368 497 // DataHandler dh = new DataHandler(fds);
alanb@368 498 // data.set(dh);
ohair@286 499 //
alanb@368 500 // FileWriter fw = new FileWriter(new File("/Users/snajper/Desktop/b.txt"));
alanb@368 501 // XMLStreamWriterImpl wi = new XMLStreamWriterImpl(fw, null);
ohair@286 502 //
ohair@286 503 // data.writeTo(wi);
alanb@368 504 // wi.flush();fw.flush();
alanb@368 505 // //System.out.println("SW: " + sw.toString());
ohair@286 506 //
ohair@286 507 // }
ohair@286 508
ohair@286 509 }

mercurial