FileDocCategorySizeDatePackage
NNTPRepositoryImpl.javaAPI DocApache James 2.3.118524Fri Jan 12 12:56:24 GMT 2007org.apache.james.nntpserver.repository

NNTPRepositoryImpl

public class NNTPRepositoryImpl extends org.apache.avalon.framework.logger.AbstractLogEnabled implements org.apache.avalon.framework.activity.Initializable, org.apache.avalon.framework.context.Contextualizable, org.apache.avalon.framework.configuration.Configurable, NNTPRepository
NNTP Repository implementation.

Fields Summary
private org.apache.avalon.framework.context.Context
context
The context employed by this repository
private org.apache.avalon.framework.configuration.Configuration
configuration
The configuration employed by this repository
private boolean
readOnly
Whether the repository is read only
private File
rootPath
The groups are located under this path.
private File
tempPath
Articles are temporarily written here and then sent to the spooler.
private NNTPSpooler
spool
The spooler for this repository.
private ArticleIDRepository
articleIDRepo
The article ID repository associated with this NNTP repository.
private HashMap
groupNameMap
A map to allow lookup of valid newsgroup names
private boolean
definedGroupsOnly
Restrict use to newsgroups specified in config only
private String
rootPathString
The root path as a String.
private String
tempPathString
The temp path as a String.
private String
articleIdPathString
The article ID path as a String.
private String
articleIDDomainSuffix
The domain suffix used for files in the article ID repository.
private String[]
overviewFormat
The ordered list of fields returned in the overview format for articles stored in this repository.
private HashMap
repositoryGroups
This is a mapping of group names to NNTP group objects. TODO: This needs to be addressed so it scales better
Constructors Summary
Methods Summary
public voidconfigure(org.apache.avalon.framework.configuration.Configuration aConfiguration)

see
org.apache.avalon.framework.configuration.Configurable#configure(Configuration)

        configuration = aConfiguration;
        readOnly = configuration.getChild("readOnly").getValueAsBoolean(false);
        articleIDDomainSuffix = configuration.getChild("articleIDDomainSuffix")
            .getValue("foo.bar.sho.boo");
        rootPathString = configuration.getChild("rootPath").getValue(null);
        if (rootPathString == null) {
            throw new ConfigurationException("Root path URL is required.");
        }
        tempPathString = configuration.getChild("tempPath").getValue(null);
        if (tempPathString == null) {
            throw new ConfigurationException("Temp path URL is required.");
        }
        articleIdPathString = configuration.getChild("articleIDPath").getValue(null);
        if (articleIdPathString == null) {
            throw new ConfigurationException("Article ID path URL is required.");
        }
        if (getLogger().isDebugEnabled()) {
            if (readOnly) {
                getLogger().debug("NNTP repository is read only.");
            } else {
                getLogger().debug("NNTP repository is writeable.");
            }
            getLogger().debug("NNTP repository root path URL is " + rootPathString);
            getLogger().debug("NNTP repository temp path URL is " + tempPathString);
            getLogger().debug("NNTP repository article ID path URL is " + articleIdPathString);
        }
        Configuration newsgroupConfiguration = configuration.getChild("newsgroups");
        definedGroupsOnly = newsgroupConfiguration.getAttributeAsBoolean("only", false);
        groupNameMap = new HashMap();
        if ( newsgroupConfiguration != null ) {
            Configuration[] children = newsgroupConfiguration.getChildren("newsgroup");
            if ( children != null ) {
                for ( int i = 0 ; i < children.length ; i++ ) {
                    String groupName = children[i].getValue();
                    groupNameMap.put(groupName, groupName);
                }
            }
        }
        getLogger().debug("Repository configuration done");
    
public voidcontextualize(org.apache.avalon.framework.context.Context context)

see
org.apache.avalon.framework.context.Contextualizable#contextualize(Context)


           
       
              
        this.context = context;
    
public voidcreateArticle(java.io.InputStream in)

