| /* |
| * Licensed to the Apache Software Foundation (ASF) under one or more |
| * contributor license agreements. See the NOTICE file distributed with |
| * this work for additional information regarding copyright ownership. |
| * The ASF licenses this file to You under the Apache License, Version 2.0 |
| * (the "License"); you may not use this file except in compliance with |
| * the License. You may obtain a copy of the License at |
| * |
| * http://www.apache.org/licenses/LICENSE-2.0 |
| * |
| * Unless required by applicable law or agreed to in writing, software |
| * distributed under the License is distributed on an "AS IS" BASIS, |
| * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
| * See the License for the specific language governing permissions and |
| * limitations under the License. |
| */ |
| package org.apache.servicemix.maven.plugin.res; |
| |
| import java.io.FilterReader; |
| import java.io.IOException; |
| import java.io.Reader; |
| import java.util.HashMap; |
| import java.util.Map; |
| |
| /** |
| */ |
| public class InterpolationFilterReader extends FilterReader { |
| /** replacement text from a token */ |
| private String replaceData; |
| |
| /** Index into replacement data */ |
| private int replaceIndex = -1; |
| |
| /** Hashtable to hold the replacee-replacer pairs (String to String). */ |
| private Map variables = new HashMap(); |
| |
| /** Character marking the beginning of a token. */ |
| private String beginToken; |
| |
| /** Character marking the end of a token. */ |
| private String endToken; |
| |
| /** Length of begin token. */ |
| private int beginTokenLength; |
| |
| /** Length of end token. */ |
| private int endTokenLength; |
| |
| public InterpolationFilterReader(Reader in, Map variables, String beginToken, String endToken) { |
| super(in); |
| |
| this.variables = variables; |
| this.beginToken = beginToken; |
| this.endToken = endToken; |
| |
| beginTokenLength = beginToken.length(); |
| endTokenLength = endToken.length(); |
| } |
| |
| /** |
| * Skips characters. This method will block until some characters are |
| * available, an I/O error occurs, or the end of the stream is reached. |
| * |
| * @param n The number of characters to skip |
| * |
| * @return the number of characters actually skipped |
| * |
| * @exception IllegalArgumentException If <code>n</code> is negative. |
| * @exception IOException If an I/O error occurs |
| */ |
| public long skip(long n) throws IOException { |
| if (n < 0L) { |
| throw new IllegalArgumentException("skip value is negative"); |
| } |
| |
| for (long i = 0; i < n; i++) { |
| if (read() == -1) { |
| return i; |
| } |
| } |
| return n; |
| } |
| |
| /** |
| * Reads characters into a portion of an array. This method will block |
| * until some input is available, an I/O error occurs, or the end of the |
| * stream is reached. |
| * |
| * @param cbuf Destination buffer to write characters to. |
| * Must not be <code>null</code>. |
| * @param off Offset at which to start storing characters. |
| * @param len Maximum number of characters to read. |
| * |
| * @return the number of characters read, or -1 if the end of the |
| * stream has been reached |
| * |
| * @exception IOException If an I/O error occurs |
| */ |
| public int read(char cbuf[], int off, int len) throws IOException { |
| for (int i = 0; i < len; i++) { |
| int ch = read(); |
| if (ch == -1) { |
| if (i == 0) { |
| return -1; |
| } else { |
| return i; |
| } |
| } |
| cbuf[off + i] = (char)ch; |
| } |
| return len; |
| } |
| |
| /** |
| * Returns the next character in the filtered stream, replacing tokens |
| * from the original stream. |
| * |
| * @return the next character in the resulting stream, or -1 |
| * if the end of the resulting stream has been reached |
| * |
| * @exception IOException if the underlying stream throws an IOException |
| * during reading |
| */ |
| public int read() throws IOException { |
| if (replaceIndex != -1) { |
| int ch = replaceData.charAt(replaceIndex++); |
| if (replaceIndex >= replaceData.length()) { |
| replaceIndex = -1; |
| } |
| return ch; |
| } |
| |
| int ch = in.read(); |
| |
| if (ch == beginToken.charAt(0)) { |
| StringBuffer key = new StringBuffer(); |
| |
| int beginTokenMatchPos = 1; |
| |
| do { |
| ch = in.read(); |
| if (ch != -1) { |
| key.append((char)ch); |
| |
| if ((beginTokenMatchPos < beginTokenLength) |
| && (ch != beginToken.charAt(beginTokenMatchPos++))) { |
| ch = -1; // not really EOF but to trigger code below |
| break; |
| } |
| } else { |
| break; |
| } |
| } while (ch != endToken.charAt(0)); |
| |
| // now test endToken |
| if (ch != -1 && endTokenLength > 1) { |
| int endTokenMatchPos = 1; |
| |
| do { |
| ch = in.read(); |
| |
| if (ch != -1) { |
| key.append((char)ch); |
| |
| if (ch != endToken.charAt(endTokenMatchPos++)) { |
| ch = -1; // not really EOF but to trigger code below |
| break; |
| } |
| |
| } else { |
| break; |
| } |
| } while (endTokenMatchPos < endTokenLength); |
| } |
| |
| // There is nothing left to read so we have the situation where the begin/end token |
| // are in fact the same and as there is nothing left to read we have got ourselves |
| // end of a token boundary so let it pass through. |
| if (ch == -1) { |
| replaceData = key.toString(); |
| replaceIndex = 0; |
| return beginToken.charAt(0); |
| } |
| |
| String variableKey = key.substring(beginTokenLength - 1, key.length() - endTokenLength); |
| |
| Object o = variables.get(variableKey); |
| if (o != null) { |
| String value = o.toString(); |
| if (value.length() != 0) { |
| replaceData = value; |
| replaceIndex = 0; |
| } |
| return read(); |
| } else { |
| replaceData = key.toString(); |
| replaceIndex = 0; |
| return beginToken.charAt(0); |
| } |
| } |
| |
| return ch; |
| } |
| } |