Classes in this File | Line Coverage | Branch Coverage | Complexity | ||||||||
InterpolationFilterReader |
|
| 6.4;6.4 |
1 | /* |
|
2 | * The Apache Software License, Version 1.1 |
|
3 | * |
|
4 | * Copyright (c) 2002-2003 The Apache Software Foundation. All rights |
|
5 | * reserved. |
|
6 | * |
|
7 | * Redistribution and use in source and binary forms, with or without |
|
8 | * modification, are permitted provided that the following conditions |
|
9 | * are met: |
|
10 | * |
|
11 | * 1. Redistributions of source code must retain the above copyright |
|
12 | * notice, this list of conditions and the following disclaimer. |
|
13 | * |
|
14 | * 2. Redistributions in binary form must reproduce the above copyright |
|
15 | * notice, this list of conditions and the following disclaimer in |
|
16 | * the documentation and/or other materials provided with the |
|
17 | * distribution. |
|
18 | * |
|
19 | * 3. The end-user documentation included with the redistribution, if |
|
20 | * any, must include the following acknowlegement: |
|
21 | * "This product includes software developed by the |
|
22 | * Apache Software Foundation (http://www.codehaus.org/)." |
|
23 | * Alternately, this acknowlegement may appear in the software itself, |
|
24 | * if and wherever such third-party acknowlegements normally appear. |
|
25 | * |
|
26 | * 4. The names "Ant" and "Apache Software |
|
27 | * Foundation" must not be used to endorse or promote products derived |
|
28 | * from this software without prior written permission. For written |
|
29 | * permission, please contact codehaus@codehaus.org. |
|
30 | * |
|
31 | * 5. Products derived from this software may not be called "Apache" |
|
32 | * nor may "Apache" appear in their names without prior written |
|
33 | * permission of the Apache Group. |
|
34 | * |
|
35 | * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED |
|
36 | * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES |
|
37 | * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE |
|
38 | * DISCLAIMED. IN NO EVENT SHALL THE APACHE SOFTWARE FOUNDATION OR |
|
39 | * ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, |
|
40 | * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT |
|
41 | * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF |
|
42 | * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND |
|
43 | * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, |
|
44 | * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT |
|
45 | * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF |
|
46 | * SUCH DAMAGE. |
|
47 | * ==================================================================== |
|
48 | * |
|
49 | * This software consists of voluntary contributions made by many |
|
50 | * individuals on behalf of the Apache Software Foundation. For more |
|
51 | * information on the Apache Software Foundation, please see |
|
52 | * <http://www.codehaus.org/>. |
|
53 | */ |
|
54 | ||
55 | package org.apache.maven.plugin.resources.util; |
|
56 | ||
57 | import java.io.FilterReader; |
|
58 | import java.io.IOException; |
|
59 | import java.io.Reader; |
|
60 | import java.util.HashMap; |
|
61 | import java.util.Map; |
|
62 | ||
63 | /** |
|
64 | */ |
|
65 | public class InterpolationFilterReader |
|
66 | extends FilterReader |
|
67 | { |
|
68 | /** replacement text from a token */ |
|
69 | 18 | private String replaceData = null; |
70 | ||
71 | /** Index into replacement data */ |
|
72 | 18 | private int replaceIndex = -1; |
73 | ||
74 | /** Hashtable to hold the replacee-replacer pairs (String to String). */ |
|
75 | 18 | private Map variables = new HashMap(); |
76 | ||
77 | /** Character marking the beginning of a token. */ |
|
78 | private String beginToken; |
|
79 | ||
80 | /** Character marking the end of a token. */ |
|
81 | private String endToken; |
|
82 | ||
83 | /** Length of begin token. */ |
|
84 | private int beginTokenLength; |
|
85 | ||
86 | /** Length of end token. */ |
|
87 | private int endTokenLength; |
|
88 | ||
89 | /** Default begin token. */ |
|
90 | 1 | private static String DEFAULT_BEGIN_TOKEN = "${"; |
91 | ||
92 | /** Default end token. */ |
|
93 | 1 | private static String DEFAULT_END_TOKEN = "}"; |
94 | ||
95 | public InterpolationFilterReader( Reader in, Map variables, String beginToken, String endToken ) |
|
96 | { |
|
97 | 18 | super( in ); |
98 | ||
99 | 18 | this.variables = variables; |
100 | 18 | this.beginToken = beginToken; |
101 | 18 | this.endToken = endToken; |
102 | ||
103 | 18 | beginTokenLength = beginToken.length(); |
104 | 18 | endTokenLength = endToken.length(); |
105 | 18 | } |
106 | ||
107 | public InterpolationFilterReader( Reader in, Map variables ) |
|
108 | { |
|
109 | 0 | this( in, variables, DEFAULT_BEGIN_TOKEN, DEFAULT_END_TOKEN ); |
110 | 0 | } |
111 | ||
112 | /** |
|
113 | * Skips characters. This method will block until some characters are |
|
114 | * available, an I/O error occurs, or the end of the stream is reached. |
|
115 | * |
|
116 | * @param n The number of characters to skip |
|
117 | * |
|
118 | * @return the number of characters actually skipped |
|
119 | * |
|
120 | * @exception IllegalArgumentException If <code>n</code> is negative. |
|
121 | * @exception IOException If an I/O error occurs |
|
122 | */ |
|
123 | public long skip( long n ) throws IOException |
|
124 | { |
|
125 | 0 | if ( n < 0L ) |
126 | { |
|
127 | 0 | throw new IllegalArgumentException( "skip value is negative" ); |
128 | } |
|
129 | ||
130 | 0 | for ( long i = 0; i < n; i++ ) |
131 | { |
|
132 | 0 | if ( read() == -1 ) |
133 | { |
|
134 | 0 | return i; |
135 | } |
|
136 | } |
|
137 | 0 | return n; |
138 | } |
|
139 | ||
140 | /** |
|
141 | * Reads characters into a portion of an array. This method will block |
|
142 | * until some input is available, an I/O error occurs, or the end of the |
|
143 | * stream is reached. |
|
144 | * |
|
145 | * @param cbuf Destination buffer to write characters to. |
|
146 | * Must not be <code>null</code>. |
|
147 | * @param off Offset at which to start storing characters. |
|
148 | * @param len Maximum number of characters to read. |
|
149 | * |
|
150 | * @return the number of characters read, or -1 if the end of the |
|
151 | * stream has been reached |
|
152 | * |
|
153 | * @exception IOException If an I/O error occurs |
|
154 | */ |
|
155 | public int read( char cbuf[], |
|
156 | int off, |
|
157 | int len ) |
|
158 | throws IOException |
|
159 | { |
|
160 | 215 | for ( int i = 0; i < len; i++ ) |
161 | { |
|
162 | 215 | int ch = read(); |
163 | 215 | if ( ch == -1 ) |
164 | { |
|
165 | 11 | if ( i == 0 ) |
166 | { |
|
167 | 6 | return -1; |
168 | } |
|
169 | else |
|
170 | { |
|
171 | 5 | return i; |
172 | } |
|
173 | } |
|
174 | 204 | cbuf[off + i] = (char) ch; |
175 | } |
|
176 | 0 | return len; |
177 | } |
|
178 | ||
179 | /** |
|
180 | * Returns the next character in the filtered stream, replacing tokens |
|
181 | * from the original stream. |
|
182 | * |
|
183 | * @return the next character in the resulting stream, or -1 |
|
184 | * if the end of the resulting stream has been reached |
|
185 | * |
|
186 | * @exception IOException if the underlying stream throws an IOException |
|
187 | * during reading |
|
188 | */ |
|
189 | public int read() throws IOException |
|
190 | { |
|
191 | 629 | if ( replaceIndex != -1 ) |
192 | { |
|
193 | 98 | int ch = replaceData.charAt( replaceIndex++ ); |
194 | 98 | if ( replaceIndex >= replaceData.length() ) |
195 | { |
|
196 | 5 | replaceIndex = -1; |
197 | } |
|
198 | 98 | return ch; |
199 | } |
|
200 | ||
201 | 531 | int ch = in.read(); |
202 | ||
203 | 531 | if ( ch == beginToken.charAt( 0 ) ) |
204 | { |
|
205 | 5 | StringBuffer key = new StringBuffer(); |
206 | ||
207 | 5 | int beginTokenMatchPos = 1; |
208 | ||
209 | do |
|
210 | { |
|
211 | 51 | ch = in.read(); |
212 | 51 | if ( ch != -1 ) |
213 | { |
|
214 | 51 | key.append( (char) ch ); |
215 | ||
216 | 51 | if ( ( beginTokenMatchPos < beginTokenLength ) && |
217 | ( ch != beginToken.charAt( beginTokenMatchPos++ ) ) ) |
|
218 | { |
|
219 | 0 | ch = -1; // not really EOF but to trigger code below |
220 | 0 | break; |
221 | } |
|
222 | } |
|
223 | else |
|
224 | { |
|
225 | break; |
|
226 | } |
|
227 | } |
|
228 | 51 | while ( ch != endToken.charAt( 0 ) ); |
229 | ||
230 | // now test endToken |
|
231 | 5 | if ( ch != -1 && endTokenLength > 1 ) |
232 | { |
|
233 | 0 | int endTokenMatchPos = 1; |
234 | ||
235 | do |
|
236 | { |
|
237 | 0 | ch = in.read(); |
238 | ||
239 | 0 | if ( ch != -1 ) |
240 | { |
|
241 | 0 | key.append( (char) ch ); |
242 | ||
243 | 0 | if ( ch != endToken.charAt( endTokenMatchPos++ ) ) |
244 | { |
|
245 | 0 | ch = -1; // not really EOF but to trigger code below |
246 | 0 | break; |
247 | } |
|
248 | ||
249 | } |
|
250 | else |
|
251 | { |
|
252 | break; |
|
253 | } |
|
254 | } |
|
255 | 0 | while ( endTokenMatchPos < endTokenLength ); |
256 | } |
|
257 | ||
258 | // There is nothing left to read so we have the situation where the begin/end token |
|
259 | // are in fact the same and as there is nothing left to read we have got ourselves |
|
260 | // end of a token boundary so let it pass through. |
|
261 | 5 | if ( ch == -1 ) |
262 | { |
|
263 | 0 | replaceData = key.toString(); |
264 | 0 | replaceIndex = 0; |
265 | 0 | return beginToken.charAt( 0 ); |
266 | } |
|
267 | ||
268 | 5 | String variableKey = key.substring( beginTokenLength - 1, key.length() - endTokenLength ); |
269 | ||
270 | 5 | Object o = variables.get(variableKey); |
271 | 5 | if ( o != null ) |
272 | { |
|
273 | 4 | String value = o.toString(); |
274 | 4 | if ( value.length() != 0 ) |
275 | { |
|
276 | 4 | replaceData = value; |
277 | 4 | replaceIndex = 0; |
278 | } |
|
279 | 4 | return read(); |
280 | } |
|
281 | else |
|
282 | { |
|
283 | 1 | replaceData = key.toString(); |
284 | 1 | replaceIndex = 0; |
285 | 1 | return beginToken.charAt(0); |
286 | } |
|
287 | } |
|
288 | ||
289 | 526 | return ch; |
290 | } |
|
291 | } |