see
org.apache.james.nntpserver.repository.NNTPRepository#createArticle(InputStream)

        StringBuffer fileBuffer =
            new StringBuffer(32)
                    .append(System.currentTimeMillis())
                    .append(".")
                    .append(Math.random());
        File f = new File(tempPath, fileBuffer.toString());
        FileOutputStream fout = null;
        try {
            fout = new FileOutputStream(f);
            byte[] readBuffer = new byte[1024];
            int bytesRead = 0;
            while ( ( bytesRead = in.read(readBuffer, 0, 1024) ) > 0 ) {
                fout.write(readBuffer, 0, bytesRead);
            }
            fout.flush();
            fout.close();
            fout = null;
            boolean renamed = f.renameTo(new File(spool.getSpoolPath(),f.getName()));
            if (!renamed) {
                throw new IOException("Could not create article on the spool.");
            }
        } catch(IOException ex) {
            throw new NNTPException("create article failed",ex);
        } finally {
            if (fout != null) {
                try {
                    fout.close();
                } catch (IOException ioe) {
                    // Ignored
                }
            }
        }
    
private NNTPSpoolercreateSpooler()
Creates an instance of the spooler class. TODO: This method doesn't properly implement the Avalon lifecycle.

        String className = "org.apache.james.nntpserver.repository.NNTPSpooler";
        Configuration spoolerConfiguration = configuration.getChild("spool");
        try {
            // Must be a subclass of org.apache.james.nntpserver.repository.NNTPSpooler
            className = spoolerConfiguration.getAttribute("class");
        } catch(ConfigurationException ce) {
            // Use the default class.
        }
        try {
            Object obj = getClass().getClassLoader().loadClass(className).newInstance();
            // TODO: Need to support service
            ContainerUtil.enableLogging(obj, getLogger());
            ContainerUtil.contextualize(obj, context);
            ContainerUtil.configure(obj, spoolerConfiguration.getChild("configuration"));
            ContainerUtil.initialize(obj);
            return (NNTPSpooler)obj;
        } catch(ClassCastException cce) {
            StringBuffer errorBuffer =
                new StringBuffer(128)
                    .append("Spooler initialization failed because the spooler class ")
                    .append(className)
                    .append(" was not a subclass of org.apache.james.nntpserver.repository.NNTPSpooler");
            String errorString = errorBuffer.toString();
            getLogger().error(errorString, cce);
            throw new ConfigurationException(errorString, cce);
        } catch(Exception ex) {
            getLogger().error("Spooler initialization failed",ex);
            throw new ConfigurationException("Spooler initialization failed",ex);
        }
    
public NNTPArticlegetArticleFromID(java.lang.String id)

see
org.apache.james.nntpserver.repository.NNTPRepository#getArticleFromID(String)

        try {
            return articleIDRepo.getArticle(this,id);
        } catch(Exception ex) {
            getLogger().error("Couldn't get article " + id + ": ", ex);
            return null;
        }
    
public java.util.IteratorgetArticlesSince(java.util.Date dt)

see
org.apache.james.nntpserver.repository.NNTPRepository#getArticlesSince(Date)

        final Iterator giter = getGroupsSince(dt);
        return new Iterator() {

                private Iterator iter = null;

                public boolean hasNext() {
                    if ( iter == null ) {
                        if ( giter.hasNext() ) {
                            NNTPGroup group = (NNTPGroup)giter.next();
                            iter = group.getArticlesSince(dt);
                        }
                        else {
                            return false;
                        }
                    }
                    if ( iter.hasNext() ) {
                        return true;
                    } else {
                        iter = null;
                        return hasNext();
                    }
                }

                public Object next() {
                    return iter.next();
                }

                public void remove() {
                    throw new UnsupportedOperationException("remove not supported");
                }
            };
    
public NNTPGroupgetGroup(java.lang.String groupName)

see
org.apache.james.nntpserver.repository.NNTPRepository#getGroup(String)

        if (definedGroupsOnly && groupNameMap.get(groupName) == null) {
            if (getLogger().isDebugEnabled()) {
                getLogger().debug(groupName + " is not a newsgroup hosted on this server.");
            }
            return null;
        }
        File groupFile = new File(rootPath,groupName);
        NNTPGroup groupToReturn = null;
        synchronized(this) {
            groupToReturn = (NNTPGroup)repositoryGroups.get(groupName);
            if ((groupToReturn == null) && groupFile.exists() && groupFile.isDirectory() ) {
                try {
                    groupToReturn = new NNTPGroupImpl(groupFile);
                    ContainerUtil.enableLogging(groupToReturn, getLogger());
                    ContainerUtil.contextualize(groupToReturn, context);
                    ContainerUtil.initialize(groupToReturn);
                    repositoryGroups.put(groupName, groupToReturn);
                } catch (Exception e) {
                    getLogger().error("Couldn't create group object.", e);
                    groupToReturn = null;
                }
            }
        }
        return groupToReturn;
    
