/* * Copyright (c) 2015 Data Harmonisation Panel * * All rights reserved. This program and the accompanying materials are made * available 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. * * You should have received a copy of the GNU Lesser General Public License * along with this distribution. If not, see <http://www.gnu.org/licenses/>. * * Contributors: * Data Harmonisation Panel <http://www.dhpanel.eu> */ package eu.esdihumboldt.hale.io.geoserver.template; import java.io.BufferedOutputStream; import java.io.ByteArrayInputStream; import java.io.File; import java.io.FileOutputStream; import java.io.IOException; import java.io.InputStream; import java.io.OutputStream; import java.io.StringWriter; import java.util.Map; import org.apache.commons.io.IOUtils; import org.apache.velocity.Template; import org.apache.velocity.VelocityContext; import org.apache.velocity.app.VelocityEngine; import com.google.common.io.Files; /** * Singleton class encapsulating a Velocity engine instance. * * @author Stefano Costa, GeoSolutions */ public class Templates { private static Templates instance; /** * Return the singleton factory instance. * * @return the factory instance * @throws TemplateException if an error occurs initializing the template * engine */ public static Templates getInstance() throws TemplateException { if (instance == null) { instance = new Templates(); } return instance; } private final File tmpDir; private final VelocityEngine ve; private Templates() throws TemplateException { ve = new VelocityEngine(); tmpDir = Files.createTempDir(); tmpDir.deleteOnExit(); ve.setProperty(VelocityEngine.RUNTIME_LOG_LOGSYSTEM_CLASS, "org.apache.velocity.runtime.log.JdkLogChute"); ve.setProperty(VelocityEngine.RESOURCE_LOADER, "file"); ve.setProperty("class.resource.loader.description", "Velocity File Resource Loader"); ve.setProperty("file.resource.loader.class", "org.apache.velocity.runtime.resource.loader.FileResourceLoader"); ve.setProperty("file.resource.loader.path", tmpDir.getAbsolutePath()); try { ve.init(); } catch (Exception e) { throw new TemplateException(e); } } /** * Loads the specified template file and merges it with a Velocity context * instance created from the provided variables; the final output is * returned as an {@link InputStream} instance. * * <p> * NOTE: due to a problem with Velocity's classpath loader not working in an * OSGi context, the template file is first copied to a temp file and then * loaded from there. {@link File#deleteOnExit()} is invoked on the temp * file <code>File</code> object after the template is merged. * </p> * * @param templateResource the template to load * @param variables the template context * @return the result of merging the template with the provided context * @throws TemplateException if an error occurs processing the template */ public InputStream loadTemplate(String templateResource, Map<String, Object> variables) throws TemplateException { VelocityContext vc = new VelocityContext(variables); try { File templateFile = copyTemplateToFile(templateResource); Template template = ve.getTemplate(templateFile.getName(), "UTF-8"); StringWriter sw = new StringWriter(); template.merge(vc, sw); templateFile.deleteOnExit(); return new ByteArrayInputStream(sw.toString().getBytes("UTF-8")); } catch (Exception e) { throw new TemplateException(e); } } private File copyTemplateToFile(String templateResource) throws IOException { InputStream templateStream = getClass().getResourceAsStream(templateResource); if (templateStream == null) { throw new IOException("Template resource not found: " + templateResource); } File templateFile = new File(tmpDir, createRandomTemplateName(templateResource)); OutputStream outputStream = null; try { outputStream = new BufferedOutputStream(new FileOutputStream(templateFile)); IOUtils.copy(templateStream, outputStream); return templateFile; } finally { closeAndIgnoreException(templateStream); closeAndIgnoreException(outputStream); } } private String createRandomTemplateName(String templateResource) { return "template" + templateResource.hashCode() + System.currentTimeMillis() + ".vm"; } private void closeAndIgnoreException(InputStream in) { if (in != null) { try { in.close(); } catch (IOException e) { // ignore } } } private void closeAndIgnoreException(OutputStream out) { if (out != null) { try { out.close(); } catch (IOException e) { // ignore } } } }