trunk/com/so/news/storage/Database.java
author chris <chris@marvin>
Tue, 20 Jan 2009 10:21:03 +0100
changeset 0 f907866f0e4b
permissions -rw-r--r--
Initial import.
chris@0
     1
/*
chris@0
     2
 *   StarOffice News Server
chris@0
     3
 *   see AUTHORS for the list of contributors
chris@0
     4
 *
chris@0
     5
 *   This program is free software: you can redistribute it and/or modify
chris@0
     6
 *   it under the terms of the GNU General Public License as published by
chris@0
     7
 *   the Free Software Foundation, either version 3 of the License, or
chris@0
     8
 *   (at your option) any later version.
chris@0
     9
 *
chris@0
    10
 *   This program is distributed in the hope that it will be useful,
chris@0
    11
 *   but WITHOUT ANY WARRANTY; without even the implied warranty of
chris@0
    12
 *   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
chris@0
    13
 *   GNU General Public License for more details.
chris@0
    14
 *
chris@0
    15
 *   You should have received a copy of the GNU General Public License
chris@0
    16
 *   along with this program.  If not, see <http://www.gnu.org/licenses/>.
chris@0
    17
 */
chris@0
    18
chris@0
    19
package com.so.news.storage;
chris@0
    20
chris@0
    21
import java.sql.Connection;
chris@0
    22
import java.sql.DriverManager;
chris@0
    23
import java.sql.ResultSet;
chris@0
    24
import java.sql.SQLException;
chris@0
    25
import java.sql.Statement;
chris@0
    26
chris@0
    27
import java.util.zip.CRC32;
chris@0
    28
import com.so.news.Config;
chris@0
    29
import com.so.news.util.StringTemplate;
chris@0
    30
chris@0
    31
/**
chris@0
    32
 * Database abstraction class.
chris@0
    33
 * @author Christian Lins (christian.lins@web.de)
chris@0
    34
 */
chris@0
    35
