1. Project Clover database Thu Nov 9 2017 18:54:49 CET
  2. Package com.xpn.xwiki.internal.file

File TemporaryDeferredFileRepository.java

 

Coverage histogram

../../../../../img/srcFileCovDistChart7.png
66% of files have more coverage

Code metrics

14
43
14
3
270
139
26
0.6
3.07
4.67
1.86

Classes

Class Line # Actions
TemporaryDeferredFileRepository 55 11 0% 6 4
0.764705976.5%
TemporaryDeferredFileRepository.TemporaryDeferredFile 65 19 0% 11 22
0.388888938.9%
TemporaryDeferredFileRepository.TemporaryDeferredStringFile 146 13 0% 9 0
1.0100%
 

Contributing tests

No tests hitting this source file were found.

Source view

1    /*
2    * See the NOTICE file distributed with this work for additional
3    * information regarding copyright ownership.
4    *
5    * This is free software; you can redistribute it and/or modify it
6    * under the terms of the GNU Lesser General Public License as
7    * published by the Free Software Foundation; either version 2.1 of
8    * the License, or (at your option) any later version.
9    *
10    * This software is distributed in the hope that it will be useful,
11    * but WITHOUT ANY WARRANTY; without even the implied warranty of
12    * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
13    * Lesser General Public License for more details.
14    *
15    * You should have received a copy of the GNU Lesser General Public
16    * License along with this software; if not, write to the Free
17    * Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
18    * 02110-1301 USA, or see the FSF site: http://www.fsf.org.
19    */
20    package com.xpn.xwiki.internal.file;
21   
22    import java.io.ByteArrayInputStream;
23    import java.io.File;
24    import java.io.FileInputStream;
25    import java.io.IOException;
26    import java.io.InputStream;
27    import java.io.InputStreamReader;
28    import java.io.OutputStream;
29    import java.io.OutputStreamWriter;
30    import java.io.Reader;
31    import java.io.StringWriter;
32    import java.io.Writer;
33    import java.nio.charset.Charset;
34    import java.util.UUID;
35    import java.util.concurrent.atomic.AtomicLong;
36   
37    import javax.inject.Inject;
38    import javax.inject.Singleton;
39   
40    import org.apache.commons.io.FileUtils;
41    import org.apache.commons.io.IOUtils;
42    import org.apache.commons.io.output.DeferredFileOutputStream;
43    import org.apache.commons.lang3.ArrayUtils;
44    import org.xwiki.component.annotation.Component;
45    import org.xwiki.environment.Environment;
46   
47    /**
48    * Provide tools to manipulate a repository of unique temporary files.
49    *
50    * @version $Id: 406eb3f8c2ae8293f569ffe9e10510cfe1e20aa7 $
51    * @since 9.0RC1
52    */
53    @Component(roles = TemporaryDeferredFileRepository.class)
54    @Singleton
 
