1 /*
   2  * Copyright (c) 2010, 2014, 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 com.sun.xml.internal.org.jvnet.staxex;
  27 
  28 import javax.activation.DataHandler;
  29 import javax.activation.DataSource;
  30 import java.io.BufferedInputStream;
  31 import java.io.Closeable;
  32 import java.io.File;
  33 import java.io.IOException;
  34 import java.io.InputStream;
  35 import java.net.URL;
  36 
  37 /**
  38  * {@link DataHandler} extended to offer better buffer management
  39  * in a streaming environment.
  40  *
  41  * <p>
  42  * {@link DataHandler} is used commonly as a data format across
  43  * multiple systems (such as JAXB/WS.) Unfortunately, {@link DataHandler}
  44  * has the semantics of "read as many times as you want", so this makes
  45  * it difficult for involving parties to handle a BLOB in a streaming fashion.
  46  *
  47  * <p>
  48  * {@link StreamingDataHandler} solves this problem by offering methods
  49  * that enable faster bulk "consume once" read operation.
  50  *
  51  * @author Jitendra Kotamraju
  52  */
  53 public abstract class StreamingDataHandler extends DataHandler implements Closeable {
  54 
  55     private String hrefCid;
  56 
  57     public StreamingDataHandler(Object o, String s) {
  58         super(o, s);
  59     }
  60 
  61     public StreamingDataHandler(URL url) {
  62         super(url);
  63     }
  64 
  65     public StreamingDataHandler(DataSource dataSource) {
  66         super(dataSource);
  67     }
  68 
  69     /**
  70      * Works like {@link #getInputStream()} except that this method
  71      * can be invoked only once.
  72      *
  73      * <p>
  74      * This is used as a signal from the caller that there will
  75      * be no further {@link #getInputStream()} invocation nor
  76      * {@link #readOnce()} invocation on this object (which would
  77      * result in {@link IOException}.)
  78      *
  79      * <p>
  80      * When {@link DataHandler} is backed by a streaming BLOB
  81      * (such as an attachment in a web service read from the network),
  82      * this allows the callee to avoid unnecessary buffering.
  83      *
  84      * <p>
  85      * Note that it is legal to call {@link #getInputStream()}
  86      * multiple times and then call {@link #readOnce()} afterward.
  87      * Streams created such a way can be read in any order &mdash;
  88      * there's no requirement that streams created earlier must be read
  89      * first.
  90      *
  91      * @return
  92      *      always non-null. Represents the content of this BLOB.
  93      *      The returned stream is generally not buffered, so for
  94      *      better performance read in a big batch or wrap this into
  95      *      {@link BufferedInputStream}.
  96      * @throws IOException
  97      *      if any i/o error
  98      */
  99     public abstract InputStream readOnce() throws IOException;
 100 
 101     /**
 102      * Obtains the BLOB into a specified file.
 103      *
 104      * <p>
 105      * Semantically, this method is roughly equivalent to the following
 106      * code, except that the actual implementation is likely to be a lot faster.
 107      *
 108      * <pre>
 109      * InputStream i = getInputStream();
 110      * OutputStream o = new FileOutputStream(dst);
 111      * int ch;
 112      * while((ch=i.read())!=-1)  o.write(ch);
 113      * i.close();
 114      * o.close();
 115      * </pre>
 116      *
 117      * <p>
 118      * The main motivation behind this method is that often
 119      * {@link DataHandler} that reads data from a streaming source
 120      * will use a temporary file as a data store to hold data
 121      * (think of commons-fileupload.) In such case this method
 122      * can be as fast as calling {@link File#renameTo(File)}.
 123      *
 124      * <p>
 125      * This method shouldn't be called when there are any
 126      * open streams.
 127      *
 128      * <p>
 129      * After this method is invoked, {@link #readOnce()} and
 130      * {@link #getInputStream()} will simply open the destination
 131      * file you've specified as an argument. So if you further
 132      * move the file or delete this file, those methods will
 133      * behave in undefined fashion. For a simliar reason,
 134      * calling this method multiple times will cause
 135      * undefined behavior.
 136      */
 137     public abstract void moveTo(File dst) throws IOException;
 138 
 139     /**
 140      * Releases any resources associated with this DataHandler.
 141      * (such as an attachment in a web service read from a temp
 142      * file will be deleted.) After calling this method, it is
 143      * illegal to call any other methods.
 144      */
 145     public abstract void close() throws IOException;
 146 
 147     public String getHrefCid() {
 148         return hrefCid;
 149     }
 150 
 151     public void setHrefCid(final String cid) {
 152         this.hrefCid = cid;
 153     }
 154 }