public class Database
chris@0
    36
{
chris@0
    37
  private static Database instance = null;
chris@0
    38
  
chris@0
    39
  /**
chris@0
    40
   * Initializes the Database subsystem, e.g. loading a JDBC driver and
chris@0
    41
   * connection to the Database Managment System.
chris@0
    42
   * This method is called when the daemon starts up or at the first
chris@0
    43
   * call to Database.getInstance().
chris@0
    44
   * @throws java.lang.Exception
chris@0
    45
   */
chris@0
    46
  public static void arise()
chris@0
    47
    throws Exception
chris@0
    48
  {
chris@0
    49
    // Tries to load the Database driver and establish a connection.
chris@0
    50
    if(instance == null)
chris@0
    51
      instance = new Database();
chris@0
    52
  }
chris@0
    53
  
chris@0
    54
  /**
chris@0
    55
   * @return Instance of the current Database backend. Returns null if an error
chris@0
    56
   * has occurred.
chris@0
    57
   */
chris@0
    58
  public static Database getInstance()
chris@0
    59
  {
chris@0
    60
    try
chris@0
    61
    {
chris@0
    62
      arise();
chris@0
    63
      return instance;
chris@0
    64
    }
chris@0
    65
    catch(Exception ex)
chris@0
    66
    {
chris@0
    67
      ex.printStackTrace();
chris@0
    68
      return null;
chris@0
    69
    }
chris@0
    70
  }
chris@0
    71
  
chris@0
    72
  private Connection conn = null;
chris@0
    73
  
chris@0
    74
  /**
chris@0
    75
   * Private constructor.
chris@0
    76
   * @throws java.lang.Exception
chris@0
    77
   */
chris@0
    78
  private Database()
chris@0
    79
    throws Exception
chris@0
    80
  {
chris@0
    81
    Class.forName(
chris@0
    82
            Config.getInstance().get("n3tpd.storage.dbmsdriver", ""));
chris@0
    83
    this.conn = DriverManager.getConnection(
chris@0
    84
            Config.getInstance().get("n3tpd.storage.database", ""),
chris@0
    85
            Config.getInstance().get("n3tpd.storage.user", "n3tpd_user"),
chris@0
    86
            Config.getInstance().get("n3tpd.storage.password", ""));
chris@0
    87
    this.conn.setAutoCommit(false);
chris@0
    88
  }
chris@0
    89
  
chris@0
    90
  /**
chris@0
    91
   * Adds an article to the database.
chris@0
    92
   * @param article
chris@0
    93
   * @return
chris@0
    94
   * @throws java.sql.SQLException
chris@0
    95
   */
chris@0
    96
  public boolean addArticle(Article article)
chris@0
    97
    throws SQLException
chris@0
    98
  {
chris@0
    99
    Statement stmt = this.conn.createStatement();
chris@0
   100
chris@0
   101
    String sql0 = "START TRANSACTION";
chris@0
   102
    String sql1 = "INSERT INTO articles (message_id,header,body)" +
chris@0
   103
            "VALUES('%mid', '%header', '%body')";
chris@0
   104
    StringTemplate tmpl = new StringTemplate(sql1);
chris@0
   105
    tmpl.set("body", article.getBody());
chris@0
   106
    tmpl.set("mid", article.getMessageID());
chris@0
   107
    tmpl.set("header", article.getHeaderSource());
chris@0
   108
    sql1 = tmpl.toString();
chris@0
   109
    
chris@0
   110
    String sql2 = "COMMIT";
chris@0
   111
    
chris@0
   112
    // Add statements as batch
chris@0
   113
    stmt.addBatch(sql0);
chris@0
   114
    stmt.addBatch(sql1);
chris@0
   115
    
chris@0
   116
    // TODO: For each newsgroup add a reference
chris@0
   117
    String sql = "INSERT INTO postings (group_id, article_id, article_index)" +
chris@0
   118
                 "VALUES (%gid, (SELECT article_id FROM articles WHERE message_id = '%mid')," +
chris@0
   119
                 " %idx)";
chris@0
   120
    
chris@0
   121
    tmpl = new StringTemplate(sql);
chris@0
   122
    tmpl.set("gid", article.getGroupID());
chris@0
   123
    tmpl.set("mid", article.getMessageID());
chris@0
   124
    tmpl.set("idx", getMaxArticleIndex() + 1);
chris@0
   125
    stmt.addBatch(tmpl.toString());
chris@0
   126
    
chris@0
   127
    // Commit
chris@0
   128
    stmt.addBatch(sql2);
chris@0
   129
    
chris@0
   130
    // And execute the batch
chris@0
   131
    stmt.executeBatch();
chris@0
   132
    
chris@0
   133
    return true;
chris@0
   134
  }
chris@0
   135
  
chris@0
   136
  /**
chris@0
   137
   * Adds a group to the Database.
chris@0
   138
   * @param name
chris@0
   139
   * @throws java.sql.SQLException
chris@0
   140
   */
chris@0
   141
  public boolean addGroup(String name)
chris@0
   142
    throws SQLException
chris@0
   143
  {
chris@0
   144
    CRC32 crc = new CRC32();
chris@0
   145
    crc.update(name.getBytes());
chris@0
   146
    
chris@0
   147
    long id = crc.getValue();
chris@0
   148
    
chris@0
   149
    Statement stmt = conn.createStatement();
chris@0
   150
    return 1 == stmt.executeUpdate("INSERT INTO Groups (ID, Name) VALUES (" + id + ", '" + name + "')");
chris@0
   151
  }
chris@0
   152
  
chris@0
   153
  public void delete(Article article)
chris@0
   154
  {
chris@0
   155
    
chris@0
   156
  }
chris@0
   157
  
chris@0
   158
  public void delete(Group group)
chris@0
   159
  {
chris@0
   160
    
chris@0
   161
  }
chris@0
   162
  
chris@0
   163
  public Article getArticle(String messageID)
chris@0
   164
    throws SQLException
chris@0
   165
  {
chris@0
   166
    Statement stmt = this.conn.createStatement();
chris@0
   167
    ResultSet rs =
chris@0
   168
      stmt.executeQuery("SELECT * FROM articles WHERE message_id = '" + messageID + "'");
chris@0
   169
    
chris@0
   170
    return new Article(rs);
chris@0
   171
  }
chris@0
   172
  
chris@0
   173
  public Article getArticle(long gid, long article_id)
chris@0
   174
    throws SQLException
chris@0
   175
  {
chris@0
   176
    Statement stmt = this.conn.createStatement();
chris@0
   177
    String sql = "SELECT * FROM articles WHERE article_id = " +
chris@0
   178
            "(SELECT article_id FROM postings WHERE " +
chris@0
   179
            "group_id = " + gid + " AND article_id = " + article_id +")";
chris@0
   180
    ResultSet rs =
chris@0
   181
      stmt.executeQuery(sql);
chris@0
   182
    
chris@0
   183
    if(rs.next())
chris@0
   184
      return new Article(rs);
chris@0
   185
    else
chris@0
   186
      return null;
chris@0
   187
  }
chris@0
   188
  
chris@0
   189
  public ResultSet getArticles()
chris@0
   190
    throws SQLException
chris@0
   191
  {
chris@0
   192
    Statement stmt = conn.createStatement();
chris@0
   193
    return stmt.executeQuery("SELECT * FROM articles");
chris@0
   194
  }
chris@0
   195
  
chris@0
   196
  /**
chris@0
   197
   * Reads all Groups from the Database.
chris@0
   198
   * @return
chris@0
   199
   * @throws java.sql.SQLException
chris@0
   200
   */
chris@0
   201
  public ResultSet getGroups()
chris@0
   202
    throws SQLException
chris@0
   203
  {
chris@0
   204
    Statement stmt = conn.createStatement();
chris@0
   205
    ResultSet rs = stmt.executeQuery("SELECT * FROM groups");
chris@0
   206
    
chris@0
   207
    return rs;
chris@0
   208
  }
chris@0
   209
  
chris@0
   210
  /**
chris@0
   211
   * Returns the Group that is identified by the name.
chris@0
   212
   * @param name
chris@0
   213
   * @return
chris@0
   214
   * @throws java.sql.SQLException
chris@0
   215
   */
chris@0
   216
  public Group getGroup(String name)
chris@0
   217
    throws SQLException
chris@0
   218
  {   
chris@0
   219
    Statement stmt = this.conn.createStatement();
chris@0
   220
    String sql = "SELECT group_id FROM groups WHERE Name = '%name'";
chris@0
   221
    StringTemplate tmpl = new StringTemplate(sql);
chris@0
   222
    tmpl.set("name", name);
chris@0
   223
    
chris@0
   224
    ResultSet rs = stmt.executeQuery(tmpl.toString());
chris@0
   225
  
chris@0
   226
    if(!rs.next())
chris@0
   227
      return null;
chris@0
   228
    else
chris@0
   229
    {
chris@0
   230
      long id = rs.getLong("group_id");
chris@0
   231
      return new Group(name, id);
chris@0
   232
    }
chris@0
   233
  }
chris@0
   234
  
chris@0
   235
  public int getMaxArticleIndex()
chris@0
   236
    throws SQLException
chris@0
   237
  {
chris@0
   238
    Statement stmt = conn.createStatement();
chris@0
   239
    ResultSet rs = stmt.executeQuery(
chris@0
   240
      "SELECT Max(article_index) FROM postings");
chris@0
   241
    
chris@0
   242
    if(!rs.next())
chris@0
   243
      return 0;
chris@0
   244
    else
chris@0
   245
      return rs.getInt(1);
chris@0
   246
  }
chris@0
   247
  
chris@0
   248
  public int getLastArticleNumber(Group group)
chris@0
   249
    throws SQLException
chris@0
   250
  {
chris@0
   251
    Statement stmt = conn.createStatement();
chris@0
   252
    ResultSet rs = stmt.executeQuery(
chris@0
   253
      "SELECT Max(article_index) FROM postings WHERE group_id = " + group.getID());
chris@0
   254
    
chris@0
   255
    if(!rs.next())
chris@0
   256
      return 0;
chris@0
   257
    else
chris@0
   258
      return rs.getInt(1);
chris@0
   259
  }
chris@0
   260
  
chris@0
   261
  public int getFirstArticleNumber(Group group)
chris@0
   262
    throws SQLException
chris@0
   263
  {
chris@0
   264
    Statement stmt = conn.createStatement();
chris@0
   265
    ResultSet rs = stmt.executeQuery(
chris@0
   266
      "SELECT Min(article_index) FROM postings WHERE group_id = " + group.getID());
chris@0
   267
  
chris@0
   268
    if(!rs.next())
chris@0
   269
      return 0;
chris@0
   270
    else
chris@0
   271
      return rs.getInt(1);
chris@0
   272
  }
chris@0
   273
  
chris@0
   274
  /**
chris@0
   275
   * Returns a group name identified by the given id.
chris@0
   276
   * @param id
chris@0
   277
   * @return
chris@0
   278
   * @throws java.sql.SQLException
chris@0
   279
   */
chris@0
   280
  public String getGroup(int id)
chris@0
   281
    throws SQLException
chris@0
   282
  {
chris@0
   283
    Statement stmt = conn.createStatement();
chris@0
   284
    ResultSet rs   = stmt.executeQuery(
chris@0
   285
            "SELECT name FROM groups WHERE group_id = '" + id + "'");
chris@0
   286
    
chris@0
   287
    if(rs.next())
chris@0
   288
    {
chris@0
   289
      return rs.getString(1);
chris@0
   290
    }
chris@0
   291
    else
chris@0
   292
      return null;
chris@0
   293
  }
chris@0
   294
  
chris@0
   295
  public Article getOldestArticle()
chris@0
   296
    throws SQLException
chris@0
   297
  {
chris@0
   298
    Statement stmt = conn.createStatement();
chris@0
   299
    ResultSet rs = 
chris@0
   300
      stmt.executeQuery("SELECT * FROM Articles WHERE Date = (SELECT Min(Date) FROM Articles)");
chris@0
   301
    
chris@0
   302
    if(rs.next())
chris@0
   303
      return new Article(rs);
chris@0
   304
    else
chris@0
   305
      return null;
chris@0
   306
  }
chris@0
   307
  
chris@0
   308
  /**
chris@0
   309
   * Checks if there is a group with the given name in the Database.
chris@0
   310
   * @param name
chris@0
   311
   * @return
chris@0
   312
   * @throws java.sql.SQLException
chris@0
   313
   */
chris@0
   314
  public boolean isGroupExisting(String name)
chris@0
   315
    throws SQLException
chris@0
   316
  {
chris@0
   317
    Statement stmt = this.conn.createStatement();
chris@0
   318
    ResultSet rs   = stmt.executeQuery("SELECT * FROM Groups WHERE Name = '" + name + "'");
chris@0
   319
    
chris@0
   320
    return rs.next();
chris@0
   321
  }
chris@0
   322
  
chris@0
   323
  public void updateArticle(Article article)
chris@0
   324
  {
chris@0
   325
    
chris@0
   326
  }
chris@0
   327
}