55    public class TemporaryDeferredFileRepository
56    {
57    private static final int THRESHOLD = 10000;
58   
59    /**
60    * The data stored in this "file" is stored in memory until the #THRESHOLD is reached in which case it start stored
61    * the data in a temporary file.
62    *
63    * @version $Id: 406eb3f8c2ae8293f569ffe9e10510cfe1e20aa7 $
64    */
 
65    public class TemporaryDeferredFile
66    {
67    private final String repositoryPath;
68   
69    private DeferredFileOutputStream currentOutputStream;
70   
71    /**
72    * @param repositoryPath the path of the repository inside the temporary directory
73    */
 
74  545 toggle TemporaryDeferredFile(String repositoryPath)
75    {
76  545 this.repositoryPath = repositoryPath;
77    }
78   
79    /**
80    * @return create a new input stream to read the data stored in that file
81    * @throws IOException when failing to create an {@link InputStream}
82    */
 
83  729 toggle public InputStream getInputStream() throws IOException
84    {
85  729 if (this.currentOutputStream != null) {
86  729 if (this.currentOutputStream.isInMemory()) {
87  541 return new ByteArrayInputStream(this.currentOutputStream.getData());
88    } else {
89  188 return new FileInputStream(this.currentOutputStream.getFile());
90    }
91    } else {
92  0 return new ByteArrayInputStream(ArrayUtils.EMPTY_BYTE_ARRAY);
93    }
94    }
95   
96    /**
97    * @return create a new output stream to read the data stored in that file
98    * @throws IOException when failing to create an {@link OutputStream}
99    */
 
100  545 toggle public OutputStream getOutputStream() throws IOException
101    {
102  545 File file = createTemporaryFile(this.repositoryPath);
103  545 this.currentOutputStream = new DeferredFileOutputStream(THRESHOLD, file);
104  545 return this.currentOutputStream;
105    }
106   
107    /**
108    * @return the length of the content
109    */
 
110  0 toggle public long length()
111    {
112  0 if (this.currentOutputStream != null) {
113  0 if (this.currentOutputStream.isInMemory()) {
114  0 return this.currentOutputStream.getData().length;
115    } else {
116  0 return this.currentOutputStream.getFile().length();
117    }
118    }
119   
120  0 return 0;
121    }
122   
123    /**
124    * @return the content of the file as byte[]
125    * @throws IOException when failing to read the file
126    */
 
127  0 toggle public byte[] getBytes() throws IOException
128    {
129  0 if (this.currentOutputStream != null) {
130  0 if (this.currentOutputStream.isInMemory()) {
131  0 return this.currentOutputStream.getData();
132    } else {
133  0 return FileUtils.readFileToByteArray(this.currentOutputStream.getFile());
134    }
135    } else {
136  0 return ArrayUtils.EMPTY_BYTE_ARRAY;
137    }
138    }
139    }
140   
141    /**
142    * {@link String} oriented {@link TemporaryDeferredFile}.
143    *
144    * @version $Id: 406eb3f8c2ae8293f569ffe9e10510cfe1e20aa7 $
145    */
 
146    public class TemporaryDeferredStringFile extends TemporaryDeferredFile
147    {
148    private final Charset charset;
149   
150    /**
151    * @param repositoryPath the path of the repository inside the temporary directory
152    * @param charset the encoding in which to read the file
153    */
 
154  545 toggle TemporaryDeferredStringFile(String repositoryPath, Charset charset)
155    {
156  545 super(repositoryPath);
157  545 this.charset = charset;
158    }
159   
160    /**
161    * @return the reader
162    * @throws IOException when failing to create a {@link Reader}
163    */
 
164  729 toggle public Reader getReader() throws IOException
165    {
166  729 return new InputStreamReader(getInputStream(), this.charset);
167    }
168   
169    /**
170    * @return the writer
171    * @throws IOException when failing to create a {@link Writer}
172    */
 
173  545 toggle public Writer getWriter() throws IOException
174    {
175  545 OutputStream stream = getOutputStream();
176   
177  545 return new OutputStreamWriter(stream, this.charset);
178    }
179   
180    /**
181    * @return the content as a {@link String}
182    * @throws IOException when failing to read the content
183    */
 
184  620 toggle public String getString() throws IOException
185    {
186  620 try (Reader reader = getReader()) {
187  620 StringWriter writer = new StringWriter();
188   
189  620 IOUtils.copyLarge(reader, writer);
190   
191  620 return writer.toString();
192    }
193    }
194   
195    /**
196    * @param str the string to write
197    * @throws IOException when failing to write the content
198    */
 
199  240 toggle public void setString(String str) throws IOException
200    {
201  240 try (Writer writer = getWriter()) {
202  240 IOUtils.write(str, writer);
203    }
204    }
205    }
206   
207    /**
208    * UID used in unique file name generation.
209    */
210    private final String uid = UUID.randomUUID().toString().replace('-', '_');
211   
212    /**
213    * Counter used in unique identifier generation.
214    */
215    private final AtomicLong counter = new AtomicLong(0);
216   
217    @Inject
218    private Environment environment;
219   
220    /**
221    * @param repositoryPath the path of the repository inside the temporary directory
222    * @return the folder associated to passed repository path
223    * @throws IOException when failing to create the repository
224    */
 
225  545 toggle public File getRepository(String repositoryPath) throws IOException
226    {
227  545 File repository = new File(this.environment.getTemporaryDirectory(), repositoryPath);
228   
229  545 if (!repository.mkdirs() && !repository.exists()) {
230  0 throw new IOException("Failed to create directory [" + repository + "]");
231    }
232   
233  545 return repository;
234    }
235   
236    /**
237    * @param repositoryPath the path of the repository inside the temporary directory
238    * @return a new temporary file in the repository, the returned instance is automatically deleting the file when
239    * it's not used anymore
240    * @throws IOException when failing to create the temporary file
241    */
 
242  545 toggle public File createTemporaryFile(String repositoryPath) throws IOException
243    {
244  545 StringBuilder filename = new StringBuilder();
245  545 filename.append(this.uid);
246  545 filename.append('-');
247  545 filename.append(this.counter.getAndIncrement());
248   
249  545 return new TemporaryFile(getRepository(repositoryPath), filename.toString());
250    }
251   
252    /**
253    * @param repositoryPath the path of the repository inside the temporary directory
254    * @return a new instance of temporary {@link TemporaryDeferredFile}
255    */
 
256  0 toggle public TemporaryDeferredFile createTemporaryDeferredFile(String repositoryPath)
257    {
258  0 return new TemporaryDeferredFile(repositoryPath);
259    }
260   
261    /**
262    * @param repositoryPath the path of the repository inside the temporary directory
263    * @param charset the encoding in which to read the file
264    * @return a new instance of temporary {@link TemporaryDeferredFile}
265    */
 
266  545 toggle public TemporaryDeferredStringFile createTemporaryDeferredStringFile(String repositoryPath, Charset charset)
267    {
268  545 return new TemporaryDeferredStringFile(repositoryPath, charset);
269    }
270    }