# HG changeset patch # User Sascha L. Teichmann # Date 1252238456 0 # Node ID e8626caac3531549ae0a975cbdf08af106305b5e # Parent a5a279a0ee359a728129d7e7b87677957a9a23a8 * Made Artifact life cycle symmetric: setup/endOfLife. * Implement defaults for Artifact and ArtifactFactory. * Added connection pooling from apache commons dbcp * Made sql schema of artifact database more compatible. * Improve example config. * Made artifactdb start with 'mvn exec:exec' * minor fixes. artifacts/trunk@25 c6561f87-3c4e-4783-a992-168aeb5c3f6f diff -r a5a279a0ee35 -r e8626caac353 Changelog --- a/Changelog Fri Sep 04 16:06:44 2009 +0000 +++ b/Changelog Sun Sep 06 12:00:56 2009 +0000 @@ -1,3 +1,51 @@ +2009-09-06 Sascha L. Teichmann + + * artifacts/src/main/java/de/intevation/artifacts/Artifact.java(setup): + Added the setup() method to have symmetric counter part to endOfLife(). + + * artifacts/src/main/java/de/intevation/artifacts/ArtifactFactory.java(timeToLiveUntouched): + Added this method to let the factory decide how long an artifact should live in ms. + This is not a part of the Artifact itself because this is only evaluated once when + the artifact is created. + + * artifact-database/src/main/java/de/intevation/artifactdatabase/DefaultArtifact.java: + New. Simple base class implementation of the Artifact interface. + + * artifact-database/src/main/java/de/intevation/artifactdatabase/DefaultArtifactFactory.java: + New. Simple base class implementation of the ArtifactFactory interface. When setup() + on instances of this class is called, it pull ttl, name, description and + the artifact class name from the node given. See artifactdb-example-conf.xml + for examples. + + * artifact-database/pom.xml: Cleaned up XML. + Introduced dependency to apache commons dbcp, used for pooling of the + database connections to artifact db. + Added parameters for the exec:exec goal to make the project + startable without building packages. + + * artifact-database/doc/schema.sql: Removed AUTO_INCREMENT from primary key + to avoid compatibility issues with other non-H2 databases (PostgreSQL, Oracle, ...) + which have no or limited support for generated keys in the JDBC driver. Now + using an explicit sequence. TTL ist now big int to bring the resolution to ms. + + * artifact-database/src/main/java/de/intevation/artifactdatabase/Config.java: + Refactored a bit to make the XPath access function usable on arbitrary XML + documents and parts of. + + * artifact-database/src/main/java/de/intevation/artifactdatabase/DBConnection.java: + New. Exposes DataSource from a apache dbcp connection pool configured by the + global configuration file. See artifactdb-example-conf.xml for examples. + TODO: Write some documentation about this. + + * artifact-database/doc/artifactdb-example-conf.xml: Adjusted to be a more realistic + example config file. Added references to DefaultArtifact/DefaultArtifactFactory and + demonstrate how to configure the connection pool. + + * TODO: Add remark to document the connection file. + + * artifact-database/src/main/java/de/intevation/artifactdatabase/FactoryBootstrap.java: + Do not crash when config does not contain any factories. + 2009-09-04 Sascha L. Teichmann * artifact-database/src/main/java/de/intevation/artifactdatabase/Config.java (getNodeXPath): diff -r a5a279a0ee35 -r e8626caac353 TODO --- a/TODO Fri Sep 04 16:06:44 2009 +0000 +++ b/TODO Sun Sep 06 12:00:56 2009 +0000 @@ -1,2 +1,3 @@ TODO: * integrate logging into artifact database. + * Document the XML of the configuration file. diff -r a5a279a0ee35 -r e8626caac353 artifact-database/doc/artifactdb-example-conf.xml --- a/artifact-database/doc/artifactdb-example-conf.xml Fri Sep 04 16:06:44 2009 +0000 +++ b/artifact-database/doc/artifactdb-example-conf.xml Sun Sep 06 12:00:56 2009 +0000 @@ -1,11 +1,24 @@ - com.example.Context + de.intevation.artifactdatabase.DefaultArtifactContextFactory - com.example.ArtifactExampleFactoryOne - com.example.ArtifactExampleFactoryTwo - com.example.ArtifactExampleFactoryThree + de.intevation.artifactdatabase.DefaultArtifactFactory + de.intevation.artifactdatabase.DefaultArtifactFactory + de.intevation.artifactdatabase.DefaultArtifactFactory + + + + + + + diff -r a5a279a0ee35 -r e8626caac353 artifact-database/doc/schema.sql --- a/artifact-database/doc/schema.sql Fri Sep 04 16:06:44 2009 +0000 +++ b/artifact-database/doc/schema.sql Sun Sep 06 12:00:56 2009 +0000 @@ -4,12 +4,16 @@ BEGIN; +-- not using AUTO_INCREMENT to be more compatible with +-- other dbms. +CREATE SEQUENCE ARTIFACTS_ID_SEQ; + CREATE TABLE artifacts ( - id INT AUTO_INCREMENT PRIMARY KEY NOT NULL, - gid UUID NOT NULL UNIQUE, - creation TIMESTAMP NOT NULL, - last_access TIMESTAMP NOT NULL, - ttl TIME, -- NULL means eternal + id INT PRIMARY KEY NOT NULL, + gid UUID NOT NULL UNIQUE, + creation TIMESTAMP NOT NULL, + last_access TIMESTAMP NOT NULL, + ttl BIGINT, -- NULL means eternal data BINARY ); diff -r a5a279a0ee35 -r e8626caac353 artifact-database/pom.xml --- a/artifact-database/pom.xml Fri Sep 04 16:06:44 2009 +0000 +++ b/artifact-database/pom.xml Sun Sep 06 12:00:56 2009 +0000 @@ -1,4 +1,5 @@ - + + artifact-system de.intevation.bsh @@ -12,35 +13,53 @@ http://maven.apache.org - - org.apache.maven.plugins - maven-jar-plugin - 2.2 - - - - de.intevation.artifactdatabase.App - - - - + + org.apache.maven.plugins + maven-jar-plugin + 2.2 + + + + de.intevation.artifactdatabase.App + + + + + + org.codehaus.mojo + exec-maven-plugin + 1.1 + + java + + -classpath + + de.intevation.artifactdatabase.App + + + - de.intevation.bsh.artifacts - artifacts - 1.0-SNAPSHOT + de.intevation.bsh.artifacts + artifacts + 1.0-SNAPSHOT - - org.restlet - org.restlet - 2.0-M3 - - com.h2database - h2 - 1.1.117 + org.restlet + org.restlet + 2.0-M3 + + + com.h2database + h2 + 1.1.117 + + + commons-dbcp + commons-dbcp + 1.2.2 diff -r a5a279a0ee35 -r e8626caac353 artifact-database/src/main/java/de/intevation/artifactdatabase/Config.java --- a/artifact-database/src/main/java/de/intevation/artifactdatabase/Config.java Fri Sep 04 16:06:44 2009 +0000 +++ b/artifact-database/src/main/java/de/intevation/artifactdatabase/Config.java Sun Sep 06 12:00:56 2009 +0000 @@ -20,6 +20,9 @@ import javax.xml.xpath.XPathExpressionException; import javax.xml.xpath.XPathConstants; +/** + * @author Sascha L. Teichmann + */ public final class Config { public static final String CONFIG_PROPERTY = "artifact.database.config"; @@ -71,6 +74,38 @@ return null; } + public static final Object getXPath( + Object root, String query, QName returnType + ) { + if (root == null) { + return null; + } + + XPathFactory factory = XPathFactory.newInstance(); + XPath xpath = factory.newXPath(); + + try { + return xpath.evaluate(query, root, returnType); + } + catch (XPathExpressionException xpee) { + xpee.printStackTrace(System.err); + } + + return null; + } + + public static final Object getXPath(String query, QName returnType) { + return getXPath(getConfig(), query, returnType); + } + + public static final NodeList getNodeSetXPath(String query) { + return (NodeList)getXPath(query, XPathConstants.NODESET); + } + + public static final Node getNodeXPath(String query) { + return (Node)getXPath(query, XPathConstants.NODE); + } + public static final String getStringXPath(String xpath) { return getStringXPath(xpath, null); } @@ -82,31 +117,25 @@ : s; } - public static final Object getXPath(String query, QName returnType) { - Document document = getConfig(); - if (document == null) { - return null; - } - - XPathFactory factory = XPathFactory.newInstance(); - XPath xpath = factory.newXPath(); - - try { - return xpath.evaluate(query, document, returnType); - } - catch (XPathExpressionException xpee) { - xpee.printStackTrace(System.err); - } - - return null; + public static final NodeList getNodeSetXPath(Object root, String query) { + return (NodeList)getXPath(root, query, XPathConstants.NODESET); } - public static final NodeList getNodeSetXPath(String query) { - return (NodeList)getXPath(query, XPathConstants.NODESET); + public static final Node getNodeXPath(Object root, String query) { + return (Node)getXPath(root, query, XPathConstants.NODE); } - public static final Node getNodeXPath(String query) { - return (Node)getXPath(query, XPathConstants.NODE); + public static final String getStringXPath(Object root, String xpath) { + return getStringXPath(root, xpath, null); + } + + public static final String getStringXPath( + Object root, String query, String def + ) { + String s = (String)getXPath(root, query, XPathConstants.STRING); + return s == null || s.length() == 0 + ? def + : s; } } // vim:set ts=4 sw=4 si et sta sts=4 fenc=utf8: diff -r a5a279a0ee35 -r e8626caac353 artifact-database/src/main/java/de/intevation/artifactdatabase/DBConnection.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/artifact-database/src/main/java/de/intevation/artifactdatabase/DBConnection.java Sun Sep 06 12:00:56 2009 +0000 @@ -0,0 +1,78 @@ +package de.intevation.artifactdatabase; + +import javax.sql.DataSource; + +import java.sql.SQLException; + +import org.apache.commons.dbcp.BasicDataSource; + +/** + * @author Sascha L. Teichmann + */ +public class DBConnection +{ + public static final String DB_DRIVER = + "/artifacts-database/database/driver/text()"; + public static final String DB_URL = + "/artifacts-database/database/url/text()"; + public static final String DB_USER = + "/artifacts-database/database/driver/user/text()"; + public static final String DB_PASSWORD = + "/artifacts-database/database/driver/password()"; + + public static final String DEFAULT_DRIVER = + "org.h2.Driver"; + + public static final String DEFAULT_URL = + "jdbc:h2:artifacts.db"; + + public static final String DEFAULT_USER = ""; + public static final String DEFAULT_PASSWORD = ""; + + private DBConnection() { + } + + private static BasicDataSource dataSource; + + private static final void addShutdownHook() { + Runtime.getRuntime().addShutdownHook(new Thread() { + public void run() { + if (dataSource != null) { + try { + dataSource.close(); + } + catch (SQLException sqle) { + } + dataSource = null; + } + } + }); + } + + public static synchronized DataSource getDataSource() { + if (dataSource == null) { + dataSource = new BasicDataSource(); + + String driver = Config.getStringXPath( + DB_DRIVER, DEFAULT_DRIVER); + + String url = Config.getStringXPath( + DB_URL, DEFAULT_URL); + + String user = Config.getStringXPath( + DB_USER, DEFAULT_USER); + + String password = Config.getStringXPath( + DB_PASSWORD, DEFAULT_PASSWORD); + + dataSource.setDriverClassName(driver); + dataSource.setUsername(user); + dataSource.setPassword(password); + dataSource.setUrl(url); + addShutdownHook(); + } + + return dataSource; + } +} +// vim:set ts=4 sw=4 si et sta sts=4 fenc=utf8: diff -r a5a279a0ee35 -r e8626caac353 artifact-database/src/main/java/de/intevation/artifactdatabase/DefaultArtifact.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/artifact-database/src/main/java/de/intevation/artifactdatabase/DefaultArtifact.java Sun Sep 06 12:00:56 2009 +0000 @@ -0,0 +1,65 @@ +package de.intevation.artifactdatabase; + +import org.w3c.dom.Document; + +import javax.xml.parsers.DocumentBuilderFactory; +import javax.xml.parsers.ParserConfigurationException; + +import de.intevation.artifacts.Artifact; + +/** + * @author Sascha L. Teichmann (sascha.teichmann@intevation.de) + */ +public class DefaultArtifact +implements Artifact +{ + protected String identifier; + + public DefaultArtifact() { + } + + protected Document newDocument() { + try { + return DocumentBuilderFactory + .newInstance() + .newDocumentBuilder() + .newDocument(); + } + catch (ParserConfigurationException pce) { + pce.printStackTrace(System.err); + } + return null; + } + + public String identifier() { + return this.identifier; + } + + public String hash() { + return String.valueOf(hashCode()); + } + + public Document describe(Object context) { + return newDocument(); + } + + public Document advance(Document target, Object context) { + return newDocument(); + } + + public Document feed(Document target, Object context) { + return newDocument(); + } + + public byte [] out(Document format, Object context) { + return new byte[0]; + } + + public void setup(String identifier, Object context) { + this.identifier = identifier; + } + + public void endOfLife(Object context) { + } +} +// vim:set ts=4 sw=4 si et sta sts=4 fenc=utf8: diff -r a5a279a0ee35 -r e8626caac353 artifact-database/src/main/java/de/intevation/artifactdatabase/DefaultArtifactFactory.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/artifact-database/src/main/java/de/intevation/artifactdatabase/DefaultArtifactFactory.java Sun Sep 06 12:00:56 2009 +0000 @@ -0,0 +1,102 @@ +package de.intevation.artifactdatabase; + +import org.w3c.dom.Document; +import org.w3c.dom.Node; + +import de.intevation.artifacts.ArtifactFactory; +import de.intevation.artifacts.Artifact; + +public class DefaultArtifactFactory +implements ArtifactFactory +{ + public static final String XPATH_TTL = "@ttl"; + public static final String XPATH_NAME = "@name"; + public static final String XPATH_DESCRIPTION = "@description"; + public static final String XPATH_ARTIFACT = "@artifact"; + + public static final String DEFAULT_DESCRIPTION = + "No description available"; + + public static final String DEFAULT_ARTIFACT = + "de.intevation.artifactdatabase.DefaultArtifact"; + + protected Long ttl; + + protected String name; + + protected String description; + + protected Class artifactClass; + + public DefaultArtifactFactory() { + } + + public String getName() { + return name; + } + + public String getDescription() { + return description; + } + + public Artifact createArtifact(String identifier, Object context) { + + try { + Artifact artifact = + (Artifact)artifactClass.newInstance(); + + artifact.setup(identifier, context); + + return artifact; + } + catch (InstantiationException ie) { + ie.printStackTrace(System.err); + } + catch (IllegalAccessException iae) { + iae.printStackTrace(System.err); + } + catch (ClassCastException cce) { + cce.printStackTrace(System.err); + } + + return null; + } + + public void setup(Document document, Node factoryNode) { + + String ttlString = Config.getStringXPath(factoryNode, XPATH_TTL); + if (ttlString != null) { + try { + ttl = Long.valueOf(ttlString); + } + catch (NumberFormatException nfe) { + nfe.printStackTrace(System.err); + } + } + + description = Config.getStringXPath( + factoryNode, XPATH_DESCRIPTION, DEFAULT_DESCRIPTION); + + name = Config.getStringXPath( + factoryNode, XPATH_NAME, toString()); + + String artifact = Config.getStringXPath( + factoryNode, XPATH_ARTIFACT, DEFAULT_ARTIFACT); + + try { + artifactClass = Class.forName(artifact); + } + catch (ClassNotFoundException cnfe) { + cnfe.printStackTrace(System.err); + } + + if (artifactClass == null) { + artifactClass = DefaultArtifact.class; + } + } + + public Long timeToLiveUntouched(Artifact artifact, Object context) { + return ttl; + } +} +// vim:set ts=4 sw=4 si et sta sts=4 fenc=utf8: diff -r a5a279a0ee35 -r e8626caac353 artifact-database/src/main/java/de/intevation/artifactdatabase/FactoryBootstrap.java --- a/artifact-database/src/main/java/de/intevation/artifactdatabase/FactoryBootstrap.java Fri Sep 04 16:06:44 2009 +0000 +++ b/artifact-database/src/main/java/de/intevation/artifactdatabase/FactoryBootstrap.java Sun Sep 06 12:00:56 2009 +0000 @@ -66,6 +66,11 @@ NodeList nodes = Config.getNodeSetXPath(ARTIFACT_FACTORIES); + if (nodes == null) { + System.err.println("ERROR: no factories found"); + return; + } + Document config = Config.getConfig(); for (int i = 0, N = nodes.getLength(); i < N; ++i) { diff -r a5a279a0ee35 -r e8626caac353 artifacts/src/main/java/de/intevation/artifacts/Artifact.java --- a/artifacts/src/main/java/de/intevation/artifacts/Artifact.java Fri Sep 04 16:06:44 2009 +0000 +++ b/artifacts/src/main/java/de/intevation/artifacts/Artifact.java Sun Sep 06 12:00:56 2009 +0000 @@ -22,6 +22,15 @@ *
  • {@link #out(Document, Object) out()}: Produces output for this artifact.
  • * * + * There are two more methods involved with the life cycle of the are: + *
      + *
    1. {@link #setup(String, Object) setup()}: Called after created by the + * factory.
    2. + *
    3. {@link #endOfLife(Object) endOfLife()}: Called when the artifact + * is going to be removed from + * system. Useful to clean up.
    4. + *
    + * * @author Sascha L. Teichmann (sascha.teichmann@intevation.de) */ public interface Artifact @@ -72,6 +81,14 @@ public byte [] out(Document format, Object context); /** + * When created by a factory this method is called to + * initialize the artifact. + * @param identifier The identifier from artifact database + * @param context The global context of the runtime system. + */ + public void setup(String identifier, Object context); + + /** * Called from artifact database when an artifact is * going to be removed from system. * @param context The global context of the runtime system. diff -r a5a279a0ee35 -r e8626caac353 artifacts/src/main/java/de/intevation/artifacts/ArtifactFactory.java --- a/artifacts/src/main/java/de/intevation/artifacts/ArtifactFactory.java Fri Sep 04 16:06:44 2009 +0000 +++ b/artifacts/src/main/java/de/intevation/artifacts/ArtifactFactory.java Sun Sep 06 12:00:56 2009 +0000 @@ -37,5 +37,17 @@ * @param factoryNode the ConfigurationNode of this Factory */ void setup(Document config, Node factoryNode); + + /** + * Tells how long an artifact should survive if it is + * not touched. This is put in the factory because + * life time is nothing a artifact should handle it self. + * This method is only called once directly after the + * artifact is created. + * @param artifact The artifact to be rated. + * @param context The global context. + * return time to live in ms. null means eternal. + */ + Long timeToLiveUntouched(Artifact artifact, Object context); } // vim:set ts=4 sw=4 si et sta sts=4 fenc=utf8: