View Javadoc
1   package nom.tam.fits.compress;
2   
3   import java.io.BufferedInputStream;
4   import java.io.ByteArrayOutputStream;
5   import java.io.FilterInputStream;
6   import java.io.IOException;
7   import java.io.InputStream;
8   import java.io.OutputStream;
9   import java.nio.charset.Charset;
10  import java.util.logging.Level;
11  import java.util.logging.Logger;
12  
13  /*
14   * #%L
15   * nom.tam FITS library
16   * %%
17   * Copyright (C) 1996 - 2024 nom-tam-fits
18   * %%
19   * This is free and unencumbered software released into the public domain.
20   *
21   * Anyone is free to copy, modify, publish, use, compile, sell, or
22   * distribute this software, either in source code form or as a compiled
23   * binary, for any purpose, commercial or non-commercial, and by any
24   * means.
25   *
26   * In jurisdictions that recognize copyright laws, the author or authors
27   * of this software dedicate any and all copyright interest in the
28   * software to the public domain. We make this dedication for the benefit
29   * of the public at large and to the detriment of our heirs and
30   * successors. We intend this dedication to be an overt act of
31   * relinquishment in perpetuity of all present and future rights to this
32   * software under copyright law.
33   *
34   * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
35   * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
36   * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
37   * IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR ANY CLAIM, DAMAGES OR
38   * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
39   * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
40   * OTHER DEALINGS IN THE SOFTWARE.
41   * #L%
42   */
43  
44  import static nom.tam.util.LoggerHelper.getLogger;
45  
46  /**
47   * (<i>for internal use</i>) Ensures that input streams aren't left open when decompressing with an external system
48   * tool, such as the UNIX <b>compress</b> or <b>bzip2</b> commands. It is discouraged to use system tools for
49   * decompressing such files, especially since we have native Java implementations through Apache's
50   * <b>commons-compress</b> classes. The system tools are not portable, whereas the <b>commons-compress</b>
51   * implementation is. Therefore, you should neer really need to use this class, which is provided only for compatibility
52   * with earlier versions of this library.
53   * 
54   * @deprecated Needed only by deprecated compression classes. And it should not have visibility outside of this package
55   *                 anyway.
56   */
57  @Deprecated
58  public class CloseIS extends FilterInputStream {
59  
60      private static final Logger LOG = getLogger(CloseIS.class);
61  
62      private static final int COPY_BUFFER_SIZE = 64 * 1024;
63  
64      private InputStream output;
65  
66      private OutputStream input;
67  
68      private String errorText;
69  
70      private IOException exception;
71  
72      private final Thread stdError;
73  
74      private final Thread copier;
75  
76      private final Process proc;
77  
78      /**
79       * Instantiates a new thread that will watch and close the input stream whenever the process using it compeletes.
80       * 
81       * @param proc       The process that is using the input stream
82       * @param compressed the compressed input stream that is used by the process.
83       */
84      @Deprecated
85      @SuppressWarnings("resource")
86      public CloseIS(Process proc, final InputStream compressed) {
87          super(new BufferedInputStream(proc.getInputStream(), CompressionManager.ONE_MEGABYTE));
88          if (compressed == null) {
89              throw new NullPointerException();
90          }
91          this.proc = proc;
92          final InputStream error = proc.getErrorStream();
93          output = proc.getInputStream();
94          input = proc.getOutputStream();
95          stdError = new Thread(new Runnable() {
96  
97              @Override
98              public void run() {
99                  try {
100                     ByteArrayOutputStream bytes = new ByteArrayOutputStream();
101                     byte[] buffer = new byte[COPY_BUFFER_SIZE];
102                     int len;
103                     while ((len = error.read(buffer, 0, buffer.length)) >= 0) {
104                         bytes.write(buffer, 0, len);
105                     }
106                     error.close();
107                     errorText = new String(bytes.toByteArray(), Charset.defaultCharset());
108                 } catch (IOException e) {
109                     exception = e;
110                 }
111             }
112         });
113         // Now copy everything in a separate thread.
114         copier = new Thread(new Runnable() {
115 
116             @Override
117             public void run() {
118                 try {
119                     byte[] buffer = new byte[COPY_BUFFER_SIZE];
120                     int len;
121                     while ((len = compressed.read(buffer, 0, buffer.length)) >= 0) {
122                         input.write(buffer, 0, len);
123                     }
124                     input.close();
125                 } catch (IOException e) {
126                     exception = e;
127                 }
128                 try {
129                     compressed.close();
130                 } catch (IOException e) {
131                     if (exception == null) {
132                         exception = e;
133                     }
134                 }
135             }
136         });
137         start();
138     }
139 
140     /**
141      * start all threads.
142      */
143     private void start() {
144         stdError.start();
145         copier.start();
146     }
147 
148     @Deprecated
149     @Override
150     public int read() throws IOException {
151         int result = 0;
152         try {
153             result = super.read();
154             return result;
155         } catch (IOException e) {
156             result = -1;
157             throw e;
158         } finally {
159             handledOccuredException(result);
160         }
161     }
162 
163     private void handledOccuredException(int result) throws IOException {
164         int exitValue = 0;
165         if (result < 0) {
166             try {
167                 stdError.join();
168                 copier.join();
169                 exitValue = proc.exitValue();
170             } catch (Exception e) {
171                 LOG.log(Level.WARNING, "could not join the stream processes", e);
172             }
173         }
174         if (exception != null || exitValue != 0) {
175             if (errorText != null && !errorText.trim().isEmpty()) {
176                 throw new IOException(errorText, exception);
177             }
178             if (exception == null) {
179                 throw new IOException("exit value was " + exitValue);
180             }
181             throw exception;
182         }
183     }
184 
185     @Deprecated
186     @Override
187     public int read(byte[] b, int off, int len) throws IOException {
188         int result = 0;
189         try {
190             result = super.read(b, off, len);
191             return result;
192         } catch (IOException e) {
193             throw e;
194         } finally {
195             handledOccuredException(result);
196         }
197     }
198 
199     @Override
200     @Deprecated
201     public void close() throws IOException {
202         super.close();
203         input.close();
204         output.close();
205     }
206 
207 }