001: /*
002: * Copyright 2001-2007 Geert Bevin <gbevin[remove] at uwyn dot com>
003: * Distributed under the terms of either:
004: * - the common development and distribution license (CDDL), v1.0; or
005: * - the GNU Lesser General Public License, v2.1 or later
006: * $Id: DatabaseResources.java 3634 2007-01-08 21:42:24Z gbevin $
007: */
008: package com.uwyn.rife.resources;
009:
010: import com.uwyn.rife.database.Datasource;
011: import com.uwyn.rife.database.DbPreparedStatement;
012: import com.uwyn.rife.database.DbPreparedStatementHandler;
013: import com.uwyn.rife.database.DbQueryManager;
014: import com.uwyn.rife.database.exceptions.DatabaseException;
015: import com.uwyn.rife.database.queries.*;
016: import com.uwyn.rife.resources.exceptions.*;
017: import com.uwyn.rife.tools.ExceptionUtils;
018: import com.uwyn.rife.tools.InnerClassException;
019: import com.uwyn.rife.tools.InputStreamUser;
020:
021: import java.net.MalformedURLException;
022: import java.net.URL;
023: import java.net.URLDecoder;
024: import java.sql.Timestamp;
025: import java.util.logging.Logger;
026:
027: /**
028: * This class offers <code>ResourceFinder</code> and <code>ResourceWriter</code>
029: * capabilities for resources that are stored in a database. The relevant database
030: * is specified through a <code>Datasource/code> instance at construction.
031: * <p>
032: * While the table can be configured through the <code>TABLE_RESOURCES</code>
033: * configuration setting, the structure of the table is fixed. It can be
034: * installed with the <code>install()</code> method and removed with the
035: * <code>remove()</code> method. The latter will implicitely erase all the
036: * resources that have been stored in the database table.
037: *
038: * @author Geert Bevin (gbevin[remove] at uwyn dot com)
039: * @version $Revision: 3634 $
040: * @see com.uwyn.rife.resources.ResourceFinder
041: * @since 1.0
042: */
043: public abstract class DatabaseResources extends DbQueryManager
044: implements ResourceFinder, ResourceWriter {
045: protected final static String PROTOCOL = "file";
046:
047: protected final static String COLUMN_NAME = "name";
048: protected final static String COLUMN_CONTENT = "content";
049: protected final static String COLUMN_MODIFIED = "modified";
050:
051: /**
052: * Creates a new instance according to the provided datasource.
053: *
054: * @param datasource the <code>Datasource</code> instance that defines the
055: * database that will be used as resources storage.
056: *
057: * @since 1.0
058: */
059: protected DatabaseResources(Datasource datasource) {
060: super (datasource);
061: }
062:
063: /**
064: * Installs the database structure that's needed to store and retrieve
065: * resources in and from a database.
066: *
067: * @exception ResourceFinderErrorException when an error occurred during the
068: * installation
069: */
070: public abstract boolean install()
071: throws ResourceWriterErrorException;
072:
073: /**
074: * Removes the database structure that's needed to store and retrieve
075: * resources in and from a database.
076: *
077: * @exception ResourceFinderErrorException when an error occurred during the
078: * removal
079: */
080: public abstract boolean remove()
081: throws ResourceWriterErrorException;
082:
083: protected boolean _install(CreateTable createTable)
084: throws ResourceWriterErrorException {
085: try {
086: executeUpdate(createTable);
087: } catch (DatabaseException e) {
088: throw new ResourceStructureInstallationException(e);
089: }
090:
091: return true;
092: }
093:
094: protected boolean _remove(DropTable dropTable)
095: throws ResourceWriterErrorException {
096: try {
097: executeUpdate(dropTable);
098: } catch (DatabaseException e) {
099: throw new ResourceStructureRemovalException(e);
100: }
101:
102: return true;
103: }
104:
105: protected void _addResource(Insert addResource, final String name,
106: final String content) throws ResourceWriterErrorException {
107: assert addResource != null;
108:
109: if (null == name)
110: throw new IllegalArgumentException("name can't be null.");
111: if (0 == name.length())
112: throw new IllegalArgumentException("name can't be empty.");
113: if (null == content)
114: throw new IllegalArgumentException("content can't be null.");
115:
116: try {
117: executeUpdate(addResource,
118: new DbPreparedStatementHandler() {
119: public void setParameters(
120: DbPreparedStatement statement) {
121: statement
122: .setString(COLUMN_NAME, name)
123: .setString(COLUMN_CONTENT, content)
124: .setTimestamp(
125: COLUMN_MODIFIED,
126: new java.sql.Timestamp(
127: System
128: .currentTimeMillis()));
129: }
130: });
131: } catch (DatabaseException e) {
132: throw new ResourceAdditionErrorException(name, content, e);
133: }
134: }
135:
136: protected boolean _updateResource(Update updateResource,
137: final String name, final String content)
138: throws ResourceWriterErrorException {
139: assert updateResource != null;
140:
141: if (null == name)
142: throw new IllegalArgumentException("name can't be null.");
143: if (0 == name.length())
144: throw new IllegalArgumentException("name can't be empty.");
145: if (null == content)
146: throw new IllegalArgumentException("content can't be null.");
147:
148: boolean result = false;
149:
150: try {
151: if (0 != executeUpdate(updateResource,
152: new DbPreparedStatementHandler() {
153: public void setParameters(
154: DbPreparedStatement statement) {
155: statement
156: .setString(COLUMN_CONTENT, content)
157: .setTimestamp(
158: COLUMN_MODIFIED,
159: new java.sql.Timestamp(
160: System
161: .currentTimeMillis()))
162: .setString(COLUMN_NAME, name);
163: }
164: })) {
165: result = true;
166: }
167: } catch (DatabaseException e) {
168: throw new ResourceUpdateErrorException(name, content, e);
169: }
170:
171: return result;
172: }
173:
174: protected boolean _removeResource(Delete removeResource,
175: final String name) throws ResourceWriterErrorException {
176: assert removeResource != null;
177:
178: if (null == name)
179: throw new IllegalArgumentException("name can't be null.");
180: if (0 == name.length())
181: throw new IllegalArgumentException("name can't be empty.");
182:
183: boolean result = false;
184:
185: try {
186: if (0 != executeUpdate(removeResource,
187: new DbPreparedStatementHandler() {
188: public void setParameters(
189: DbPreparedStatement statement) {
190: statement.setString(COLUMN_NAME, name);
191: }
192: })) {
193: result = true;
194: }
195: } catch (DatabaseException e) {
196: throw new ResourceRemovalErrorException(name, e);
197: }
198:
199: return result;
200: }
201:
202: protected URL _getResource(Select hasResource, final String name) {
203: assert hasResource != null;
204:
205: if (null == name) {
206: return null;
207: }
208:
209: URL resource = null;
210:
211: try {
212: if (executeHasResultRows(hasResource,
213: new DbPreparedStatementHandler() {
214: public void setParameters(
215: DbPreparedStatement statement) {
216: statement.setString(COLUMN_NAME, name);
217: }
218: })) {
219: resource = new URL(PROTOCOL, "", name);
220: }
221: } catch (MalformedURLException e) {
222: return null;
223: } catch (DatabaseException e) {
224: Logger.getLogger("com.uwyn.rife.resources").severe(
225: "Error while retrieving the resource with name '"
226: + name + "' :\n"
227: + ExceptionUtils.getExceptionStackTrace(e));
228: return null;
229: }
230:
231: return resource;
232: }
233:
234: protected <ResultType> ResultType _useStream(
235: Select getResourceContent, final URL resource,
236: InputStreamUser user) throws ResourceFinderErrorException,
237: InnerClassException {
238: assert getResourceContent != null;
239:
240: if (null == resource || null == user) {
241: return null;
242: }
243:
244: if (!PROTOCOL.equals(resource.getProtocol())) {
245: return null;
246: }
247:
248: try {
249: return (ResultType) executeUseFirstBinaryStream(
250: getResourceContent, user,
251: new DbPreparedStatementHandler() {
252: public void setParameters(
253: DbPreparedStatement statement) {
254: statement.setString(COLUMN_NAME, URLDecoder
255: .decode(resource.getFile()));
256: }
257: });
258: } catch (DatabaseException e) {
259: throw new CantOpenResourceStreamException(resource, e);
260: }
261: }
262:
263: protected String _getContent(Select getResourceContent,
264: final URL resource, String encoding)
265: throws ResourceFinderErrorException {
266: assert getResourceContent != null;
267:
268: if (null == resource) {
269: return null;
270: }
271:
272: if (!PROTOCOL.equals(resource.getProtocol())) {
273: return null;
274: }
275:
276: String result = null;
277: try {
278: result = executeGetFirstString(getResourceContent,
279: new DbPreparedStatementHandler() {
280: public void setParameters(
281: DbPreparedStatement statement) {
282: statement.setString(COLUMN_NAME, URLDecoder
283: .decode(resource.getFile()));
284: }
285: });
286: } catch (DatabaseException e) {
287: throw new CantRetrieveResourceContentException(resource,
288: encoding, e);
289: }
290:
291: return result;
292: }
293:
294: protected long _getModificationTime(Select getResourceModified,
295: final URL resource) {
296: assert getResourceModified != null;
297:
298: if (null == resource) {
299: return -1;
300: }
301:
302: if (!PROTOCOL.equals(resource.getProtocol())) {
303: return -1;
304: }
305:
306: try {
307: long result = -1;
308:
309: Timestamp timestamp = executeGetFirstTimestamp(
310: getResourceModified,
311: new DbPreparedStatementHandler() {
312: public void setParameters(
313: DbPreparedStatement statement) {
314: statement.setString(COLUMN_NAME, URLDecoder
315: .decode(resource.getFile()));
316: }
317: });
318: if (null == timestamp) {
319: return -1;
320: }
321: result = timestamp.getTime();
322:
323: return result;
324: } catch (DatabaseException e) {
325: return -1;
326: }
327: }
328:
329: public <ResultType> ResultType useStream(String name,
330: InputStreamUser user) throws ResourceFinderErrorException,
331: InnerClassException {
332: if (null == name || null == user) {
333: return null;
334: }
335:
336: URL resource = getResource(name);
337: if (null == resource) {
338: return null;
339: }
340:
341: return (ResultType) useStream(resource, user);
342: }
343:
344: public String getContent(String name)
345: throws ResourceFinderErrorException {
346: return getContent(name, null);
347: }
348:
349: public String getContent(String name, String encoding)
350: throws ResourceFinderErrorException {
351: if (null == name) {
352: return null;
353: }
354:
355: URL resource = getResource(name);
356: if (null == resource) {
357: return null;
358: }
359:
360: return getContent(resource, encoding);
361: }
362:
363: public String getContent(URL resource)
364: throws ResourceFinderErrorException {
365: return getContent(resource, null);
366: }
367:
368: public long getModificationTime(String name)
369: throws ResourceFinderErrorException {
370: if (null == name) {
371: return -1;
372: }
373:
374: URL resource = getResource(name);
375: if (null == resource) {
376: return -1;
377: }
378:
379: return getModificationTime(resource);
380: }
381: }
|