src/org/sonews/storage/impl/DrupalDatabase.java
author František Kučera <franta-hg@frantovo.cz>
Tue Oct 11 16:34:17 2011 +0200 (2011-10-11)
changeset 71 beb11d70f0eb
parent 70 2177f9b14688
child 72 aae4b4688700
permissions -rw-r--r--
Drupal: správný formát data (RFC 822)
franta-hg@63
     1
/*
franta-hg@63
     2
 *   SONEWS News Server
franta-hg@63
     3
 *   see AUTHORS for the list of contributors
franta-hg@63
     4
 *
franta-hg@63
     5
 *   This program is free software: you can redistribute it and/or modify
franta-hg@63
     6
 *   it under the terms of the GNU General Public License as published by
franta-hg@63
     7
 *   the Free Software Foundation, either version 3 of the License, or
franta-hg@63
     8
 *   (at your option) any later version.
franta-hg@63
     9
 *
franta-hg@63
    10
 *   This program is distributed in the hope that it will be useful,
franta-hg@63
    11
 *   but WITHOUT ANY WARRANTY; without even the implied warranty of
franta-hg@63
    12
 *   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
franta-hg@63
    13
 *   GNU General Public License for more details.
franta-hg@63
    14
 *
franta-hg@63
    15
 *   You should have received a copy of the GNU General Public License
franta-hg@63
    16
 *   along with this program.  If not, see <http://www.gnu.org/licenses/>.
franta-hg@63
    17
 */
franta-hg@63
    18
package org.sonews.storage.impl;
franta-hg@63
    19
franta-hg@68
    20
import java.io.UnsupportedEncodingException;
franta-hg@68
    21
import java.sql.Connection;
franta-hg@68
    22
import java.sql.DriverManager;
franta-hg@68
    23
import java.sql.PreparedStatement;
franta-hg@68
    24
import java.sql.ResultSet;
franta-hg@64
    25
import java.sql.SQLException;
franta-hg@68
    26
import java.sql.Statement;
franta-hg@71
    27
import java.text.SimpleDateFormat;
franta-hg@68
    28
import java.util.ArrayList;
franta-hg@65
    29
import java.util.Collections;
franta-hg@70
    30
import java.util.Date;
franta-hg@64
    31
import java.util.List;
franta-hg@71
    32
import java.util.Locale;
franta-hg@65
    33
import java.util.logging.Level;
franta-hg@66
    34
import java.util.logging.Logger;
franta-hg@70
    35
import javax.mail.internet.MailDateFormat;
franta-hg@68
    36
import javax.mail.internet.MimeUtility;
franta-hg@70
    37
import org.apache.commons.codec.net.BCodec;
franta-hg@69
    38
import org.apache.commons.codec.net.QuotedPrintableCodec;
franta-hg@68
    39
import org.sonews.config.Config;
franta-hg@64
    40
import org.sonews.feed.Subscription;
franta-hg@64
    41
import org.sonews.storage.Article;
franta-hg@64
    42
import org.sonews.storage.ArticleHead;
franta-hg@64
    43
import org.sonews.storage.Group;
franta-hg@64
    44
import org.sonews.storage.Storage;
franta-hg@64
    45
import org.sonews.storage.StorageBackendException;
franta-hg@64
    46
import org.sonews.util.Pair;
franta-hg@64
    47
franta-hg@63
    48
/**
franta-hg@63
    49
 *
franta-hg@63
    50
 * @author František Kučera (frantovo.cz)
franta-hg@63
    51
 */
franta-hg@64
    52
