Source code: org/roller/presentation/velocity/DataSourceResourceLoader.java
1 package org.roller.presentation.velocity;
2
3
4 /*
5 * The Apache Software License, Version 1.1
6 *
7 * Copyright (c) 2001 The Apache Software Foundation. All rights
8 * reserved.
9 *
10 * Redistribution and use in source and binary forms, with or without
11 * modification, are permitted provided that the following conditions
12 * are met:
13 *
14 * 1. Redistributions of source code must retain the above copyright
15 * notice, this list of conditions and the following disclaimer.
16 *
17 * 2. Redistributions in binary form must reproduce the above copyright
18 * notice, this list of conditions and the following disclaimer in
19 * the documentation and/or other materials provided with the
20 * distribution.
21 *
22 * 3. The end-user documentation included with the redistribution, if
23 * any, must include the following acknowlegement:
24 * "This product includes software developed by the
25 * Apache Software Foundation (http://www.apache.org/)."
26 * Alternately, this acknowlegement may appear in the software itself,
27 * if and wherever such third-party acknowlegements normally appear.
28 *
29 * 4. The names "The Jakarta Project", "Velocity", and "Apache Software
30 * Foundation" must not be used to endorse or promote products derived
31 * from this software without prior written permission. For written
32 * permission, please contact apache@apache.org.
33 *
34 * 5. Products derived from this software may not be called "Apache"
35 * nor may "Apache" appear in their names without prior written
36 * permission of the Apache Group.
37 *
38 * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED
39 * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
40 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
41 * DISCLAIMED. IN NO EVENT SHALL THE APACHE SOFTWARE FOUNDATION OR
42 * ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
43 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
44 * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
45 * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
46 * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
47 * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
48 * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
49 * SUCH DAMAGE.
50 * ====================================================================
51 *
52 * This software consists of voluntary contributions made by many
53 * individuals on behalf of the Apache Software Foundation. For more
54 * information on the Apache Software Foundation, please see
55 * <http://www.apache.org/>.
56 */
57
58 import java.io.InputStream;
59 import java.io.BufferedInputStream;
60 import java.util.Map;
61 import java.util.Hashtable;
62
63 import java.sql.*;
64 import javax.sql.DataSource;
65 import javax.naming.InitialContext;
66
67 import org.apache.velocity.runtime.Runtime;
68 import org.apache.velocity.runtime.resource.Resource;
69
70 import org.apache.velocity.exception.ResourceNotFoundException;
71
72 import org.apache.commons.collections.ExtendedProperties;
73
74 import org.apache.velocity.runtime.resource.loader.*;
75
76 /**
77 * This is a simple template file loader that loads templates
78 * from a DataSource instead of plain files.
79 *
80 * It can be configured with a datasource name, a table name,
81 * id column (name), content column (the template body) and a
82 * timestamp column (for last modification info).
83 * <br />
84 * <br />
85 * Example configuration snippet for velocity.properties:
86 * <br />
87 * <br />
88 * resource.loader.1.public.name = DataSource <br />
89 * resource.loader.1.description = Velocity DataSource Resource Loader <br />
90 * resource.loader.1.class = org.apache.velocity.runtime.resource.loader.DataSourceResourceLoader <br />
91 * resource.loader.1.resource.datasource = jdbc/SomeDS <br />
92 * resource.loader.1.resource.table = template_table <br />
93 * resource.loader.1.resource.keycolumn = template_id <br />
94 * resource.loader.1.resource.templatecolumn = template_definition <br />
95 * resource.loader.1.resource.timestampcolumn = template_timestamp <br />
96 * resource.loader.1.cache = false <br />
97 * resource.loader.1.modificationCheckInterval = 60<br />
98 *
99 * @author <a href="mailto:david.kinnvall@alertir.com">David Kinnvall</a>
100 * @author <a href="mailto:paulo.gaspar@krankikom.de">Paulo Gaspar</a>
101 * @version $Id: DataSourceResourceLoader.java,v 1.2 2002/08/09 17:21:42 mraible Exp $
102 */
103 public class DataSourceResourceLoader extends ResourceLoader
104 {
105 private String dataSourceName;
106 private String tableName;
107 private String keyColumn;
108 private String templateColumn;
109 private String timestampColumn;
110 private InitialContext ctx;
111 private DataSource dataSource;
112
113 public void init( ExtendedProperties configuration)
114 {
115 dataSourceName = configuration.getString("resource.datasource");
116 tableName = configuration.getString("resource.table");
117 keyColumn = configuration.getString("resource.keycolumn");
118 templateColumn = configuration.getString("resource.templatecolumn");
119 timestampColumn = configuration.getString("resource.timestampcolumn");
120
121 System.err.println("Resources Loaded From: " + dataSourceName + "/" + tableName);
122 System.err.println( "Resource Loader using columns: " + keyColumn + ", "
123 + templateColumn + " and " + timestampColumn);
124 System.err.println("Resource Loader Initalized.");
125
126 /*Runtime.info("Resources Loaded From: " + dataSourceName + "/" + tableName);
127 Runtime.info( "Resource Loader using columns: " + keyColumn + ", "
128 + templateColumn + " and " + timestampColumn);
129 Runtime.info("Resource Loader Initalized.");*/
130 }
131
132 public boolean isSourceModified(Resource resource)
133 {
134 return (resource.getLastModified() !=
135 readLastModified(resource, "checking timestamp"));
136 }
137
138 public long getLastModified(Resource resource)
139 {
140 return readLastModified(resource, "getting timestamp");
141 }
142
143 /**
144 * Get an InputStream so that the Runtime can build a
145 * template with it.
146 *
147 * @param name name of template
148 * @return InputStream containing template
149 */
150 public synchronized InputStream getResourceStream( String name )
151 throws ResourceNotFoundException
152 {
153 if (name == null || name.length() == 0)
154 {
155 throw new ResourceNotFoundException ("Need to specify a template name!");
156 }
157
158 try
159 {
160 Connection conn = openDbConnection();
161
162 try
163 {
164 ResultSet rs = readData(conn, templateColumn, name);
165
166 try
167 {
168 if (rs.next())
169 {
170 return new
171 BufferedInputStream(rs.getAsciiStream(templateColumn));
172 }
173 else
174 {
175 String msg = "DataSourceResourceLoader Error: cannot find resource "
176 + name;
177 Runtime.error(msg );
178
179 throw new ResourceNotFoundException (msg);
180 }
181 }
182 finally
183 {
184 rs.close();
185 }
186 }
187 finally
188 {
189 closeDbConnection(conn);
190 }
191 }
192 catch(Exception e)
193 {
194 String msg = "DataSourceResourceLoader Error: database problem trying to load resource "
195 + name + ": " + e.toString();
196
197 Runtime.error( msg );
198
199 throw new ResourceNotFoundException (msg);
200
201 }
202
203 }
204
205 /**
206 * Fetches the last modification time of the resource
207 *
208 * @param resource Resource object we are finding timestamp of
209 * @param i_operation string for logging, indicating caller's intention
210 *
211 * @return timestamp as long
212 */
213 private long readLastModified(Resource resource, String i_operation)
214 {
215 /*
216 * get the template name from the resource
217 */
218
219 String name = resource.getName();
220 try
221 {
222 Connection conn = openDbConnection();
223
224 try
225 {
226 ResultSet rs = readData(conn, timestampColumn, name);
227 try
228 {
229 if (rs.next())
230 {
231 return rs.getLong(timestampColumn);
232 }
233 else
234 {
235 Runtime.error("DataSourceResourceLoader Error: while "
236 + i_operation
237 + " could not find resource " + name);
238 }
239 }
240 finally
241 {
242 rs.close();
243 }
244 }
245 finally
246 {
247 closeDbConnection(conn);
248 }
249 }
250 catch(Exception e)
251 {
252 Runtime.error( "DataSourceResourceLoader Error: error while "
253 + i_operation + " when trying to load resource "
254 + name + ": " + e.toString() );
255 }
256 return 0;
257 }
258
259 /**
260 * gets connection to the datasource specified through the configuration
261 * parameters.
262 *
263 * @return connection
264 */
265 private Connection openDbConnection()
266 throws Exception
267 {
268 if(ctx == null)
269 {
270 ctx = new InitialContext();
271 }
272
273 if(dataSource == null)
274 {
275 dataSource = (DataSource)ctx.lookup(dataSourceName);
276 }
277
278 return dataSource.getConnection();
279 }
280
281 /**
282 * Closes connection to the datasource
283 */
284 private void closeDbConnection(Connection conn)
285 {
286 try
287 {
288 conn.close();
289 }
290 catch (Exception e)
291 {
292 Runtime.info(
293 "DataSourceResourceLoader Quirk: problem when closing connection: "
294 + e.toString());
295 }
296 }
297
298 /**
299 * Reads the data from the datasource. It simply does the following query :
300 * <br />
301 * SELECT <i>columnNames</i> FROM <i>tableName</i> WHERE <i>keyColumn</i>
302 * = '<i>templateName</i>'
303 * <br />
304 * where <i>keyColumn</i> is a class member set in init()
305 *
306 * @param conn connection to datasource
307 * @param columnNames columns to fetch from datasource
308 * @param templateName name of template to fetch
309 * @return result set from query
310 */
311 private ResultSet readData(Connection conn, String columnNames, String templateName)
312 throws SQLException
313 {
314 Statement stmt = conn.createStatement();
315
316 String sql = "SELECT " + columnNames
317 + " FROM " + tableName
318 + " WHERE " + keyColumn + " = '" + templateName + "'";
319
320 return stmt.executeQuery(sql);
321 }
322 }
323
324
325
326