Drupal: ověřování uživatelů.
3 * see AUTHORS for the list of contributors
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.
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.
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/>.
18 package org.sonews.storage.impl;
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.daemon.Connections;
32 import org.sonews.feed.Subscription;
33 import org.sonews.storage.Article;
34 import org.sonews.storage.ArticleHead;
35 import org.sonews.storage.DrupalArticle;
36 import org.sonews.storage.DrupalMessage;
37 import org.sonews.storage.Group;
38 import org.sonews.storage.Storage;
39 import org.sonews.storage.StorageBackendException;
40 import org.sonews.util.Pair;
44 * @author František Kučera (frantovo.cz)
46 public class DrupalDatabase implements Storage {
48 private static final Logger log = Logger.getLogger(DrupalDatabase.class.getName());
49 public static final String CHARSET = "UTF-8";
50 public static final String CRLF = "\r\n";
51 protected Connection conn = null;
52 // TODO: správná doména
53 private String myDomain = "nntp.i1984.cz";
55 public DrupalDatabase() throws StorageBackendException {
59 private void connectDatabase() throws StorageBackendException {
61 // Load database driver
62 String driverClass = Config.inst().get(Config.LEVEL_FILE, Config.STORAGE_DBMSDRIVER, "java.lang.Object");
63 Class.forName(driverClass);
65 // Establish database connection
66 String url = Config.inst().get(Config.LEVEL_FILE, Config.STORAGE_DATABASE, "<not specified>");
67 String username = Config.inst().get(Config.LEVEL_FILE, Config.STORAGE_USER, "root");
68 String password = Config.inst().get(Config.LEVEL_FILE, Config.STORAGE_PASSWORD, "");
69 conn = DriverManager.getConnection(url, username, password);
71 conn.setTransactionIsolation(Connection.TRANSACTION_SERIALIZABLE);
72 if (conn.getTransactionIsolation() != Connection.TRANSACTION_SERIALIZABLE) {
73 log.warning("Database is NOT fully serializable!");
75 } catch (Exception e) {
76 throw new StorageBackendException(e);
80 protected static void close(Connection connection, Statement statement, ResultSet resultSet) {
81 if (resultSet != null) {
84 } catch (Exception e) {
87 if (statement != null) {
90 } catch (Exception e) {
93 if (connection != null) {
96 } catch (Exception e) {
103 * @param messageID <{0}-{1}-{2}@domain.tld> where {0} is nntp_id and {1} is group_id and {2} is group_name
104 * @return array where [0] = nntp_id and [1] = group_id and [2] = group_name or returns null if messageID is invalid
106 private static String[] parseMessageID(String messageID) {
107 if (messageID.matches("<[0-9]+\\-[0-9]+\\-[a-z0-9\\.]+@.+>")) {
108 return messageID.substring(1).split("@")[0].split("\\-");
114 private static Long parseArticleID(String messageID) {
115 String[] localPart = parseMessageID(messageID);
116 if (localPart == null) {
119 return Long.parseLong(localPart[0]);
123 private static Long parseGroupID(String messageID) {
124 String[] localPart = parseMessageID(messageID);
125 if (localPart == null) {
128 return Long.parseLong(localPart[1]);
130 // parseGroupName() will be same as this method, just with:
131 // return localPart[2];
136 public List<Group> getGroups() throws StorageBackendException {
137 PreparedStatement ps = null;
140 ps = conn.prepareStatement("SELECT * FROM nntp_group");
141 rs = ps.executeQuery();
142 List<Group> skupiny = new ArrayList<Group>();
145 skupiny.add(new Group(rs.getString("name"), rs.getInt("id"), Group.READONLY));
149 } catch (Exception e) {
150 throw new StorageBackendException(e);
157 public Group getGroup(String name) throws StorageBackendException {
158 PreparedStatement ps = null;
161 ps = conn.prepareStatement("SELECT * FROM nntp_group WHERE name = ?");
162 ps.setString(1, name);
163 rs = ps.executeQuery();
166 return new Group(rs.getString("name"), rs.getInt("id"), Group.READONLY);
170 } catch (Exception e) {
171 throw new StorageBackendException(e);
178 public boolean isGroupExisting(String groupname) throws StorageBackendException {
179 return getGroup(groupname) != null;
183 public Article getArticle(String messageID) throws StorageBackendException {
184 Long articleID = parseArticleID(messageID);
185 Long groupID = parseGroupID(messageID);
187 if (articleID == null || groupID == null) {
188 log.log(Level.SEVERE, "Invalid messageID: {0}", new Object[]{messageID});
191 return getArticle(articleID, groupID);
196 public Article getArticle(long articleID, long groupID) throws StorageBackendException {
197 PreparedStatement ps = null;
200 ps = conn.prepareStatement("SELECT * FROM nntp_article WHERE id = ? AND group_id = ?");
201 ps.setLong(1, articleID);
202 ps.setLong(2, groupID);
203 rs = ps.executeQuery();
206 DrupalMessage m = new DrupalMessage(rs, myDomain, true);
207 return new DrupalArticle(m);
211 } catch (Exception e) {
212 throw new StorageBackendException(e);
219 public List<Pair<Long, ArticleHead>> getArticleHeads(Group group, long first, long last) throws StorageBackendException {
220 PreparedStatement ps = null;
223 ps = conn.prepareStatement("SELECT * FROM nntp_article WHERE group_id = ? AND id >= ? AND id <= ? ORDER BY id");
224 ps.setLong(1, group.getInternalID());
225 ps.setLong(2, first);
227 rs = ps.executeQuery();
229 List<Pair<Long, ArticleHead>> heads = new ArrayList<Pair<Long, ArticleHead>>();
232 DrupalMessage m = new DrupalMessage(rs, myDomain, false);
233 String headers = m.getHeaders();
234 heads.add(new Pair<Long, ArticleHead>(rs.getLong("id"), new ArticleHead(headers)));
238 } catch (Exception e) {
239 throw new StorageBackendException(e);
246 public long getArticleIndex(Article article, Group group) throws StorageBackendException {
247 Long id = parseArticleID(article.getMessageID());
249 throw new StorageBackendException("Invalid messageID: " + article.getMessageID());
256 public List<Long> getArticleNumbers(long groupID) throws StorageBackendException {
257 PreparedStatement ps = null;
260 ps = conn.prepareStatement("SELECT id FROM nntp_article WHERE group_id = ?");
261 ps.setLong(1, groupID);
262 rs = ps.executeQuery();
263 List<Long> articleNumbers = new ArrayList<Long>();
265 articleNumbers.add(rs.getLong(1));
267 return articleNumbers;
268 } catch (Exception e) {
269 throw new StorageBackendException(e);
276 public int getFirstArticleNumber(Group group) throws StorageBackendException {
277 PreparedStatement ps = null;
280 ps = conn.prepareStatement("SELECT min(id) FROM nntp_article WHERE group_id = ?");
281 ps.setLong(1, group.getInternalID());
282 rs = ps.executeQuery();
285 } catch (Exception e) {
286 throw new StorageBackendException(e);
293 public int getLastArticleNumber(Group group) throws StorageBackendException {
294 PreparedStatement ps = null;
297 ps = conn.prepareStatement("SELECT max(id) FROM nntp_article WHERE group_id = ?");
298 ps.setLong(1, group.getInternalID());
299 rs = ps.executeQuery();
302 } catch (Exception e) {
303 throw new StorageBackendException(e);
310 public boolean isArticleExisting(String messageID) throws StorageBackendException {
311 Long articleID = parseArticleID(messageID);
312 Long groupID = parseGroupID(messageID);
314 if (articleID == null || groupID == null) {
317 PreparedStatement ps = null;
320 ps = conn.prepareStatement("SELECT count(*) FROM nntp_article WHERE id = ? AND group_id = ?");
321 ps.setLong(1, articleID);
322 ps.setLong(2, groupID);
323 rs = ps.executeQuery();
326 return rs.getInt(1) == 1;
327 } catch (Exception e) {
328 throw new StorageBackendException(e);
336 public int countArticles() throws StorageBackendException {
337 PreparedStatement ps = null;
340 ps = conn.prepareStatement("SELECT count(*) FROM nntp_article");
341 rs = ps.executeQuery();
344 } catch (Exception e) {
345 throw new StorageBackendException(e);
352 public int countGroups() throws StorageBackendException {
353 PreparedStatement ps = null;
356 ps = conn.prepareStatement("SELECT count(*) FROM nntp_group");
357 rs = ps.executeQuery();
360 } catch (Exception e) {
361 throw new StorageBackendException(e);
368 public int getPostingsCount(String groupname) throws StorageBackendException {
369 PreparedStatement ps = null;
372 ps = conn.prepareStatement("SELECT count(*) FROM nntp_article WHERE group_name = ?");
373 ps.setString(1, groupname);
374 rs = ps.executeQuery();
377 } catch (Exception e) {
378 throw new StorageBackendException(e);
385 public List<Pair<Long, String>> getArticleHeaders(Group group, long start, long end, String header, String pattern) throws StorageBackendException {
386 log.log(Level.SEVERE, "TODO: getArticleHeaders {0} / {1} / {2} / {3} / {4}", new Object[]{group, start, end, header, pattern});
388 return Collections.emptyList();
392 * Checks username and password.
395 * @return true if credentials are valid | false otherwise
396 * @throws StorageBackendException it there is any error during authentication process
397 * (but should not be thrown if only bad thing is wrong username or password)
400 public boolean authenticateUser(String username, char[] password) throws StorageBackendException {
401 PreparedStatement ps = null;
404 ps = conn.prepareStatement("SELECT nntp_login(?, ?)");
405 ps.setString(1, username);
406 ps.setString(2, String.copyValueOf(password));
407 rs = ps.executeQuery();
409 return rs.getInt(1) == 1;
410 } catch (Exception e) {
411 throw new StorageBackendException(e);
418 public void addArticle(Article art) throws StorageBackendException {
419 if (art.getAuthenticatedUser() == null) {
420 log.log(Level.SEVERE, "User was not authenticated, so his article was rejected.");
421 throw new StorageBackendException("User must be authenticated to post articles");
424 log.log(Level.INFO, "User ''{0}'' has posted an article", art.getAuthenticatedUser());
429 public void addEvent(long timestamp, int type, long groupID) throws StorageBackendException {
430 log.log(Level.SEVERE, "TODO: addEvent {0} / {1} / {2}", new Object[]{timestamp, type, groupID});
434 public void addGroup(String groupname, int flags) throws StorageBackendException {
435 log.log(Level.SEVERE, "TODO: addGroup {0} / {1}", new Object[]{groupname, flags});
439 public void delete(String messageID) throws StorageBackendException {
440 log.log(Level.SEVERE, "TODO: delete {0}", new Object[]{messageID});
444 public String getConfigValue(String key) throws StorageBackendException {
445 //log.log(Level.SEVERE, "TODO: getConfigValue {0}", new Object[]{key});
450 public void setConfigValue(String key, String value) throws StorageBackendException {
451 log.log(Level.SEVERE, "TODO: setConfigValue {0} = {1}", new Object[]{key, value});
455 public int getEventsCount(int eventType, long startTimestamp, long endTimestamp, Group group) throws StorageBackendException {
456 log.log(Level.SEVERE, "TODO: getEventsCount {0} / {1} / {2} / {3}", new Object[]{eventType, startTimestamp, endTimestamp, group});
461 public double getEventsPerHour(int key, long gid) throws StorageBackendException {
462 log.log(Level.SEVERE, "TODO: getEventsPerHour {0} / {1}", new Object[]{key, gid});
467 public List<String> getGroupsForList(String listAddress) throws StorageBackendException {
468 log.log(Level.SEVERE, "TODO: getGroupsForList {0}", new Object[]{listAddress});
469 return Collections.emptyList();
473 public List<String> getListsForGroup(String groupname) throws StorageBackendException {
474 log.log(Level.SEVERE, "TODO: getListsForGroup {0}", new Object[]{groupname});
475 return Collections.emptyList();
479 public String getOldestArticle() throws StorageBackendException {
480 log.log(Level.SEVERE, "TODO: getOldestArticle");
485 public List<Subscription> getSubscriptions(int type) throws StorageBackendException {
486 log.log(Level.SEVERE, "TODO: getSubscriptions {0}", new Object[]{type});
487 return Collections.emptyList();
491 public void purgeGroup(Group group) throws StorageBackendException {
492 log.log(Level.SEVERE, "TODO: purgeGroup {0}", new Object[]{group});
496 public boolean update(Article article) throws StorageBackendException {
497 log.log(Level.SEVERE, "TODO: update {0}", new Object[]{article});
498 throw new StorageBackendException("Not implemented yet.");
502 public boolean update(Group group) throws StorageBackendException {
503 log.log(Level.SEVERE, "TODO: update {0}", new Object[]{group});
504 throw new StorageBackendException("Not implemented yet.");