/*
* Copyright 2001-2008 Geert Bevin <gbevin[remove] at uwyn dot com>
* Licensed under the Apache License, Version 2.0 (the "License")
* $Id: DatabaseResources.java 3918 2008-04-14 17:35:35Z gbevin $
*/
package com.uwyn.rife.resources;
import com.uwyn.rife.database.Datasource;
import com.uwyn.rife.database.DbPreparedStatement;
import com.uwyn.rife.database.DbPreparedStatementHandler;
import com.uwyn.rife.database.DbQueryManager;
import com.uwyn.rife.database.exceptions.DatabaseException;
import com.uwyn.rife.database.queries.*;
import com.uwyn.rife.resources.exceptions.*;
import com.uwyn.rife.tools.ExceptionUtils;
import com.uwyn.rife.tools.exceptions.InnerClassException;
import com.uwyn.rife.tools.InputStreamUser;
import java.net.MalformedURLException;
import java.net.URL;
import java.net.URLDecoder;
import java.sql.Timestamp;
import java.util.logging.Logger;
/**
* This class offers <code>ResourceFinder</code> and <code>ResourceWriter</code>
* capabilities for resources that are stored in a database. The relevant database
* is specified through a <code>Datasource/code> instance at construction.
* <p>
* While the table can be configured through the <code>TABLE_RESOURCES</code>
* configuration setting, the structure of the table is fixed. It can be
* installed with the <code>install()</code> method and removed with the
* <code>remove()</code> method. The latter will implicitely erase all the
* resources that have been stored in the database table.
*
* @author Geert Bevin (gbevin[remove] at uwyn dot com)
* @version $Revision: 3918 $
* @see com.uwyn.rife.resources.ResourceFinder
* @since 1.0
*/
public abstract class DatabaseResources extends DbQueryManager implements ResourceFinder, ResourceWriter
{
protected final static String PROTOCOL = "file";
protected final static String COLUMN_NAME = "name";
protected final static String COLUMN_CONTENT = "content";
protected final static String COLUMN_MODIFIED = "modified";
/**
* Creates a new instance according to the provided datasource.
*
* @param datasource the <code>Datasource</code> instance that defines the
* database that will be used as resources storage.
*
* @since 1.0
*/
protected DatabaseResources(Datasource datasource)
{
super(datasource);
}
/**
* Installs the database structure that's needed to store and retrieve
* resources in and from a database.
*
* @exception ResourceFinderErrorException when an error occurred during the
* installation
*/
public abstract boolean install() throws ResourceWriterErrorException;
/**
* Removes the database structure that's needed to store and retrieve
* resources in and from a database.
*
* @exception ResourceFinderErrorException when an error occurred during the
* removal
*/
public abstract boolean remove() throws ResourceWriterErrorException;
protected boolean _install(CreateTable createTable)
throws ResourceWriterErrorException
{
try
{
executeUpdate(createTable);
}
catch (DatabaseException e)
{
throw new ResourceStructureInstallationException(e);
}
return true;
}
protected boolean _remove(DropTable dropTable)
throws ResourceWriterErrorException
{
try
{
executeUpdate(dropTable);
}
catch (DatabaseException e)
{
throw new ResourceStructureRemovalException(e);
}
return true;
}
protected void _addResource(Insert addResource, final String name, final String content)
throws ResourceWriterErrorException
{
assert addResource != null;
if (null == name) throw new IllegalArgumentException("name can't be null.");
if (0 == name.length()) throw new IllegalArgumentException("name can't be empty.");
if (null == content) throw new IllegalArgumentException("content can't be null.");
try
{
executeUpdate(addResource, new DbPreparedStatementHandler() {
public void setParameters(DbPreparedStatement statement)
{
statement
.setString(COLUMN_NAME, name)
.setString(COLUMN_CONTENT, content)
.setTimestamp(COLUMN_MODIFIED, new java.sql.Timestamp(System.currentTimeMillis()));
}
});
}
catch (DatabaseException e)
{
throw new ResourceAdditionErrorException(name, content, e);
}
}
protected boolean _updateResource(Update updateResource, final String name, final String content)
throws ResourceWriterErrorException
{
assert updateResource != null;
if (null == name) throw new IllegalArgumentException("name can't be null.");
if (0 == name.length()) throw new IllegalArgumentException("name can't be empty.");
if (null == content) throw new IllegalArgumentException("content can't be null.");
boolean result = false;
try
{
if (0 != executeUpdate(updateResource, new DbPreparedStatementHandler() {
public void setParameters(DbPreparedStatement statement)
{
statement
.setString(COLUMN_CONTENT, content)
.setTimestamp(COLUMN_MODIFIED, new java.sql.Timestamp(System.currentTimeMillis()))
.setString(COLUMN_NAME, name);
}
}))
{
result = true;
}
}
catch (DatabaseException e)
{
throw new ResourceUpdateErrorException(name, content, e);
}
return result;
}
protected boolean _removeResource(Delete removeResource, final String name)
throws ResourceWriterErrorException
{
assert removeResource != null;
if (null == name) throw new IllegalArgumentException("name can't be null.");
if (0 == name.length()) throw new IllegalArgumentException("name can't be empty.");
boolean result = false;
try
{
if (0 != executeUpdate(removeResource, new DbPreparedStatementHandler() {
public void setParameters(DbPreparedStatement statement)
{
statement
.setString(COLUMN_NAME, name);
}
}))
{
result = true;
}
}
catch (DatabaseException e)
{
throw new ResourceRemovalErrorException(name, e);
}
return result;
}
protected URL _getResource(Select hasResource, final String name)
{
assert hasResource != null;
if (null == name)
{
return null;
}
URL resource = null;
try
{
if (executeHasResultRows(hasResource, new DbPreparedStatementHandler() {
public void setParameters(DbPreparedStatement statement)
{
statement
.setString(COLUMN_NAME, name);
}
}))
{
resource = new URL(PROTOCOL, "", name);
}
}
catch (MalformedURLException e)
{
return null;
}
catch (DatabaseException e)
{
Logger.getLogger("com.uwyn.rife.resources").severe("Error while retrieving the resource with name '"+name+"' :\n"+ExceptionUtils.getExceptionStackTrace(e));
return null;
}
return resource;
}
protected <ResultType> ResultType _useStream(Select getResourceContent, final URL resource, InputStreamUser user)
throws ResourceFinderErrorException, InnerClassException
{
assert getResourceContent != null;
if (null == resource ||
null == user)
{
return null;
}
if (!PROTOCOL.equals(resource.getProtocol()))
{
return null;
}
try
{
return (ResultType)executeUseFirstBinaryStream(getResourceContent, user, new DbPreparedStatementHandler() {
public void setParameters(DbPreparedStatement statement)
{
statement
.setString(COLUMN_NAME, URLDecoder.decode(resource.getFile()));
}
});
}
catch (DatabaseException e)
{
throw new CantOpenResourceStreamException(resource, e);
}
}
protected String _getContent(Select getResourceContent, final URL resource, String encoding)
throws ResourceFinderErrorException
{
assert getResourceContent != null;
if (null == resource)
{
return null;
}
if (!PROTOCOL.equals(resource.getProtocol()))
{
return null;
}
String result = null;
try
{
result = executeGetFirstString(getResourceContent, new DbPreparedStatementHandler() {
public void setParameters(DbPreparedStatement statement)
{
statement
.setString(COLUMN_NAME, URLDecoder.decode(resource.getFile()));
}
});
}
catch (DatabaseException e)
{
throw new CantRetrieveResourceContentException(resource, encoding, e);
}
return result;
}
protected long _getModificationTime(Select getResourceModified, final URL resource)
{
assert getResourceModified != null;
if (null == resource)
{
return -1;
}
if (!PROTOCOL.equals(resource.getProtocol()))
{
return -1;
}
try
{
long result = -1;
Timestamp timestamp = executeGetFirstTimestamp(getResourceModified, new DbPreparedStatementHandler() {
public void setParameters(DbPreparedStatement statement)
{
statement
.setString(COLUMN_NAME, URLDecoder.decode(resource.getFile()));
}
});
if (null == timestamp)
{
return -1;
}
result = timestamp.getTime();
return result;
}
catch (DatabaseException e)
{
return -1;
}
}
public <ResultType> ResultType useStream(String name, InputStreamUser user)
throws ResourceFinderErrorException, InnerClassException
{
if (null == name ||
null == user)
{
return null;
}
URL resource = getResource(name);
if (null == resource)
{
return null;
}
return (ResultType)useStream(resource, user);
}
public String getContent(String name)
throws ResourceFinderErrorException
{
return getContent(name, null);
}
public String getContent(String name, String encoding)
throws ResourceFinderErrorException
{
if (null == name)
{
return null;
}
URL resource = getResource(name);
if (null == resource)
{
return null;
}
return getContent(resource, encoding);
}
public String getContent(URL resource)
throws ResourceFinderErrorException
{
return getContent(resource, null);
}
public long getModificationTime(String name)
throws ResourceFinderErrorException
{
if (null == name)
{
return -1;
}
URL resource = getResource(name);
if (null == resource)
{
return -1;
}
return getModificationTime(resource);
}
}