1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22 package org.opencastproject.util;
23
24 import static org.opencastproject.util.PathSupport.path;
25 import static org.opencastproject.util.data.Either.left;
26 import static org.opencastproject.util.data.Either.right;
27 import static org.opencastproject.util.data.Option.none;
28 import static org.opencastproject.util.data.Option.option;
29 import static org.opencastproject.util.data.Option.some;
30 import static org.opencastproject.util.data.functions.Misc.chuck;
31
32 import org.opencastproject.security.api.TrustedHttpClient;
33 import org.opencastproject.security.api.TrustedHttpClientException;
34 import org.opencastproject.util.data.Effect0;
35 import org.opencastproject.util.data.Either;
36 import org.opencastproject.util.data.Function;
37 import org.opencastproject.util.data.Function0;
38 import org.opencastproject.util.data.Function2;
39 import org.opencastproject.util.data.Option;
40
41 import com.entwinemedia.fn.Fn;
42 import com.entwinemedia.fn.FnX;
43 import com.entwinemedia.fn.Prelude;
44 import com.entwinemedia.fn.Unit;
45 import com.google.common.io.Resources;
46
47 import org.apache.commons.io.IOUtils;
48 import org.apache.http.HttpResponse;
49 import org.apache.http.client.methods.HttpGet;
50 import org.slf4j.Logger;
51 import org.slf4j.LoggerFactory;
52
53 import java.io.ByteArrayInputStream;
54 import java.io.ByteArrayOutputStream;
55 import java.io.Closeable;
56 import java.io.DataInputStream;
57 import java.io.File;
58 import java.io.FileInputStream;
59 import java.io.FileNotFoundException;
60 import java.io.IOException;
61 import java.io.InputStream;
62 import java.io.ObjectInputStream;
63 import java.io.ObjectOutputStream;
64 import java.io.OutputStream;
65 import java.io.RandomAccessFile;
66 import java.io.Serializable;
67 import java.net.URISyntaxException;
68 import java.net.URL;
69 import java.nio.channels.FileLock;
70 import java.nio.charset.Charset;
71 import java.util.Properties;
72
73 import de.schlichtherle.io.FileWriter;
74
75
76
77
78 public final class IoSupport {
79
80
81
82
83 private static Logger logger = LoggerFactory.getLogger(IoSupport.class.getName());
84
85 public static String getSystemTmpDir() {
86 String tmpdir = System.getProperty("java.io.tmpdir");
87 if (tmpdir == null) {
88 tmpdir = File.separator + "tmp" + File.separator;
89 } else {
90 if (!tmpdir.endsWith(File.separator)) {
91 tmpdir += File.separator;
92 }
93 }
94 return tmpdir;
95 }
96
97 private IoSupport() {
98 }
99
100
101
102
103
104
105
106 public static boolean closeQuietly(final Closeable s) {
107 if (s == null) {
108 return false;
109 }
110 try {
111 s.close();
112 return true;
113 } catch (IOException e) {
114 return false;
115 }
116 }
117
118
119
120
121
122
123
124
125 public static boolean closeQuietly(final Process process) {
126 if (process != null) {
127 closeQuietly(process.getInputStream());
128 closeQuietly(process.getErrorStream());
129 closeQuietly(process.getOutputStream());
130 return true;
131 }
132 return false;
133 }
134
135
136
137
138
139
140
141
142
143
144 public static void writeUTF8File(URL file, String contents) throws IOException {
145 try {
146 writeUTF8File(new File(file.toURI()), contents);
147 } catch (URISyntaxException e) {
148 throw new IOException("Couldn't parse the URL", e);
149 }
150 }
151
152
153
154
155
156
157
158
159
160 public static void writeUTF8File(File file, String contents) throws IOException {
161 writeUTF8File(file.getAbsolutePath(), contents);
162 }
163
164
165
166
167
168
169
170
171
172 public static void writeUTF8File(String filename, String contents) throws IOException {
173 FileWriter out = new FileWriter(filename);
174 try {
175 out.write(contents);
176 } finally {
177 closeQuietly(out);
178 }
179 }
180
181
182
183
184
185
186
187
188
189 @Deprecated
190 public static String readFileFromURL(URL url) {
191 return readFileFromURL(url, null);
192 }
193
194
195
196
197
198
199
200
201
202
203
204
205 @Deprecated
206 public static String readFileFromURL(URL url, TrustedHttpClient trustedClient) {
207 StringBuilder sb = new StringBuilder();
208 DataInputStream in = null;
209 HttpResponse response = null;
210 try {
211
212 if ("file".equals(url.getProtocol())) {
213 in = new DataInputStream(url.openStream());
214 } else {
215 if (trustedClient == null) {
216 logger.error("Unable to read from remote source {} because trusted client is null!", url.getFile());
217 return null;
218 }
219 HttpGet get = new HttpGet(url.toURI());
220 try {
221 response = trustedClient.execute(get);
222 } catch (TrustedHttpClientException e) {
223 logger.warn("Unable to fetch file from {}.", url, e);
224 trustedClient.close(response);
225 return null;
226 }
227 in = new DataInputStream(response.getEntity().getContent());
228 }
229 int c = 0;
230 while ((c = in.read()) != -1) {
231 sb.append((char) c);
232 }
233 } catch (IOException e) {
234 logger.warn("IOException attempting to get file from {}.", url);
235 return null;
236 } catch (URISyntaxException e) {
237 logger.warn("URI error attempting to get file from {}.", url);
238 return null;
239 } catch (NullPointerException e) {
240 logger.warn("Nullpointer attempting to get file from {}.", url);
241 return null;
242 } finally {
243 IOUtils.closeQuietly(in);
244
245 if (response != null) {
246 try {
247 trustedClient.close(response);
248 } catch (IOException e) {
249 }
250 }
251 }
252
253 return sb.toString();
254 }
255
256 public static Properties loadPropertiesFromUrl(final URL url) {
257 try {
258 return loadPropertiesFromStream(url.openStream());
259 } catch (IOException e) {
260 return chuck(e);
261 }
262 }
263
264
265 public static Properties loadPropertiesFromStream(final InputStream stream) {
266 return withResource(stream, new Function.X<InputStream, Properties>() {
267 @Override
268 public Properties xapply(InputStream in) throws Exception {
269 final Properties p = new Properties();
270 p.load(in);
271 return p;
272 }
273 });
274 }
275
276
277
278
279 public static <A, B extends Closeable> A withResource(B b, Function<B, A> f) {
280 try {
281 return f.apply(b);
282 } finally {
283 IoSupport.closeQuietly(b);
284 }
285 }
286
287
288
289
290 public static <A, B extends Closeable> A withResource(B b, Fn<? super B, ? extends A> f) {
291 try {
292 return f.apply(b);
293 } finally {
294 IoSupport.closeQuietly(b);
295 }
296 }
297
298
299
300
301
302
303 public static Option<InputStream> openClassPathResource(String resource, Class<?> clazz) {
304 return option(clazz.getResourceAsStream(resource));
305 }
306
307
308
309
310
311
312 public static Option<InputStream> openClassPathResource(String resource) {
313 return openClassPathResource(resource, IoSupport.class);
314 }
315
316
317 public static Option<File> classPathResourceAsFile(String resource) {
318 try {
319 final URL res = IoSupport.class.getResource(resource);
320 if (res != null) {
321 return Option.some(new File(res.toURI()));
322 } else {
323 return Option.none();
324 }
325 } catch (URISyntaxException e) {
326 return Option.none();
327 }
328 }
329
330
331
332
333
334
335 public static Option<String> loadFileFromClassPathAsString(String resource, Class<?> clazz) {
336 try {
337 final URL url = clazz.getResource(resource);
338 return url != null ? some(Resources.toString(clazz.getResource(resource), Charset.forName("UTF-8")))
339 : none(String.class);
340 } catch (IOException e) {
341 return none();
342 }
343 }
344
345
346
347
348
349
350 public static Option<String> loadFileFromClassPathAsString(String resource) {
351 return loadFileFromClassPathAsString(resource, IoSupport.class);
352 }
353
354
355
356
357
358
359
360
361
362
363 public static <A> Option<A> withFile(File file, Function2<InputStream, File, A> f) {
364 InputStream s = null;
365 try {
366 s = new FileInputStream(file);
367 return some(f.apply(s, file));
368 } catch (FileNotFoundException ignore) {
369 return none();
370 } finally {
371 IoSupport.closeQuietly(s);
372 }
373 }
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388 @Deprecated
389 public static <A, Err> Either<Err, A> withStream(Function0<InputStream> s, Function<Exception, Err> toErr,
390 Function<InputStream, A> f) {
391 InputStream in = null;
392 try {
393 in = s.apply();
394 return right(f.apply(in));
395 } catch (Exception e) {
396 return left(toErr.apply(e));
397 } finally {
398 IoSupport.closeQuietly(in);
399 }
400 }
401
402
403
404
405
406
407
408
409
410
411
412 public static <A, Err, B extends Closeable> Either<Err, A> withResource(Function0<B> r,
413 Function<Exception, Err> toErr, Function<B, A> f) {
414 B b = null;
415 try {
416 b = r.apply();
417 return right(f.apply(b));
418 } catch (Exception e) {
419 return left(toErr.apply(e));
420 } finally {
421 IoSupport.closeQuietly(b);
422 }
423 }
424
425
426
427
428
429
430 @Deprecated
431 public static <A> A withStream(OutputStream s, Function<OutputStream, A> f) {
432 try {
433 return f.apply(s);
434 } finally {
435 IoSupport.closeQuietly(s);
436 }
437 }
438
439
440 public static final Function<InputStream, String> readToString = new Function.X<InputStream, String>() {
441 @Override
442 public String xapply(InputStream in) throws IOException {
443 return IOUtils.toString(in, "utf-8");
444 }
445 };
446
447
448 public static Function0<InputStream> fileInputStream(final File a) {
449 return new Function0.X<InputStream>() {
450 @Override
451 public InputStream xapply() throws Exception {
452 return new FileInputStream(a);
453 }
454 };
455 }
456
457
458 public static File file(String... pathElems) {
459 return new File(path(pathElems));
460 }
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475 public static synchronized <A> A locked(File file, Function<File, A> f) throws NotFoundException, IOException {
476 final Effect0 key = acquireLock(file);
477 try {
478 return f.apply(file);
479 } finally {
480 key.apply();
481 }
482 }
483
484
485
486
487
488
489
490
491
492
493
494 private static Effect0 acquireLock(File file) throws NotFoundException, IOException {
495 final RandomAccessFile raf;
496 try {
497 raf = new RandomAccessFile(file, "rw");
498 } catch (FileNotFoundException e) {
499
500
501 throw new NotFoundException("Error acquiring lock for " + file.getAbsolutePath(), e);
502 }
503 final FileLock lock = raf.getChannel().lock();
504 return new Effect0() {
505 @Override
506 protected void run() {
507 try {
508 lock.release();
509 } catch (IOException ignore) {
510 }
511 IoSupport.closeQuietly(raf);
512 }
513 };
514 }
515
516
517
518
519 public static <A extends Serializable> A serializeDeserialize(final A a) {
520 final ByteArrayOutputStream out = new ByteArrayOutputStream();
521 try {
522 withResource(
523 new ObjectOutputStream(out),
524 new FnX<ObjectOutputStream, Unit>() {
525 @Override public Unit applyX(ObjectOutputStream out) throws Exception {
526 out.writeObject(a);
527 return Unit.unit;
528 }
529 });
530 return withResource(
531 new ObjectInputStream(new ByteArrayInputStream(out.toByteArray())),
532 new FnX<ObjectInputStream, A>() {
533 @Override public A applyX(ObjectInputStream in) throws Exception {
534 return (A) in.readObject();
535 }
536 });
537 } catch (IOException e) {
538 return Prelude.chuck(e);
539 }
540 }
541 }