You are viewing a plain text version of this content. The canonical link for it is here.
Posted to server-dev@james.apache.org by no...@apache.org on 2011/04/15 13:14:39 UTC
svn commit: r1092663 - in /james/mailbox/trunk:
jcr/src/main/java/org/apache/james/mailbox/jcr/mail/
jpa/src/main/java/org/apache/james/mailbox/jpa/mail/
maildir/src/main/java/org/apache/james/mailbox/maildir/mail/
memory/src/main/java/org/apache/james...
Author: norman
Date: Fri Apr 15 11:14:39 2011
New Revision: 1092663
URL: http://svn.apache.org/viewvc?rev=1092663&view=rev
Log:
Remove the search(...) method from MessageMapper and its implementation and provide a generic implementation for search in StoreMessageManager. We will later make it possible to plugin an MessageSearchIndex for more performant searching. This is part of MAILBOX-10
Modified:
james/mailbox/trunk/jcr/src/main/java/org/apache/james/mailbox/jcr/mail/JCRMessageMapper.java
james/mailbox/trunk/jpa/src/main/java/org/apache/james/mailbox/jpa/mail/JPAMessageMapper.java
james/mailbox/trunk/maildir/src/main/java/org/apache/james/mailbox/maildir/mail/MaildirMessageMapper.java
james/mailbox/trunk/memory/src/main/java/org/apache/james/mailbox/inmemory/mail/InMemoryMessageMapper.java
james/mailbox/trunk/store/src/main/java/org/apache/james/mailbox/store/StoreMessageManager.java
james/mailbox/trunk/store/src/main/java/org/apache/james/mailbox/store/mail/MessageMapper.java
Modified: james/mailbox/trunk/jcr/src/main/java/org/apache/james/mailbox/jcr/mail/JCRMessageMapper.java
URL: http://svn.apache.org/viewvc/james/mailbox/trunk/jcr/src/main/java/org/apache/james/mailbox/jcr/mail/JCRMessageMapper.java?rev=1092663&r1=1092662&r2=1092663&view=diff
==============================================================================
--- james/mailbox/trunk/jcr/src/main/java/org/apache/james/mailbox/jcr/mail/JCRMessageMapper.java (original)
+++ james/mailbox/trunk/jcr/src/main/java/org/apache/james/mailbox/jcr/mail/JCRMessageMapper.java Fri Apr 15 11:14:39 2011
@@ -39,15 +39,11 @@ import org.apache.jackrabbit.util.ISO907
import org.apache.james.mailbox.MailboxException;
import org.apache.james.mailbox.MailboxSession;
import org.apache.james.mailbox.MessageRange;
-import org.apache.james.mailbox.SearchQuery;
-import org.apache.james.mailbox.UpdatedFlags;
import org.apache.james.mailbox.MessageRange.Type;
-import org.apache.james.mailbox.SearchQuery.Criterion;
-import org.apache.james.mailbox.SearchQuery.NumericRange;
+import org.apache.james.mailbox.UpdatedFlags;
import org.apache.james.mailbox.jcr.AbstractJCRMapper;
import org.apache.james.mailbox.jcr.MailboxSessionJCRRepository;
import org.apache.james.mailbox.jcr.mail.model.JCRMessage;
-import org.apache.james.mailbox.store.SearchQueryIterator;
import org.apache.james.mailbox.store.mail.MessageMapper;
import org.apache.james.mailbox.store.mail.model.Mailbox;
import org.apache.james.mailbox.store.mail.model.MailboxMembership;
@@ -571,101 +567,7 @@ public class JCRMessageMapper extends Ab
}
}
- /*
- * (non-Javadoc)
- * @see org.apache.james.mailbox.store.mail.MessageMapper#searchMailbox(org.apache.james.mailbox.store.mail.model.Mailbox, org.apache.james.mailbox.SearchQuery)
- */
- public Iterator<Long> searchMailbox(Mailbox<String> mailbox, SearchQuery query) throws MailboxException {
- try {
- final Query xQuery = formulateXPath(mailbox, query);
-
- QueryResult result = xQuery.execute();
-
- final NodeIterator it = result.getNodes();
-
-
- // Lazy build the JCRMessage instances
- return new SearchQueryIterator(new Iterator<MailboxMembership<?>>() {
- public boolean hasNext() {
- return it.hasNext();
- }
-
- public MailboxMembership<?> next() {
- return new JCRMessage(it.nextNode(), getLogger());
-
- }
-
- public void remove() {
- it.remove();
- }
-
- }, query, getLogger());
- } catch (RepositoryException e) {
- throw new MailboxException("Unable to search messages for query " + query + " in mailbox " + mailbox, e);
- }
- }
-
-
- /**
- * Generate the XPath query for the SearchQuery
- *
- * @param uuid
- * @param query
- * @return xpathQuery
- * @throws RepositoryException
- * @throws ItemNotFoundException
- */
- private Query formulateXPath(Mailbox<String> mailbox, SearchQuery query) throws ItemNotFoundException, RepositoryException {
- final StringBuilder queryBuilder = new StringBuilder();
- queryBuilder.append("/jcr:root" + getMailboxPath(mailbox) + "//element(*,jamesMailbox:message)");
- final List<Criterion> criteria = query.getCriterias();
- boolean range = false;
- int rangeLength = -1;
- if (criteria.size() == 1) {
- final Criterion firstCriterion = criteria.get(0);
- if (firstCriterion instanceof SearchQuery.UidCriterion) {
- final SearchQuery.UidCriterion uidCriterion = (SearchQuery.UidCriterion) firstCriterion;
- final NumericRange[] ranges = uidCriterion.getOperator().getRange();
- rangeLength = ranges.length;
- for (int i = 0; i < ranges.length; i++) {
- final long low = ranges[i].getLowValue();
- final long high = ranges[i].getHighValue();
- if (i > 0) {
- // We need to use an OR here. See MAILBOX-49
- queryBuilder.append(" or ");
- } else {
- queryBuilder.append("[");
- }
- if (low == Long.MAX_VALUE) {
- range = true;
- queryBuilder.append("@" + JCRMessage.UID_PROPERTY +"<=").append(high);
- } else if (low == high) {
- range = false;
- queryBuilder.append("@" + JCRMessage.UID_PROPERTY +"=").append(low);
- } else {
- range = true;
- queryBuilder.append("@" + JCRMessage.UID_PROPERTY +"<=").append(high).append(" and @" + JCRMessage.UID_PROPERTY + ">=").append(low);
- }
- }
- }
- }
- if (rangeLength > 0) queryBuilder.append("]");
-
- if (rangeLength != 0 || range) {
- queryBuilder.append(" order by @" + JCRMessage.UID_PROPERTY);
- }
-
- QueryManager manager = getSession().getWorkspace().getQueryManager();
- Query xQuery = manager.createQuery(queryBuilder.toString(), Query.XPATH);
-
- // Check if we only need to fetch 1 message, if so we can set a limit to speed up things
- if (rangeLength == 1 && range == false) {
- xQuery.setLimit(1);
- }
- return xQuery;
- }
-
/*
* (non-Javadoc)
Modified: james/mailbox/trunk/jpa/src/main/java/org/apache/james/mailbox/jpa/mail/JPAMessageMapper.java
URL: http://svn.apache.org/viewvc/james/mailbox/trunk/jpa/src/main/java/org/apache/james/mailbox/jpa/mail/JPAMessageMapper.java?rev=1092663&r1=1092662&r2=1092663&view=diff
==============================================================================
--- james/mailbox/trunk/jpa/src/main/java/org/apache/james/mailbox/jpa/mail/JPAMessageMapper.java (original)
+++ james/mailbox/trunk/jpa/src/main/java/org/apache/james/mailbox/jpa/mail/JPAMessageMapper.java Fri Apr 15 11:14:39 2011
@@ -29,17 +29,13 @@ import javax.persistence.Query;
import org.apache.james.mailbox.MailboxException;
import org.apache.james.mailbox.MessageRange;
-import org.apache.james.mailbox.SearchQuery;
-import org.apache.james.mailbox.UpdatedFlags;
import org.apache.james.mailbox.MessageRange.Type;
-import org.apache.james.mailbox.SearchQuery.Criterion;
-import org.apache.james.mailbox.SearchQuery.NumericRange;
+import org.apache.james.mailbox.UpdatedFlags;
import org.apache.james.mailbox.jpa.JPATransactionalMapper;
import org.apache.james.mailbox.jpa.mail.model.JPAMailbox;
import org.apache.james.mailbox.jpa.mail.model.openjpa.AbstractJPAMailboxMembership;
import org.apache.james.mailbox.jpa.mail.model.openjpa.JPAMailboxMembership;
import org.apache.james.mailbox.jpa.mail.model.openjpa.JPAStreamingMailboxMembership;
-import org.apache.james.mailbox.store.SearchQueryIterator;
import org.apache.james.mailbox.store.mail.MessageMapper;
import org.apache.james.mailbox.store.mail.model.Mailbox;
import org.apache.james.mailbox.store.mail.model.MailboxMembership;
@@ -247,65 +243,6 @@ public class JPAMessageMapper extends JP
/*
* (non-Javadoc)
- * @see org.apache.james.mailbox.store.mail.MessageMapper#searchMailbox(org.apache.james.mailbox.store.mail.model.Mailbox, org.apache.james.mailbox.SearchQuery)
- */
- @SuppressWarnings("unchecked")
- public Iterator<Long> searchMailbox(Mailbox<Long> mailbox, SearchQuery query) throws MailboxException {
- try {
- final StringBuilder queryBuilder = new StringBuilder(50);
- queryBuilder.append("SELECT membership FROM Membership membership WHERE membership.mailbox.mailboxId = ").append(mailbox.getMailboxId());
- final List<Criterion> criteria = query.getCriterias();
- boolean range = false;
- int rangeLength = -1;
-
- if (criteria.size() == 1) {
- final Criterion firstCriterion = criteria.get(0);
- if (firstCriterion instanceof SearchQuery.UidCriterion) {
- final SearchQuery.UidCriterion uidCriterion = (SearchQuery.UidCriterion) firstCriterion;
- final NumericRange[] ranges = uidCriterion.getOperator().getRange();
- rangeLength = ranges.length;
-
- for (int i = 0; i < ranges.length; i++) {
- final long low = ranges[i].getLowValue();
- final long high = ranges[i].getHighValue();
- if (i == 0) {
- queryBuilder.append(" AND ");
- } else {
- // We need to use an OR here. See MAILBOX-49
- queryBuilder.append(" OR ");
- }
- if (low == Long.MAX_VALUE) {
- queryBuilder.append("membership.uid<=").append(high);
- range = true;
- } else if (low == high) {
- queryBuilder.append("membership.uid=").append(low);
- range = false;
- } else {
- queryBuilder.append("membership.uid BETWEEN ").append(low).append(" AND ").append(high);
- range = true;
- }
- }
- }
- }
- if (rangeLength != 0 || range) {
- queryBuilder.append(" order by membership.uid");
- }
-
- Query jQuery = getEntityManager().createQuery(queryBuilder.toString());
-
- // Check if we only need to fetch 1 message, if so we can set a limit to speed up things
- if (rangeLength == 1 && range == false) {
- jQuery.setMaxResults(1);
- }
- return new SearchQueryIterator(jQuery.getResultList().iterator(), query);
-
- } catch (PersistenceException e) {
- throw new MailboxException("Search of messages via the query " + query + " failed in mailbox " + mailbox, e);
- }
- }
-
- /*
- * (non-Javadoc)
* @see org.apache.james.mailbox.store.mail.MessageMapper#delete(java.lang.Object, org.apache.james.mailbox.store.mail.model.MailboxMembership)
*/
public void delete(Mailbox<Long> mailbox, MailboxMembership<Long> message) throws MailboxException {
Modified: james/mailbox/trunk/maildir/src/main/java/org/apache/james/mailbox/maildir/mail/MaildirMessageMapper.java
URL: http://svn.apache.org/viewvc/james/mailbox/trunk/maildir/src/main/java/org/apache/james/mailbox/maildir/mail/MaildirMessageMapper.java?rev=1092663&r1=1092662&r2=1092663&view=diff
==============================================================================
--- james/mailbox/trunk/maildir/src/main/java/org/apache/james/mailbox/maildir/mail/MaildirMessageMapper.java (original)
+++ james/mailbox/trunk/maildir/src/main/java/org/apache/james/mailbox/maildir/mail/MaildirMessageMapper.java Fri Apr 15 11:14:39 2011
@@ -25,29 +25,23 @@ import java.io.IOException;
import java.io.InputStream;
import java.util.ArrayList;
import java.util.Iterator;
-import java.util.LinkedList;
import java.util.List;
-import java.util.SortedMap;
import java.util.Map.Entry;
+import java.util.SortedMap;
import javax.mail.Flags;
import org.apache.commons.io.FileUtils;
import org.apache.james.mailbox.MailboxException;
import org.apache.james.mailbox.MessageRange;
-import org.apache.james.mailbox.SearchQuery;
-import org.apache.james.mailbox.UpdatedFlags;
import org.apache.james.mailbox.MessageRange.Type;
-import org.apache.james.mailbox.SearchQuery.Criterion;
-import org.apache.james.mailbox.SearchQuery.NumericRange;
+import org.apache.james.mailbox.UpdatedFlags;
import org.apache.james.mailbox.maildir.MaildirFolder;
import org.apache.james.mailbox.maildir.MaildirMessageName;
import org.apache.james.mailbox.maildir.MaildirStore;
-import org.apache.james.mailbox.maildir.UidConstraint;
import org.apache.james.mailbox.maildir.mail.model.AbstractMaildirMessage;
import org.apache.james.mailbox.maildir.mail.model.LazyLoadingMaildirMessage;
import org.apache.james.mailbox.maildir.mail.model.MaildirMessage;
-import org.apache.james.mailbox.store.SearchQueryIterator;
import org.apache.james.mailbox.store.mail.MessageMapper;
import org.apache.james.mailbox.store.mail.model.Mailbox;
import org.apache.james.mailbox.store.mail.model.MailboxMembership;
@@ -368,60 +362,7 @@ public class MaildirMessageMapper extend
}
- /*
- * (non-Javadoc)
- * @see org.apache.james.mailbox.store.mail.MessageMapper#searchMailbox(org.apache.james.mailbox.store.mail.model.Mailbox, org.apache.james.mailbox.SearchQuery)
- */
- public Iterator<Long> searchMailbox(Mailbox<Integer> mailbox, SearchQuery query)
- throws MailboxException {
- final List<Criterion> criteria = query.getCriterias();
- boolean range = false;
- int rangeLength = -1;
- UidConstraint constraint = new UidConstraint();
-
- if (criteria.size() == 1) {
- final Criterion firstCriterion = criteria.get(0);
- if (firstCriterion instanceof SearchQuery.UidCriterion) {
- final SearchQuery.UidCriterion uidCriterion = (SearchQuery.UidCriterion) firstCriterion;
- final NumericRange[] ranges = uidCriterion.getOperator().getRange();
- rangeLength = ranges.length;
-
- for (int i = 0; i < ranges.length; i++) {
- final long low = ranges[i].getLowValue();
- final long high = ranges[i].getHighValue();
-
- if (low == Long.MAX_VALUE) {
- constraint.lessOrEquals(high);
- range = true;
- } else if (low == high) {
- constraint.equals(low);
- range = false;
- } else {
- constraint.between(low, high);
- range = true;
- }
- }
- }
- }
- MaildirFolder folder = maildirStore.createMaildirFolder(mailbox);
- SortedMap<Long, MaildirMessageName> uidMap;
- try {
- uidMap = folder.getUidMap(0, -1);
- } catch (IOException e) {
- throw new MailboxException("Failure while search in Mailbox " + mailbox, e );
- }
- LinkedList<MailboxMembership<?>> messages = new LinkedList<MailboxMembership<?>>();
- for (Entry<Long, MaildirMessageName> entry : uidMap.entrySet()) {
- //System.out.println("check " + entry.getKey());
- if (constraint.isAllowed(entry.getKey())) {
- //System.out.println("allow " + entry.getKey());
- messages.add(new LazyLoadingMaildirMessage(mailbox, entry.getKey(), entry.getValue()));
- // Check if we only need to fetch 1 message, if so we can set a limit to speed up things
- if (rangeLength == 1 && range == false) break;
- }
- }
- return new SearchQueryIterator(messages.iterator(), query);
- }
+
/*
* (non-Javadoc)
Modified: james/mailbox/trunk/memory/src/main/java/org/apache/james/mailbox/inmemory/mail/InMemoryMessageMapper.java
URL: http://svn.apache.org/viewvc/james/mailbox/trunk/memory/src/main/java/org/apache/james/mailbox/inmemory/mail/InMemoryMessageMapper.java?rev=1092663&r1=1092662&r2=1092663&view=diff
==============================================================================
--- james/mailbox/trunk/memory/src/main/java/org/apache/james/mailbox/inmemory/mail/InMemoryMessageMapper.java (original)
+++ james/mailbox/trunk/memory/src/main/java/org/apache/james/mailbox/inmemory/mail/InMemoryMessageMapper.java Fri Apr 15 11:14:39 2011
@@ -30,10 +30,8 @@ import javax.mail.Flags;
import org.apache.james.mailbox.MailboxException;
import org.apache.james.mailbox.MessageRange;
-import org.apache.james.mailbox.SearchQuery;
import org.apache.james.mailbox.UpdatedFlags;
import org.apache.james.mailbox.inmemory.mail.model.SimpleMailboxMembership;
-import org.apache.james.mailbox.store.SearchQueryIterator;
import org.apache.james.mailbox.store.mail.MessageMapper;
import org.apache.james.mailbox.store.mail.model.Mailbox;
import org.apache.james.mailbox.store.mail.model.MailboxMembership;
@@ -208,17 +206,6 @@ public class InMemoryMessageMapper exten
}
- /*
- * (non-Javadoc)
- * @see org.apache.james.mailbox.store.mail.MessageMapper#searchMailbox(org.apache.james.mailbox.store.mail.model.Mailbox, org.apache.james.mailbox.SearchQuery)
- */
- public Iterator<Long> searchMailbox(Mailbox<Long> mailbox, SearchQuery query) throws MailboxException {
- List<MailboxMembership<?>> memberships = new ArrayList<MailboxMembership<?>>(getMembershipByUidForMailbox(mailbox).values());
- Collections.sort(memberships, MailboxMembershipComparator.INSTANCE);
-
- return new SearchQueryIterator(memberships.iterator(), query);
- }
-
public void deleteAll() {
mailboxByUid.clear();
}
Modified: james/mailbox/trunk/store/src/main/java/org/apache/james/mailbox/store/StoreMessageManager.java
URL: http://svn.apache.org/viewvc/james/mailbox/trunk/store/src/main/java/org/apache/james/mailbox/store/StoreMessageManager.java?rev=1092663&r1=1092662&r2=1092663&view=diff
==============================================================================
--- james/mailbox/trunk/store/src/main/java/org/apache/james/mailbox/store/StoreMessageManager.java (original)
+++ james/mailbox/trunk/store/src/main/java/org/apache/james/mailbox/store/StoreMessageManager.java Fri Apr 15 11:14:39 2011
@@ -26,6 +26,7 @@ import java.io.InputStream;
import java.io.PushbackInputStream;
import java.util.ArrayList;
import java.util.Arrays;
+import java.util.Collections;
import java.util.Date;
import java.util.Iterator;
import java.util.List;
@@ -43,14 +44,18 @@ import org.apache.james.mailbox.MailboxS
import org.apache.james.mailbox.MessageRange;
import org.apache.james.mailbox.MessageResult;
import org.apache.james.mailbox.SearchQuery;
+import org.apache.james.mailbox.SearchQuery.NumericRange;
+import org.apache.james.mailbox.SearchQuery.UidCriterion;
import org.apache.james.mailbox.UpdatedFlags;
import org.apache.james.mailbox.MessageResult.FetchGroup;
+import org.apache.james.mailbox.SearchQuery.Criterion;
import org.apache.james.mailbox.store.mail.MessageMapper;
import org.apache.james.mailbox.store.mail.MessageMapperFactory;
import org.apache.james.mailbox.store.mail.UidProvider;
import org.apache.james.mailbox.store.mail.model.Header;
import org.apache.james.mailbox.store.mail.model.Mailbox;
import org.apache.james.mailbox.store.mail.model.MailboxMembership;
+import org.apache.james.mailbox.store.mail.model.MailboxMembershipComparator;
import org.apache.james.mailbox.store.mail.model.PropertyBuilder;
import org.apache.james.mailbox.store.streaming.ConfigurableMimeTokenStream;
import org.apache.james.mailbox.store.streaming.CountingInputStream;
@@ -574,7 +579,64 @@ public abstract class StoreMessageManage
* @see org.apache.james.mailbox.Mailbox#search(org.apache.james.mailbox.SearchQuery, org.apache.james.mailbox.MailboxSession)
*/
public Iterator<Long> search(SearchQuery query, MailboxSession mailboxSession) throws MailboxException {
- return mapperFactory.getMessageMapper(mailboxSession).searchMailbox(getMailboxEntity(), query);
+ MessageMapper<Id> messageMapper = mapperFactory.getMessageMapper(mailboxSession);
+ List<Criterion> crits = query.getCriterias();
+
+ if (crits.size() == 1 && crits.get(0) instanceof UidCriterion) {
+ final List<Long> uids = new ArrayList<Long>();
+ UidCriterion uidCrit = (UidCriterion) crits.get(0);
+ NumericRange[] ranges = uidCrit.getOperator().getRange();
+ for (int i = 0; i < ranges.length; i++) {
+ NumericRange r = ranges[i];
+ messageMapper.findInMailbox(getMailboxEntity(), MessageRange.range(r.getLowValue(), r.getHighValue()), new MailboxMembershipCallback<Id>() {
+
+ public void onMailboxMembers(List<MailboxMembership<Id>> list) throws MailboxException {
+ for (int i = 0; i < list.size(); i++) {
+ long uid = list.get(i).getUid();
+ if (uids.contains(uid) == false) {
+ uids.add(uid);
+ }
+ }
+ }
+ });
+ }
+ Collections.sort(uids);
+ return uids.iterator();
+
+
+ } else {
+ final List<MailboxMembership<Id>> hits = new ArrayList<MailboxMembership<Id>>();
+
+ messageMapper.findInMailbox(getMailboxEntity(), MessageRange.all(), new MailboxMembershipCallback<Id>() {
+
+ public void onMailboxMembers(List<MailboxMembership<Id>> list) throws MailboxException {
+ for (int i = 0; i < list.size(); i++) {
+ MailboxMembership<Id> m = list.get(i);
+ if (hits.contains(m) == false) {
+ hits.add(m);
+ }
+ }
+ }
+ });
+ Collections.sort(hits, MailboxMembershipComparator.INSTANCE);
+
+ return new SearchQueryIterator(new Iterator<MailboxMembership<?>>() {
+ final Iterator<MailboxMembership<Id>> it = hits.iterator();
+ public boolean hasNext() {
+ return it.hasNext();
+ }
+
+ public MailboxMembership<?> next() {
+ return it.next();
+ }
+
+ public void remove() {
+ it.remove();
+ }
+
+ }, query, mailboxSession.getLog());
+ }
+
}
Modified: james/mailbox/trunk/store/src/main/java/org/apache/james/mailbox/store/mail/MessageMapper.java
URL: http://svn.apache.org/viewvc/james/mailbox/trunk/store/src/main/java/org/apache/james/mailbox/store/mail/MessageMapper.java?rev=1092663&r1=1092662&r2=1092663&view=diff
==============================================================================
--- james/mailbox/trunk/store/src/main/java/org/apache/james/mailbox/store/mail/MessageMapper.java (original)
+++ james/mailbox/trunk/store/src/main/java/org/apache/james/mailbox/store/mail/MessageMapper.java Fri Apr 15 11:14:39 2011
@@ -25,7 +25,6 @@ import javax.mail.Flags;
import org.apache.james.mailbox.MailboxException;
import org.apache.james.mailbox.MessageRange;
-import org.apache.james.mailbox.SearchQuery;
import org.apache.james.mailbox.UpdatedFlags;
import org.apache.james.mailbox.store.mail.model.Mailbox;
import org.apache.james.mailbox.store.mail.model.MailboxMembership;
@@ -82,15 +81,6 @@ public interface MessageMapper<Id> exten
public abstract long countUnseenMessagesInMailbox(Mailbox<Id> mailbox)
throws MailboxException;
- /**
- * Return a List of uids which matched the {@link SearchQuery}
- * The list must be ordered by the {@link Message} uid
- * @param mailbox
- * @param query
- * @return
- * @throws StorageException
- */
- public abstract Iterator<Long> searchMailbox(Mailbox<Id> mailbox, SearchQuery query) throws MailboxException;
/**
* Delete the given {@link MailboxMembership}
---------------------------------------------------------------------
To unsubscribe, e-mail: server-dev-unsubscribe@james.apache.org
For additional commands, e-mail: server-dev-help@james.apache.org