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