1.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000
1.2 +++ b/trunk/com/so/news/storage/Article.java Tue Jan 20 10:21:03 2009 +0100
1.3 @@ -0,0 +1,307 @@
1.4 +/*
1.5 + * StarOffice News Server
1.6 + * see AUTHORS for the list of contributors
1.7 + *
1.8 + * This program is free software: you can redistribute it and/or modify
1.9 + * it under the terms of the GNU General Public License as published by
1.10 + * the Free Software Foundation, either version 3 of the License, or
1.11 + * (at your option) any later version.
1.12 + *
1.13 + * This program is distributed in the hope that it will be useful,
1.14 + * but WITHOUT ANY WARRANTY; without even the implied warranty of
1.15 + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
1.16 + * GNU General Public License for more details.
1.17 + *
1.18 + * You should have received a copy of the GNU General Public License
1.19 + * along with this program. If not, see <http://www.gnu.org/licenses/>.
1.20 + */
1.21 +
1.22 +package com.so.news.storage;
1.23 +
1.24 +import java.sql.ResultSet;
1.25 +import java.sql.SQLException;
1.26 +import java.util.Date;
1.27 +import java.util.HashMap;
1.28 +import java.util.Map;
1.29 +import java.util.Map.Entry;
1.30 +import java.util.UUID;
1.31 +
1.32 +import com.so.news.Config;
1.33 +import com.so.news.Debug;
1.34 +
1.35 +/**
1.36 + * Represents a newsgroup article.
1.37 + * @author Christian Lins
1.38 + * @author Denis Schwerdel
1.39 + */
1.40 +public class Article
1.41 +{
1.42 + /**
1.43 + * Loads the Article identified by the given ID from the Database.
1.44 + * @param messageID
1.45 + * @return null if Article is not found or if an error occurred.
1.46 + */
1.47 + public static Article getByMessageID(String messageID)
1.48 + {
1.49 + try
1.50 + {
1.51 + return Database.getInstance().getArticle(messageID);
1.52 + }
1.53 + catch(SQLException ex)
1.54 + {
1.55 + ex.printStackTrace(Debug.getInstance().getStream());
1.56 + return null;
1.57 + }
1.58 + }
1.59 +
1.60 + public static Article getByNumberInGroup(Group group, int number)
1.61 + throws SQLException
1.62 + {
1.63 + long gid = group.getID();
1.64 + return Database.getInstance().getArticle(gid, number); // Is number her correct?
1.65 + }
1.66 +
1.67 + private String body = "";
1.68 + private long groupID = -1;
1.69 + private Map<String, String> header = new HashMap<String, String>();
1.70 + private int numberInGroup = -1;
1.71 + private String msgID = null;
1.72 +
1.73 + /**
1.74 + * Default constructor.
1.75 + */
1.76 + public Article()
1.77 + {
1.78 + }
1.79 +
1.80 + /**
1.81 + * Creates a new Article object using the date from the given
1.82 + * ResultSet. It is expected that ResultSet.next() was already
1.83 + * called by the Database class.
1.84 + * This construction has only package visibility.
1.85 + * @param rs
1.86 + */
1.87 + Article(ResultSet rs)
1.88 + throws SQLException
1.89 + {
1.90 + this.body = rs.getString("body");
1.91 + this.msgID = rs.getString("message_id");
1.92 +
1.93 + // Parse the header
1.94 + parseHeader(rs.getString("header"));
1.95 + }
1.96 +
1.97 + /**
1.98 + * Parses the header fields and puts them into a map for faster access.
1.99 + * TODO: There could be fields that go over more than one line, some
1.100 + * bad clients do create them.
1.101 + * @param hsrc
1.102 + */
1.103 + private void parseHeader(String hsrc)
1.104 + {
1.105 + String[] lines = hsrc.split("\n");
1.106 +
1.107 + for(String line : lines)
1.108 + {
1.109 + String[] kv = line.split(":");
1.110 + if(kv.length < 2)
1.111 + {
1.112 + Debug.getInstance().log("Invalid header field: " + line);
1.113 + continue;
1.114 + }
1.115 + else
1.116 + {
1.117 + // Set value in the header hash map
1.118 + String value = kv[1];
1.119 + for(int n = 2; n < kv.length; n++)
1.120 + value += ":" + kv[n];
1.121 + this.header.put(kv[0], value);
1.122 + }
1.123 + }
1.124 + }
1.125 +
1.126 + /**
1.127 + * Returnes the next Article in the group of this Article.
1.128 + * @return
1.129 + */
1.130 + public Article nextArticleInGroup()
1.131 + {
1.132 + return null;
1.133 + }
1.134 +
1.135 + /**
1.136 + * Returns the previous Article in the group of this Article.
1.137 + * @return
1.138 + */
1.139 + public Article prevArticleInGroup()
1.140 + {
1.141 + return null;
1.142 + }
1.143 +
1.144 + /**
1.145 + * Generates a message id for this article and sets it into
1.146 + * the header HashMap.
1.147 + */
1.148 + private String generateMessageID()
1.149 + {
1.150 + this.msgID = "<" + UUID.randomUUID() + "@"
1.151 + + Config.getInstance().get("n3tpd.hostname", "localhost") + ">";
1.152 +
1.153 + this.header.put("Message-ID", msgID);
1.154 +
1.155 + return msgID;
1.156 + }
1.157 +
1.158 + /**
1.159 + * Tries to delete this article.
1.160 + * @return false if the article could not be deleted, otherwise true
1.161 + */
1.162 + public boolean delete()
1.163 + {
1.164 + return false;
1.165 + }
1.166 +
1.167 + /**
1.168 + * Checks if all necessary header fields are within this header.
1.169 + */
1.170 + private void validateHeader()
1.171 + {
1.172 + // Forces a MessageID creation if not existing
1.173 + getMessageID();
1.174 +
1.175 + // Check if the references are correct...
1.176 + String rep = header.get("In-Reply-To");
1.177 + if(rep == null) // Some clients use only references instead of In-Reply-To
1.178 + return; //rep = header.get("References");
1.179 +
1.180 + String ref = getMessageID();
1.181 +
1.182 + if(rep != null && !rep.equals(""))
1.183 + {
1.184 + Article art = null; //TODO // getByMessageID(rep, articleDir);
1.185 + if(art != null)
1.186 + {
1.187 + ref = art.header.get("References") + " " + rep;
1.188 + }
1.189 + }
1.190 + header.put("References", ref);
1.191 + }
1.192 +
1.193 + /**
1.194 + * Returns the body string.
1.195 + */
1.196 + public String getBody()
1.197 + {
1.198 + return body;
1.199 + }
1.200 +
1.201 + /**
1.202 + * @return Numerical ID of the associated Group.
1.203 + */
1.204 + long getGroupID()
1.205 + {
1.206 + if(groupID == -1) // If the GroupID was not determined yet
1.207 + {
1.208 + // Determining GroupID
1.209 + String newsgroups = this.header.get("Newsgroups");
1.210 + if(newsgroups != null)
1.211 + {
1.212 + String[] newsgroup = newsgroups.split(",");
1.213 + // Crossposting is not supported
1.214 + try
1.215 + {
1.216 + Group group;
1.217 + if(newsgroup.length > 0)
1.218 + group = Database.getInstance().getGroup(newsgroup[0].trim());
1.219 + else
1.220 + group = Database.getInstance().getGroup(newsgroups.trim());
1.221 + // TODO: What to do if Group does not exist?
1.222 + this.groupID = group.getID();
1.223 + }
1.224 + catch(SQLException ex)
1.225 + {
1.226 + ex.printStackTrace(Debug.getInstance().getStream());
1.227 + System.err.println(ex.getLocalizedMessage());
1.228 + }
1.229 + }
1.230 + else
1.231 + System.err.println("Should never happen: Article::getGroupID");
1.232 + }
1.233 + return this.groupID;
1.234 + }
1.235 +
1.236 + public void setBody(String body)
1.237 + {
1.238 + this.body = body;
1.239 + }
1.240 +
1.241 + public int getNumberInGroup()
1.242 + {
1.243 + return this.numberInGroup;
1.244 + }
1.245 +
1.246 + public void setHeader(HashMap<String, String> header)
1.247 + {
1.248 + this.header = header;
1.249 + }
1.250 +
1.251 + public void setNumberInGroup(int id)
1.252 + {
1.253 + this.numberInGroup = id;
1.254 + }
1.255 +
1.256 + public String getMessageID()
1.257 + {
1.258 + if(msgID == null)
1.259 + msgID = generateMessageID();
1.260 + return msgID;
1.261 + }
1.262 +
1.263 + /**
1.264 + * @return Header source code of this Article.
1.265 + */
1.266 + public String getHeaderSource()
1.267 + {
1.268 + StringBuffer buf = new StringBuffer();
1.269 +
1.270 + for(Entry<String, String> entry : this.header.entrySet())
1.271 + {
1.272 + buf.append(entry.getKey());
1.273 + buf.append(":");
1.274 + buf.append(entry.getValue());
1.275 + buf.append("\n");
1.276 + }
1.277 +
1.278 + return buf.toString();
1.279 + }
1.280 +
1.281 + public Map<String, String> getHeader()
1.282 + {
1.283 + return this.header;
1.284 + }
1.285 +
1.286 + public Date getDate()
1.287 + {
1.288 + try
1.289 + {
1.290 + String date = this.header.get("Date");
1.291 + return new Date(Date.parse(date));
1.292 + }
1.293 + catch(Exception e)
1.294 + {
1.295 + e.printStackTrace(Debug.getInstance().getStream());
1.296 + return null;
1.297 + }
1.298 + }
1.299 +
1.300 + public void setDate(Date date)
1.301 + {
1.302 + this.header.put("Date", date.toString());
1.303 + }
1.304 +
1.305 + @Override
1.306 + public String toString()
1.307 + {
1.308 + return getMessageID();
1.309 + }
1.310 +}