/*
* (C) Copyright 2006-2010 Nuxeo SAS (http://nuxeo.com/) and contributors.
*
* All rights reserved. This program and the accompanying materials
* are made available under the terms of the GNU Lesser General Public License
* (LGPL) version 2.1 which accompanies this distribution, and is available at
* http://www.gnu.org/licenses/lgpl.html
*
* This library 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.
*
* Contributors:
* Nuxeo - initial API and implementation
* bstefanescu, jcarsique
*
* $Id$
*/
package org.nuxeo.common.utils;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;
import java.util.Properties;
import java.util.StringTokenizer;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
/**
* Text template processing.
* <p>
* Copy files or directories replacing parameters matching pattern
* '${[a-zA-Z_0-9\-\.]+}' with values from a {@link Map} (deprecated) or a
* {@link Properties}.
* <p>
* Method {@link #setParsingExtensions(String)} allow to set list of files being
* processed when using {@link #processDirectory(File, File)} or #pro, others
* are simply copied.
*
* @author <a href="mailto:bs@nuxeo.com">Bogdan Stefanescu</a>
*/
public class TextTemplate {
private static final Pattern PATTERN = Pattern.compile("\\$\\{([a-zA-Z_0-9\\-\\.]+)\\}");
private final Properties vars;
private boolean trim = false;
private List<String> extensions;
public boolean isTrim() {
return trim;
}
/**
* Set to true in order to trim invisible characters (spaces) from values.
*/
public void setTrim(boolean trim) {
this.trim = trim;
}
public TextTemplate() {
vars = new Properties();
}
/**
* @deprecated prefer use of {@link #TextTemplate(Properties)}
*/
@Deprecated
public TextTemplate(Map<String, String> vars) {
this.vars = new Properties();
this.vars.putAll(vars);
}
/**
* @param vars Properties containing keys and values for template processing
*/
public TextTemplate(Properties vars) {
this.vars = vars;
}
/**
* @deprecated prefer use of {@link #getVariables()} then {@link Properties}
* .load()
*/
@Deprecated
public void setVariables(Map<String, String> vars) {
this.vars.putAll(vars);
}
public void setVariable(String name, String value) {
vars.setProperty(name, value);
}
public String getVariable(String name) {
return vars.getProperty(name);
}
public Properties getVariables() {
return vars;
}
public String process(CharSequence text) {
Matcher m = PATTERN.matcher(text);
StringBuffer sb = new StringBuffer();
while (m.find()) {
String var = m.group(1);
String value = getVariable(var);
if (value != null) {
if (trim) {
value = value.trim();
}
// Allow use of backslash and dollars characters
String valueL = Matcher.quoteReplacement(value);
m.appendReplacement(sb, valueL);
}
}
m.appendTail(sb);
return sb.toString();
}
public String process(InputStream in) throws IOException {
String text = FileUtils.read(in);
return process(text);
}
public void process(InputStream in, OutputStream out) throws IOException {
process(in, out, true);
}
/**
* Recursive call {@link #process(InputStream, OutputStream, boolean)} on
* each file from "in" directory to "out" directory.
*
* @param in Directory to read files from
* @param out Directory to write files to
*/
public void processDirectory(File in, File out)
throws FileNotFoundException, IOException {
if (in.isFile()) {
if (out.isDirectory()) {
out = new File(out, in.getName());
}
int extIndex = in.getName().lastIndexOf('.');
String extension = extIndex == -1 ? "" : in.getName().substring(
extIndex + 1).toLowerCase();
FileInputStream is = null;
FileOutputStream os = new FileOutputStream(out);
try {
is = new FileInputStream(in);
process(is, os,
extensions == null || extensions.contains(extension));
} finally {
if (is != null) {
is.close();
}
os.close();
}
} else if (in.isDirectory()) {
if (!out.exists()) {
// allow renaming destination directory
out.mkdirs();
} else if (!out.getName().equals(in.getName())) {
// allow copy over existing arborescence
out = new File(out, in.getName());
out.mkdir();
}
for (File file : in.listFiles()) {
processDirectory(file, out);
}
}
}
/**
* @param processText if true, text is processed for parameters replacement
*/
public void process(InputStream is, OutputStream os, boolean processText)
throws IOException {
if (processText) {
String text = FileUtils.read(is);
text = process(text);
os.write(text.getBytes());
} else {
FileUtils.copy(is, os);
}
}
/**
* @param extensionsList comma-separated list of files extensions to parse
*/
public void setParsingExtensions(String extensionsList) {
StringTokenizer st = new StringTokenizer(extensionsList, ",");
extensions = new ArrayList<String>();
while (st.hasMoreTokens()) {
extensions.add(st.nextToken());
}
}
}