Author: norman
Date: Tue Jan 18 18:50:17 2011
New Revision: 1060532

URL: http://svn.apache.org/viewvc?rev=1060532&view=rev
Log:
switch to "real NIO" for imapserver

Added:
    
james/server/trunk/imapserver/src/main/java/org/apache/james/imapserver/netty/ChannelImapResponseWriter.java
    
james/server/trunk/imapserver/src/main/java/org/apache/james/imapserver/netty/ImapChannelUpstreamHandler.java
      - copied, changed from r1060047, 
james/server/trunk/imapserver/src/main/java/org/apache/james/imapserver/netty/ImapStreamChannelUpstreamHandler.java
    
james/server/trunk/imapserver/src/main/java/org/apache/james/imapserver/netty/ImapLineHandlerAdapter.java
    
james/server/trunk/imapserver/src/main/java/org/apache/james/imapserver/netty/ImapRequestFrameDecoder.java
    
james/server/trunk/imapserver/src/main/java/org/apache/james/imapserver/netty/NettyImapRequestLineReader.java
    
james/server/trunk/imapserver/src/main/java/org/apache/james/imapserver/netty/NettyImapSession.java
    
james/server/trunk/imapserver/src/main/java/org/apache/james/imapserver/netty/NotEnoughDataException.java
Removed:
    
james/server/trunk/imapserver/src/main/java/org/apache/james/imapserver/netty/BlockingChannelBufferInputStream.java
    
james/server/trunk/imapserver/src/main/java/org/apache/james/imapserver/netty/ChannelOutputStream.java
    
james/server/trunk/imapserver/src/main/java/org/apache/james/imapserver/netty/ImapStreamChannelUpstreamHandler.java
    
james/server/trunk/imapserver/src/main/java/org/apache/james/imapserver/netty/StreamHandler.java
Modified:
    
james/server/trunk/imapserver/src/main/java/org/apache/james/imapserver/netty/IMAPServer.java

Added: 
james/server/trunk/imapserver/src/main/java/org/apache/james/imapserver/netty/ChannelImapResponseWriter.java
URL: 
http://svn.apache.org/viewvc/james/server/trunk/imapserver/src/main/java/org/apache/james/imapserver/netty/ChannelImapResponseWriter.java?rev=1060532&view=auto
==============================================================================
--- 
james/server/trunk/imapserver/src/main/java/org/apache/james/imapserver/netty/ChannelImapResponseWriter.java
 (added)
+++ 
james/server/trunk/imapserver/src/main/java/org/apache/james/imapserver/netty/ChannelImapResponseWriter.java
 Tue Jan 18 18:50:17 2011
@@ -0,0 +1,81 @@
+/****************************************************************
+ * 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.imapserver.netty;
+
+import java.io.IOException;
+import java.nio.ByteBuffer;
+import java.nio.channels.Channels;
+import java.nio.channels.WritableByteChannel;
+
+import org.apache.james.imap.main.AbstractImapResponseWriter;
+import org.apache.james.imap.message.response.Literal;
+import org.jboss.netty.buffer.ChannelBuffer;
+import org.jboss.netty.buffer.ChannelBufferOutputStream;
+import org.jboss.netty.buffer.ChannelBuffers;
+import org.jboss.netty.channel.Channel;
+
+public class ChannelImapResponseWriter extends AbstractImapResponseWriter{
+
+    private Channel channel;
+    public ChannelImapResponseWriter(Channel channel) {
+        this.channel = channel;
+    }
+    
+    /*
+     * (non-Javadoc)
+     * @see 
org.apache.james.imap.main.AbstractImapResponseWriter#write(java.nio.ByteBuffer)
+     */
+    protected void write(ByteBuffer buffer) throws IOException {
+        channel.write(ChannelBuffers.wrappedBuffer(buffer));
+    }
+
+    /*
+     * (non-Javadoc)
+     * @see 
org.apache.james.imap.main.AbstractImapResponseWriter#write(org.apache.james.imap.message.response.Literal)
+     */
+    protected void write(Literal literal) throws IOException {
+        ChannelBuffer buf = ChannelBuffers.buffer((int)literal.size());
+        literal.writeTo(Channels.newChannel(new 
ChannelBufferOutputStream(buf)));
+        channel.write(buf);
+    }
+
+    
+    private final class ChannelWritableByteChannel implements 
WritableByteChannel {
+
+        public void close() throws IOException {
+            // do nothing
+        }
+
+        public boolean isOpen() {
+            return channel.isOpen();
+        }
+
+        /*
+         * (non-Javadoc)
+         * @see 
java.nio.channels.WritableByteChannel#write(java.nio.ByteBuffer)
+         */
+        public int write(ByteBuffer src) throws IOException {
+            int size = src.limit();
+            channel.write(ChannelBuffers.wrappedBuffer(src));
+            return size;
+        }
+        
+    }
+}