private java.util.IteratorgetGroups(java.io.File[] f)
Gets an iterator of all news groups represented by the files in the parameter array.

param
f the array of files that correspond to news groups
return
an iterator of news groups

        List list = new ArrayList();
        for ( int i = 0 ; i < f.length ; i++ ) {
            if (f[i] != null) {
                list.add(getGroup(f[i].getName()));
            }
        }
        return list.iterator();
    
public java.util.IteratorgetGroupsSince(java.util.Date dt)

see
org.apache.james.nntpserver.repository.NNTPRepository#getGroupsSince(Date)

        File[] f = rootPath.listFiles(new AndFileFilter(new GroupFilter(), new AndFileFilter
            (new DirectoryFileFilter(),new DateSinceFileFilter(dt.getTime()))));
        return getGroups(f);
    
public java.util.IteratorgetMatchedGroups(java.lang.String wildmat)

see
org.apache.james.nntpserver.repository.NNTPRepository#getMatchedGroups(String)

        File[] f = rootPath.listFiles(new AndFileFilter(new GroupFilter(), new AndFileFilter
            (new DirectoryFileFilter(),new GlobFilenameFilter(wildmat))));
        return getGroups(f);
    
public java.lang.String[]getOverviewFormat()

see
org.apache.james.nntpserver.repository.NNTPRepository#getOverviewFormat()

        return overviewFormat;
    
public voidinitialize()

see
org.apache.avalon.framework.activity.Initializable#initialize()


        getLogger().debug("Starting initialize");
        File articleIDPath = null;

        try {
            rootPath = AvalonContextUtilities.getFile(context, rootPathString);
            tempPath = AvalonContextUtilities.getFile(context, tempPathString);
            articleIDPath = AvalonContextUtilities.getFile(context, articleIdPathString);
        } catch (Exception e) {
            getLogger().fatalError(e.getMessage(), e);
            throw e;
        }

        if ( articleIDPath.exists() == false ) {
            articleIDPath.mkdirs();
        }

        articleIDRepo = new ArticleIDRepository(articleIDPath, articleIDDomainSuffix);
        spool = (NNTPSpooler)createSpooler();
        spool.setRepository(this);
        spool.setArticleIDRepository(articleIDRepo);
        if (getLogger().isDebugEnabled()) {
            getLogger().debug("repository:readOnly=" + readOnly);
            getLogger().debug("repository:rootPath=" + rootPath.getAbsolutePath());
            getLogger().debug("repository:tempPath=" + tempPath.getAbsolutePath());
        }

        if ( rootPath.exists() == false ) {
            rootPath.mkdirs();
        } else if (!(rootPath.isDirectory())) {
            StringBuffer errorBuffer =
                new StringBuffer(128)
                    .append("NNTP repository root directory is improperly configured.  The specified path ")
                    .append(rootPathString)
                    .append(" is not a directory.");
            throw new ConfigurationException(errorBuffer.toString());
        }

        Set groups = groupNameMap.keySet();
        Iterator groupIterator = groups.iterator();
        while( groupIterator.hasNext() ) {
            String groupName = (String)groupIterator.next();
            File groupFile = new File(rootPath,groupName);
            if ( groupFile.exists() == false ) {
                groupFile.mkdirs();
            } else if (!(groupFile.isDirectory())) {
                StringBuffer errorBuffer =
                    new StringBuffer(128)
                        .append("A file exists in the NNTP root directory with the same name as a newsgroup.  File ")
                        .append(groupName)
                        .append("in directory ")
                        .append(rootPathString)
                        .append(" is not a directory.");
                throw new ConfigurationException(errorBuffer.toString());
            }
        }
        if ( tempPath.exists() == false ) {
            tempPath.mkdirs();
        } else if (!(tempPath.isDirectory())) {
            StringBuffer errorBuffer =
                new StringBuffer(128)
                    .append("NNTP repository temp directory is improperly configured.  The specified path ")
                    .append(tempPathString)
                    .append(" is not a directory.");
            throw new ConfigurationException(errorBuffer.toString());
        }

        getLogger().debug("repository initialization done");
    
public booleanisReadOnly()

see
org.apache.james.nntpserver.repository.NNTPRepository#isReadOnly()

        return readOnly;