Just a minor comment from a quick review.

The synchronized(session) should be removed.. You use an AtomicBoolean
so you should be safe here..

Will have a deeper look later

Bye,
Nomrna


2010/12/15  <nik...@apache.org>:
> Author: niklas
> Date: Wed Dec 15 16:00:25 2010
> New Revision: 1049622
>
> URL: http://svn.apache.org/viewvc?rev=1049622&view=rev
> Log:
> Added initial support for IDLE (IMAP-239).
>
> Added:
>    
> james/imap/trunk/api/src/main/java/org/apache/james/imap/api/ContinuationReader.java
>    
> james/imap/trunk/message/src/main/java/org/apache/james/imap/decode/parser/IdleCommandParser.java
>    
> james/imap/trunk/message/src/main/java/org/apache/james/imap/encode/ContinuationResponseEncoder.java
>    
> james/imap/trunk/message/src/main/java/org/apache/james/imap/message/request/IdleRequest.java
>    
> james/imap/trunk/message/src/main/java/org/apache/james/imap/message/response/ContinuationResponse.java
>    
> james/imap/trunk/processor/src/main/java/org/apache/james/imap/processor/IdleProcessor.java
> Modified:
>    
> james/imap/trunk/api/src/main/java/org/apache/james/imap/api/ImapConstants.java
>    
> james/imap/trunk/api/src/main/java/org/apache/james/imap/api/ImapMessageFactory.java
>    
> james/imap/trunk/api/src/main/java/org/apache/james/imap/api/display/HumanReadableText.java
>    
> james/imap/trunk/message/src/main/java/org/apache/james/imap/decode/ImapRequestLineReader.java
>    
> james/imap/trunk/message/src/main/java/org/apache/james/imap/decode/parser/ImapParserFactory.java
>    
> james/imap/trunk/message/src/main/java/org/apache/james/imap/encode/ImapResponseComposer.java
>    
> james/imap/trunk/message/src/main/java/org/apache/james/imap/encode/ImapResponseWriter.java
>    
> james/imap/trunk/message/src/main/java/org/apache/james/imap/encode/base/ImapResponseComposerImpl.java
>    
> james/imap/trunk/message/src/main/java/org/apache/james/imap/encode/main/DefaultImapEncoderFactory.java
>    
> james/imap/trunk/message/src/main/java/org/apache/james/imap/main/ChannelImapResponseWriter.java
>    
> james/imap/trunk/message/src/main/java/org/apache/james/imap/message/request/BaseImap4Rev1MessageFactory.java
>    
> james/imap/trunk/message/src/test/java/org/apache/james/imap/encode/MockImapResponseWriter.java
>    
> james/imap/trunk/message/src/test/java/org/apache/james/imap/encode/base/ByteImapResponseWriter.java
>    
> james/imap/trunk/processor/src/main/java/org/apache/james/imap/processor/DefaultProcessorChain.java
>
> Added: 
> james/imap/trunk/api/src/main/java/org/apache/james/imap/api/ContinuationReader.java
> URL: 
> http://svn.apache.org/viewvc/james/imap/trunk/api/src/main/java/org/apache/james/imap/api/ContinuationReader.java?rev=1049622&view=auto
> ==============================================================================
> --- 
> james/imap/trunk/api/src/main/java/org/apache/james/imap/api/ContinuationReader.java
>  (added)
> +++ 
> james/imap/trunk/api/src/main/java/org/apache/james/imap/api/ContinuationReader.java
>  Wed Dec 15 16:00:25 2010
> @@ -0,0 +1,27 @@
> +/****************************************************************
> + * Licensed to the Apache Software Foundation (ASF) under one   *
> + * or more contributor license agreements.  See the NOTICE file *
> + * distributed with this work for additional information        *
> + * regarding copyright ownership.  The ASF licenses this file   *
> + * to you under the Apache License, Version 2.0 (the            *
> + * "License"); you may not use this file except in compliance   *
> + * with the License.  You may obtain a copy of the License at   *
> + *                                                              *
> + *   http://www.apache.org/licenses/LICENSE-2.0                 *
> + *                                                              *
> + * Unless required by applicable law or agreed to in writing,   *
> + * software distributed under the License is distributed on an  *
> + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY       *
> + * KIND, either express or implied.  See the License for the    *
> + * specific language governing permissions and limitations      *
> + * under the License.                                           *
> + ****************************************************************/
> +package org.apache.james.imap.api;
> +
> +import java.io.IOException;
> +
> +public interface ContinuationReader {
> +
> +    public String readContinuation() throws IOException;
> +
> +}
>
> Modified: 
> james/imap/trunk/api/src/main/java/org/apache/james/imap/api/ImapConstants.java
> URL: 
> http://svn.apache.org/viewvc/james/imap/trunk/api/src/main/java/org/apache/james/imap/api/ImapConstants.java?rev=1049622&r1=1049621&r2=1049622&view=diff
> ==============================================================================
> --- 
> james/imap/trunk/api/src/main/java/org/apache/james/imap/api/ImapConstants.java
>  (original)
> +++ 
> james/imap/trunk/api/src/main/java/org/apache/james/imap/api/ImapConstants.java
>  Wed Dec 15 16:00:25 2010
> @@ -31,6 +31,8 @@ public interface ImapConstants {
>
>     public static final String UNTAGGED = "*";
>
> +    public static final String CONTINUATION = "+";
> +
>     public static final String SP = " ";
>
>     public static final String NIL = "NIL";
> @@ -105,6 +107,8 @@ public interface ImapConstants {
>
>     public static final String SUPPORTS_STARTTLS = "STARTTLS";
>
> +    public static final String SUPPORTS_IDLE = "IDLE";
> +
>     public static final char HIERARCHY_DELIMITER_CHAR = '.';
>
>     public static final char NAMESPACE_PREFIX_CHAR = '#';
> @@ -183,6 +187,8 @@ public interface ImapConstants {
>
>     public static final String NOOP_COMMAND_NAME = "NOOP";
>
> +    public static final String IDLE_COMMAND_NAME = "IDLE";
> +
>     public static final String LSUB_COMMAND_NAME = "LSUB";
>
>     public static final String LOGOUT_COMMAND_NAME = "LOGOUT";
>
> Modified: 
> james/imap/trunk/api/src/main/java/org/apache/james/imap/api/ImapMessageFactory.java
> URL: 
> http://svn.apache.org/viewvc/james/imap/trunk/api/src/main/java/org/apache/james/imap/api/ImapMessageFactory.java?rev=1049622&r1=1049621&r2=1049622&view=diff
> ==============================================================================
> --- 
> james/imap/trunk/api/src/main/java/org/apache/james/imap/api/ImapMessageFactory.java
>  (original)
> +++ 
> james/imap/trunk/api/src/main/java/org/apache/james/imap/api/ImapMessageFactory.java
>  Wed Dec 15 16:00:25 2010
> @@ -68,6 +68,9 @@ public interface ImapMessageFactory {
>     public ImapMessage createNoopMessage(final ImapCommand command,
>             final String tag);
>
> +    public ImapMessage createIdleMessage(final ImapCommand command,
> +            final ContinuationReader reader, final String tag);
> +
>     public ImapMessage createCloseMessage(final ImapCommand command,
>             final String tag);
>
>
> Modified: 
> james/imap/trunk/api/src/main/java/org/apache/james/imap/api/display/HumanReadableText.java
> URL: 
> http://svn.apache.org/viewvc/james/imap/trunk/api/src/main/java/org/apache/james/imap/api/display/HumanReadableText.java?rev=1049622&r1=1049621&r2=1049622&view=diff
> ==============================================================================
> --- 
> james/imap/trunk/api/src/main/java/org/apache/james/imap/api/display/HumanReadableText.java
>  (original)
> +++ 
> james/imap/trunk/api/src/main/java/org/apache/james/imap/api/display/HumanReadableText.java
>  Wed Dec 15 16:00:25 2010
> @@ -196,6 +196,9 @@ public class HumanReadableText {
>     public static final HumanReadableText BYE_UNKNOWN_COMMAND = new 
> HumanReadableText(
>             "org.apache.james.imap.BYE_UNKNOWN_COMMAND", "Unknown command.");
>
> +    public static final HumanReadableText IDLING = new HumanReadableText(
> +            "org.apache.james.imap.IDLING", "Idling");
> +
>     private final String defaultValue;
>
>     private final String key;
>
> Modified: 
> james/imap/trunk/message/src/main/java/org/apache/james/imap/decode/ImapRequestLineReader.java
> URL: 
> http://svn.apache.org/viewvc/james/imap/trunk/message/src/main/java/org/apache/james/imap/decode/ImapRequestLineReader.java?rev=1049622&r1=1049621&r2=1049622&view=diff
> ==============================================================================
> --- 
> james/imap/trunk/message/src/main/java/org/apache/james/imap/decode/ImapRequestLineReader.java
>  (original)
> +++ 
> james/imap/trunk/message/src/main/java/org/apache/james/imap/decode/ImapRequestLineReader.java
>  Wed Dec 15 16:00:25 2010
> @@ -19,8 +19,10 @@
>
>  package org.apache.james.imap.decode;
>
> +import java.io.IOException;
>  import java.io.InputStream;
>
> +import org.apache.james.imap.api.ContinuationReader;
>  import org.apache.james.imap.api.display.HumanReadableText;
>
>  /**
> @@ -30,7 +32,7 @@ import org.apache.james.imap.api.display
>  *
>  * @version $Revision: 109034 $
>  */
> -public abstract class ImapRequestLineReader {
> +public abstract class ImapRequestLineReader implements ContinuationReader {
>
>
>     protected boolean nextSeen = false;
> @@ -154,4 +156,22 @@ public abstract class ImapRequestLineRea
>         }
>         consume();
>     }
> +
> +    public String readContinuation() throws IOException {
> +        // Consume the '\n' from the previous line.
> +        consume();
> +
> +        StringBuilder sb = new StringBuilder();
> +        char next = nextChar();
> +        while (next != '\r') {
> +            sb.append(next);
> +            consume();
> +            next = nextChar();
> +        }
> +        consume();
> +
> +        // NOTE: This code leaves the '\n' as next char. This seems to be 
> what is expected by the code which parses commands.
> +
> +        return sb.toString();
> +    }
>  }
>
> Added: 
> james/imap/trunk/message/src/main/java/org/apache/james/imap/decode/parser/IdleCommandParser.java
> URL: 
> http://svn.apache.org/viewvc/james/imap/trunk/message/src/main/java/org/apache/james/imap/decode/parser/IdleCommandParser.java?rev=1049622&view=auto
> ==============================================================================
> --- 
> james/imap/trunk/message/src/main/java/org/apache/james/imap/decode/parser/IdleCommandParser.java
>  (added)
> +++ 
> james/imap/trunk/message/src/main/java/org/apache/james/imap/decode/parser/IdleCommandParser.java
>  Wed Dec 15 16:00:25 2010
> @@ -0,0 +1,51 @@
> +/****************************************************************
> + * Licensed to the Apache Software Foundation (ASF) under one   *
> + * or more contributor license agreements.  See the NOTICE file *
> + * distributed with this work for additional information        *
> + * regarding copyright ownership.  The ASF licenses this file   *
> + * to you under the Apache License, Version 2.0 (the            *
> + * "License"); you may not use this file except in compliance   *
> + * with the License.  You may obtain a copy of the License at   *
> + *                                                              *
> + *   http://www.apache.org/licenses/LICENSE-2.0                 *
> + *                                                              *
> + * Unless required by applicable law or agreed to in writing,   *
> + * software distributed under the License is distributed on an  *
> + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY       *
> + * KIND, either express or implied.  See the License for the    *
> + * specific language governing permissions and limitations      *
> + * under the License.                                           *
> + ****************************************************************/
> +package org.apache.james.imap.decode.parser;
> +
> +import org.apache.commons.logging.Log;
> +import org.apache.james.imap.api.ImapCommand;
> +import org.apache.james.imap.api.ImapConstants;
> +import org.apache.james.imap.api.ImapMessage;
> +import org.apache.james.imap.decode.ImapRequestLineReader;
> +import org.apache.james.imap.decode.DecodingException;
> +import org.apache.james.imap.decode.base.AbstractImapCommandParser;
> +
> +/**
> + *
> + * Parses IDLE commands
> + *
> + */
> +public class IdleCommandParser extends AbstractImapCommandParser {
> +
> +    public IdleCommandParser() {
> +        
> super(ImapCommand.selectedStateCommand(ImapConstants.IDLE_COMMAND_NAME));
> +    }
> +
> +    /*
> +     * (non-Javadoc)
> +     * @see 
> org.apache.james.imap.decode.base.AbstractImapCommandParser#decode(org.apache.james.imap.api.ImapCommand,
>  org.apache.james.imap.decode.ImapRequestLineReader, java.lang.String, 
> org.apache.commons.logging.Log)
> +     */
> +    protected ImapMessage decode(ImapCommand command,
> +            ImapRequestLineReader request, String tag, Log logger) throws 
> DecodingException {
> +        endLine(request);
> +        final ImapMessage result = 
> getMessageFactory().createIdleMessage(command, request, tag);
> +        return result;
> +    }
> +
> +}
>
> Modified: 
> james/imap/trunk/message/src/main/java/org/apache/james/imap/decode/parser/ImapParserFactory.java
> URL: 
> http://svn.apache.org/viewvc/james/imap/trunk/message/src/main/java/org/apache/james/imap/decode/parser/ImapParserFactory.java?rev=1049622&r1=1049621&r2=1049622&view=diff
> ==============================================================================
> --- 
> james/imap/trunk/message/src/main/java/org/apache/james/imap/decode/parser/ImapParserFactory.java
>  (original)
> +++ 
> james/imap/trunk/message/src/main/java/org/apache/james/imap/decode/parser/ImapParserFactory.java
>  Wed Dec 15 16:00:25 2010
> @@ -104,7 +104,7 @@ public class ImapParserFactory implement
>         // _imapCommands.put( "MYRIGHTS", MyRightsCommand.class );
>
>         // Commands only valid in SELECTED state.
> -        // CHECK, CLOSE, EXPUNGE, SEARCH, FETCH, STORE, COPY, and UID
> +        // CHECK, CLOSE, EXPUNGE, SEARCH, FETCH, STORE, COPY, UID and IDLE
>         _imapCommands.put(ImapConstants.CHECK_COMMAND_NAME,
>                 CheckCommandParser.class);
>         _imapCommands.put(ImapConstants.CLOSE_COMMAND_NAME,
> @@ -121,6 +121,8 @@ public class ImapParserFactory implement
>                 StoreCommandParser.class);
>         _imapCommands.put(ImapConstants.UID_COMMAND_NAME,
>                 UidCommandParser.class);
> +        _imapCommands.put(ImapConstants.IDLE_COMMAND_NAME,
> +                IdleCommandParser.class);
>         _imapCommands.put(ImapConstants.STARTTLS, 
> StartTLSCommandParser.class);
>     }
>
>
> Added: 
> james/imap/trunk/message/src/main/java/org/apache/james/imap/encode/ContinuationResponseEncoder.java
> URL: 
> http://svn.apache.org/viewvc/james/imap/trunk/message/src/main/java/org/apache/james/imap/encode/ContinuationResponseEncoder.java?rev=1049622&view=auto
> ==============================================================================
> --- 
> james/imap/trunk/message/src/main/java/org/apache/james/imap/encode/ContinuationResponseEncoder.java
>  (added)
> +++ 
> james/imap/trunk/message/src/main/java/org/apache/james/imap/encode/ContinuationResponseEncoder.java
>  Wed Dec 15 16:00:25 2010
> @@ -0,0 +1,60 @@
> +/****************************************************************
> + * Licensed to the Apache Software Foundation (ASF) under one   *
> + * or more contributor license agreements.  See the NOTICE file *
> + * distributed with this work for additional information        *
> + * regarding copyright ownership.  The ASF licenses this file   *
> + * to you under the Apache License, Version 2.0 (the            *
> + * "License"); you may not use this file except in compliance   *
> + * with the License.  You may obtain a copy of the License at   *
> + *                                                              *
> + *   http://www.apache.org/licenses/LICENSE-2.0                 *
> + *                                                              *
> + * Unless required by applicable law or agreed to in writing,   *
> + * software distributed under the License is distributed on an  *
> + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY       *
> + * KIND, either express or implied.  See the License for the    *
> + * specific language governing permissions and limitations      *
> + * under the License.                                           *
> + ****************************************************************/
> +
> +package org.apache.james.imap.encode;
> +
> +import java.io.IOException;
> +import java.util.ArrayList;
> +import java.util.Locale;
> +
> +import org.apache.james.imap.api.ImapMessage;
> +import org.apache.james.imap.api.display.HumanReadableText;
> +import org.apache.james.imap.api.display.Locales;
> +import org.apache.james.imap.api.display.Localizer;
> +import org.apache.james.imap.api.process.ImapSession;
> +import org.apache.james.imap.encode.base.AbstractChainedImapEncoder;
> +import org.apache.james.imap.message.response.ContinuationResponse;
> +
> +public class ContinuationResponseEncoder extends AbstractChainedImapEncoder {
> +
> +    private final Localizer localizer;
> +
> +    public ContinuationResponseEncoder(ImapEncoder next, final Localizer 
> localizer) {
> +        super(next);
> +        this.localizer = localizer;
> +    }
> +
> +    protected void doEncode(ImapMessage acceptableMessage,
> +            ImapResponseComposer composer, ImapSession session) throws 
> IOException {
> +
> +        ContinuationResponse response = (ContinuationResponse) 
> acceptableMessage;
> +        final String message = response.getData() != null ? 
> response.getData() : asString(response.getTextKey(), session);
> +        composer.continuationResponse(message);
> +    }
> +
> +    private String asString(HumanReadableText text, ImapSession session) {
> +        // TODO: calculate locales
> +        return localizer.localize(text, new Locales(new ArrayList<Locale>(), 
> null));
> +    }
> +
> +    protected boolean isAcceptable(ImapMessage message) {
> +        return (message instanceof ContinuationResponse);
> +    }
> +
> +}
>
> Modified: 
> james/imap/trunk/message/src/main/java/org/apache/james/imap/encode/ImapResponseComposer.java
> URL: 
> http://svn.apache.org/viewvc/james/imap/trunk/message/src/main/java/org/apache/james/imap/encode/ImapResponseComposer.java?rev=1049622&r1=1049621&r2=1049622&view=diff
> ==============================================================================
> --- 
> james/imap/trunk/message/src/main/java/org/apache/james/imap/encode/ImapResponseComposer.java
>  (original)
> +++ 
> james/imap/trunk/message/src/main/java/org/apache/james/imap/encode/ImapResponseComposer.java
>  Wed Dec 15 16:00:25 2010
> @@ -293,4 +293,13 @@ public interface ImapResponseComposer {
>      * @throws IOException
>      */
>     public ImapResponseComposer capabilities(List<String> capabilities) 
> throws IOException;
> +
> +    /**
> +     * Writes a continuation response.
> +     *
> +     * @param message
> +     *            message for display, not null
> +     */
> +    public abstract void continuationResponse(String message) throws 
> IOException;
> +
>  }
> \ No newline at end of file
>
> Modified: 
> james/imap/trunk/message/src/main/java/org/apache/james/imap/encode/ImapResponseWriter.java
> URL: 
> http://svn.apache.org/viewvc/james/imap/trunk/message/src/main/java/org/apache/james/imap/encode/ImapResponseWriter.java?rev=1049622&r1=1049621&r2=1049622&view=diff
> ==============================================================================
> --- 
> james/imap/trunk/message/src/main/java/org/apache/james/imap/encode/ImapResponseWriter.java
>  (original)
> +++ 
> james/imap/trunk/message/src/main/java/org/apache/james/imap/encode/ImapResponseWriter.java
>  Wed Dec 15 16:00:25 2010
> @@ -47,6 +47,14 @@ public interface ImapResponseWriter {
>     void tag(String tag) throws IOException;
>
>     /**
> +     * Starts a continuation response.
> +     *
> +     * @param message
> +     *            the message, not null
> +     */
> +    void continuation(String message) throws IOException;
> +
> +    /**
>      * Writes a command name.
>      *
>      * @param commandName
>
> Modified: 
> james/imap/trunk/message/src/main/java/org/apache/james/imap/encode/base/ImapResponseComposerImpl.java
> URL: 
> http://svn.apache.org/viewvc/james/imap/trunk/message/src/main/java/org/apache/james/imap/encode/base/ImapResponseComposerImpl.java?rev=1049622&r1=1049621&r2=1049622&view=diff
> ==============================================================================
> --- 
> james/imap/trunk/message/src/main/java/org/apache/james/imap/encode/base/ImapResponseComposerImpl.java
>  (original)
> +++ 
> james/imap/trunk/message/src/main/java/org/apache/james/imap/encode/base/ImapResponseComposerImpl.java
>  Wed Dec 15 16:00:25 2010
> @@ -90,6 +90,15 @@ public class ImapResponseComposerImpl im
>
>     /**
>      * @throws IOException
> +     * @see 
> org.apache.james.imap.encode.ImapResponseComposer#continuationResponse(String)
> +     */
> +    public void continuationResponse(String message) throws IOException {
> +        writer.continuation(message);
> +        end();
> +    }
> +
> +    /**
> +     * @throws IOException
>      * @see 
> org.apache.james.imap.encode.ImapResponseComposer#flagsResponse(javax.mail.Flags)
>      */
>     public void flagsResponse(Flags flags) throws IOException {
>
> Modified: 
> james/imap/trunk/message/src/main/java/org/apache/james/imap/encode/main/DefaultImapEncoderFactory.java
> URL: 
> http://svn.apache.org/viewvc/james/imap/trunk/message/src/main/java/org/apache/james/imap/encode/main/DefaultImapEncoderFactory.java?rev=1049622&r1=1049621&r2=1049622&view=diff
> ==============================================================================
> --- 
> james/imap/trunk/message/src/main/java/org/apache/james/imap/encode/main/DefaultImapEncoderFactory.java
>  (original)
> +++ 
> james/imap/trunk/message/src/main/java/org/apache/james/imap/encode/main/DefaultImapEncoderFactory.java
>  Wed Dec 15 16:00:25 2010
> @@ -21,6 +21,7 @@ package org.apache.james.imap.encode.mai
>
>  import org.apache.james.imap.api.display.Localizer;
>  import org.apache.james.imap.encode.CapabilityResponseEncoder;
> +import org.apache.james.imap.encode.ContinuationResponseEncoder;
>  import org.apache.james.imap.encode.ExistsResponseEncoder;
>  import org.apache.james.imap.encode.ExpungeResponseEncoder;
>  import org.apache.james.imap.encode.FetchResponseEncoder;
> @@ -73,7 +74,9 @@ public class DefaultImapEncoderFactory i
>                 listResponseEncoder);
>         final CapabilityResponseEncoder capabilityResponseEncoder = new 
> CapabilityResponseEncoder(
>                 flagsResponseEncoder);
> -        return capabilityResponseEncoder;
> +        final ContinuationResponseEncoder continuationResponseEncoder = new 
> ContinuationResponseEncoder(
> +                capabilityResponseEncoder, localizer);
> +        return continuationResponseEncoder;
>     }
>
>     private final Localizer localizer;
>
> Modified: 
> james/imap/trunk/message/src/main/java/org/apache/james/imap/main/ChannelImapResponseWriter.java
> URL: 
> http://svn.apache.org/viewvc/james/imap/trunk/message/src/main/java/org/apache/james/imap/main/ChannelImapResponseWriter.java?rev=1049622&r1=1049621&r2=1049622&view=diff
> ==============================================================================
> --- 
> james/imap/trunk/message/src/main/java/org/apache/james/imap/main/ChannelImapResponseWriter.java
>  (original)
> +++ 
> james/imap/trunk/message/src/main/java/org/apache/james/imap/main/ChannelImapResponseWriter.java
>  Wed Dec 15 16:00:25 2010
> @@ -253,4 +253,8 @@ public class ChannelImapResponseWriter i
>     public void quoteUpperCaseAscii(String message) throws IOException {
>         upperCaseAscii(message, true);
>     }
> +
> +    public void continuation(String message) throws IOException {
> +        writeASCII(CONTINUATION + SP + message);
> +    }
>  }
>
> Modified: 
> james/imap/trunk/message/src/main/java/org/apache/james/imap/message/request/BaseImap4Rev1MessageFactory.java
> URL: 
> http://svn.apache.org/viewvc/james/imap/trunk/message/src/main/java/org/apache/james/imap/message/request/BaseImap4Rev1MessageFactory.java?rev=1049622&r1=1049621&r2=1049622&view=diff
> ==============================================================================
> --- 
> james/imap/trunk/message/src/main/java/org/apache/james/imap/message/request/BaseImap4Rev1MessageFactory.java
>  (original)
> +++ 
> james/imap/trunk/message/src/main/java/org/apache/james/imap/message/request/BaseImap4Rev1MessageFactory.java
>  Wed Dec 15 16:00:25 2010
> @@ -23,6 +23,7 @@ import java.util.Date;
>
>  import javax.mail.Flags;
>
> +import org.apache.james.imap.api.ContinuationReader;
>  import org.apache.james.imap.api.ImapMessageFactory;
>  import org.apache.james.imap.api.ImapCommand;
>  import org.apache.james.imap.api.ImapMessage;
> @@ -85,6 +86,14 @@ public class BaseImap4Rev1MessageFactory
>
>     /*
>      * (non-Javadoc)
> +     * @see 
> org.apache.james.imap.api.ImapMessageFactory#createNoopMessage(org.apache.james.imap.api.ImapCommand,
>  java.lang.String)
> +     */
> +    public ImapMessage createIdleMessage(ImapCommand command, 
> ContinuationReader reader, String tag) {
> +        return new IdleRequest(command, reader, tag);
> +    }
> +
> +    /*
> +     * (non-Javadoc)
>      * @see 
> org.apache.james.imap.api.ImapMessageFactory#createCloseMessage(org.apache.james.imap.api.ImapCommand,
>  java.lang.String)
>      */
>     public ImapMessage createCloseMessage(ImapCommand command, String tag) {
>
> Added: 
> james/imap/trunk/message/src/main/java/org/apache/james/imap/message/request/IdleRequest.java
> URL: 
> http://svn.apache.org/viewvc/james/imap/trunk/message/src/main/java/org/apache/james/imap/message/request/IdleRequest.java?rev=1049622&view=auto
> ==============================================================================
> --- 
> james/imap/trunk/message/src/main/java/org/apache/james/imap/message/request/IdleRequest.java
>  (added)
> +++ 
> james/imap/trunk/message/src/main/java/org/apache/james/imap/message/request/IdleRequest.java
>  Wed Dec 15 16:00:25 2010
> @@ -0,0 +1,36 @@
> +/****************************************************************
> + * Licensed to the Apache Software Foundation (ASF) under one   *
> + * or more contributor license agreements.  See the NOTICE file *
> + * distributed with this work for additional information        *
> + * regarding copyright ownership.  The ASF licenses this file   *
> + * to you under the Apache License, Version 2.0 (the            *
> + * "License"); you may not use this file except in compliance   *
> + * with the License.  You may obtain a copy of the License at   *
> + *                                                              *
> + *   http://www.apache.org/licenses/LICENSE-2.0                 *
> + *                                                              *
> + * Unless required by applicable law or agreed to in writing,   *
> + * software distributed under the License is distributed on an  *
> + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY       *
> + * KIND, either express or implied.  See the License for the    *
> + * specific language governing permissions and limitations      *
> + * under the License.                                           *
> + ****************************************************************/
> +package org.apache.james.imap.message.request;
> +
> +import org.apache.james.imap.api.ContinuationReader;
> +import org.apache.james.imap.api.ImapCommand;
> +
> +public class IdleRequest extends AbstractImapRequest {
> +
> +    private final ContinuationReader reader;
> +
> +    public IdleRequest(ImapCommand command, ContinuationReader reader, 
> String tag) {
> +        super(tag, command);
> +        this.reader = reader;
> +    }
> +
> +    public ContinuationReader getContinuationReader() {
> +        return reader;
> +    }
> +}
>
> Added: 
> james/imap/trunk/message/src/main/java/org/apache/james/imap/message/response/ContinuationResponse.java
> URL: 
> http://svn.apache.org/viewvc/james/imap/trunk/message/src/main/java/org/apache/james/imap/message/response/ContinuationResponse.java?rev=1049622&view=auto
> ==============================================================================
> --- 
> james/imap/trunk/message/src/main/java/org/apache/james/imap/message/response/ContinuationResponse.java
>  (added)
> +++ 
> james/imap/trunk/message/src/main/java/org/apache/james/imap/message/response/ContinuationResponse.java
>  Wed Dec 15 16:00:25 2010
> @@ -0,0 +1,50 @@
> +/****************************************************************
> + * Licensed to the Apache Software Foundation (ASF) under one   *
> + * or more contributor license agreements.  See the NOTICE file *
> + * distributed with this work for additional information        *
> + * regarding copyright ownership.  The ASF licenses this file   *
> + * to you under the Apache License, Version 2.0 (the            *
> + * "License"); you may not use this file except in compliance   *
> + * with the License.  You may obtain a copy of the License at   *
> + *                                                              *
> + *   http://www.apache.org/licenses/LICENSE-2.0                 *
> + *                                                              *
> + * Unless required by applicable law or agreed to in writing,   *
> + * software distributed under the License is distributed on an  *
> + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY       *
> + * KIND, either express or implied.  See the License for the    *
> + * specific language governing permissions and limitations      *
> + * under the License.                                           *
> + ****************************************************************/
> +
> +package org.apache.james.imap.message.response;
> +
> +import org.apache.james.imap.api.display.HumanReadableText;
> +import org.apache.james.imap.api.message.response.ImapResponseMessage;
> +
> +public class ContinuationResponse implements ImapResponseMessage {
> +
> +    private final String data;
> +
> +    private final HumanReadableText textKey;
> +
> +    public ContinuationResponse(final String data) {
> +        super();
> +        this.data = data;
> +        this.textKey = null;
> +    }
> +
> +    public ContinuationResponse(final HumanReadableText textKey) {
> +        super();
> +        this.data = null;
> +        this.textKey = textKey;
> +    }
> +
> +    public String getData() {
> +        return data;
> +    }
> +
> +    public HumanReadableText getTextKey() {
> +        return textKey;
> +    }
> +}
>
> Modified: 
> james/imap/trunk/message/src/test/java/org/apache/james/imap/encode/MockImapResponseWriter.java
> URL: 
> http://svn.apache.org/viewvc/james/imap/trunk/message/src/test/java/org/apache/james/imap/encode/MockImapResponseWriter.java?rev=1049622&r1=1049621&r2=1049622&view=diff
> ==============================================================================
> --- 
> james/imap/trunk/message/src/test/java/org/apache/james/imap/encode/MockImapResponseWriter.java
>  (original)
> +++ 
> james/imap/trunk/message/src/test/java/org/apache/james/imap/encode/MockImapResponseWriter.java
>  Wed Dec 15 16:00:25 2010
> @@ -279,6 +279,17 @@ public class MockImapResponseWriter impl
>
>     }
>
> +    public static class ContinuationOperation {
> +        public boolean equals(Object obj) {
> +            return obj instanceof ContinuationOperation;
> +        }
> +
> +        public int hashCode() {
> +            return 3;
> +        }
> +
> +    }
> +
>     public void closeParen() {
>         operations.add(new BracketOperation(false, false));
>     }
> @@ -442,4 +453,8 @@ public class MockImapResponseWriter impl
>
>     public void space() {
>     }
> +
> +    public void continuation(String message) {
> +        operations.add(new ContinuationOperation());
> +    }
>  }
>
> Modified: 
> james/imap/trunk/message/src/test/java/org/apache/james/imap/encode/base/ByteImapResponseWriter.java
> URL: 
> http://svn.apache.org/viewvc/james/imap/trunk/message/src/test/java/org/apache/james/imap/encode/base/ByteImapResponseWriter.java?rev=1049622&r1=1049621&r2=1049622&view=diff
> ==============================================================================
> --- 
> james/imap/trunk/message/src/test/java/org/apache/james/imap/encode/base/ByteImapResponseWriter.java
>  (original)
> +++ 
> james/imap/trunk/message/src/test/java/org/apache/james/imap/encode/base/ByteImapResponseWriter.java
>  Wed Dec 15 16:00:25 2010
> @@ -204,4 +204,8 @@ public class ByteImapResponseWriter impl
>     public void quoteUpperCaseAscii(String message) {
>         upperCaseAscii(message, true);
>     }
> +
> +    public void continuation(String message) throws IOException {
> +        writer.print(CONTINUATION + SP + message);
> +    }
>  }
>
> Modified: 
> james/imap/trunk/processor/src/main/java/org/apache/james/imap/processor/DefaultProcessorChain.java
> URL: 
> http://svn.apache.org/viewvc/james/imap/trunk/processor/src/main/java/org/apache/james/imap/processor/DefaultProcessorChain.java?rev=1049622&r1=1049621&r2=1049622&view=diff
> ==============================================================================
> --- 
> james/imap/trunk/processor/src/main/java/org/apache/james/imap/processor/DefaultProcessorChain.java
>  (original)
> +++ 
> james/imap/trunk/processor/src/main/java/org/apache/james/imap/processor/DefaultProcessorChain.java
>  Wed Dec 15 16:00:25 2010
> @@ -84,8 +84,10 @@ public class DefaultProcessorChain {
>                 appendProcessor, mailboxManager, statusResponseFactory);
>         final NoopProcessor noopProcessor = new NoopProcessor(storeProcessor,
>                 mailboxManager, statusResponseFactory);
> +        final IdleProcessor idleProcessor = new IdleProcessor(noopProcessor,
> +                mailboxManager, statusResponseFactory);
>         final StatusProcessor statusProcessor = new StatusProcessor(
> -                noopProcessor, mailboxManager, statusResponseFactory);
> +                idleProcessor, mailboxManager, statusResponseFactory);
>         final LSubProcessor lsubProcessor = new LSubProcessor(statusProcessor,
>                 mailboxManager, subscriptionManager, statusResponseFactory);
>         final ListProcessor listProcessor = new ListProcessor(lsubProcessor,
> @@ -97,6 +99,7 @@ public class DefaultProcessorChain {
>         final NamespaceProcessor namespaceProcessor = new NamespaceProcessor(
>                 selectProcessor, mailboxManager, statusResponseFactory);
>
> +        capabilityProcessor.addProcessor(idleProcessor);
>         capabilityProcessor.addProcessor(namespaceProcessor);
>
>         final ImapProcessor fetchProcessor = new 
> FetchProcessor(namespaceProcessor,
>
> Added: 
> james/imap/trunk/processor/src/main/java/org/apache/james/imap/processor/IdleProcessor.java
> URL: 
> http://svn.apache.org/viewvc/james/imap/trunk/processor/src/main/java/org/apache/james/imap/processor/IdleProcessor.java?rev=1049622&view=auto
> ==============================================================================
> --- 
> james/imap/trunk/processor/src/main/java/org/apache/james/imap/processor/IdleProcessor.java
>  (added)
> +++ 
> james/imap/trunk/processor/src/main/java/org/apache/james/imap/processor/IdleProcessor.java
>  Wed Dec 15 16:00:25 2010
> @@ -0,0 +1,134 @@
> +/****************************************************************
> + * Licensed to the Apache Software Foundation (ASF) under one   *
> + * or more contributor license agreements.  See the NOTICE file *
> + * distributed with this work for additional information        *
> + * regarding copyright ownership.  The ASF licenses this file   *
> + * to you under the Apache License, Version 2.0 (the            *
> + * "License"); you may not use this file except in compliance   *
> + * with the License.  You may obtain a copy of the License at   *
> + *                                                              *
> + *   http://www.apache.org/licenses/LICENSE-2.0                 *
> + *                                                              *
> + * Unless required by applicable law or agreed to in writing,   *
> + * software distributed under the License is distributed on an  *
> + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY       *
> + * KIND, either express or implied.  See the License for the    *
> + * specific language governing permissions and limitations      *
> + * under the License.                                           *
> + ****************************************************************/
> +
> +package org.apache.james.imap.processor;
> +
> +import static org.apache.james.imap.api.ImapConstants.SUPPORTS_IDLE;
> +
> +import java.io.IOException;
> +import java.util.Arrays;
> +import java.util.List;
> +import java.util.concurrent.atomic.AtomicBoolean;
> +
> +import org.apache.james.imap.api.ContinuationReader;
> +import org.apache.james.imap.api.ImapCommand;
> +import org.apache.james.imap.api.ImapMessage;
> +import org.apache.james.imap.api.display.HumanReadableText;
> +import org.apache.james.imap.api.message.request.ImapRequest;
> +import org.apache.james.imap.api.message.response.StatusResponse;
> +import org.apache.james.imap.api.message.response.StatusResponseFactory;
> +import org.apache.james.imap.api.process.ImapProcessor;
> +import org.apache.james.imap.api.process.ImapSession;
> +import org.apache.james.imap.message.request.IdleRequest;
> +import org.apache.james.imap.message.response.ContinuationResponse;
> +import org.apache.james.imap.processor.base.ImapSessionUtils;
> +import org.apache.james.mailbox.MailboxException;
> +import org.apache.james.mailbox.MailboxListener;
> +import org.apache.james.mailbox.MailboxManager;
> +import org.apache.james.mailbox.MailboxSession;
> +
> +public class IdleProcessor extends AbstractMailboxProcessor implements 
> CapabilityImplementingProcessor {
> +
> +    private final StatusResponseFactory factory;
> +
> +    public IdleProcessor(final ImapProcessor next, final MailboxManager 
> mailboxManager,
> +            final StatusResponseFactory factory) {
> +        super(next, mailboxManager, factory);
> +
> +        this.factory = factory;
> +    }
> +
> +    protected boolean isAcceptable(ImapMessage message) {
> +        return (message instanceof IdleRequest);
> +    }
> +
> +    protected void doProcess(ImapRequest message, ImapSession session,
> +            String tag, ImapCommand command, Responder responder) {
> +
> +        try {
> +            IdleRequest request = (IdleRequest) message;
> +            ContinuationReader reader = request.getContinuationReader();
> +
> +            responder.respond(new 
> ContinuationResponse(HumanReadableText.IDLING));
> +            unsolicitedResponses(session, responder, false);
> +
> +            MailboxManager mailboxManager = getMailboxManager();
> +            MailboxSession mailboxSession = 
> ImapSessionUtils.getMailboxSession(session);
> +            AtomicBoolean closed = new AtomicBoolean(false);
> +
> +            String line = null;
> +            try {
> +                mailboxManager.addListener(session.getSelected().getPath(),
> +                        new IdleMailboxListener(closed, session, responder), 
> mailboxSession);
> +
> +                line = reader.readContinuation();
> +            } finally {
> +                synchronized (session) {
> +                    closed.set(true);
> +                }
> +            }
> +            if (!"DONE".equals(line.toUpperCase())) {
> +                StatusResponse response = factory.taggedBad(tag, command,
> +                        HumanReadableText.INVALID_COMMAND);
> +                responder.respond(response);
> +            } else {
> +                okComplete(command, tag, responder);
> +            }
> +        } catch (IOException e) {
> +            // TODO: What should we do here?
> +            no(command, tag, responder, 
> HumanReadableText.GENERIC_FAILURE_DURING_PROCESSING);
> +        } catch (MailboxException e) {
> +            // TODO: What should we do here?
> +            no(command, tag, responder, 
> HumanReadableText.GENERIC_FAILURE_DURING_PROCESSING);
> +        }
> +    }
> +
> +    public List<String> getImplementedCapabilities(ImapSession session) {
> +        return Arrays.asList(SUPPORTS_IDLE);
> +    }
> +
> +    private class IdleMailboxListener implements MailboxListener {
> +
> +        private final AtomicBoolean closed;
> +        private final ImapSession session;
> +        private final Responder responder;
> +
> +        public IdleMailboxListener(AtomicBoolean closed, ImapSession 
> session, Responder responder) {
> +            this.closed = closed;
> +            this.session = session;
> +            this.responder = responder;
> +        }
> +
> +        public void event(Event event) {
> +            synchronized (session) {
> +                if (isClosed()) {
> +                    return;
> +                }
> +                if (event instanceof Added || event instanceof Expunged || 
> event instanceof FlagsUpdated) {
> +                    unsolicitedResponses(session, responder, false);
> +                }
> +            }
> +        }
> +
> +        public boolean isClosed() {
> +            return closed.get();
> +        }
> +
> +    }
> +}
>
>
>
> ---------------------------------------------------------------------
> To unsubscribe, e-mail: server-dev-unsubscr...@james.apache.org
> For additional commands, e-mail: server-dev-h...@james.apache.org
>
>

---------------------------------------------------------------------
To unsubscribe, e-mail: server-dev-unsubscr...@james.apache.org
For additional commands, e-mail: server-dev-h...@james.apache.org

Reply via email to