Modified: 
james/server/trunk/imapserver/src/main/java/org/apache/james/imapserver/netty/IMAPServer.java
URL: 
http://svn.apache.org/viewvc/james/server/trunk/imapserver/src/main/java/org/apache/james/imapserver/netty/IMAPServer.java?rev=1060532&r1=1060531&r2=1060532&view=diff
==============================================================================
--- 
james/server/trunk/imapserver/src/main/java/org/apache/james/imapserver/netty/IMAPServer.java
 (original)
+++ 
james/server/trunk/imapserver/src/main/java/org/apache/james/imapserver/netty/IMAPServer.java
 Tue Jan 18 18:50:17 2011
@@ -29,7 +29,6 @@ import org.apache.james.imap.api.ImapCon
 import org.apache.james.imap.api.process.ImapProcessor;
 import org.apache.james.imap.decode.ImapDecoder;
 import org.apache.james.imap.encode.ImapEncoder;
-import org.apache.james.imap.main.ImapRequestStreamHandler;
 import org.apache.james.protocols.impl.ChannelGroupHandler;
 import org.apache.james.protocols.impl.TimeoutHandler;
 import org.apache.james.protocols.lib.netty.AbstractConfigurableAsyncServer;
@@ -121,7 +120,8 @@ public class IMAPServer extends Abstract
                 
                 // Add the text line decoder which limit the max line length, 
don't strip the delimiter and use CRLF as delimiter
                 pipeline.addLast("framer", new 
DelimiterBasedFrameDecoder(MAX_LINE_LENGTH, false, Delimiters.lineDelimiter()));
-               
+                pipeline.addLast("requestDecoder", new 
ImapRequestFrameDecoder(decoder));
+
                 
                 if (isSSLSocket()) {
                     // We need to set clientMode to false.
@@ -133,12 +133,11 @@ public class IMAPServer extends Abstract
                 }
                 pipeline.addLast("connectionCountHandler", 
getConnectionCountHandler());
                 
-                final ImapRequestStreamHandler handler = new 
ImapRequestStreamHandler(decoder, processor, encoder);
                 
                 if (isStartTLSSupported())  {
-                    pipeline.addLast("coreHandler",  new 
ImapStreamChannelUpstreamHandler(hello, handler, getLogger(), timer, 
IMAPServer.this.getTimeout(), compress, getSSLContext(), 
getEnabledCipherSuites()));
+                    pipeline.addLast("coreHandler",  new 
ImapChannelUpstreamHandler(hello, processor, encoder, getLogger(), compress, 
getSSLContext(), getEnabledCipherSuites()));
                 } else {
-                    pipeline.addLast("coreHandler",  new 
ImapStreamChannelUpstreamHandler(hello, handler, getLogger(), timer, 
IMAPServer.this.getTimeout(), compress));
+                    pipeline.addLast("coreHandler",  new 
ImapChannelUpstreamHandler(hello, processor, encoder, getLogger(), compress));
                 }
                 
                 return pipeline;

Copied: 
james/server/trunk/imapserver/src/main/java/org/apache/james/imapserver/netty/ImapChannelUpstreamHandler.java
 (from r1060047, 
james/server/trunk/imapserver/src/main/java/org/apache/james/imapserver/netty/ImapStreamChannelUpstreamHandler.java)
URL: 
http://svn.apache.org/viewvc/james/server/trunk/imapserver/src/main/java/org/apache/james/imapserver/netty/ImapChannelUpstreamHandler.java?p2=james/server/trunk/imapserver/src/main/java/org/apache/james/imapserver/netty/ImapChannelUpstreamHandler.java&p1=james/server/trunk/imapserver/src/main/java/org/apache/james/imapserver/netty/ImapStreamChannelUpstreamHandler.java&r1=1060047&r2=1060532&rev=1060532&view=diff
==============================================================================
--- 
james/server/trunk/imapserver/src/main/java/org/apache/james/imapserver/netty/ImapStreamChannelUpstreamHandler.java
 (original)
+++ 
james/server/trunk/imapserver/src/main/java/org/apache/james/imapserver/netty/ImapChannelUpstreamHandler.java
 Tue Jan 18 18:50:17 2011
@@ -20,17 +20,21 @@ package org.apache.james.imapserver.nett
 
 import java.io.FilterOutputStream;
 import java.io.IOException;
-import java.io.InputStream;
 import java.io.OutputStream;
 import java.net.InetSocketAddress;
