diff -r 000000000000 -r f907866f0e4b trunk/com/so/news/storage/Article.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/trunk/com/so/news/storage/Article.java Tue Jan 20 10:21:03 2009 +0100 @@ -0,0 +1,307 @@ +/* + * StarOffice News Server + * see AUTHORS for the list of contributors + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +package com.so.news.storage; + +import java.sql.ResultSet; +import java.sql.SQLException; +import java.util.Date; +import java.util.HashMap; +import java.util.Map; +import java.util.Map.Entry; +import java.util.UUID; + +import com.so.news.Config; +import com.so.news.Debug; + +/** + * Represents a newsgroup article. + * @author Christian Lins + * @author Denis Schwerdel + */ +public class Article +{ + /** + * Loads the Article identified by the given ID from the Database. + * @param messageID + * @return null if Article is not found or if an error occurred. + */ + public static Article getByMessageID(String messageID) + { + try + { + return Database.getInstance().getArticle(messageID); + } + catch(SQLException ex) + { + ex.printStackTrace(Debug.getInstance().getStream()); + return null; + } + } + + public static Article getByNumberInGroup(Group group, int number) + throws SQLException + { + long gid = group.getID(); + return Database.getInstance().getArticle(gid, number); // Is number her correct? + } + + private String body = ""; + private long groupID = -1; + private Map header = new HashMap(); + private int numberInGroup = -1; + private String msgID = null; + + /** + * Default constructor. + */ + public Article() + { + } + + /** + * Creates a new Article object using the date from the given + * ResultSet. It is expected that ResultSet.next() was already + * called by the Database class. + * This construction has only package visibility. + * @param rs + */ + Article(ResultSet rs) + throws SQLException + { + this.body = rs.getString("body"); + this.msgID = rs.getString("message_id"); + + // Parse the header + parseHeader(rs.getString("header")); + } + + /** + * Parses the header fields and puts them into a map for faster access. + * TODO: There could be fields that go over more than one line, some + * bad clients do create them. + * @param hsrc + */ + private void parseHeader(String hsrc) + { + String[] lines = hsrc.split("\n"); + + for(String line : lines) + { + String[] kv = line.split(":"); + if(kv.length < 2) + { + Debug.getInstance().log("Invalid header field: " + line); + continue; + } + else + { + // Set value in the header hash map + String value = kv[1]; + for(int n = 2; n < kv.length; n++) + value += ":" + kv[n]; + this.header.put(kv[0], value); + } + } + } + + /** + * Returnes the next Article in the group of this Article. + * @return + */ + public Article nextArticleInGroup() + { + return null; + } + + /** + * Returns the previous Article in the group of this Article. + * @return + */ + public Article prevArticleInGroup() + { + return null; + } + + /** + * Generates a message id for this article and sets it into + * the header HashMap. + */ + private String generateMessageID() + { + this.msgID = "<" + UUID.randomUUID() + "@" + + Config.getInstance().get("n3tpd.hostname", "localhost") + ">"; + + this.header.put("Message-ID", msgID); + + return msgID; + } + + /** + * Tries to delete this article. + * @return false if the article could not be deleted, otherwise true + */ + public boolean delete() + { + return false; + } + + /** + * Checks if all necessary header fields are within this header. + */ + private void validateHeader() + { + // Forces a MessageID creation if not existing + getMessageID(); + + // Check if the references are correct... + String rep = header.get("In-Reply-To"); + if(rep == null) // Some clients use only references instead of In-Reply-To + return; //rep = header.get("References"); + + String ref = getMessageID(); + + if(rep != null && !rep.equals("")) + { + Article art = null; //TODO // getByMessageID(rep, articleDir); + if(art != null) + { + ref = art.header.get("References") + " " + rep; + } + } + header.put("References", ref); + } + + /** + * Returns the body string. + */ + public String getBody() + { + return body; + } + + /** + * @return Numerical ID of the associated Group. + */ + long getGroupID() + { + if(groupID == -1) // If the GroupID was not determined yet + { + // Determining GroupID + String newsgroups = this.header.get("Newsgroups"); + if(newsgroups != null) + { + String[] newsgroup = newsgroups.split(","); + // Crossposting is not supported + try + { + Group group; + if(newsgroup.length > 0) + group = Database.getInstance().getGroup(newsgroup[0].trim()); + else + group = Database.getInstance().getGroup(newsgroups.trim()); + // TODO: What to do if Group does not exist? + this.groupID = group.getID(); + } + catch(SQLException ex) + { + ex.printStackTrace(Debug.getInstance().getStream()); + System.err.println(ex.getLocalizedMessage()); + } + } + else + System.err.println("Should never happen: Article::getGroupID"); + } + return this.groupID; + } + + public void setBody(String body) + { + this.body = body; + } + + public int getNumberInGroup() + { + return this.numberInGroup; + } + + public void setHeader(HashMap header) + { + this.header = header; + } + + public void setNumberInGroup(int id) + { + this.numberInGroup = id; + } + + public String getMessageID() + { + if(msgID == null) + msgID = generateMessageID(); + return msgID; + } + + /** + * @return Header source code of this Article. + */ + public String getHeaderSource() + { + StringBuffer buf = new StringBuffer(); + + for(Entry entry : this.header.entrySet()) + { + buf.append(entry.getKey()); + buf.append(":"); + buf.append(entry.getValue()); + buf.append("\n"); + } + + return buf.toString(); + } + + public Map getHeader() + { + return this.header; + } + + public Date getDate() + { + try + { + String date = this.header.get("Date"); + return new Date(Date.parse(date)); + } + catch(Exception e) + { + e.printStackTrace(Debug.getInstance().getStream()); + return null; + } + } + + public void setDate(Date date) + { + this.header.put("Date", date.toString()); + } + + @Override + public String toString() + { + return getMessageID(); + } +}