src/org/sonews/storage/impl/DrupalDatabase.java
changeset 102 d843b4fee5dc
parent 101 d54786065fa3
child 103 a788bf0e1080
     1.1 --- a/src/org/sonews/storage/impl/DrupalDatabase.java	Wed Oct 19 21:40:51 2011 +0200
     1.2 +++ b/src/org/sonews/storage/impl/DrupalDatabase.java	Thu Oct 20 09:59:04 2011 +0200
     1.3 @@ -28,12 +28,13 @@
     1.4  import java.util.logging.Level;
     1.5  import java.util.logging.Logger;
     1.6  import org.sonews.config.Config;
     1.7 -import org.sonews.daemon.Connections;
     1.8  import org.sonews.feed.Subscription;
     1.9  import org.sonews.storage.Article;
    1.10  import org.sonews.storage.ArticleHead;
    1.11  import org.sonews.storage.DrupalArticle;
    1.12  import org.sonews.storage.DrupalMessage;
    1.13 +import static org.sonews.storage.DrupalMessage.parseArticleID;
    1.14 +import static org.sonews.storage.DrupalMessage.parseGroupID;
    1.15  import org.sonews.storage.Group;
    1.16  import org.sonews.storage.Storage;
    1.17  import org.sonews.storage.StorageBackendException;
    1.18 @@ -68,6 +69,18 @@
    1.19  			String password = Config.inst().get(Config.LEVEL_FILE, Config.STORAGE_PASSWORD, "");
    1.20  			conn = DriverManager.getConnection(url, username, password);
    1.21  
    1.22 +			/**
    1.23 +			 * Kódování češtiny:
    1.24 +			 * SET NAMES utf8 → dobrá čeština
    1.25 +			 *		Client characterset:    utf8
    1.26 +			 *		Conn.  characterset:    utf8
    1.27 +			 * SET CHARACTER SET utf8; → dobrá čeština jen pro SLECT, ale při volání funkce se zmrší
    1.28 +			 *		Client characterset:    utf8
    1.29 +			 *		Conn.  characterset:    latin1
    1.30 +			 * 
    1.31 +			 * Správné řešení:
    1.32 +			 *		V JDBC URL musí být: ?useUnicode=true&characterEncoding=UTF-8
    1.33 +			 */
    1.34  			conn.setTransactionIsolation(Connection.TRANSACTION_SERIALIZABLE);
    1.35  			if (conn.getTransactionIsolation() != Connection.TRANSACTION_SERIALIZABLE) {
    1.36  				log.warning("Database is NOT fully serializable!");
    1.37 @@ -98,40 +111,6 @@
    1.38  		}
    1.39  	}
    1.40  
    1.41 -	/**
    1.42 -	 * 
    1.43 -	 * @param messageID <{0}-{1}-{2}@domain.tld> where {0} is nntp_id and {1} is group_id and {2} is group_name
    1.44 -	 * @return array where [0] = nntp_id and [1] = group_id and [2] = group_name or returns null if messageID is invalid
    1.45 -	 */
    1.46 -	private static String[] parseMessageID(String messageID) {
    1.47 -		if (messageID.matches("<[0-9]+\\-[0-9]+\\-[a-z0-9\\.]+@.+>")) {
    1.48 -			return messageID.substring(1).split("@")[0].split("\\-");
    1.49 -		} else {
    1.50 -			return null;
    1.51 -		}
    1.52 -	}
    1.53 -
    1.54 -	private static Long parseArticleID(String messageID) {
    1.55 -		String[] localPart = parseMessageID(messageID);
    1.56 -		if (localPart == null) {
    1.57 -			return null;
    1.58 -		} else {
    1.59 -			return Long.parseLong(localPart[0]);
    1.60 -		}
    1.61 -	}
    1.62 -
    1.63 -	private static Long parseGroupID(String messageID) {
    1.64 -		String[] localPart = parseMessageID(messageID);
    1.65 -		if (localPart == null) {
    1.66 -			return null;
    1.67 -		} else {
    1.68 -			return Long.parseLong(localPart[1]);
    1.69 -			// If needed:
    1.70 -			// parseGroupName() will be same as this method, just with:
    1.71 -			// return localPart[2];
    1.72 -		}
    1.73 -	}
    1.74 -
    1.75  	@Override
    1.76  	public List<Group> getGroups() throws StorageBackendException {
    1.77  		PreparedStatement ps = null;
    1.78 @@ -397,7 +376,8 @@
    1.79  	 * (but should not be thrown if only bad thing is wrong username or password)
    1.80  	 */
    1.81  	@Override
    1.82 -	public boolean authenticateUser(String username, char[] password) throws StorageBackendException {
    1.83 +	public boolean authenticateUser(String username,
    1.84 +			char[] password) throws StorageBackendException {
    1.85  		PreparedStatement ps = null;
    1.86  		ResultSet rs = null;
    1.87  		try {
    1.88 @@ -414,14 +394,81 @@
    1.89  		}
    1.90  	}
    1.91  
    1.92 +	/**
    1.93 +	 * Validates article and if OK, calls {@link #insertArticle(java.lang.String, java.lang.String, java.lang.String, java.lang.Long, java.lang.Long) }
    1.94 +	 * @param article
    1.95 +	 * @throws StorageBackendException 
    1.96 +	 */
    1.97  	@Override
    1.98 -	public void addArticle(Article art) throws StorageBackendException {
    1.99 -		if (art.getAuthenticatedUser() == null) {
   1.100 +	public void addArticle(Article article) throws StorageBackendException {
   1.101 +		if (article.getAuthenticatedUser() == null) {
   1.102  			log.log(Level.SEVERE, "User was not authenticated, so his article was rejected.");
   1.103  			throw new StorageBackendException("User must be authenticated to post articles");
   1.104  		} else {
   1.105 +			try {
   1.106 +				DrupalMessage m = new DrupalMessage(article);
   1.107  
   1.108 -			log.log(Level.INFO, "User ''{0}'' has posted an article", art.getAuthenticatedUser());
   1.109 +				Long parentID = m.getParentID();
   1.110 +				Long groupID = m.getGroupID();
   1.111 +
   1.112 +				if (parentID == null || groupID == null) {
   1.113 +					throw new StorageBackendException("No valid In-Reply-To header was found → rejecting posted message.");
   1.114 +				} else {
   1.115 +					if (m.isMimeType("text/plain")) {
   1.116 +						Object content = m.getContent();
   1.117 +						if (content instanceof String) {
   1.118 +							String subject = m.getSubject();
   1.119 +							String text = (String) content;
   1.120 +
   1.121 +							/**
   1.122 +							 * TODO: validovat a transformovat text
   1.123 +							 * (v současné době se o to stará až Drupal při výstupu)
   1.124 +							 */
   1.125 +							if (subject == null || subject.length() < 1) {
   1.126 +								subject = text.substring(0, Math.min(10, text.length()));
   1.127 +							}
   1.128 +
   1.129 +							insertArticle(article.getAuthenticatedUser(), subject, text, parentID, groupID);
   1.130 +							log.log(Level.INFO, "User ''{0}'' has posted an article", article.getAuthenticatedUser());
   1.131 +						}
   1.132 +					} else {
   1.133 +						throw new StorageBackendException("Only text/plain messages are supported for now – post it as plain text please.");
   1.134 +					}
   1.135 +				}
   1.136 +			} catch (Exception e) {
   1.137 +				throw new StorageBackendException(e);
   1.138 +			}
   1.139 +		}
   1.140 +	}
   1.141 +
   1.142 +	/**
   1.143 +	 * Physically stores article in database.
   1.144 +	 * @param subject
   1.145 +	 * @param text
   1.146 +	 * @param parentID
   1.147 +	 * @param groupID 
   1.148 +	 */
   1.149 +	private void insertArticle(String sender, String subject, String text, Long parentID, Long groupID) throws StorageBackendException {
   1.150 +		PreparedStatement ps = null;
   1.151 +		ResultSet rs = null;
   1.152 +		try {
   1.153 +			ps = conn.prepareStatement("SELECT nntp_post_article(?, ?, ?, ?, ?)");
   1.154 +
   1.155 +			ps.setString(1, sender);
   1.156 +			ps.setString(2, subject);
   1.157 +			ps.setString(3, text);
   1.158 +			ps.setLong(4, parentID);
   1.159 +			ps.setLong(5, groupID);
   1.160 +
   1.161 +			rs = ps.executeQuery();
   1.162 +			rs.next();
   1.163 +
   1.164 +			Long articleID = rs.getLong(1);
   1.165 +			log.log(Level.INFO, "Article was succesfully stored as {0}", articleID);
   1.166 +		} catch (Exception e) {
   1.167 +			throw new StorageBackendException(e);
   1.168 +		} finally {
   1.169 +			close(null, ps, rs);
   1.170  		}
   1.171  	}
   1.172