-import java.util.concurrent.TimeUnit;
 
 import javax.net.ssl.SSLContext;
 
 import org.apache.commons.logging.Log;
-import org.apache.james.imap.api.ImapConstants;
-import org.apache.james.imap.main.ImapRequestStreamHandler;
-import org.apache.james.imap.main.ImapSessionImpl;
+import org.apache.james.imap.api.ImapMessage;
+import org.apache.james.imap.api.ImapSessionState;
+import org.apache.james.imap.api.process.ImapProcessor;
+import org.apache.james.imap.api.process.ImapSession;
+import org.apache.james.imap.encode.ImapEncoder;
+import org.apache.james.imap.encode.ImapResponseComposer;
+import org.apache.james.imap.encode.base.ImapResponseComposerImpl;
+import org.apache.james.imap.main.ResponseEncoder;
+import org.apache.james.protocols.impl.ChannelAttributeSupport;
 import org.apache.james.protocols.impl.SessionLog;
 import org.jboss.netty.buffer.ChannelBuffer;
 import org.jboss.netty.buffer.ChannelBuffers;
@@ -38,24 +42,21 @@ import org.jboss.netty.channel.Channel;
 import org.jboss.netty.channel.ChannelHandlerContext;
 import org.jboss.netty.channel.ChannelStateEvent;
 import org.jboss.netty.channel.ExceptionEvent;
-import org.jboss.netty.handler.codec.compression.ZlibDecoder;
-import org.jboss.netty.handler.codec.compression.ZlibEncoder;
-import org.jboss.netty.handler.codec.compression.ZlibWrapper;
+import org.jboss.netty.channel.MessageEvent;
+import org.jboss.netty.channel.SimpleChannelUpstreamHandler;
 import org.jboss.netty.handler.ssl.SslHandler;
-import org.jboss.netty.util.Timer;
 
 /**
  * {@link StreamHandler} which handles IMAP
  * 
  *
  */
