001: /****************************************************************
002: * Licensed to the Apache Software Foundation (ASF) under one *
003: * or more contributor license agreements. See the NOTICE file *
004: * distributed with this work for additional information *
005: * regarding copyright ownership. The ASF licenses this file *
006: * to you under the Apache License, Version 2.0 (the *
007: * "License"); you may not use this file except in compliance *
008: * with the License. You may obtain a copy of the License at *
009: * *
010: * http://www.apache.org/licenses/LICENSE-2.0 *
011: * *
012: * Unless required by applicable law or agreed to in writing, *
013: * software distributed under the License is distributed on an *
014: * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY *
015: * KIND, either express or implied. See the License for the *
016: * specific language governing permissions and limitations *
017: * under the License. *
018: ****************************************************************/package org.apache.james.nntpserver.repository;
019:
020: import org.apache.avalon.framework.logger.AbstractLogEnabled;
021: import org.apache.james.nntpserver.DateSinceFileFilter;
022: import org.apache.james.util.io.AndFileFilter;
023: import org.apache.james.util.io.ExtensionFileFilter;
024: import org.apache.james.util.io.IOUtil;
025: import org.apache.james.util.io.InvertedFileFilter;
026:
027: import java.io.File;
028: import java.io.FileOutputStream;
029: import java.io.InputStream;
030: import java.io.IOException;
031: import java.util.ArrayList;
032: import java.util.Date;
033: import java.util.Iterator;
034: import java.util.List;
035:
036: /**
037: * Group is represented by a directory.
038: * Articles are stored in files with the name of file == article number
039: *
040: */
041: class NNTPGroupImpl extends AbstractLogEnabled implements NNTPGroup {
042:
043: /**
044: * The directory to which this group maps.
045: */
046: private final File root;
047:
048: /**
049: * The last article number in the group
050: */
051: private int lastArticle;
052:
053: /**
054: * The last article number in the group
055: */
056: private int firstArticle;
057:
058: /**
059: * The number of articles in the group.
060: */
061: private int numOfArticles;
062:
063: /**
064: * Whether the first, last, and total number of articles in the
065: * group have been read from disk.
066: * An instance may collect range info once. This involves disk I/O
067: */
068: private boolean articleRangeInfoCollected = false;
069:
070: /**
071: * The sole constructor for this particular NNTPGroupImpl.
072: *
073: * @param root the directory containing the articles
074: */
075: NNTPGroupImpl(File root) {
076: this .root = root;
077: }
078:
079: /**
080: * @see org.apache.james.nntpserver.NNTPGroup#getName()
081: */
082: public String getName() {
083: return root.getName();
084: }
085:
086: /**
087: * @see org.apache.james.nntpserver.NNTPGroup#getDescription()
088: */
089: public String getDescription() {
090: return getName();
091: }
092:
093: /**
094: * @see org.apache.james.nntpserver.NNTPGroup#isPostAllowed()
095: */
096: public boolean isPostAllowed() {
097: return true;
098: }
099:
100: /**
101: * Generates the first, last, and number of articles from the
102: * information in the group directory.
103: */
104: private void collectArticleRangeInfo() {
105: if (articleRangeInfoCollected) {
106: return;
107: }
108: String[] list = root.list();
109: int first = -1;
110: int last = -1;
111: for (int i = 0; i < list.length; i++) {
112: int num = Integer.parseInt(list[i]);
113: if (first == -1 || num < first) {
114: first = num;
115: }
116: if (num > last) {
117: last = num;
118: }
119: }
120: numOfArticles = list.length;
121: firstArticle = Math.max(first, 0);
122: lastArticle = Math.max(last, 0);
123: articleRangeInfoCollected = true;
124: }
125:
126: /**
127: * @see org.apache.james.nntpserver.NNTPGroup#getNumberOfArticles()
128: */
129: public int getNumberOfArticles() {
130: collectArticleRangeInfo();
131: return numOfArticles;
132: }
133:
134: /**
135: * @see org.apache.james.nntpserver.NNTPGroup#getFirstArticleNumber()
136: */
137: public int getFirstArticleNumber() {
138: collectArticleRangeInfo();
139: return firstArticle;
140: }
141:
142: /**
143: * @see org.apache.james.nntpserver.NNTPGroup#getLastArticleNumber()
144: */
145: public int getLastArticleNumber() {
146: collectArticleRangeInfo();
147: return lastArticle;
148: }
149:
150: /**
151: * @see org.apache.james.nntpserver.NNTPGroup#getArticle(int)
152: */
153: public NNTPArticle getArticle(int number) {
154: File f = new File(root, number + "");
155: return f.exists() ? new NNTPArticleImpl(this , f) : null;
156: }
157:
158: /**
159: * @see org.apache.james.nntpserver.NNTPGroup#getArticlesSince(Date)
160: */
161: public Iterator getArticlesSince(Date dt) {
162: File[] f = root
163: .listFiles(new AndFileFilter(new DateSinceFileFilter(dt
164: .getTime()), new InvertedFileFilter(
165: new ExtensionFileFilter(".id"))));
166: List list = new ArrayList();
167: for (int i = 0; i < f.length; i++) {
168: list.add(new NNTPArticleImpl(this , f[i]));
169: }
170: return list.iterator();
171: }
172:
173: /**
174: * @see org.apache.james.nntpserver.NNTPGroup#getArticles()
175: */
176: public Iterator getArticles() {
177: File[] f = root.listFiles();
178: List list = new ArrayList();
179: for (int i = 0; i < f.length; i++)
180: list.add(new NNTPArticleImpl(this , f[i]));
181: return list.iterator();
182: }
183:
184: /**
185: * @see org.apache.james.nntpserver.repository.NNTPGroup#getListFormat()
186: */
187: public String getListFormat() {
188: StringBuffer showBuffer = new StringBuffer(128).append(
189: getName()).append(" ").append(getLastArticleNumber())
190: .append(" ").append(getFirstArticleNumber())
191: .append(" ").append((isPostAllowed() ? "y" : "n"));
192: return showBuffer.toString();
193: }
194:
195: /**
196: * @see org.apache.james.nntpserver.repository.NNTPGroup#getListNewsgroupsFormat()
197: */
198: public String getListNewsgroupsFormat() {
199: StringBuffer showBuffer = new StringBuffer(128).append(
200: getName()).append(" ").append(getDescription());
201: return showBuffer.toString();
202: }
203:
204: /**
205: * @see org.apache.james.nntpserver.repository.NNTPGroup#addArticle(InputStream)
206: */
207: public NNTPArticle addArticle(InputStream newsStream)
208: throws IOException {
209: File articleFile = null;
210: synchronized (this ) {
211: int artNum;
212: if (numOfArticles < 0)
213: throw new IllegalStateException(
214: "NNTP Group is corrupt (articles < 0).");
215: else if (numOfArticles == 0) {
216: firstArticle = 1;
217: artNum = 1;
218: } else {
219: artNum = getLastArticleNumber() + 1;
220: }
221:
222: articleFile = new File(root, artNum + "");
223: articleFile.createNewFile();
224: lastArticle = artNum;
225: numOfArticles++;
226: }
227: if (getLogger().isDebugEnabled()) {
228: getLogger().debug(
229: "Copying message to: "
230: + articleFile.getAbsolutePath());
231: }
232: FileOutputStream fout = null;
233: try {
234: fout = new FileOutputStream(articleFile);
235: IOUtil.copy(newsStream, fout);
236: fout.flush();
237: } finally {
238: try {
239: if (fout != null) {
240: fout.close();
241: }
242: } catch (IOException ioe) {
243: // Ignore this exception so we don't
244: // trash any "real" exceptions
245: }
246: }
247: return new NNTPArticleImpl(this , articleFile);
248: }
249:
250: // public NNTPArticle getArticleFromID(String id) {
251: // if ( id == null )
252: // return null;
253: // int idx = id.indexOf('@');
254: // if ( idx != -1 )
255: // id = id.substring(0,idx);
256: // File f = new File(root,id + ".id");
257: // if ( f.exists() == false )
258: // return null;
259: // try {
260: // FileInputStream fin = new FileInputStream(f);
261: // int count = fin.available();
262: // byte[] ba = new byte[count];
263: // fin.read(ba);
264: // fin.close();
265: // String str = new String(ba);
266: // int num = Integer.parseInt(str);
267: // return getArticle(num);
268: // } catch(IOException ioe) {
269: // throw new NNTPException("could not fectch article: "+id,ioe);
270: // }
271: // }
272:
273: }
|