1 | /** |
2 | * Licensed to jclouds, Inc. (jclouds) under one or more |
3 | * contributor license agreements. See the NOTICE file |
4 | * distributed with this work for additional information |
5 | * regarding copyright ownership. jclouds licenses this file |
6 | * to you under the Apache License, Version 2.0 (the |
7 | * "License"); you may not use this file except in compliance |
8 | * with the License. You may obtain a copy of the License at |
9 | * |
10 | * http://www.apache.org/licenses/LICENSE-2.0 |
11 | * |
12 | * Unless required by applicable law or agreed to in writing, |
13 | * software distributed under the License is distributed on an |
14 | * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY |
15 | * KIND, either express or implied. See the License for the |
16 | * specific language governing permissions and limitations |
17 | * under the License. |
18 | */ |
19 | package org.jclouds.util; |
20 | |
21 | import java.io.IOException; |
22 | import java.io.InputStream; |
23 | import java.util.LinkedList; |
24 | |
25 | /** |
26 | * {@link InputStream} implementation that allows chaining of various streams for seamless |
27 | * sequential reading |
28 | * |
29 | * @author Adrian Cole |
30 | * @author Tomas Varaneckas <tomas.varaneckas@gmail.com> |
31 | */ |
32 | public class InputStreamChain extends InputStream { |
33 | |
34 | /** |
35 | * Input stream chain |
36 | */ |
37 | private final LinkedList<InputStream> streams = new LinkedList<InputStream>(); |
38 | |
39 | /** |
40 | * Currently active stream |
41 | */ |
42 | private InputStream current; |
43 | |
44 | public InputStreamChain(InputStream... inputStreams) { |
45 | for (InputStream stream : inputStreams) { |
46 | addInputStream(stream); |
47 | } |
48 | } |
49 | |
50 | /** |
51 | * Adds input stream to the end of chain |
52 | * |
53 | * @param stream |
54 | * InputStream to add to chain |
55 | * @return instance of self (for fluent calls) |
56 | */ |
57 | public InputStreamChain addInputStream(final InputStream stream) { |
58 | streams.addLast(stream); |
59 | if (current == null) { |
60 | current = streams.removeFirst(); |
61 | } |
62 | return this; |
63 | } |
64 | |
65 | /** |
66 | * Adds a String to the end of chain |
67 | * |
68 | * @param value |
69 | * String to add to the chain |
70 | * @return instance of self (for fluent calls) |
71 | */ |
72 | public InputStreamChain addAsInputStream(final String value) { |
73 | return addInputStream(Strings2.toInputStream(value)); |
74 | } |
75 | |
76 | @Override |
77 | public int read() throws IOException { |
78 | int bit = current.read(); |
79 | if (bit == -1 && streams.size() > 0) { |
80 | try { |
81 | current.close(); |
82 | } catch (final IOException e) { |
83 | // replace this with a call to logging facility |
84 | e.printStackTrace(); |
85 | } |
86 | current = streams.removeFirst(); |
87 | bit = read(); |
88 | } |
89 | return bit; |
90 | } |
91 | |
92 | @Override |
93 | public int available() throws IOException { |
94 | int available = current.available(); |
95 | for (InputStream stream : streams) { |
96 | available += stream.available(); |
97 | } |
98 | return available; |
99 | } |
100 | |
101 | @Override |
102 | public void close() throws IOException { |
103 | current.close(); |
104 | } |
105 | |
106 | @Override |
107 | public boolean markSupported() { |
108 | return current.markSupported(); |
109 | } |
110 | |
111 | @Override |
112 | public synchronized void mark(int i) { |
113 | current.mark(i); |
114 | } |
115 | |
116 | @Override |
117 | public synchronized void reset() throws IOException { |
118 | current.reset(); |
119 | } |
120 | |
121 | @Override |
122 | public long skip(long l) throws IOException { |
123 | return current.skip(l); |
124 | } |
125 | |
126 | } |