-public class ImapStreamChannelUpstreamHandler extends StreamHandler{
+public class ImapChannelUpstreamHandler extends SimpleChannelUpstreamHandler 
implements ChannelAttributeSupport{
 
     private final Log logger;
 
     private final String hello;
 
-    private final ImapRequestStreamHandler handler;
 
     private String[] enabledCipherSuites;
 
@@ -63,19 +64,20 @@ public class ImapStreamChannelUpstreamHa
 
     private boolean compress;
 
-    private final static String IMAP_SESSION = "IMAP_SESSION"; 
-    private final static String BUFFERED_OUT = "BUFFERED_OUT";
-    
-    public ImapStreamChannelUpstreamHandler(final String hello, final 
ImapRequestStreamHandler handler, final Log logger, final Timer timer, final 
long readTimeout, boolean compress) {
-        this(hello, handler, logger, timer, readTimeout, compress, null, null);
+    private ImapProcessor processor;
+
+    private ImapEncoder encoder;
+
+    public ImapChannelUpstreamHandler(final String hello, final ImapProcessor 
processor, ImapEncoder encoder, final Log logger,  boolean compress) {
+        this(hello, processor, encoder, logger, compress, null, null);
     }
     
 
-    public ImapStreamChannelUpstreamHandler(final String hello, final 
ImapRequestStreamHandler handler, final Log logger, final Timer timer, final 
long readTimeout, boolean compress, SSLContext context, String[] 
enabledCipherSuites) {
-        super(timer, readTimeout, TimeUnit.SECONDS);
+    public ImapChannelUpstreamHandler(final String hello, final ImapProcessor 
processor, ImapEncoder encoder, final Log logger, boolean compress, SSLContext 
context, String[] enabledCipherSuites) {
         this.logger = logger;
         this.hello = hello;
-        this.handler = handler;
+        this.processor = processor;
+        this.encoder = encoder;
         this.context = context;
         this.enabledCipherSuites = enabledCipherSuites;
         this.compress = compress;
@@ -84,98 +86,12 @@ public class ImapStreamChannelUpstreamHa
     private Log getLogger(Channel channel) {
         return new SessionLog(""+channel.getId(), logger);
     }
-    @Override
-    protected void processStreamIo(final ChannelHandlerContext ctx, final 
InputStream in, final OutputStream out) {
-        final ImapSessionImpl imapSession = (ImapSessionImpl) 
getAttachment(ctx).get(IMAP_SESSION);
-        Channel channel = ctx.getChannel();
-       
-        // Store the stream as attachment
-        OutputStream bufferedOut = new StartTLSOutputStream(out);
-        getAttachment(ctx).put(BUFFERED_OUT, bufferedOut);
-
-        
-        // handle requests in a loop
-        while (channel.isConnected() && handler.handleRequest(in, bufferedOut, 
imapSession));
-        
-        if (imapSession != null) imapSession.logout();
-        
-        getLogger(ctx.getChannel()).debug("Thread execution complete for 
session " + channel.getId());
-
-        channel.close();
-    }
-    
 
     @Override
     public void channelBound(final ChannelHandlerContext ctx, 
ChannelStateEvent e) throws Exception {
         
-        // create the imap session and store it in the IoSession for later 
usage
-        ImapSessionImpl imapsession = new ImapSessionImpl() {
-
-            @Override
-            public boolean startTLS() {
-                if (supportStartTLS() == false) return false; 
-                
-              
-                OutputStream out =  
(OutputStream)getAttachment(ctx).get(KEY_OUT);
-                try {
-                    out.flush();
-                } catch (IOException e) {
-                    getLog().info("Unable to start TLS", e);
-                    return false;
-                }
-                
-                
-                // enable buffering of the stream
-                
((StartTLSOutputStream)getAttachment(ctx).get(BUFFERED_OUT)).bufferTillCRLF();
-
-                SslHandler filter = new SslHandler(context.createSSLEngine(), 
true);
-                filter.getEngine().setUseClientMode(false);
-                if (enabledCipherSuites != null && enabledCipherSuites.length 
> 0) {
-                    
filter.getEngine().setEnabledCipherSuites(enabledCipherSuites);
-                }
-                if (ctx.getPipeline().get("zlibDecoder") == null) {
-                    ctx.getPipeline().addFirst("sslHandler", filter);
-                } else {
-                    ctx.getPipeline().addAfter("zlibDecoder", "sslHandler", 
filter);
-
-                }
-
-                return true;
-            }
-
-            @Override
-            public boolean supportStartTLS() {
-                 return context != null;
-            }
-
-            @Override
-            public boolean isCompressionSupported() {
-                return compress;
-            }
-
-            @Override
-            public boolean startCompression() {
-                ctx.getChannel().setReadable(false);
-                // enable buffering of the stream
-                OutputStream out =  
(OutputStream)getAttachment(ctx).get(KEY_OUT);
-                try {
-                    out.flush();
-                } catch (IOException e) {
-                    getLog().info("Unable to start compression", e);
-                    return false;
-                }                
-                ctx.getPipeline().addFirst("zlibDecoder", new 
ZlibDecoder(ZlibWrapper.NONE));
-                ctx.getPipeline().addFirst("zlibEncoder", new 
ZlibEncoder(ZlibWrapper.NONE, 5));
-
-                ctx.getChannel().setReadable(true);
-
-                return true;
-            }
-            
-        };
-        imapsession.setLog(getLogger(ctx.getChannel()));
-        
-        getAttachment(ctx).put(IMAP_SESSION, imapsession);
+        ImapSession imapsession = new NettyImapSession(ctx, logger, context, 
enabledCipherSuites, compress);
+        attributes.set(ctx.getChannel(), imapsession);
         super.channelBound(ctx, e);
     }
 
@@ -194,8 +110,13 @@ public class ImapStreamChannelUpstreamHa
         InetSocketAddress address = (InetSocketAddress) 
ctx.getChannel().getRemoteAddress();
         getLogger(ctx.getChannel()).info("Connection established from " + 
address.getHostName() + " (" + address.getAddress().getHostAddress()+ ")");
 
+        ImapResponseComposer response = new ImapResponseComposerImpl(
+                new ChannelImapResponseWriter(ctx.getChannel()));
+        ctx.setAttachment(response);
+        
         // write hello to client
-        
ctx.getChannel().write(ChannelBuffers.copiedBuffer((ImapConstants.UNTAGGED + " 
OK " + hello +" " + new String(ImapConstants.BYTES_LINE_END)).getBytes()));
+        response.hello(hello);
+        
//ctx.getChannel().write(ChannelBuffers.copiedBuffer((ImapConstants.UNTAGGED + 
" OK " + hello +" " + new String(ImapConstants.BYTES_LINE_END)).getBytes()));
         
         super.channelConnected(ctx, e);
         
@@ -206,7 +127,7 @@ public class ImapStreamChannelUpstreamHa
         getLogger(ctx.getChannel()).debug("Error while processing imap 
request" ,e.getCause());
         
         // logout on error not sure if that is the best way to handle it
-        final ImapSessionImpl imapSession = (ImapSessionImpl) 
getAttachment(ctx).get(IMAP_SESSION);     
+        final ImapSession imapSession = (ImapSession) 
attributes.get(ctx.getChannel());    
         if (imapSession != null) imapSession.logout();
 
         // just close the channel now!
@@ -215,6 +136,35 @@ public class ImapStreamChannelUpstreamHa
         super.exceptionCaught(ctx, e);
     }
     
+    @Override
+    public void messageReceived(ChannelHandlerContext ctx, MessageEvent e) 
throws Exception {
+        ImapSession session = (ImapSession) attributes.get(ctx.getChannel());
+        ImapResponseComposer response = (ImapResponseComposer) 
ctx.getAttachment();
+        ImapMessage message = (ImapMessage) e.getMessage();
+
+        
+        final ResponseEncoder responseEncoder = new ResponseEncoder(encoder,
+                response, session);
+        processor.process(message, responseEncoder, session);
+        
+        if (session.getState() == ImapSessionState.LOGOUT) {
+            ctx.getChannel().close();
+        }
+        final IOException failure = responseEncoder.getFailure();
+        
+        if (failure != null) {
+            final Log logger = session.getLog();
+            logger.info(failure.getMessage());
+            if (logger.isDebugEnabled()) {
+                logger.debug("Failed to write " + message, failure);
+            }
+            throw failure;
+        }
+        
+        
+        super.messageReceived(ctx, e);
+    }
+
     /**
      * Because Netty {@link SslHandler} need to NOT encrypt the first response 
send to client this {@link FilterOutputStream} is needed. It
      * buffer the data till the complete response was written to the stream 
(searching for the CRLF). 

Added: 
james/server/trunk/imapserver/src/main/java/org/apache/james/imapserver/netty/ImapLineHandlerAdapter.java
URL: 
http://svn.apache.org/viewvc/james/server/trunk/imapserver/src/main/java/org/apache/james/imapserver/netty/ImapLineHandlerAdapter.java?rev=1060532&view=auto
==============================================================================
--- 
james/server/trunk/imapserver/src/main/java/org/apache/james/imapserver/netty/ImapLineHandlerAdapter.java
 (added)
+++ 
james/server/trunk/imapserver/src/main/java/org/apache/james/imapserver/netty/ImapLineHandlerAdapter.java
 Tue Jan 18 18:50:17 2011
@@ -0,0 +1,42 @@
+/****************************************************************
+ * 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.imapserver.netty;
+
+import org.apache.james.imap.api.process.ImapLineHandler;
+import org.apache.james.imap.api.process.ImapSession;
+import org.apache.james.protocols.impl.ChannelAttributeSupport;
+import org.jboss.netty.buffer.ChannelBuffer;
+import org.jboss.netty.channel.ChannelHandlerContext;
+import org.jboss.netty.channel.MessageEvent;
+import org.jboss.netty.channel.SimpleChannelUpstreamHandler;
+
+public class ImapLineHandlerAdapter extends SimpleChannelUpstreamHandler 
implements ChannelAttributeSupport{
+
+    private ImapLineHandler lineHandler;
+
+    public ImapLineHandlerAdapter(ImapLineHandler lineHandler) {
+        this.lineHandler = lineHandler;
+    }
+    
+    @Override
+    public void messageReceived(ChannelHandlerContext ctx, MessageEvent e) 
throws Exception {
+        lineHandler.onLine((ImapSession) attributes.get(ctx.getChannel()), 
((ChannelBuffer)e.getMessage()).array());
+    }
+
+}

Added: 
james/server/trunk/imapserver/src/main/java/org/apache/james/imapserver/netty/ImapRequestFrameDecoder.java
URL: 
http://svn.apache.org/viewvc/james/server/trunk/imapserver/src/main/java/org/apache/james/imapserver/netty/ImapRequestFrameDecoder.java?rev=1060532&view=auto
==============================================================================
--- 
james/server/trunk/imapserver/src/main/java/org/apache/james/imapserver/netty/ImapRequestFrameDecoder.java
 (added)
+++ 
james/server/trunk/imapserver/src/main/java/org/apache/james/imapserver/netty/ImapRequestFrameDecoder.java
 Tue Jan 18 18:50:17 2011
@@ -0,0 +1,77 @@
+/****************************************************************
+ * 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.imapserver.netty;
+
+import org.apache.james.imap.api.ImapMessage;
+import org.apache.james.imap.api.process.ImapSession;
+import org.apache.james.imap.decode.ImapDecoder;
+import org.apache.james.imap.decode.ImapRequestLineReader;
+import org.apache.james.protocols.impl.ChannelAttributeSupport;
+import org.jboss.netty.buffer.ChannelBuffer;
+import org.jboss.netty.channel.Channel;
+import org.jboss.netty.channel.ChannelHandlerContext;
+import org.jboss.netty.handler.codec.frame.FrameDecoder;
+
+/**
+ * {@link FrameDecoder} which will decode via and {@link ImapDecoder} instance
+ *
+ */
+public class ImapRequestFrameDecoder extends FrameDecoder implements 
ChannelAttributeSupport{
+
+    private ImapDecoder decoder;
+
+    public ImapRequestFrameDecoder(ImapDecoder decoder) {
+        this.decoder = decoder;
+    }
+    
+    @Override
+    protected Object decode(ChannelHandlerContext ctx, Channel channel, 
ChannelBuffer buffer) throws Exception {
+        buffer.markReaderIndex();
+        
+        // check if we failed before and if we already know how much data we 
need to sucess next run
+        Object attachment = ctx.getAttachment();
+        if (attachment != null) {
+            int size = (Integer) attachment;
+            if (size != NotEnoughDataException.UNKNOWN_SIZE && size > 
buffer.readableBytes()) {
+                buffer.resetReaderIndex();
+                
+                return null;
+            }
+        }
+        
+        try {
+            ImapRequestLineReader reader = new 
NettyImapRequestLineReader(channel, buffer);
+            ImapMessage message = decoder.decode(reader, (ImapSession) 
attributes.get(channel));
+
+            // ok no errors found consume the rest of the line
+            reader.consumeLine();
+
+            ctx.setAttachment(null);
+            return message;
+        } catch (NotEnoughDataException e) {
+            // this exception was thrown because we don't have enough data yet 
+            int neededData = e.getDataSize();
+            ctx.setAttachment(neededData);
+            buffer.resetReaderIndex();
+            return null;
+        }
+    }
+
+}

Added: 
james/server/trunk/imapserver/src/main/java/org/apache/james/imapserver/netty/NettyImapRequestLineReader.java
URL: 
http://svn.apache.org/viewvc/james/server/trunk/imapserver/src/main/java/org/apache/james/imapserver/netty/NettyImapRequestLineReader.java?rev=1060532&view=auto
==============================================================================
--- 
james/server/trunk/imapserver/src/main/java/org/apache/james/imapserver/netty/NettyImapRequestLineReader.java
 (added)
+++ 
james/server/trunk/imapserver/src/main/java/org/apache/james/imapserver/netty/NettyImapRequestLineReader.java
 Tue Jan 18 18:50:17 2011
@@ -0,0 +1,80 @@
+/****************************************************************
+ * 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.imapserver.netty;
+
+import java.io.InputStream;
+
+import org.apache.james.imap.decode.DecodingException;
+import org.apache.james.imap.decode.ImapRequestLineReader;
+import org.jboss.netty.buffer.ChannelBuffer;
+import org.jboss.netty.buffer.ChannelBufferInputStream;
+import org.jboss.netty.buffer.ChannelBuffers;
+import org.jboss.netty.channel.Channel;
+
+public class NettyImapRequestLineReader extends ImapRequestLineReader{
+
+    private ChannelBuffer buffer;
+    private Channel channel;
+    private ChannelBuffer cRequest = 
ChannelBuffers.wrappedBuffer("+\r\n".getBytes());
+
+    public NettyImapRequestLineReader(Channel channel, ChannelBuffer buffer) {
+        this.buffer = buffer;
+        this.channel = channel;
+    }
+
+    /*
+     * (non-Javadoc)
+     * @see org.apache.james.imap.decode.ImapRequestLineReader#nextChar()
+     */
+    public char nextChar() throws DecodingException {
+        if (!nextSeen) {
+            int next = -1;
+
+            try {
+                next = buffer.readByte();
+            } catch (IndexOutOfBoundsException e) {
+                throw new NotEnoughDataException();
+            }
+
+            nextSeen = true;
+            nextChar = (char) next;
+        }
+        return nextChar;
+    }
+
+    /*
+     * (non-Javadoc)
+     * @see org.apache.james.imap.decode.ImapRequestLineReader#read(int)
+     */
+    public InputStream read(int size) throws DecodingException {
+        if (size > buffer.readableBytes()) {
+            throw new NotEnoughDataException(size);
+        }
+        return new ChannelBufferInputStream(buffer, size);
+    }
+
+    /*
+     * (non-Javadoc)
+     * @see 
org.apache.james.imap.decode.ImapRequestLineReader#commandContinuationRequest()
+     */
+    protected void commandContinuationRequest() throws DecodingException {
+        channel.write(cRequest);
+    }
+}

Added: 
james/server/trunk/imapserver/src/main/java/org/apache/james/imapserver/netty/NettyImapSession.java
URL: 
http://svn.apache.org/viewvc/james/server/trunk/imapserver/src/main/java/org/apache/james/imapserver/netty/NettyImapSession.java?rev=1060532&view=auto
==============================================================================
--- 
james/server/trunk/imapserver/src/main/java/org/apache/james/imapserver/netty/NettyImapSession.java
 (added)
+++ 
james/server/trunk/imapserver/src/main/java/org/apache/james/imapserver/netty/NettyImapSession.java
 Tue Jan 18 18:50:17 2011
@@ -0,0 +1,238 @@
+/****************************************************************
+ * 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.imapserver.netty;
+
+import java.util.HashMap;
+import java.util.Map;
+
+import javax.net.ssl.SSLContext;
+
+import org.apache.commons.logging.Log;
+import org.apache.james.imap.api.ImapSessionState;
+import org.apache.james.imap.api.process.ImapLineHandler;
+import org.apache.james.imap.api.process.ImapSession;
+import org.apache.james.imap.api.process.SelectedMailbox;
+import org.apache.james.protocols.impl.SessionLog;
+import org.jboss.netty.channel.ChannelHandlerContext;
+import org.jboss.netty.handler.codec.compression.ZlibDecoder;
+import org.jboss.netty.handler.codec.compression.ZlibEncoder;
+import org.jboss.netty.handler.codec.compression.ZlibWrapper;
+import org.jboss.netty.handler.ssl.SslHandler;
+
+public class NettyImapSession implements ImapSession{
+
+    private ImapSessionState state = ImapSessionState.NON_AUTHENTICATED;
+    private SelectedMailbox selectedMailbox;
+    private Map<String, Object> attributesByKey = new HashMap<String, 
Object>();
+    private SSLContext sslContext;
+    private String[] enabledCipherSuites;
+    private boolean compress;
+    private SessionLog log;
+    private ChannelHandlerContext context;
+    private int handlerCount;
+    
+    public NettyImapSession(ChannelHandlerContext context, Log log, SSLContext 
sslContext, String[] enabledCipherSuites, boolean compress) {
+        this.context = context;
+        this.log = new SessionLog(context.getChannel().getId() + "", log);
+        this.sslContext = sslContext;
+        this.enabledCipherSuites = enabledCipherSuites;
+        this.compress = compress;
+    }
+
+    /*
+     * (non-Javadoc)
+     * @see org.apache.james.imap.api.process.ImapSession#logout()
+     */
+    public void logout() {
+        closeMailbox();
+        state = ImapSessionState.LOGOUT;
+    }
+
+    /*
+     * (non-Javadoc)
+     * @see org.apache.james.imap.api.process.ImapSession#authenticated()
+     */
+    public void authenticated() {
+        this.state = ImapSessionState.AUTHENTICATED;
+    }
+
+    /*
+     * (non-Javadoc)
+     * @see org.apache.james.imap.api.process.ImapSession#deselect()
+     */
+    public void deselect() {
+        this.state = ImapSessionState.AUTHENTICATED;
+        closeMailbox();
+    }
+
+    /*
+     * (non-Javadoc)
+     * @see 
org.apache.james.imap.api.process.ImapSession#selected(org.apache.james.imap.api.process.SelectedMailbox)
+     */
+    public void selected(SelectedMailbox mailbox) {
+        this.state = ImapSessionState.SELECTED;
+        closeMailbox();
+        this.selectedMailbox = mailbox;
+    }
+
+    /*
+     * (non-Javadoc)
+     * @see org.apache.james.imap.api.process.ImapSession#getSelected()
+     */
+    public SelectedMailbox getSelected() {
+        return this.selectedMailbox;
+    }
+
+    /*
+     * (non-Javadoc)
+     * @see org.apache.james.imap.api.process.ImapSession#getState()
+     */
+    public ImapSessionState getState() {
+        return this.state;
+    }
+
+    private void closeMailbox() {
+        if (selectedMailbox != null) {
+            selectedMailbox.deselect();
+            selectedMailbox = null;
+        }
+    }
+
+    /*
+     * (non-Javadoc)
+     * @see 
org.apache.james.imap.api.process.ImapSession#getAttribute(java.lang.String)
+     */
+    public Object getAttribute(String key) {
+        final Object result = attributesByKey .get(key);
+        return result;
+    }
+
+    /*
+     * (non-Javadoc)
+     * @see 
org.apache.james.imap.api.process.ImapSession#setAttribute(java.lang.String, 
java.lang.Object)
+     */
+    public void setAttribute(String key, Object value) {
+        if (value == null) {
+            attributesByKey.remove(key);
+        } else {
+            attributesByKey.put(key, value);
+        }
+    }
+
+    /*
+     * (non-Javadoc)
+     * @see org.apache.james.imap.api.process.ImapSession#startTLS()
+     */
+    public boolean startTLS() {
+        if (supportStartTLS() == false) return false; 
+        
+        
+        /*
+        OutputStream out =  (OutputStream)getAttachment(ctx).get(KEY_OUT);
+        try {
+            out.flush();
+        } catch (IOException e) {
+            getLog().info("Unable to start TLS", e);
+            return false;
+        }
+        
+        
+        // enable buffering of the stream
+        
//((StartTLSOutputStream)getAttachment(ctx).get(BUFFERED_OUT)).bufferTillCRLF();
+*/
+        SslHandler filter = new SslHandler(sslContext.createSSLEngine(), 
false);
+        filter.getEngine().setUseClientMode(false);
+        if (enabledCipherSuites != null && enabledCipherSuites.length > 0) {
+            filter.getEngine().setEnabledCipherSuites(enabledCipherSuites);
+        }
+        if (context.getPipeline().get("zlibDecoder") == null) {
+            context.getPipeline().addFirst("sslHandler", filter);
+        } else {
+            context.getPipeline().addAfter("zlibDecoder", "sslHandler", 
filter);
+
+        }
+
+        return true;
+    }
+
+    /*
+     * (non-Javadoc)
+     * @see org.apache.james.imap.api.process.ImapSession#supportStartTLS()
+     */
+    public boolean supportStartTLS() {
+        return sslContext != null;
+    }
+
+    /*
+     * (non-Javadoc)
+     * @see 
org.apache.james.imap.api.process.ImapSession#isCompressionSupported()
+     */
+    public boolean isCompressionSupported() {
+        return compress;
+    }
+
+    /*
+     * (non-Javadoc)
+     * @see org.apache.james.imap.api.process.ImapSession#startCompression()
+     */
+    public boolean startCompression() {
+        context.getChannel().setReadable(false);
+        /*
+        // enable buffering of the stream
+        OutputStream out =  (OutputStream)getAttachment(ctx).get(KEY_OUT);
+        try {
+            out.flush();
+        } catch (IOException e) {
+            getLog().info("Unable to start compression", e);
+            return false;
+        }  
+        */              
+        context.getPipeline().addFirst("zlibDecoder", new 
ZlibDecoder(ZlibWrapper.NONE));
+        context.getPipeline().addFirst("zlibEncoder", new 
ZlibEncoder(ZlibWrapper.NONE, 5));
+
+        context.getChannel().setReadable(true);
+
+        return true;
+    }
+
+    /*
+     * (non-Javadoc)
+     * @see 
org.apache.james.imap.api.process.ImapSession#pushLineHandler(org.apache.james.imap.api.process.ImapLineHandler)
+     */
+    public void pushLineHandler(ImapLineHandler lineHandler) {
+        context.getPipeline().addBefore("requestDecoder", "lineHandler" + 
handlerCount++, new ImapLineHandlerAdapter(lineHandler));
+    }
+
+    /*
+     * (non-Javadoc)
+     * @see org.apache.james.imap.api.process.ImapSession#popLineHandler()
+     */
+    public void popLineHandler() {
+        context.getPipeline().remove("lineHandler" + --handlerCount);
+    }
+    
+    /*
+     * (non-Javadoc)
+     * @see org.apache.james.imap.api.process.ImapSession#getLog()
+     */
+    public Log getLog() {
+        return log;
+    }
+
+}

Added: 
james/server/trunk/imapserver/src/main/java/org/apache/james/imapserver/netty/NotEnoughDataException.java
URL: 
http://svn.apache.org/viewvc/james/server/trunk/imapserver/src/main/java/org/apache/james/imapserver/netty/NotEnoughDataException.java?rev=1060532&view=auto
==============================================================================
--- 
james/server/trunk/imapserver/src/main/java/org/apache/james/imapserver/netty/NotEnoughDataException.java
 (added)
+++ 
james/server/trunk/imapserver/src/main/java/org/apache/james/imapserver/netty/NotEnoughDataException.java
 Tue Jan 18 18:50:17 2011
@@ -0,0 +1,37 @@
+/****************************************************************
+ * 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.imapserver.netty;
+
+public class NotEnoughDataException extends RuntimeException{
+
+    public final static int UNKNOWN_SIZE = -1;
+    private int size;
+
+    public NotEnoughDataException(int size) {
+        this.size = size;
+    }
+    
+    public NotEnoughDataException() {
+        this(UNKNOWN_SIZE);
+    }
+    public int getDataSize() {
+        return size;
+    }
+}



---------------------------------------------------------------------
To unsubscribe, e-mail: [email protected]
For additional commands, e-mail: [email protected]

Reply via email to