Hi people,
below is my shot at a DBResourceLoader for Velocity.
I needed this for the project I am currently involved in
and figured it might be useful for others as well. Could
you please have a look and perhaps consider it for inclusion
into the main Velocity tree if it's not too shabby?
Regards,
David.
velocity.properties snippet for configuring it:
#---
# DBResourceLoader config
#---
#
resource.loader.2.public.name = DB
resource.loader.2.description = Velocity DB Resource Loader
resource.loader.2.class =
org.apache.velocity.runtime.resource.loader.DBResourceLoader
resource.loader.2.resource.datasource = jdbc/SomeDS
resource.loader.2.resource.table = template_table
resource.loader.2.resource.keycolumn = template_id
resource.loader.2.resource.templatecolumn = template_definition
resource.loader.2.resource.timestampcolumn = template_timestamp
resource.loader.2.cache = false
resource.loader.2.modificationCheckInterval = 2
and DBResourceLoader.java itself:
package org.apache.velocity.runtime.resource.loader;
/*
* The Apache Software License, Version 1.1
*
* Copyright (c) 2000 The Apache Software Foundation. All rights
* reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
*
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
*
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in
* the documentation and/or other materials provided with the
* distribution.
*
* 3. The end-user documentation included with the redistribution, if
* any, must include the following acknowlegement:
* "This product includes software developed by the
* Apache Software Foundation (http://www.apache.org/)."
* Alternately, this acknowlegement may appear in the software itself,
* if and wherever such third-party acknowlegements normally appear.
*
* 4. The names "The Jakarta Project", "Tomcat", and "Apache Software
* Foundation" must not be used to endorse or promote products derived
* from this software without prior written permission. For written
* permission, please contact [EMAIL PROTECTED]
*
* 5. Products derived from this software may not be called "Apache"
* nor may "Apache" appear in their names without prior written
* permission of the Apache Group.
*
* THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED
* WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
* OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
* DISCLAIMED. IN NO EVENT SHALL THE APACHE SOFTWARE FOUNDATION OR
* ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
* LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
* USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
* ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
* OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
* OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
* SUCH DAMAGE.
* ====================================================================
*
* This software consists of voluntary contributions made by many
* individuals on behalf of the Apache Software Foundation. For more
* information on the Apache Software Foundation, please see
* <http://www.apache.org/>.
*/
import java.io.InputStream;
import java.io.StringReader;
import java.io.BufferedInputStream;
import java.sql.*;
import javax.sql.DataSource;
import javax.naming.InitialContext;
import java.util.Map;
import java.util.Hashtable;
import org.apache.velocity.util.StringUtils;
import org.apache.velocity.runtime.Runtime;
import org.apache.velocity.runtime.resource.Resource;
/**
* This is a simple template file loader that loads templates
* from a DataSource instead of plain files.
*
* It can be configured with a datasource name, a table name,
* id column (name), content column (the template body) and a
* timestamp column (for last modification info).
*
* @author <a href="mailto:[EMAIL PROTECTED]">David Kinnvall</a>
*/
public class DBResourceLoader extends ResourceLoader
{
private String dataSourceName;
private String tableName;
private String keyColumn;
private String templateColumn;
private String timestampColumn;
private InitialContext ctx;
private DataSource dataSource;
/*
* This should probably be moved into the super class,
* the stand init stuff. For the properties that all
* loaders will probably share.
*/
public void init(Map initializer)
{
dataSourceName = (String) initializer.get("resource.datasource");
tableName = (String) initializer.get("resource.table");
keyColumn = (String) initializer.get("resource.keycolumn");
templateColumn = (String) initializer.get("resource.templatecolumn");
timestampColumn = (String)
initializer.get("resource.timestampcolumn");
Runtime.info("Resources Loaded From: " + dataSourceName + "/" +
tableName);
Runtime.info("Resource Loader using columns: " + keyColumn + ", "
+ templateColumn + " and " + timestampColumn);
Runtime.info("Resource Loader Initalized.");
}
/**
* Get an InputStream so that the Runtime can build a
* template with it.
*/
public synchronized InputStream getResourceStream( String name )
throws Exception
{
if (name == null || name.length() == 0)
{
throw new Exception ("Need to specify a template name!");
}
Connection conn = null;
try {
if(ctx == null) ctx = new InitialContext();
if(dataSource == null) dataSource =
(DataSource)ctx.lookup(dataSourceName);
conn = dataSource.getConnection();
Statement stmt = conn.createStatement();
String query = "select " + templateColumn
+ " from " + tableName
+ " where " + keyColumn + " = '" + name + "'";
ResultSet rs = stmt.executeQuery(query);
if(rs.next())
{
return new
BufferedInputStream(rs.getAsciiStream(templateColumn));
}
else
{
Runtime.error("DBResourceLoader Error: cannot find
resource " + name);
}
} catch (Exception e) {
Runtime.error("DBResourceLoader Error: database problem trying
to load resource " + name + ": " + e.toString());
} finally {
try {
conn.close();
} catch (Exception e) {
Runtime.info("DBResourceLoader Quirk: problem when closing
connection: " + e.toString());
}
}
return null;
}
public boolean isSourceModified(Resource resource)
{
String name = resource.getName();
Connection conn = null;
try {
if(ctx == null) ctx = new InitialContext();
if(dataSource == null) dataSource =
(DataSource)ctx.lookup(dataSourceName);
conn = dataSource.getConnection();
Statement stmt = conn.createStatement();
String query = "select " + timestampColumn
+ " from " + tableName
+ " where " + keyColumn + " = '" + name + "'";
ResultSet rs = stmt.executeQuery(query);
if(rs.next())
{
long lastModified = rs.getLong(timestampColumn);
if (lastModified != resource.getLastModified())
return true;
else
return false;
}
else
{
Runtime.info("DBResourceLoader Error: cannot check
timestamp on resource " + name);
}
} catch (Exception e) {
Runtime.info("DBResourceLoader Error: database problem
checking timestamp on resource " + name + ": " + e.toString());
} finally {
try {
conn.close();
} catch (Exception e) {
Runtime.info("DBResourceLoader Quirk: problem when closing
connection: " + e.toString());
}
}
return true;
}
public long getLastModified(Resource resource)
{
String name = resource.getName();
Connection conn = null;
try {
if(ctx == null) ctx = new InitialContext();
if(dataSource == null) dataSource =
(DataSource)ctx.lookup(dataSourceName);
conn = dataSource.getConnection();
Statement stmt = conn.createStatement();
String query = "select " + timestampColumn
+ " from " + tableName
+ " where " + keyColumn + " = '" + name + "'";
ResultSet rs = stmt.executeQuery(query);
if(rs.next())
{
return rs.getLong(timestampColumn);
}
else
{
Runtime.info("DBResourceLoader Error: cannot get timestamp
on resource " + name);
}
} catch (Exception e) {
Runtime.info("DBResourceLoader Error: database problem getting
timestamp on resource " + name + ": " + e.toString());
} finally {
try {
conn.close();
} catch (Exception e) {
Runtime.info("DBResourceLoader Quirk: problem when closing
connection: " + e.toString());
}
}
return 0;
}
}
--
David Kinnvall
Alert Investor Relations AB
+46 31 802640/10, +46 31 802670 (fax), +46 705 818432 (mobile)