Work on hsqldb support
authorcli
Tue, 07 Jun 2011 11:55:22 +0200
changeset 445d7d1adf387f
parent 43 7d0e65712a95
child 45 7e24949b87b0
Work on hsqldb support
helpers/database_hsqldb_tmpl.sql
helpers/sonews.conf.sample
src/org/sonews/storage/impl/HSQLDB.java
src/org/sonews/storage/impl/HSQLDBProvider.java
src/org/sonews/storage/impl/JDBCDatabase.java
src/org/sonews/storage/impl/JDBCDatabaseProvider.java
src/org/sonews/util/DatabaseSetup.java
src/org/sonews/util/io/Resource.java
     1.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
     1.2 +++ b/helpers/database_hsqldb_tmpl.sql	Tue Jun 07 11:55:22 2011 +0200
     1.3 @@ -0,0 +1,142 @@
     1.4 +/* 
     1.5 +  flags:
     1.6 +  If bit 0 is set, groups is a mirrorred mailing list. 
     1.7 +  If not set default newsgroup.
     1.8 +
     1.9 +  Normalization: 1NF, 2NF, 3NF
    1.10 +*/
    1.11 +CREATE CACHED TABLE groups 
    1.12 +(
    1.13 +  group_id      INT,
    1.14 +  name          VARCHAR(80) NOT NULL,
    1.15 +  flags         TINYINT DEFAULT 0,
    1.16 +
    1.17 +  PRIMARY KEY(group_id),
    1.18 +  UNIQUE(name)
    1.19 +);
    1.20 +
    1.21 +CREATE CACHED TABLE articles 
    1.22 +(
    1.23 +  article_id    INT,
    1.24 +  body          VARBINARY,
    1.25 +
    1.26 +  PRIMARY KEY(article_id)
    1.27 +);
    1.28 +
    1.29 +CREATE CACHED TABLE article_ids
    1.30 +(
    1.31 +  article_id  INT,
    1.32 +  message_id  VARCHAR(255),
    1.33 +
    1.34 +  PRIMARY KEY(article_id),
    1.35 +  UNIQUE(message_id),
    1.36 +  FOREIGN KEY(article_id) REFERENCES articles(article_id) ON DELETE CASCADE
    1.37 +);
    1.38 +
    1.39 +CREATE CACHED TABLE headers
    1.40 +(
    1.41 +  article_id    INT,
    1.42 +  header_key    VARCHAR(255),
    1.43 +  header_value  LONGVARCHAR,
    1.44 +  header_index  INT,
    1.45 +
    1.46 +  PRIMARY KEY(article_id, header_key, header_index),
    1.47 +  FOREIGN KEY(article_id) REFERENCES articles(article_id) ON DELETE CASCADE
    1.48 +);
    1.49 +
    1.50 +/*
    1.51 +  Normalization: 1NF, 2NF
    1.52 +*/
    1.53 +CREATE CACHED TABLE postings 
    1.54 +(
    1.55 +  group_id      INTEGER,
    1.56 +  article_id    INTEGER,
    1.57 +  article_index INTEGER NOT NULL, 
    1.58 +
    1.59 +  PRIMARY KEY(group_id, article_id),
    1.60 +  FOREIGN KEY(article_id) REFERENCES articles(article_id) ON DELETE CASCADE
    1.61 +);
    1.62 +
    1.63 +/* 
    1.64 +  Table for association of newsgroups and mailing-lists 
    1.65 +
    1.66 +  Normalization: 1NF, 2NF, 3NF
    1.67 +*/
    1.68 +CREATE CACHED TABLE groups2list
    1.69 +(
    1.70 +  group_id    INTEGER,
    1.71 +  listaddress VARCHAR(255),
    1.72 +
    1.73 +  PRIMARY KEY(group_id, listaddress),
    1.74 +  UNIQUE(listaddress),
    1.75 +  FOREIGN KEY(group_id) REFERENCES groups(group_id) ON DELETE CASCADE 
    1.76 +);
    1.77 +
    1.78 +/* 
    1.79 +  Configuration table, containing key/value pairs 
    1.80 +
    1.81 +  Normalization: 1NF, 2NF, 3NF
    1.82 +*/
    1.83 +CREATE CACHED TABLE config
    1.84 +(
    1.85 +  config_key     VARCHAR(255),
    1.86 +  config_value   LONGVARCHAR,
    1.87 +
    1.88 +  PRIMARY KEY(config_key)
    1.89 +);
    1.90 +
    1.91 +/* 
    1.92 +  Newsserver peers 
    1.93 +  feedtype: 0: pullfeed 1: pushfeed
    1.94 +  Normalization: 1NF (atomic values), 2NF
    1.95 +*/
    1.96 +CREATE CACHED TABLE peers
    1.97 +(
    1.98 +  peer_id     INT,
    1.99 +  host        VARCHAR(255),
   1.100 +  port        INT,
   1.101 +
   1.102 +  PRIMARY KEY(peer_id),
   1.103 +  UNIQUE(host, port)
   1.104 +);
   1.105 +
   1.106 +/* 
   1.107 +  List of newsgroups to feed into sonews 
   1.108 +
   1.109 +  Normalization: 1NF, 2NF, 3NF
   1.110 +*/
   1.111 +CREATE CACHED TABLE peer_subscriptions
   1.112 +(
   1.113 +  peer_id    INTEGER,
   1.114 +  group_id   INTEGER,
   1.115 +  feedtype   TINYINT DEFAULT 0,
   1.116 +
   1.117 +  PRIMARY KEY(peer_id, group_id, feedtype),
   1.118 +  FOREIGN KEY(peer_id) REFERENCES peers(peer_id) ON DELETE CASCADE,
   1.119 +  FOREIGN KEY(group_id) REFERENCES groups(group_id) ON DELETE CASCADE
   1.120 +);
   1.121 +
   1.122 +/* 
   1.123 +   Tables for server event statistics
   1.124 +
   1.125 +   Possible statistic keys:
   1.126 +   1=CONNECTIONS     (active connections)
   1.127 +   2=POSTED_NEWS     (directly to the server posted unique messages)
   1.128 +   3=GATEWAYED_NEWS  (posted unique message gateways through the ML-gateway)
   1.129 +   4=FEEDED_NEWS     (unique messages feed via NNTP)
   1.130 +
   1.131 +   The server will create snapshots of the above data.
   1.132 +
   1.133 +   Normalization: 1NF, 2NF
   1.134 +*/
   1.135 +CREATE CACHED TABLE events
   1.136 +(
   1.137 +  event_time         BIGINT,   /* time of this snapshot */
   1.138 +  event_key          TINYINT,  /* which data */
   1.139 +  group_id           INT ,
   1.140 +
   1.141 +  PRIMARY KEY(event_time, event_key),
   1.142 +  FOREIGN KEY(group_id) REFERENCES groups(group_id) ON DELETE CASCADE
   1.143 +);
   1.144 +
   1.145 +COMMIT;
     2.1 --- a/helpers/sonews.conf.sample	Tue Jun 07 09:23:34 2011 +0200
     2.2 +++ b/helpers/sonews.conf.sample	Tue Jun 07 11:55:22 2011 +0200
     2.3 @@ -1,4 +1,4 @@
     2.4  sonews.storage.database=jdbc:hsqldb:file:sonewsdb
     2.5 -sonews.storage.user=
     2.6 +sonews.storage.user=SA
     2.7  sonews.storage.dbmsdriver=org.hsqldb.jdbcDriver
     2.8  sonews.storage.password=
     3.1 --- a/src/org/sonews/storage/impl/HSQLDB.java	Tue Jun 07 09:23:34 2011 +0200
     3.2 +++ b/src/org/sonews/storage/impl/HSQLDB.java	Tue Jun 07 11:55:22 2011 +0200
     3.3 @@ -17,141 +17,14 @@
     3.4   */
     3.5  package org.sonews.storage.impl;
     3.6  
     3.7 -import java.util.List;
     3.8 -import org.sonews.feed.Subscription;
     3.9 -import org.sonews.storage.Article;
    3.10 -import org.sonews.storage.ArticleHead;
    3.11 -import org.sonews.storage.Channel;
    3.12 -import org.sonews.storage.Group;
    3.13  import org.sonews.storage.Storage;
    3.14 -import org.sonews.storage.StorageBackendException;
    3.15 -import org.sonews.util.Pair;
    3.16  
    3.17  /**
    3.18 - *
    3.19 + * A specialized JDBCDatabase supporting HSQLDB.
    3.20   * @author Christian Lins
    3.21   * @since sonews/1.1
    3.22   */
    3.23 -public class HSQLDB implements Storage {
    3.24 +public class HSQLDB extends JDBCDatabase implements Storage {
    3.25  
    3.26 -	public void addArticle(Article art) throws StorageBackendException {
    3.27 -		throw new UnsupportedOperationException("Not supported yet.");
    3.28 -	}
    3.29 -
    3.30 -	public void addEvent(long timestamp, int type, long groupID) throws StorageBackendException {
    3.31 -		throw new UnsupportedOperationException("Not supported yet.");
    3.32 -	}
    3.33 -
    3.34 -	public void addGroup(String groupname, int flags) throws StorageBackendException {
    3.35 -		throw new UnsupportedOperationException("Not supported yet.");
    3.36 -	}
    3.37 -
    3.38 -	public int countArticles() throws StorageBackendException {
    3.39 -		throw new UnsupportedOperationException("Not supported yet.");
    3.40 -	}
    3.41 -
    3.42 -	public int countGroups() throws StorageBackendException {
    3.43 -		throw new UnsupportedOperationException("Not supported yet.");
    3.44 -	}
    3.45 -
    3.46 -	public void delete(String messageID) throws StorageBackendException {
    3.47 -		throw new UnsupportedOperationException("Not supported yet.");
    3.48 -	}
    3.49 -
    3.50 -	public Article getArticle(String messageID) throws StorageBackendException {
    3.51 -		throw new UnsupportedOperationException("Not supported yet.");
    3.52 -	}
    3.53 -
    3.54 -	public Article getArticle(long articleIndex, long groupID) throws StorageBackendException {
    3.55 -		throw new UnsupportedOperationException("Not supported yet.");
    3.56 -	}
    3.57 -
    3.58 -	public List<Pair<Long, String>> getArticleHeaders(Channel channel, long start, long end, String header, String pattern) throws StorageBackendException {
    3.59 -		throw new UnsupportedOperationException("Not supported yet.");
    3.60 -	}
    3.61 -
    3.62 -	public List<Pair<Long, ArticleHead>> getArticleHeads(Group group, long first, long last) throws StorageBackendException {
    3.63 -		throw new UnsupportedOperationException("Not supported yet.");
    3.64 -	}
    3.65 -
    3.66 -	public long getArticleIndex(Article art, Group group) throws StorageBackendException {
    3.67 -		throw new UnsupportedOperationException("Not supported yet.");
    3.68 -	}
    3.69 -
    3.70 -	public List<Long> getArticleNumbers(long groupID) throws StorageBackendException {
    3.71 -		throw new UnsupportedOperationException("Not supported yet.");
    3.72 -	}
    3.73 -
    3.74 -	public String getConfigValue(String key) throws StorageBackendException {
    3.75 -		throw new UnsupportedOperationException("Not supported yet.");
    3.76 -	}
    3.77 -
    3.78 -	public int getEventsCount(int eventType, long startTimestamp, long endTimestamp, Channel channel) throws StorageBackendException {
    3.79 -		throw new UnsupportedOperationException("Not supported yet.");
    3.80 -	}
    3.81 -
    3.82 -	public double getEventsPerHour(int key, long gid) throws StorageBackendException {
    3.83 -		throw new UnsupportedOperationException("Not supported yet.");
    3.84 -	}
    3.85 -
    3.86 -	public int getFirstArticleNumber(Group group) throws StorageBackendException {
    3.87 -		throw new UnsupportedOperationException("Not supported yet.");
    3.88 -	}
    3.89 -
    3.90 -	public Group getGroup(String name) throws StorageBackendException {
    3.91 -		throw new UnsupportedOperationException("Not supported yet.");
    3.92 -	}
    3.93 -
    3.94 -	public List<Channel> getGroups() throws StorageBackendException {
    3.95 -		throw new UnsupportedOperationException("Not supported yet.");
    3.96 -	}
    3.97 -
    3.98 -	public List<String> getGroupsForList(String listAddress) throws StorageBackendException {
    3.99 -		throw new UnsupportedOperationException("Not supported yet.");
   3.100 -	}
   3.101 -
   3.102 -	public int getLastArticleNumber(Group group) throws StorageBackendException {
   3.103 -		throw new UnsupportedOperationException("Not supported yet.");
   3.104 -	}
   3.105 -
   3.106 -	public List<String> getListsForGroup(String groupname) throws StorageBackendException {
   3.107 -		throw new UnsupportedOperationException("Not supported yet.");
   3.108 -	}
   3.109 -
   3.110 -	public String getOldestArticle() throws StorageBackendException {
   3.111 -		throw new UnsupportedOperationException("Not supported yet.");
   3.112 -	}
   3.113 -
   3.114 -	public int getPostingsCount(String groupname) throws StorageBackendException {
   3.115 -		throw new UnsupportedOperationException("Not supported yet.");
   3.116 -	}
   3.117 -
   3.118 -	public List<Subscription> getSubscriptions(int type) throws StorageBackendException {
   3.119 -		throw new UnsupportedOperationException("Not supported yet.");
   3.120 -	}
   3.121 -
   3.122 -	public boolean isArticleExisting(String messageID) throws StorageBackendException {
   3.123 -		throw new UnsupportedOperationException("Not supported yet.");
   3.124 -	}
   3.125 -
   3.126 -	public boolean isGroupExisting(String groupname) throws StorageBackendException {
   3.127 -		throw new UnsupportedOperationException("Not supported yet.");
   3.128 -	}
   3.129 -
   3.130 -	public void purgeGroup(Group group) throws StorageBackendException {
   3.131 -		throw new UnsupportedOperationException("Not supported yet.");
   3.132 -	}
   3.133 -
   3.134 -	public void setConfigValue(String key, String value) throws StorageBackendException {
   3.135 -		throw new UnsupportedOperationException("Not supported yet.");
   3.136 -	}
   3.137 -
   3.138 -	public boolean update(Article article) throws StorageBackendException {
   3.139 -		throw new UnsupportedOperationException("Not supported yet.");
   3.140 -	}
   3.141 -
   3.142 -	public boolean update(Group group) throws StorageBackendException {
   3.143 -		throw new UnsupportedOperationException("Not supported yet.");
   3.144 -	}
   3.145  
   3.146  }
     4.1 --- a/src/org/sonews/storage/impl/HSQLDBProvider.java	Tue Jun 07 09:23:34 2011 +0200
     4.2 +++ b/src/org/sonews/storage/impl/HSQLDBProvider.java	Tue Jun 07 11:55:22 2011 +0200
     4.3 @@ -29,7 +29,7 @@
     4.4  public class HSQLDBProvider implements StorageProvider {
     4.5  
     4.6  	public boolean isSupported(String uri) {
     4.7 -		throw new UnsupportedOperationException("Not supported yet.");
     4.8 +		return uri.startsWith("jdbc:hsqldb");
     4.9  	}
    4.10  
    4.11  	public Storage storage(Thread thread) throws StorageBackendException {
     5.1 --- a/src/org/sonews/storage/impl/JDBCDatabase.java	Tue Jun 07 09:23:34 2011 +0200
     5.2 +++ b/src/org/sonews/storage/impl/JDBCDatabase.java	Tue Jun 07 11:55:22 2011 +0200
     5.3 @@ -53,49 +53,49 @@
     5.4  {
     5.5  
     5.6  	public static final int MAX_RESTARTS = 2;
     5.7 -	private Connection conn = null;
     5.8 -	private PreparedStatement pstmtAddArticle1 = null;
     5.9 -	private PreparedStatement pstmtAddArticle2 = null;
    5.10 -	private PreparedStatement pstmtAddArticle3 = null;
    5.11 -	private PreparedStatement pstmtAddArticle4 = null;
    5.12 -	private PreparedStatement pstmtAddGroup0 = null;
    5.13 -	private PreparedStatement pstmtAddEvent = null;
    5.14 -	private PreparedStatement pstmtCountArticles = null;
    5.15 -	private PreparedStatement pstmtCountGroups = null;
    5.16 -	private PreparedStatement pstmtDeleteArticle0 = null;
    5.17 -	private PreparedStatement pstmtDeleteArticle1 = null;
    5.18 -	private PreparedStatement pstmtDeleteArticle2 = null;
    5.19 -	private PreparedStatement pstmtDeleteArticle3 = null;
    5.20 -	private PreparedStatement pstmtGetArticle0 = null;
    5.21 -	private PreparedStatement pstmtGetArticle1 = null;
    5.22 -	private PreparedStatement pstmtGetArticleHeaders0 = null;
    5.23 -	private PreparedStatement pstmtGetArticleHeaders1 = null;
    5.24 -	private PreparedStatement pstmtGetArticleHeads = null;
    5.25 -	private PreparedStatement pstmtGetArticleIDs = null;
    5.26 -	private PreparedStatement pstmtGetArticleIndex = null;
    5.27 -	private PreparedStatement pstmtGetConfigValue = null;
    5.28 -	private PreparedStatement pstmtGetEventsCount0 = null;
    5.29 -	private PreparedStatement pstmtGetEventsCount1 = null;
    5.30 -	private PreparedStatement pstmtGetGroupForList = null;
    5.31 -	private PreparedStatement pstmtGetGroup0 = null;
    5.32 -	private PreparedStatement pstmtGetGroup1 = null;
    5.33 -	private PreparedStatement pstmtGetFirstArticleNumber = null;
    5.34 -	private PreparedStatement pstmtGetListForGroup = null;
    5.35 -	private PreparedStatement pstmtGetLastArticleNumber = null;
    5.36 -	private PreparedStatement pstmtGetMaxArticleID = null;
    5.37 -	private PreparedStatement pstmtGetMaxArticleIndex = null;
    5.38 -	private PreparedStatement pstmtGetOldestArticle = null;
    5.39 -	private PreparedStatement pstmtGetPostingsCount = null;
    5.40 -	private PreparedStatement pstmtGetSubscriptions = null;
    5.41 -	private PreparedStatement pstmtIsArticleExisting = null;
    5.42 -	private PreparedStatement pstmtIsGroupExisting = null;
    5.43 -	private PreparedStatement pstmtPurgeGroup0 = null;
    5.44 -	private PreparedStatement pstmtPurgeGroup1 = null;
    5.45 -	private PreparedStatement pstmtSetConfigValue0 = null;
    5.46 -	private PreparedStatement pstmtSetConfigValue1 = null;
    5.47 -	private PreparedStatement pstmtUpdateGroup = null;
    5.48 +	protected Connection conn = null;
    5.49 +	protected PreparedStatement pstmtAddArticle1 = null;
    5.50 +	protected PreparedStatement pstmtAddArticle2 = null;
    5.51 +	protected PreparedStatement pstmtAddArticle3 = null;
    5.52 +	protected PreparedStatement pstmtAddArticle4 = null;
    5.53 +	protected PreparedStatement pstmtAddGroup0 = null;
    5.54 +	protected PreparedStatement pstmtAddEvent = null;
    5.55 +	protected PreparedStatement pstmtCountArticles = null;
    5.56 +	protected PreparedStatement pstmtCountGroups = null;
    5.57 +	protected PreparedStatement pstmtDeleteArticle0 = null;
    5.58 +	protected PreparedStatement pstmtDeleteArticle1 = null;
    5.59 +	protected PreparedStatement pstmtDeleteArticle2 = null;
    5.60 +	protected PreparedStatement pstmtDeleteArticle3 = null;
    5.61 +	protected PreparedStatement pstmtGetArticle0 = null;
    5.62 +	protected PreparedStatement pstmtGetArticle1 = null;
    5.63 +	protected PreparedStatement pstmtGetArticleHeaders0 = null;
    5.64 +	protected PreparedStatement pstmtGetArticleHeaders1 = null;
    5.65 +	protected PreparedStatement pstmtGetArticleHeads = null;
    5.66 +	protected PreparedStatement pstmtGetArticleIDs = null;
    5.67 +	protected PreparedStatement pstmtGetArticleIndex = null;
    5.68 +	protected PreparedStatement pstmtGetConfigValue = null;
    5.69 +	protected PreparedStatement pstmtGetEventsCount0 = null;
    5.70 +	protected PreparedStatement pstmtGetEventsCount1 = null;
    5.71 +	protected PreparedStatement pstmtGetGroupForList = null;
    5.72 +	protected PreparedStatement pstmtGetGroup0 = null;
    5.73 +	protected PreparedStatement pstmtGetGroup1 = null;
    5.74 +	protected PreparedStatement pstmtGetFirstArticleNumber = null;
    5.75 +	protected PreparedStatement pstmtGetListForGroup = null;
    5.76 +	protected PreparedStatement pstmtGetLastArticleNumber = null;
    5.77 +	protected PreparedStatement pstmtGetMaxArticleID = null;
    5.78 +	protected PreparedStatement pstmtGetMaxArticleIndex = null;
    5.79 +	protected PreparedStatement pstmtGetOldestArticle = null;
    5.80 +	protected PreparedStatement pstmtGetPostingsCount = null;
    5.81 +	protected PreparedStatement pstmtGetSubscriptions = null;
    5.82 +	protected PreparedStatement pstmtIsArticleExisting = null;
    5.83 +	protected PreparedStatement pstmtIsGroupExisting = null;
    5.84 +	protected PreparedStatement pstmtPurgeGroup0 = null;
    5.85 +	protected PreparedStatement pstmtPurgeGroup1 = null;
    5.86 +	protected PreparedStatement pstmtSetConfigValue0 = null;
    5.87 +	protected PreparedStatement pstmtSetConfigValue1 = null;
    5.88 +	protected PreparedStatement pstmtUpdateGroup = null;
    5.89  	/** How many times the database connection was reinitialized */
    5.90 -	private int restarts = 0;
    5.91 +	protected int restarts = 0;
    5.92  
    5.93  	/**
    5.94  	 * Rises the database: reconnect and recreate all prepared statements.
     6.1 --- a/src/org/sonews/storage/impl/JDBCDatabaseProvider.java	Tue Jun 07 09:23:34 2011 +0200
     6.2 +++ b/src/org/sonews/storage/impl/JDBCDatabaseProvider.java	Tue Jun 07 11:55:22 2011 +0200
     6.3 @@ -35,7 +35,7 @@
     6.4  
     6.5  	@Override
     6.6  	public boolean isSupported(String uri) {
     6.7 -		throw new UnsupportedOperationException("Not supported yet.");
     6.8 +		return uri.startsWith("jdbc:mysql") || uri.startsWith("jdbc:postgresql");
     6.9  	}
    6.10  
    6.11  	@Override
     7.1 --- a/src/org/sonews/util/DatabaseSetup.java	Tue Jun 07 09:23:34 2011 +0200
     7.2 +++ b/src/org/sonews/util/DatabaseSetup.java	Tue Jun 07 11:55:22 2011 +0200
     7.3 @@ -15,13 +15,13 @@
     7.4   *   You should have received a copy of the GNU General Public License
     7.5   *   along with this program.  If not, see <http://www.gnu.org/licenses/>.
     7.6   */
     7.7 -
     7.8  package org.sonews.util;
     7.9  
    7.10  import java.io.BufferedReader;
    7.11  import java.io.InputStreamReader;
    7.12  import java.sql.Connection;
    7.13  import java.sql.DriverManager;
    7.14 +import java.sql.SQLException;
    7.15  import java.sql.Statement;
    7.16  import java.util.HashMap;
    7.17  import java.util.Map;
    7.18 @@ -32,8 +32,7 @@
    7.19   * @author Christian Lins
    7.20   * @since sonews/0.5.0
    7.21   */
    7.22 -public final class DatabaseSetup
    7.23 -{
    7.24 +public final class DatabaseSetup {
    7.25  
    7.26  	private static final Map<String, String> templateMap = new HashMap<String, String>();
    7.27  	private static final Map<String, StringTemplate> urlMap = new HashMap<String, StringTemplate>();
    7.28 @@ -42,58 +41,79 @@
    7.29  	static {
    7.30  		templateMap.put("1", "helpers/database_mysql5_tmpl.sql");
    7.31  		templateMap.put("2", "helpers/database_postgresql8_tmpl.sql");
    7.32 +		templateMap.put("3", "helpers/database_hsqldb_tmpl.sql");
    7.33  
    7.34  		urlMap.put("1", new StringTemplate("jdbc:mysql://%HOSTNAME/%DB"));
    7.35  		urlMap.put("2", new StringTemplate("jdbc:postgresql://%HOSTNAME/%DB"));
    7.36  
    7.37  		driverMap.put("1", "com.mysql.jdbc.Driver");
    7.38  		driverMap.put("2", "org.postgresql.Driver");
    7.39 +		driverMap.put("3", "org.hsqldb.jdbcDriver");
    7.40  	}
    7.41  
    7.42  	public static void main(String[] args)
    7.43 -		throws Exception
    7.44 -	{
    7.45 -		System.out.println("sonews Database setup helper");
    7.46 -		System.out.println("This program will create a initial database table structure");
    7.47 -		System.out.println("for the sonews Newsserver.");
    7.48 -		System.out.println("You need to create a database and a db user manually before!");
    7.49 +			throws Exception {
    7.50 +		
    7.51 +		loadJDBCDriver();
    7.52  
    7.53 -		System.out.println("Select DBMS type:");
    7.54 -		System.out.println("[1] MySQL 5.x or higher");
    7.55 -		System.out.println("[2] PostgreSQL 8.x or higher");
    7.56 -		System.out.print("Your choice: ");
    7.57 +		if (args.length == 0) {
    7.58 +			System.out.println("sonews Database setup helper");
    7.59 +			System.out.println("This program will create a initial database table structure");
    7.60 +			System.out.println("for the sonews Newsserver.");
    7.61 +			System.out.println("You need to create a database and a db user manually before!");
    7.62  
    7.63 -		BufferedReader in = new BufferedReader(new InputStreamReader(System.in));
    7.64 -		String dbmsType = in.readLine();
    7.65 -		String tmplName = templateMap.get(dbmsType);
    7.66 -		if (tmplName == null) {
    7.67 -			System.err.println("Invalid choice. Try again you fool!");
    7.68 -			main(args);
    7.69 -			return;
    7.70 +			System.out.println("Select DBMS type:");
    7.71 +			System.out.println("[1] MySQL 5.x or higher");
    7.72 +			System.out.println("[2] PostgreSQL 8.x or higher");
    7.73 +			System.out.print("Your choice: ");
    7.74 +
    7.75 +			BufferedReader in = new BufferedReader(new InputStreamReader(System.in));
    7.76 +			String dbmsType = in.readLine();
    7.77 +			String tmplName = templateMap.get(dbmsType);
    7.78 +			if (tmplName == null) {
    7.79 +				System.err.println("Invalid choice. Try again you fool!");
    7.80 +				main(args);
    7.81 +				return;
    7.82 +			}
    7.83 +
    7.84 +			String tmpl = Resource.getAsString(tmplName, true);
    7.85 +
    7.86 +			System.out.print("Database server hostname (e.g. localhost): ");
    7.87 +			String dbHostname = in.readLine();
    7.88 +
    7.89 +			System.out.print("Database name: ");
    7.90 +			String dbName = in.readLine();
    7.91 +
    7.92 +			System.out.print("Give name of DB user that can create tables: ");
    7.93 +			String dbUser = in.readLine();
    7.94 +
    7.95 +			System.out.print("Password: ");
    7.96 +			String dbPassword = in.readLine();
    7.97 +
    7.98 +			String url = urlMap.get(dbmsType).set("HOSTNAME", dbHostname).set("DB", dbName).toString();
    7.99 +			createTables(tmpl, url, dbUser, dbPassword);
   7.100 +
   7.101 +			// TODO: Create config file
   7.102 +
   7.103 +		} else if(args.length == 4) {
   7.104 +			String tmplName = args[0];
   7.105 +			String url = args[1];
   7.106 +			String dbUser = args[2];
   7.107 +			String dbPassword = args[3];
   7.108 +
   7.109 +			String tmpl = Resource.getAsString(tmplName, true);
   7.110 +			createTables(tmpl, url, dbUser, dbPassword);
   7.111 +		} else {
   7.112 +			System.out.println("Wrong number of parameters!");
   7.113  		}
   7.114  
   7.115 -		// Load JDBC Driver class
   7.116 -		Class.forName(driverMap.get(dbmsType));
   7.117 +		System.out.println("Ok");
   7.118 +	}
   7.119  
   7.120 -		String tmpl = Resource.getAsString(tmplName, true);
   7.121 -
   7.122 -		System.out.print("Database server hostname (e.g. localhost): ");
   7.123 -		String dbHostname = in.readLine();
   7.124 -
   7.125 -		System.out.print("Database name: ");
   7.126 -		String dbName = in.readLine();
   7.127 -
   7.128 -		System.out.print("Give name of DB user that can create tables: ");
   7.129 -		String dbUser = in.readLine();
   7.130 -
   7.131 -		System.out.print("Password: ");
   7.132 -		String dbPassword = in.readLine();
   7.133 -
   7.134 -		String url = urlMap.get(dbmsType).set("HOSTNAME", dbHostname).set("DB", dbName).toString();
   7.135 -
   7.136 +	public static void createTables(String tmpl, String url, String dbUser, String dbPassword)
   7.137 +			throws SQLException {
   7.138  		Connection conn =
   7.139 -			DriverManager.getConnection(url, dbUser, dbPassword);
   7.140 -		conn.setAutoCommit(false);
   7.141 +				DriverManager.getConnection(url, dbUser, dbPassword);
   7.142  
   7.143  		String[] tmplChunks = tmpl.split(";");
   7.144  
   7.145 @@ -107,10 +127,16 @@
   7.146  		}
   7.147  
   7.148  		conn.commit();
   7.149 -		conn.setAutoCommit(true);
   7.150 +		conn.close();
   7.151 +	}
   7.152  
   7.153 -		// Create config file
   7.154 -
   7.155 -		System.out.println("Ok");
   7.156 +	public static void loadJDBCDriver() {
   7.157 +		for(String className : driverMap.values()) {
   7.158 +			try {
   7.159 +				Class.forName(className);
   7.160 +			} catch (ClassNotFoundException ex) {
   7.161 +				System.out.println("Could not load JDBC driver: " + className);
   7.162 +			}
   7.163 +		}
   7.164  	}
   7.165  }
     8.1 --- a/src/org/sonews/util/io/Resource.java	Tue Jun 07 09:23:34 2011 +0200
     8.2 +++ b/src/org/sonews/util/io/Resource.java	Tue Jun 07 11:55:22 2011 +0200
     8.3 @@ -19,6 +19,8 @@
     8.4  package org.sonews.util.io;
     8.5  
     8.6  import java.io.BufferedReader;
     8.7 +import java.io.File;
     8.8 +import java.io.FileInputStream;
     8.9  import java.io.IOException;
    8.10  import java.io.InputStream;
    8.11  import java.io.InputStreamReader;
    8.12 @@ -59,6 +61,10 @@
    8.13  		try {
    8.14  			URL url = getAsURL(name);
    8.15  			if (url == null) {
    8.16 +				File file = new File(name);
    8.17 +				if(file.exists()) {
    8.18 +					return new FileInputStream(file);
    8.19 +				}
    8.20  				return null;
    8.21  			} else {
    8.22  				return url.openStream();