/* * Copyright (c) 2005-2016 Vincent Vandenschrick. All rights reserved. * * This file is part of the Jspresso framework. * * Jspresso is free software: you can redistribute it and/or modify * it under the terms of the GNU Lesser General Public License as published by * the Free Software Foundation, either version 3 of the License, or * (at your option) any later version. * * Jspresso is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public License * along with Jspresso. If not, see <http://www.gnu.org/licenses/>. */ package org.jspresso.framework.util.io; import java.io.FilterInputStream; import java.io.IOException; import java.io.InputStream; import java.util.Map; /** * A filtered input stream that replaces placeholders on the fly based on a * substitution map. * * @author Vincent Vandenschrick */ public class PlaceholderInputStream extends FilterInputStream { private final Map<String, String> variables; private String buffer; private int buffOffset; /** * Creates an PlaceholderInputStream.. * * @param sourceStream * the InputStream to be filtered. * @param variables * the map of key/value pairs. */ public PlaceholderInputStream(InputStream sourceStream, Map<String, String> variables) { super(sourceStream); this.variables = variables; this.buffOffset = -1; } /** * Reads the next byte from the stream per the general contract of * InputStream.read(). Returns -1 on error or end of stream. * <p> * {@inheritDoc} */ @Override public int read() throws IOException { if (buffer != null) { if (buffOffset >= 0 && buffOffset < buffer.length()) { return buffer.charAt(buffOffset++); } buffer = null; buffOffset = -1; } int first = super.read(); if ('$' == first) { int second = super.read(); if ('{' == second) { StringBuilder temp = new StringBuilder(); int next = super.read(); while (next > 0 && next != '}') { temp.append((char) next); next = super.read(); } if (next < 0) { buffer = "{" + temp.toString(); buffOffset = 0; return '$'; } if (temp.length() > 0) { buffer = temp.toString(); if (variables.containsKey(buffer)) { buffer = variables.get(buffer); } else { buffer = "${" + buffer + "}"; } if (buffer != null && buffer.length() > 0) { buffOffset = 1; return buffer.charAt(0); } return read(); } return read(); } buffer = new String(new char[] { (char) second }); buffOffset = 0; return '$'; } return first; } /** * Returns false. * @return false; */ @Override public boolean markSupported() { return false; } /** * {@inheritDoc} */ @Override public int read(byte[] b, int off, int len) throws IOException { // return super.read(b, off, len); if (b == null) { throw new NullPointerException(); } if ((off < 0) || (off > b.length) || (len < 0) || ((off + len) > b.length) || ((off + len) < 0)) { throw new IndexOutOfBoundsException(); } if (len == 0) { return 0; } int c = read(); if (c == -1) { return -1; } b[off] = (byte) c; int i = 1; try { for (; i < len; i++) { c = read(); if (c == -1) { break; } b[off + i] = (byte) c; } } catch (IOException ee) { // Never } return i; } // public static void main(String[] args) throws IOException { // String test = // "Ceci ${missing} est un test ${good} [${null},${empty}]. ${missingclosing"; // Map<String, String> variables = new HashMap<String, String>(); // variables.put("good", "Vincent"); // variables.put("null", null); // variables.put("empty", ""); // InputStream is = new ByteArrayInputStream(test.getBytes()); // is = new PlaceholderInputStream(is, variables); // int next = is.read(); // while (next > 0) { // System.out.print((char) next); // next = is.read(); // } // } }