public class DrupalDatabase implements Storage {
franta-hg@67
    53
franta-hg@66
    54
	private static final Logger log = Logger.getLogger(DrupalDatabase.class.getName());
franta-hg@70
    55
	public static final String CHARSET = "UTF-8";
franta-hg@68
    56
	public static final String CRLF = "\r\n";
franta-hg@68
    57
	public static final int MAX_RESTARTS = 2;
franta-hg@68
    58
	/** How many times the database connection was reinitialized */
franta-hg@68
    59
	protected int restarts = 0;
franta-hg@68
    60
	protected Connection conn = null;
franta-hg@70
    61
	private QuotedPrintableCodec qpc = new QuotedPrintableCodec(CHARSET);
franta-hg@71
    62
	private SimpleDateFormat RFC822_DATE = new SimpleDateFormat("EEE', 'dd' 'MMM' 'yyyy' 'HH:mm:ss' 'Z", Locale.US);
franta-hg@70
    63
	// TODO: správná doména
franta-hg@70
    64
	private String myDomain = "kinderporno.cz";
franta-hg@68
    65
franta-hg@68
    66
	public DrupalDatabase() throws StorageBackendException {
franta-hg@68
    67
		connectDatabase();
franta-hg@68
    68
	}
franta-hg@68
    69
franta-hg@68
    70
	private void connectDatabase() throws StorageBackendException {
franta-hg@68
    71
		try {
franta-hg@68
    72
			// Load database driver
franta-hg@68
    73
			String driverClass = Config.inst().get(Config.LEVEL_FILE, Config.STORAGE_DBMSDRIVER, "java.lang.Object");
franta-hg@68
    74
			Class.forName(driverClass);
franta-hg@68
    75
franta-hg@68
    76
			// Establish database connection
franta-hg@68
    77
			String url = Config.inst().get(Config.LEVEL_FILE, Config.STORAGE_DATABASE, "<not specified>");
franta-hg@68
    78
			String username = Config.inst().get(Config.LEVEL_FILE, Config.STORAGE_USER, "root");
franta-hg@68
    79
			String password = Config.inst().get(Config.LEVEL_FILE, Config.STORAGE_PASSWORD, "");
franta-hg@68
    80
			conn = DriverManager.getConnection(url, username, password);
franta-hg@68
    81
franta-hg@68
    82
			conn.setTransactionIsolation(Connection.TRANSACTION_SERIALIZABLE);
franta-hg@68
    83
			if (conn.getTransactionIsolation() != Connection.TRANSACTION_SERIALIZABLE) {
franta-hg@68
    84
				log.warning("Database is NOT fully serializable!");
franta-hg@68
    85
			}
franta-hg@68
    86
		} catch (Exception e) {
franta-hg@68
    87
			throw new StorageBackendException(e);
franta-hg@68
    88
		}
franta-hg@68
    89
	}
franta-hg@68
    90
franta-hg@68
    91
	protected static void close(Connection connection, Statement statement, ResultSet resultSet) {
franta-hg@68
    92
		if (resultSet != null) {
franta-hg@68
    93
			try {
franta-hg@68
    94
				resultSet.close();
franta-hg@68
    95
			} catch (Exception e) {
franta-hg@68
    96
			}
franta-hg@68
    97
		}
franta-hg@68
    98
		if (statement != null) {
franta-hg@68
    99
			try {
franta-hg@68
   100
				statement.close();
franta-hg@68
   101
			} catch (Exception e) {
franta-hg@68
   102
			}
franta-hg@68
   103
		}
franta-hg@68
   104
		if (connection != null) {
franta-hg@68
   105
			try {
franta-hg@68
   106
				connection.close();
franta-hg@68
   107
			} catch (Exception e) {
franta-hg@68
   108
			}
franta-hg@68
   109
		}
franta-hg@68
   110
	}
franta-hg@64
   111
franta-hg@64
   112
	/**
franta-hg@68
   113
	 * 
franta-hg@70
   114
	 * @param messageID &lt;{0}-{1}-{2}@domain.tld&gt; where {0} is nntp_id and {1} is group_id and {2} is group_name
franta-hg@68
   115
	 * @return array where [0] = nntp_id and [1] = group_id and [2] = group_name or returns null if messageID is invalid
franta-hg@64
   116
	 */
franta-hg@68
   117
	private static String[] parseMessageID(String messageID) {
franta-hg@70
   118
		if (messageID.matches("<[0-9]+\\-[0-9]+\\-[a-z0-9\\.]+@.+>")) {
franta-hg@70
   119
			return messageID.substring(1).split("@")[0].split("\\-");
franta-hg@68
   120
		} else {
franta-hg@68
   121
			return null;
franta-hg@68
   122
		}
franta-hg@68
   123
	}
franta-hg@68
   124
franta-hg@68
   125
	private static Long parseArticleID(String messageID) {
franta-hg@68
   126
		String[] localPart = parseMessageID(messageID);
franta-hg@68
   127
		if (localPart == null) {
franta-hg@68
   128
			return null;
franta-hg@68
   129
		} else {
franta-hg@68
   130
			return Long.parseLong(localPart[0]);
franta-hg@68
   131
		}
franta-hg@68
   132
	}
franta-hg@68
   133
franta-hg@68
   134
	private static Long parseGroupID(String messageID) {
franta-hg@68
   135
		String[] localPart = parseMessageID(messageID);
franta-hg@68
   136
		if (localPart == null) {
franta-hg@68
   137
			return null;
franta-hg@68
   138
		} else {
franta-hg@68
   139
			return Long.parseLong(localPart[1]);
franta-hg@68
   140
		}
franta-hg@68
   141
	}
franta-hg@68
   142
franta-hg@68
   143
	private static String parseGroupName(String messageID) {
franta-hg@68
   144
		String[] localPart = parseMessageID(messageID);
franta-hg@68
   145
		if (localPart == null) {
franta-hg@68
   146
			return null;
franta-hg@68
   147
		} else {
franta-hg@68
   148
			return localPart[2];
franta-hg@68
   149
		}
franta-hg@68
   150
	}
franta-hg@68
   151
franta-hg@70
   152
	private static String constructMessageId(int articleID, int groupID, String groupName, String domainName) {
franta-hg@70
   153
		StringBuilder sb = new StringBuilder();
franta-hg@70
   154
		sb.append("<");
franta-hg@70
   155
		sb.append(articleID);
franta-hg@70
   156
		sb.append("-");
franta-hg@70
   157
		sb.append(groupID);
franta-hg@70
   158
		sb.append("-");
franta-hg@70
   159
		sb.append(groupName);
franta-hg@70
   160
		sb.append("@");
franta-hg@70
   161
		sb.append(domainName);
franta-hg@70
   162
		sb.append(">");
franta-hg@70
   163
		return sb.toString();
franta-hg@70
   164
	}
franta-hg@70
   165
franta-hg@70
   166
	/**
franta-hg@70
   167
	 * 
franta-hg@70
   168
	 * @param sb header list to be appended with new header. List must be terminated by line end.
franta-hg@70
   169
	 * @param key header name (without : and space)
franta-hg@70
   170
	 * @param value header value
franta-hg@70
   171
	 * @param encode true if value should be encoded/escaped before appending
franta-hg@70
   172
	 * @throws UnsupportedEncodingException 
franta-hg@70
   173
	 */
franta-hg@70
   174
	private static void addHeader(StringBuilder sb, String key, String value, boolean encode) throws UnsupportedEncodingException {
franta-hg@70
   175
		sb.append(key);
franta-hg@70
   176
		sb.append(": ");
franta-hg@70
   177
		if (encode) {
franta-hg@70
   178
			sb.append(MimeUtility.encodeWord(value));
franta-hg@70
   179
		} else {
franta-hg@70
   180
			sb.append(value);
franta-hg@70
   181
		}
franta-hg@70
   182
		sb.append(CRLF);
franta-hg@70
   183
	}
franta-hg@70
   184
franta-hg@70
   185
	private String constructHeaders(ResultSet rs) throws SQLException, UnsupportedEncodingException {
franta-hg@68
   186
		StringBuilder sb = new StringBuilder();
franta-hg@69
   187
franta-hg@70
   188
		addHeader(sb, "Message-id", constructMessageId(rs.getInt("id"), rs.getInt("group_id"), rs.getString("group_name"), myDomain), false);
franta-hg@70
   189
		addHeader(sb, "From", MimeUtility.encodeWord(rs.getString("sender_name")) + " <>", false);
franta-hg@70
   190
		addHeader(sb, "Subject", rs.getString("subject"), true);
franta-hg@70
   191
		/** TODO: správný formát data: */
franta-hg@71
   192
		addHeader(sb, "Date", RFC822_DATE.format(new Date(rs.getLong("created"))), false);
franta-hg@70
   193
		addHeader(sb, "Content-Type", "text/html; charset=" + CHARSET, false);
franta-hg@70
   194
		addHeader(sb, "Content-Transfer-Encoding", "quoted-printable", false);
franta-hg@70
   195
		//addHeader(sb, "Content-Transfer-Encoding", "base64", false);
franta-hg@69
   196
franta-hg@70
   197
		Integer parentID = rs.getInt("parent_id");
franta-hg@70
   198
		if (parentID != null && parentID > 0) {
franta-hg@70
   199
			String parentMessageID = constructMessageId(parentID, rs.getInt("group_id"), rs.getString("group_name"), myDomain);
franta-hg@70
   200
			addHeader(sb, "In-Reply-To", parentMessageID, false);
franta-hg@70
   201
			addHeader(sb, "References", parentMessageID, false);
franta-hg@70
   202
		}
franta-hg@68
   203
franta-hg@68
   204
		return sb.toString();
franta-hg@64
   205
	}
franta-hg@64
   206
franta-hg@64
   207
	@Override
franta-hg@67
   208
	public List<Group> getGroups() throws StorageBackendException {
franta-hg@68
   209
		PreparedStatement ps = null;
franta-hg@68
   210
		ResultSet rs = null;
franta-hg@68
   211
		try {
franta-hg@68
   212
			ps = conn.prepareStatement("SELECT * FROM nntp_group");
franta-hg@68
   213
			rs = ps.executeQuery();
franta-hg@68
   214
			List<Group> skupiny = new ArrayList<Group>();
franta-hg@68
   215
franta-hg@68
   216
			while (rs.next()) {
franta-hg@68
   217
				skupiny.add(new Group(rs.getString("name"), rs.getInt("id"), Group.READONLY));
franta-hg@68
   218
			}
franta-hg@68
   219
franta-hg@68
   220
			return skupiny;
franta-hg@68
   221
		} catch (Exception e) {
franta-hg@68
   222
			throw new StorageBackendException(e);
franta-hg@68
   223
		} finally {
franta-hg@68
   224
			close(null, ps, rs);
franta-hg@68
   225
		}
franta-hg@64
   226
	}
franta-hg@64
   227
franta-hg@64
   228
	@Override
franta-hg@67
   229
	public Group getGroup(String name) throws StorageBackendException {
franta-hg@68
   230
		PreparedStatement ps = null;
franta-hg@68
   231
		ResultSet rs = null;
franta-hg@68
   232
		try {
franta-hg@68
   233
			ps = conn.prepareStatement("SELECT * FROM nntp_group WHERE name = ?");
franta-hg@68
   234
			ps.setString(1, name);
franta-hg@68
   235
			rs = ps.executeQuery();
franta-hg@68
   236
franta-hg@68
   237
			while (rs.next()) {
franta-hg@68
   238
				return new Group(rs.getString("name"), rs.getInt("id"), Group.READONLY);
franta-hg@68
   239
			}
franta-hg@68
   240
franta-hg@68
   241
			return null;
franta-hg@68
   242
		} catch (Exception e) {
franta-hg@68
   243
			throw new StorageBackendException(e);
franta-hg@68
   244
		} finally {
franta-hg@68
   245
			close(null, ps, rs);
franta-hg@68
   246
		}
franta-hg@64
   247
	}
franta-hg@64
   248
franta-hg@64
   249
	@Override
franta-hg@67
   250
	public boolean isGroupExisting(String groupname) throws StorageBackendException {
franta-hg@68
   251
		return getGroup(groupname) != null;
franta-hg@64
   252
	}
franta-hg@64
   253
franta-hg@64
   254
	@Override
franta-hg@64
   255
	public Article getArticle(String messageID) throws StorageBackendException {
franta-hg@68
   256
		Long articleID = parseArticleID(messageID);
franta-hg@68
   257
		Long groupID = parseGroupID(messageID);
franta-hg@68
   258
franta-hg@68
   259
		if (articleID == null || groupID == null) {
franta-hg@68
   260
			log.log(Level.SEVERE, "Invalid messageID: {0}", new Object[]{messageID});
franta-hg@68
   261
			return null;
franta-hg@68
   262
		} else {
franta-hg@68
   263
			return getArticle(articleID, groupID);
franta-hg@68
   264
		}
franta-hg@64
   265
	}
franta-hg@64
   266
franta-hg@64
   267
	@Override
franta-hg@68
   268
	public Article getArticle(long articleID, long groupID) throws StorageBackendException {
franta-hg@68
   269
		PreparedStatement ps = null;
franta-hg@68
   270
		ResultSet rs = null;
franta-hg@68
   271
		try {
franta-hg@68
   272
			ps = conn.prepareStatement("SELECT * FROM nntp_article WHERE id = ? AND group_id = ?");
franta-hg@68
   273
			ps.setLong(1, articleID);
franta-hg@68
   274
			ps.setLong(2, groupID);
franta-hg@68
   275
			rs = ps.executeQuery();
franta-hg@68
   276
franta-hg@68
   277
			if (rs.next()) {
franta-hg@68
   278
				String headers = constructHeaders(rs);
franta-hg@70
   279
				// TODO: fold?
franta-hg@70
   280
				BCodec bc = new BCodec(CHARSET);
franta-hg@69
   281
				byte[] body = qpc.encode(rs.getString("text")).getBytes();
franta-hg@70
   282
				//byte[] body = bc.encode(rs.getString("text")).getBytes();
franta-hg@69
   283
franta-hg@68
   284
				return new Article(headers, body);
franta-hg@68
   285
			} else {
franta-hg@68
   286
				return null;
franta-hg@68
   287
			}
franta-hg@68
   288
		} catch (Exception e) {
franta-hg@68
   289
			throw new StorageBackendException(e);
franta-hg@68
   290
		} finally {
franta-hg@68
   291
			close(null, ps, rs);
franta-hg@68
   292
		}
franta-hg@64
   293
	}
franta-hg@64
   294
franta-hg@64
   295
	@Override
franta-hg@64
   296
	public List<Pair<Long, ArticleHead>> getArticleHeads(Group group, long first, long last) throws StorageBackendException {
franta-hg@68
   297
		PreparedStatement ps = null;
franta-hg@68
   298
		ResultSet rs = null;
franta-hg@68
   299
		try {
franta-hg@70
   300
			// TODO: je nutné řazení?
franta-hg@70
   301
			ps = conn.prepareStatement("SELECT * FROM nntp_article WHERE group_id = ? AND id >= ? AND id <= ? ORDER BY id");
franta-hg@68
   302
			ps.setLong(1, group.getInternalID());
franta-hg@68
   303
			ps.setLong(2, first);
franta-hg@68
   304
			ps.setLong(3, last);
franta-hg@68
   305
			rs = ps.executeQuery();
franta-hg@68
   306
franta-hg@68
   307
			List<Pair<Long, ArticleHead>> heads = new ArrayList<Pair<Long, ArticleHead>>();
franta-hg@68
   308
franta-hg@68
   309
			while (rs.next()) {
franta-hg@68
   310
				String headers = constructHeaders(rs);
franta-hg@68
   311
				heads.add(new Pair<Long, ArticleHead>(rs.getLong("id"), new ArticleHead(headers)));
franta-hg@68
   312
			}
franta-hg@68
   313
franta-hg@68
   314
			return heads;
franta-hg@68
   315
		} catch (Exception e) {
franta-hg@68
   316
			throw new StorageBackendException(e);
franta-hg@68
   317
		} finally {
franta-hg@68
   318
			close(null, ps, rs);
franta-hg@68
   319
		}
franta-hg@64
   320
	}
franta-hg@64
   321
franta-hg@64
   322
	@Override
franta-hg@64
   323
	public List<Pair<Long, String>> getArticleHeaders(Group group, long start, long end, String header, String pattern) throws StorageBackendException {
franta-hg@66
   324
		log.log(Level.SEVERE, "TODO: getArticleHeaders {0} / {1} / {2} / {3} / {4}", new Object[]{group, start, end, header, pattern});
franta-hg@65
   325
		/** TODO: */
franta-hg@65
   326
		return Collections.emptyList();
franta-hg@64
   327
	}
franta-hg@64
   328
franta-hg@64
   329
	@Override
franta-hg@68
   330
	public long getArticleIndex(Article article, Group group) throws StorageBackendException {
franta-hg@68
   331
		Long id = parseArticleID(article.getMessageID());
franta-hg@68
   332
		if (id == null) {
franta-hg@68
   333
			throw new StorageBackendException("Invalid messageID: " + article.getMessageID());
franta-hg@68
   334
		} else {
franta-hg@68
   335
			return id;
franta-hg@68
   336
		}
franta-hg@64
   337
	}
franta-hg@64
   338
franta-hg@64
   339
	@Override
franta-hg@64
   340
	public List<Long> getArticleNumbers(long groupID) throws StorageBackendException {
franta-hg@68
   341
		PreparedStatement ps = null;
franta-hg@68
   342
		ResultSet rs = null;
franta-hg@68
   343
		try {
franta-hg@68
   344
			ps = conn.prepareStatement("SELECT id FROM nntp_article WHERE group_id = ?");
franta-hg@68
   345
			ps.setLong(1, groupID);
franta-hg@68
   346
			rs = ps.executeQuery();
franta-hg@68
   347
			List<Long> articleNumbers = new ArrayList<Long>();
franta-hg@68
   348
			while (rs.next()) {
franta-hg@68
   349
				articleNumbers.add(rs.getLong(1));
franta-hg@68
   350
			}
franta-hg@68
   351
			return articleNumbers;
franta-hg@68
   352
		} catch (Exception e) {
franta-hg@68
   353
			throw new StorageBackendException(e);
franta-hg@68
   354
		} finally {
franta-hg@68
   355
			close(null, ps, rs);
franta-hg@68
   356
		}
franta-hg@64
   357
	}
franta-hg@64
   358
franta-hg@64
   359
	@Override
franta-hg@67
   360
	public int getFirstArticleNumber(Group group) throws StorageBackendException {
franta-hg@68
   361
		PreparedStatement ps = null;
franta-hg@68
   362
		ResultSet rs = null;
franta-hg@68
   363
		try {
franta-hg@68
   364
			ps = conn.prepareStatement("SELECT min(id) FROM nntp_article WHERE group_id = ?");
franta-hg@68
   365
			ps.setLong(1, group.getInternalID());
franta-hg@68
   366
			rs = ps.executeQuery();
franta-hg@68
   367
			rs.next();
franta-hg@68
   368
			return rs.getInt(1);
franta-hg@68
   369
		} catch (Exception e) {
franta-hg@68
   370
			throw new StorageBackendException(e);
franta-hg@68
   371
		} finally {
franta-hg@68
   372
			close(null, ps, rs);
franta-hg@68
   373
		}
franta-hg@67
   374
	}
franta-hg@67
   375
franta-hg@67
   376
	@Override
franta-hg@67
   377
	public int getLastArticleNumber(Group group) throws StorageBackendException {
franta-hg@68
   378
		PreparedStatement ps = null;
franta-hg@68
   379
		ResultSet rs = null;
franta-hg@68
   380
		try {
franta-hg@68
   381
			ps = conn.prepareStatement("SELECT max(id) FROM nntp_article WHERE group_id = ?");
franta-hg@68
   382
			ps.setLong(1, group.getInternalID());
franta-hg@68
   383
			rs = ps.executeQuery();
franta-hg@68
   384
			rs.next();
franta-hg@68
   385
			return rs.getInt(1);
franta-hg@68
   386
		} catch (Exception e) {
franta-hg@68
   387
			throw new StorageBackendException(e);
franta-hg@68
   388
		} finally {
franta-hg@68
   389
			close(null, ps, rs);
franta-hg@68
   390
		}
franta-hg@67
   391
	}
franta-hg@67
   392
franta-hg@67
   393
	@Override
franta-hg@67
   394
	public boolean isArticleExisting(String messageID) throws StorageBackendException {
franta-hg@68
   395
		Long articleID = parseArticleID(messageID);
franta-hg@68
   396
		Long groupID = parseGroupID(messageID);
franta-hg@68
   397
franta-hg@68
   398
		if (articleID == null || groupID == null) {
franta-hg@68
   399
			return false;
franta-hg@68
   400
		} else {
franta-hg@68
   401
			PreparedStatement ps = null;
franta-hg@68
   402
			ResultSet rs = null;
franta-hg@68
   403
			try {
franta-hg@68
   404
				ps = conn.prepareStatement("SELECT count(*) FROM nntp_article WHERE id = ? AND group_id = ?");
franta-hg@68
   405
				ps.setLong(1, articleID);
franta-hg@68
   406
				ps.setLong(2, groupID);
franta-hg@68
   407
				rs = ps.executeQuery();
franta-hg@68
   408
franta-hg@68
   409
				rs.next();
franta-hg@68
   410
				return rs.getInt(1) == 1;
franta-hg@68
   411
			} catch (Exception e) {
franta-hg@68
   412
				throw new StorageBackendException(e);
franta-hg@68
   413
			} finally {
franta-hg@68
   414
				close(null, ps, rs);
franta-hg@68
   415
			}
franta-hg@68
   416
		}
franta-hg@67
   417
	}
franta-hg@67
   418
franta-hg@67
   419
	//
franta-hg@67
   420
	// --- zatím neimplementovat ---
franta-hg@67
   421
	//
franta-hg@67
   422
	@Override
franta-hg@67
   423
	public void addArticle(Article art) throws StorageBackendException {
franta-hg@67
   424
		log.log(Level.SEVERE, "TODO: addArticle {0}", new Object[]{art});
franta-hg@67
   425
	}
franta-hg@67
   426
franta-hg@67
   427
	@Override
franta-hg@67
   428
	public void addEvent(long timestamp, int type, long groupID) throws StorageBackendException {
franta-hg@67
   429
		log.log(Level.SEVERE, "TODO: addEvent {0} / {1} / {2}", new Object[]{timestamp, type, groupID});
franta-hg@67
   430
	}
franta-hg@67
   431
franta-hg@67
   432
	@Override
franta-hg@67
   433
	public void addGroup(String groupname, int flags) throws StorageBackendException {
franta-hg@67
   434
		log.log(Level.SEVERE, "TODO: addGroup {0} / {1}", new Object[]{groupname, flags});
franta-hg@67
   435
	}
franta-hg@67
   436
franta-hg@67
   437
	@Override
franta-hg@67
   438
	public int countArticles() throws StorageBackendException {
franta-hg@69
   439
		PreparedStatement ps = null;
franta-hg@69
   440
		ResultSet rs = null;
franta-hg@69
   441
		try {
franta-hg@69
   442
			ps = conn.prepareStatement("SELECT count(*) FROM nntp_article");
franta-hg@69
   443
			rs = ps.executeQuery();
franta-hg@69
   444
			rs.next();
franta-hg@69
   445
			return rs.getInt(1);
franta-hg@69
   446
		} catch (Exception e) {
franta-hg@69
   447
			throw new StorageBackendException(e);
franta-hg@69
   448
		} finally {
franta-hg@69
   449
			close(null, ps, rs);
franta-hg@69
   450
		}
franta-hg@67
   451
	}
franta-hg@67
   452
franta-hg@67
   453
	@Override
franta-hg@67
   454
	public int countGroups() throws StorageBackendException {
franta-hg@69
   455
		PreparedStatement ps = null;
franta-hg@69
   456
		ResultSet rs = null;
franta-hg@69
   457
		try {
franta-hg@69
   458
			ps = conn.prepareStatement("SELECT count(*) FROM nntp_group");
franta-hg@69
   459
			rs = ps.executeQuery();
franta-hg@69
   460
			rs.next();
franta-hg@69
   461
			return rs.getInt(1);
franta-hg@69
   462
		} catch (Exception e) {
franta-hg@69
   463
			throw new StorageBackendException(e);
franta-hg@69
   464
		} finally {
franta-hg@69
   465
			close(null, ps, rs);
franta-hg@69
   466
		}
franta-hg@67
   467
	}
franta-hg@67
   468
franta-hg@67
   469
	@Override
franta-hg@67
   470
	public void delete(String messageID) throws StorageBackendException {
franta-hg@67
   471
		log.log(Level.SEVERE, "TODO: delete {0}", new Object[]{messageID});
franta-hg@67
   472
	}
franta-hg@67
   473
franta-hg@67
   474
	@Override
franta-hg@64
   475
	public String getConfigValue(String key) throws StorageBackendException {
franta-hg@69
   476
		//log.log(Level.SEVERE, "TODO: getConfigValue {0}", new Object[]{key});
franta-hg@65
   477
		return null;
franta-hg@64
   478
	}
franta-hg@64
   479
franta-hg@64
   480
	@Override
franta-hg@64
   481
	public int getEventsCount(int eventType, long startTimestamp, long endTimestamp, Group group) throws StorageBackendException {
franta-hg@66
   482
		log.log(Level.SEVERE, "TODO: getEventsCount {0} / {1} / {2} / {3}", new Object[]{eventType, startTimestamp, endTimestamp, group});
franta-hg@65
   483
		return 0;
franta-hg@64
   484
	}
franta-hg@64
   485
franta-hg@64
   486
	@Override
franta-hg@64
   487
	public double getEventsPerHour(int key, long gid) throws StorageBackendException {
franta-hg@66
   488
		log.log(Level.SEVERE, "TODO: getEventsPerHour {0} / {1}", new Object[]{key, gid});
franta-hg@65
   489
		return 0;
franta-hg@64
   490
	}
franta-hg@64
   491
franta-hg@64
   492
	@Override
franta-hg@64
   493
	public List<String> getGroupsForList(String listAddress) throws StorageBackendException {
franta-hg@66
   494
		log.log(Level.SEVERE, "TODO: getGroupsForList {0}", new Object[]{listAddress});
franta-hg@65
   495
		return Collections.emptyList();
franta-hg@64
   496
	}
franta-hg@64
   497
franta-hg@64
   498
	@Override
franta-hg@64
   499
	public List<String> getListsForGroup(String groupname) throws StorageBackendException {
franta-hg@66
   500
		log.log(Level.SEVERE, "TODO: getListsForGroup {0}", new Object[]{groupname});
franta-hg@65
   501
		return Collections.emptyList();
franta-hg@64
   502
	}
franta-hg@64
   503
franta-hg@64
   504
	@Override
franta-hg@64
   505
	public String getOldestArticle() throws StorageBackendException {
franta-hg@66
   506
		log.log(Level.SEVERE, "TODO: getOldestArticle");
franta-hg@65
   507
		return null;
franta-hg@64
   508
	}
franta-hg@64
   509
franta-hg@64
   510
	@Override
franta-hg@64
   511
	public int getPostingsCount(String groupname) throws StorageBackendException {
franta-hg@69
   512
		PreparedStatement ps = null;
franta-hg@69
   513
		ResultSet rs = null;
franta-hg@69
   514
		try {
franta-hg@69
   515
			ps = conn.prepareStatement("SELECT count(*) FROM nntp_article WHERE group_name = ?");
franta-hg@69
   516
			ps.setString(1, groupname);
franta-hg@69
   517
			rs = ps.executeQuery();
franta-hg@69
   518
			rs.next();
franta-hg@69
   519
			return rs.getInt(1);
franta-hg@69
   520
		} catch (Exception e) {
franta-hg@69
   521
			throw new StorageBackendException(e);
franta-hg@69
   522
		} finally {
franta-hg@69
   523
			close(null, ps, rs);
franta-hg@69
   524
		}
franta-hg@64
   525
	}
franta-hg@64
   526
franta-hg@64
   527
	@Override
franta-hg@64
   528
	public List<Subscription> getSubscriptions(int type) throws StorageBackendException {
franta-hg@66
   529
		log.log(Level.SEVERE, "TODO: getSubscriptions {0}", new Object[]{type});
franta-hg@65
   530
		return Collections.emptyList();
franta-hg@64
   531
	}
franta-hg@64
   532
franta-hg@64
   533
	@Override
franta-hg@64
   534
	public void purgeGroup(Group group) throws StorageBackendException {
franta-hg@66
   535
		log.log(Level.SEVERE, "TODO: purgeGroup {0}", new Object[]{group});
franta-hg@64
   536
	}
franta-hg@64
   537
franta-hg@64
   538
	@Override
franta-hg@64
   539
	public void setConfigValue(String key, String value) throws StorageBackendException {
franta-hg@66
   540
		log.log(Level.SEVERE, "TODO: setConfigValue {0} = {1}", new Object[]{key, value});
franta-hg@64
   541
	}
franta-hg@64
   542
franta-hg@64
   543
	@Override
franta-hg@64
   544
	public boolean update(Article article) throws StorageBackendException {
franta-hg@66
   545
		log.log(Level.SEVERE, "TODO: update {0}", new Object[]{article});
franta-hg@65
   546
		throw new StorageBackendException("Not implemented yet.");
franta-hg@64
   547
	}
franta-hg@64
   548
franta-hg@64
   549
	@Override
franta-hg@64
   550
	public boolean update(Group group) throws StorageBackendException {
franta-hg@66
   551
		log.log(Level.SEVERE, "TODO: update {0}", new Object[]{group});
franta-hg@65
   552
		throw new StorageBackendException("Not implemented yet.");
franta-hg@64
   553
	}
franta-hg@63
   554
}