/******************************************************************************* * Copyright (c) 2010 Weltevree Beheer BV, Remain Software & Industrial-TSI * * All rights reserved. This program and the accompanying materials * are made available under the terms of the Eclipse Public License v1.0 * which accompanies this distribution, and is available at * http://www.eclipse.org/legal/epl-v10.html * * Contributors: * Wim Jongman - initial API and implementation *******************************************************************************/ package org.eclipse.ecf.protocol.nntp.core.internal; import java.util.ArrayList; import java.util.Arrays; import java.util.Calendar; import java.util.Collection; import java.util.Collections; import java.util.Date; import java.util.HashMap; import java.util.Iterator; import java.util.Map; import org.eclipse.ecf.protocol.nntp.core.ArticleEventListnersFactory; import org.eclipse.ecf.protocol.nntp.core.Debug; import org.eclipse.ecf.protocol.nntp.core.StoreStore; import org.eclipse.ecf.protocol.nntp.core.StringUtils; import org.eclipse.ecf.protocol.nntp.model.IArticle; import org.eclipse.ecf.protocol.nntp.model.INewsgroup; import org.eclipse.ecf.protocol.nntp.model.IServer; import org.eclipse.ecf.protocol.nntp.model.IServerConnection; import org.eclipse.ecf.protocol.nntp.model.IServerStoreFacade; import org.eclipse.ecf.protocol.nntp.model.IStore; import org.eclipse.ecf.protocol.nntp.model.NNTPConnectException; import org.eclipse.ecf.protocol.nntp.model.NNTPException; import org.eclipse.ecf.protocol.nntp.model.NNTPIOException; import org.eclipse.ecf.protocol.nntp.model.ArticleEvent; import org.eclipse.ecf.protocol.nntp.model.SALVO; import org.eclipse.ecf.protocol.nntp.model.StoreException; import org.eclipse.ecf.protocol.nntp.model.UnexpectedResponseException; public class ServerStoreFacade implements IServerStoreFacade { public ServerStoreFacade() { } public void init() { // startUpdateThread(); } public IStore[] getStores() { return StoreStore.instance().getStores(); } public boolean postArticle(IArticle article) { return false; } public IArticle getArticle(INewsgroup newsgroup, int articleId) throws NNTPIOException, UnexpectedResponseException, StoreException { IArticle article = null; for (int i = 0; i < getStores().length;) { article = getStores()[i].getArticle(newsgroup, articleId); break; } if (article == null) { return newsgroup.getServer().getServerConnection() .getArticle(newsgroup, articleId); } return article; } public Exception getLastException() { // FIXME remove throw new RuntimeException("not implemented"); } public void catchUp(INewsgroup newsgroup) throws NNTPIOException { // FIXME implement throw new RuntimeException("not yet implemented"); } public void unsubscribeNewsgroup(INewsgroup newsGroup, boolean permanent) throws StoreException { for (int i = 0; i < getStores().length; i++) { getStores()[i].unsubscribeNewsgroup(newsGroup, permanent); } } public boolean cancelArticle(IArticle article) { // TODO Auto-generated method stub return false; } public void subscribeNewsgroup(INewsgroup group) throws NNTPIOException, UnexpectedResponseException, StoreException { for (int i = 0; i < getStores().length; i++) { getStores()[i].subscribeNewsgroup(group); } syncStoreWithServer(group,false); //updateAttributes(group); } public void subscribeServer(IServer server, String passWord) throws StoreException { for (int i = 0; i < getStores().length; i++) { getStores()[i].subscribeServer(server, passWord); } } public void unsubscribeServer(IServer server, boolean permanent) throws StoreException { for (int i = 0; i < getStores().length; i++) { getStores()[i].unsubscribeServer(server, permanent); } } public void updateAttributes(INewsgroup newsgroup) throws NNTPIOException, UnexpectedResponseException, StoreException { try { newsgroup.getServer().getServerConnection() .setWaterMarks(newsgroup); } catch (NNTPConnectException e) { throw new NNTPIOException(e.getMessage(), e); } for (int i = 0; i < getStores().length; i++) { getStores()[i].updateAttributes(newsgroup); } } public void updateAttributesInStore(INewsgroup newsgroup) throws NNTPIOException, UnexpectedResponseException, StoreException { for (int i = 0; i < getStores().length; i++) { getStores()[i].updateAttributes(newsgroup); } } public INewsgroup[] getSubscribedNewsgroups(IServer server) throws StoreException { for (int i = 0; i < getStores().length;) { return getStores()[i].getSubscribedNewsgroups(server); } return new INewsgroup[0]; } // public IArticle[] getArticles(INewsgroup newsgroup, int from, // int to) throws NNTPIOException { // // try { // IServerConnection connection = newsgroup.getServer() // .getServerConnection(); // // // Adjust for sanity // if ((to - from) > SALVO.BATCH_SIZE) // from = to - SALVO.BATCH_SIZE; // // // Check what is first in store // IStore firstStore = getFirstStore(); // int firstInStore = 0; // if (firstStore != null // && firstStore.getFirstArticle(newsgroup) != null) // firstInStore = getFirstStore().getFirstArticle(newsgroup) // .getArticleNumber(); // // // Fetch from the server what is not in store // if (firstInStore > 0 && firstInStore > from) { // IArticle[] result = connection.getArticles(newsgroup, // from, firstInStore); // if (result != null) { // for (int i = 0; i < stores.length; i++) { // stores[i].storeArticles(result); // } // // // Adjust the requested values // if (firstStore != null) // firstInStore = firstStore.getFirstArticle(newsgroup) // .getArticleNumber(); // if (firstInStore > from) // from = firstInStore; // } // // // Check what is last in store // int lastInStore = 0; // if (firstStore != null // && firstStore.getLastArticle(newsgroup) != null) // lastInStore = firstStore.getLastArticle(newsgroup) // .getArticleNumber(); // // // Fetch from the server what is not in store // if (lastInStore > 0 && lastInStore < to) { // result = connection.getArticles(newsgroup, // lastInStore, to); // if (result != null) // for (int i = 0; i < stores.length; i++) { // stores[i].storeArticles(result); // // // Adjust the requested values // if (firstStore != null) // lastInStore = firstStore.getLastArticle(newsgroup) // .getArticleNumber(); // if (lastInStore < to) // to = lastInStore; // } // // result = null; // if (firstStore != null) // result = firstStore.getArticles(newsgroup, from, to); // // if (result == null) { // result = connection.getArticles(newsgroup, from, to); // if (result != null) // for (int i = 0; i < stores.length; i++) { // stores[i].storeArticles(result); // } // if (firstStore != null) // result = firstStore.getArticles(newsgroup, from, to); // } // if (result == null) // result = new IArticle[0]; // return result; // // }}} catch (NNTPIOException e) { // throw new NNTPIOException(e.getMessage(), e); // } // } public IArticle[] getArticles(INewsgroup newsgroup, int from, int to) throws NNTPIOException, UnexpectedResponseException, StoreException { try { IServerConnection connection = newsgroup.getServer() .getServerConnection(); // Adjust for sanity if ((to - from) > SALVO.BATCH_SIZE) from = to - SALVO.BATCH_SIZE; // Check what is first in store IStore firstStore = getFirstStore(); int firstArticleInStore = 0; if (firstStore != null && firstStore.getFirstArticle(newsgroup) != null) firstArticleInStore = getFirstStore() .getFirstArticle(newsgroup).getArticleNumber(); // Fetch from the server what is not in store if (firstArticleInStore > 0 && firstArticleInStore > from) { IArticle[] result = connection.getArticles(newsgroup, from, firstArticleInStore); if (result != null) { for (int i = 0; i < getStores().length; i++) { getStores()[i].storeArticles(result); } } // Adjust the requested values if (firstStore != null) firstArticleInStore = firstStore.getFirstArticle(newsgroup) .getArticleNumber(); if (firstArticleInStore > from) from = firstArticleInStore; } // Check what is last in store int lastArticleInStore = 0; if (firstStore != null && firstStore.getLastArticle(newsgroup) != null) lastArticleInStore = firstStore.getLastArticle(newsgroup) .getArticleNumber(); // Fetch from the server what is not in store if (lastArticleInStore > 0 && lastArticleInStore < to) { IArticle[] result = connection.getArticles(newsgroup, lastArticleInStore, to); if (result != null) { for (int i = 0; i < getStores().length; i++) { getStores()[i].storeArticles(result); } } // Adjust the requested values if (firstStore != null) lastArticleInStore = firstStore.getLastArticle(newsgroup) .getArticleNumber(); if (lastArticleInStore < to) to = lastArticleInStore; } IArticle[] result = null; if (firstStore != null) result = firstStore.getArticles(newsgroup, from, to); if (result == null) { result = connection.getArticles(newsgroup, from, to); if (result != null) { for (int i = 0; i < getStores().length; i++) { getStores()[i].storeArticles(result); } } if (firstStore != null) result = firstStore.getArticles(newsgroup, from, to); } if (result == null) result = new IArticle[0]; return result; } catch (NNTPConnectException e) { throw new NNTPIOException(e.getMessage(), e); } } public IStore getFirstStore() { if (getStores().length > 0) return getStores()[0]; return null; } // public String[] getBody(IArticle article) throws NNTPIOException, // UnexpectedResponseException { // // // FIXME Decide thru preference if article bodies should be stored in // // the store or always fetched from server? // // // Get From Store // String[] body = null; // if (getFirstStore() != null) // try { // body = getFirstStore().getArticleBody(article); // } catch (NNTPConnectException e) { // Debug.log(getClass(), e); // throw new NNTPIOException(e.getMessage(), e); // } // // // Not in store get from server // if (body == null) { // try { // body = article.getServer().getServerConnection() // .getArticleBody(article); // } catch (UnexpectedResponseException e) { // Debug.log(getClass(), e); // throw e; // } // // if (!(body == null)) { // for (int i = 0; i < stores.length; i++) { // stores[i].storeArticleBody(article, body); // } // } // } // return body; // } public IArticle[] getFollowUps(IArticle article) throws NNTPIOException, UnexpectedResponseException, StoreException { // FIXME Decide if article bodies should be stored in the store or // always fetched from server. IArticle[] result = null; if (getFirstStore() != null) Debug.log(getClass(), "Trying to Fetch articles from store..."); result = getFirstStore().getFollowUps(article); if (result == null) { try { Debug.log(getClass(), "Trying to Fetch articles from server..."); result = article.getServer().getServerConnection() .getFollowUps(article); } catch (NNTPConnectException e) { throw new NNTPIOException(e.getMessage(), e); } if (!(result == null)) { if (getFirstStore() != null) getFirstStore().storeArticles(result); } } return result; } // public IArticle[] getAllFollowUps(IArticle article) // throws NNTPIOException { // // // FIXME Decide if article bodies should be stored in the store or // // always fetched from server. // IArticle[] result2 = getFollowUps(article); // Collection result = new ArrayList<IArticle>(result2); // for (IArticle reply : result) { // Collection<IArticle> r2 = getAllFollowUps(reply); // result2.addAll(r2); // } // return result2; // } public IArticle[] getAllFollowUps(IArticle article) throws NNTPIOException, UnexpectedResponseException, StoreException { // FIXME Decide if article bodies should be stored in the store or // always fetched from server. ArrayList result2 = new ArrayList(); result2.addAll(Arrays.asList(getFollowUps(article))); Collection result = new ArrayList(result2); for (Iterator iterator = result.iterator(); iterator.hasNext();) { IArticle reply = (IArticle) iterator.next(); Collection r2 = Arrays.asList(getAllFollowUps(reply)); result2.addAll(r2); } return (IArticle[]) result2.toArray(new IArticle[0]); } public void updateArticle(IArticle article) throws StoreException { for (int i = 0; i < getStores().length; i++) { getStores()[i].updateArticle(article); } } public void replyToArticle(String replySubject, IArticle article, String body) throws NNTPIOException, UnexpectedResponseException, StoreException { article.getServer().getServerConnection().replyToArticle(replySubject, article, body); syncStoreWithServer(article.getNewsgroup(),true); } public void postNewArticle(INewsgroup[] newsgroups, String subject, String body) throws NNTPIOException, StoreException { try { IServerConnection connection = newsgroups[0].getServer() .getServerConnection(); connection.postNewArticle(newsgroups, subject, body); for (int i = 0; i < newsgroups.length; i++) { if (newsgroups[i].isSubscribed()) { syncStoreWithServer(newsgroups[i],true); } } } catch (UnexpectedResponseException e) { throw new NNTPIOException(e.getMessage(), e); } } public INewsgroup[] listNewsgroups(IServer server) throws NNTPIOException, NNTPIOException, UnexpectedResponseException { return server.getServerConnection().listNewsgroups(server); } public INewsgroup[] listNewsgroups(IServer server, Date since) throws NNTPIOException, UnexpectedResponseException { // FIXME implement throw new RuntimeException("not yet implemented"); // return listNewsgroups(server); } public String[] getArticleBody(IArticle article) throws NNTPIOException, UnexpectedResponseException, StoreException { try { String[] articleBody = getStores()[0].getArticleBody(article); if (articleBody.length > 0) return articleBody; } catch (UnexpectedResponseException e) { // cannot happen } String[] articleBody = article.getServer().getServerConnection() .getArticleBody(article); for (int i = 0; i < getStores().length; i++) { getStores()[i].storeArticleBody(article, articleBody); } return articleBody; } public void setWaterMarks(INewsgroup newsgroup) throws NNTPIOException, UnexpectedResponseException, StoreException { newsgroup.getServer().getServerConnection().setWaterMarks(newsgroup); for (int i = 0; i < getStores().length; i++) { getStores()[i].setWaterMarks(newsgroup); } } public String[] getOverviewHeaders(IServer server) throws NNTPIOException, UnexpectedResponseException { return server.getServerConnection().getOverviewHeaders(server); } public void setModeReader(IServer server) throws NNTPIOException, UnexpectedResponseException { setModeReader(server); } public IServer[] getServers() throws NNTPException { return getStores()[0].getServers(); } public INewsgroup getSubscribedNewsgroup(IServer server, String newsgroup) { // FIXME implement throw new RuntimeException("not yet implemented"); } public IArticle getArticle(String URL) throws NNTPIOException, UnexpectedResponseException, NNTPException { int articleNumber; String newsgroup; String server; try { String[] split = StringUtils.split(URL, "/"); server = split[2]; split = StringUtils.split(split[split.length - 1], "?"); articleNumber = Integer.parseInt(split[1]); newsgroup = split[0]; } catch (Exception e) { throw new NNTPException("Error parsing URL " + URL, e); } IServer[] servers = getServers(); for (int i = 0; i < servers.length; i++) { if (servers[i].getAddress().equals(server)) { INewsgroup[] groups = getSubscribedNewsgroups(servers[i]); for (int j = 0; j < groups.length; j++) { if (groups[j].getNewsgroupName().equals(newsgroup)) return getArticle(groups[j], articleNumber); } return null; } } return null; } public int purge(Calendar purgeDate, int number) throws NNTPIOException { IStore[] stores = getStores(); int result = 0; if (stores.length > 0) result = stores[0].purge(purgeDate, number); for (int i = 1; i < stores.length; i++) { stores[i].purge(purgeDate, number); } return result; } public int delete(IArticle article) throws NNTPIOException { IStore[] stores = getStores(); int result = 0; if (stores.length > 0) result = stores[0].delete(article); for (int i = 1; i < stores.length; i++) { stores[i].delete(article); } return result; } public IArticle[] getThisUserArticles(INewsgroup newsgroup) { return getFirstStore().getArticlesByUserId(newsgroup, newsgroup.getServer().getServerConnection().getFullUserName()); } public IArticle[] getMarkedArticles(INewsgroup newsgroup) { return orderArticlesFromNewestFirst (getFirstStore().getMarkedArticles(newsgroup)); } public IArticle[] getAllMarkedArticles(IServer server) { return orderArticlesFromNewestFirst (getFirstStore().getAllMarkedArticles(server)); } public IArticle getArticleByMsgId(INewsgroup newsgroup, String msgId) { return getFirstStore().getArticleByMsgId(newsgroup, msgId); } public IArticle getFirstArticleOfTread(IArticle article) { if (article.getLastReference() == null) { return article; } else { return getFirstArticleOfTread(getArticleByMsgId( article.getNewsgroup(), article.getLastReference())); } } public IArticle[] getFirstArticleOfThisUserThreads(INewsgroup newsgroup) { IArticle[] thisUserarticles = getThisUserArticles(newsgroup); ArrayList<IArticle> result = new ArrayList<IArticle>(); for (IArticle thisUserArticle : thisUserarticles) { IArticle firstArticle = getFirstArticleOfTread(thisUserArticle); if (!result.contains(firstArticle)) { // prevent duplicates result.add(firstArticle); } } IArticle[] unorderedArticles = (IArticle[]) result.toArray(new IArticle[0]); return orderArticlesFromNewestFirst(unorderedArticles); } public int getLastReplyArticleNumber(IArticle article){ int lastArticleNumber = article.getArticleNumber(); try { IArticle[] followups = getAllFollowUps(article); if (followups.length == 0) { // For no reply return lastArticleNumber; } for (IArticle followupArticle : followups) { if (followupArticle.getArticleNumber() > lastArticleNumber) { lastArticleNumber = followupArticle.getArticleNumber(); } } } catch (NNTPException e) { Debug.log(getClass(), e); } return lastArticleNumber; } public IArticle[] orderArticlesFromNewestFirst(IArticle[] articles) { Map<Integer, IArticle> unorderedArticles = new HashMap<Integer, IArticle>(); Integer[] lastArticleNumbers = new Integer[articles.length]; for (int i = 0; i < articles.length; i++) { int articleNumber = getLastReplyArticleNumber(articles[i]); unorderedArticles.put(articleNumber, articles[i]); lastArticleNumbers[i] = articleNumber; } Arrays.sort(lastArticleNumbers, Collections.reverseOrder()); IArticle[] orderedArticles = new IArticle[articles.length]; for (int i = 0; i < articles.length; i++) { orderedArticles[i] = unorderedArticles.get(lastArticleNumbers[i]); } return orderedArticles; } public int getStoreHighWatermark (INewsgroup newsgroup) { return newsgroup.getHighWaterMark(); } public int[] getServerWatermarks (INewsgroup newsgroup) { try { return newsgroup.getServer().getServerConnection().getWaterMarks(newsgroup); } catch (NNTPException e) { Debug.log(getClass(), e); return null; } } public void syncStoreWithServer(INewsgroup newsgroup, boolean isNewArticlePosted) throws NNTPIOException, UnexpectedResponseException, StoreException { int storeHighWatermark = getStoreHighWatermark(newsgroup); int serverHighWatermark = getServerWatermarks(newsgroup)[2]; IArticle[] articles = null; if (storeHighWatermark < serverHighWatermark) { articles = getArticles(newsgroup, storeHighWatermark+1, serverHighWatermark); } updateAttributesInStore(newsgroup); if (articles != null) { if (isNewArticlePosted && articles.length == 1) { ArticleEventListnersFactory.instance().getRegistry().fireEvent(new ArticleEvent(articles,false)); } else { ArticleEventListnersFactory.instance().getRegistry().fireEvent(new ArticleEvent(articles,true)); } } } }