View Javadoc
1   /*
2    * Copyright (c) 2002-2026 Gargoyle Software Inc.
3    *
4    * Licensed under the Apache License, Version 2.0 (the "License");
5    * you may not use this file except in compliance with the License.
6    * You may obtain a copy of the License at
7    * https://www.apache.org/licenses/LICENSE-2.0
8    *
9    * Unless required by applicable law or agreed to in writing, software
10   * distributed under the License is distributed on an "AS IS" BASIS,
11   * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12   * See the License for the specific language governing permissions and
13   * limitations under the License.
14   */
15  package org.htmlunit;
16  
17  import java.io.ByteArrayInputStream;
18  import java.io.File;
19  import java.io.IOException;
20  import java.io.InputStream;
21  import java.io.Serializable;
22  import java.lang.ref.Cleaner;
23  import java.nio.file.Files;
24  
25  import org.apache.commons.io.FileUtils;
26  import org.htmlunit.util.ArrayUtils;
27  
28  /**
29   * Wrapper for content downloaded from a remote server.
30   *
31   * @author Marc Guillemot
32   * @author Ronald Brill
33   */
34  public interface DownloadedContent extends Serializable {
35  
36      /**
37       * Implementation keeping content in memory.
38       */
39      class InMemory implements DownloadedContent {
40          private final byte[] bytes_;
41  
42          InMemory(final byte[] byteArray) {
43              if (byteArray == null) {
44                  bytes_ = ArrayUtils.EMPTY_BYTE_ARRAY;
45              }
46              else {
47                  bytes_ = byteArray;
48              }
49          }
50  
51          @Override
52          public InputStream getInputStream() {
53              return new ByteArrayInputStream(bytes_);
54          }
55  
56          @Override
57          public void cleanUp() {
58              // nothing to do
59          }
60  
61          @Override
62          public boolean isEmpty() {
63              return length() == 0;
64          }
65  
66          @Override
67          public long length() {
68              return bytes_.length;
69          }
70      }
71  
72      /**
73       * Implementation keeping content on the file system.
74       */
75      class OnFile implements DownloadedContent {
76  
77          private final File file_;
78          private final Cleaner.Cleanable cleanable_;
79  
80          private static final class OnFileCleaningAction implements Runnable {
81              private File file_;
82  
83              OnFileCleaningAction(final File file) {
84                  file_ = file;
85              }
86  
87              @Override
88              public synchronized void run() {
89                  if (file_ != null) {
90                      FileUtils.deleteQuietly(file_);
91                      file_ = null;
92                  }
93              }
94          }
95  
96          /**
97           * Ctor.
98           *
99           * @param file the file
100          * @param temporary if true, the file will be deleted when cleanUp() is called.
101          */
102         OnFile(final File file, final boolean temporary) {
103             file_ = file;
104             if (temporary) {
105                 cleanable_ = WebClient.registerCleanerAction(this, new OnFileCleaningAction(file));
106             }
107             else {
108                 cleanable_ = null;
109             }
110         }
111 
112         @Override
113         public InputStream getInputStream() throws IOException {
114             return Files.newInputStream(file_.toPath());
115         }
116 
117         @Override
118         public void cleanUp() {
119             if (cleanable_ != null) {
120                 cleanable_.clean();
121             }
122         }
123 
124         @Override
125         public boolean isEmpty() {
126             return false;
127         }
128 
129         @Override
130         public long length() {
131             if (file_ == null) {
132                 return 0;
133             }
134 
135             return file_.length();
136         }
137     }
138 
139     /**
140      * Returns a new {@link InputStream} allowing to read the downloaded content.
141      * @return the InputStream
142      * @throws IOException in case of problem accessing the content
143      */
144     InputStream getInputStream() throws IOException;
145 
146     /**
147      * Clean up resources associated to this content.
148      */
149     void cleanUp();
150 
151     /**
152      * Returns true if the content is empty.
153      * @return true or false
154      */
155     boolean isEmpty();
156 
157     /**
158      * Returns the number of bytes.
159      * @return the length
160      */
161     long length();
162 }