james-server-dev mailing list archives

Site index · List index
Message view « Date » · « Thread »
Top « Date » · « Thread »
From btell...@apache.org
Subject [2/2] james-project git commit: MAILBOX:270: support setMetadata command, imap protocol add request for update annotation
Date Wed, 29 Jun 2016 04:25:55 GMT
MAILBOX:270: support setMetadata command, imap protocol add request for update annotation


Project: http://git-wip-us.apache.org/repos/asf/james-project/repo
Commit: http://git-wip-us.apache.org/repos/asf/james-project/commit/ecaaf3bf
Tree: http://git-wip-us.apache.org/repos/asf/james-project/tree/ecaaf3bf
Diff: http://git-wip-us.apache.org/repos/asf/james-project/diff/ecaaf3bf

Branch: refs/heads/master
Commit: ecaaf3bfb56a8f1ed873c7b0e0562ec2b1b6f734
Parents: caf66ab
Author: Quynh Nguyen <qnguyen@linagora.com>
Authored: Thu Jun 23 14:14:57 2016 +0700
Committer: Benoit Tellier <btellier@linagora.com>
Committed: Wed Jun 29 11:25:02 2016 +0700

----------------------------------------------------------------------
 protocols/imap/pom.xml                          |   5 +
 .../apache/james/imap/api/ImapConstants.java    |   4 +
 .../imap/decode/parser/ImapParserFactory.java   |   3 +
 .../parser/SetAnnotationCommandParser.java      |  83 ++++++++++
 .../message/request/SetAnnotationRequest.java   |  47 ++++++
 .../imap/processor/DefaultProcessorChain.java   |   9 +-
 .../imap/processor/SetAnnotationProcessor.java  |  71 ++++++++
 .../parser/SetAnnotationCommandParserTest.java  | 163 +++++++++++++++++++
 .../processor/SetAnnotationProcessorTest.java   | 160 ++++++++++++++++++
 protocols/pom.xml                               |   5 +
 10 files changed, 549 insertions(+), 1 deletion(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/james-project/blob/ecaaf3bf/protocols/imap/pom.xml
----------------------------------------------------------------------
diff --git a/protocols/imap/pom.xml b/protocols/imap/pom.xml
index 305985d..810ca87 100644
--- a/protocols/imap/pom.xml
+++ b/protocols/imap/pom.xml
@@ -92,6 +92,11 @@
             <scope>test</scope>
         </dependency>
         <dependency>
+            <groupId>org.assertj</groupId>
+            <artifactId>assertj-guava</artifactId>
+            <scope>test</scope>
+        </dependency>
+        <dependency>
             <groupId>org.jmock</groupId>
             <artifactId>jmock</artifactId>
             <scope>test</scope>

http://git-wip-us.apache.org/repos/asf/james-project/blob/ecaaf3bf/protocols/imap/src/main/java/org/apache/james/imap/api/ImapConstants.java
----------------------------------------------------------------------
diff --git a/protocols/imap/src/main/java/org/apache/james/imap/api/ImapConstants.java b/protocols/imap/src/main/java/org/apache/james/imap/api/ImapConstants.java
index e758477..70d1b22 100644
--- a/protocols/imap/src/main/java/org/apache/james/imap/api/ImapConstants.java
+++ b/protocols/imap/src/main/java/org/apache/james/imap/api/ImapConstants.java
@@ -106,6 +106,8 @@ public interface ImapConstants {
     String SUPPORTS_ACL = "ACL";
 
     String SUPPORTS_QUOTA = "QUOTA";
+
+    String SUPPORTS_ANNOTATION = "ANNOTATION";
     
     String INBOX_NAME = "INBOX";
 
@@ -235,6 +237,8 @@ public interface ImapConstants {
 
     String SETQUOTA_COMMAND_NAME = "SETQUOTA";
 
+    String SETANNOTATION_COMMAND_NAME = "SETMETADATA";
+
     String LIST_RESPONSE_NAME = "LIST";
 
     String XLIST_RESPONSE_NAME = "XLIST";

http://git-wip-us.apache.org/repos/asf/james-project/blob/ecaaf3bf/protocols/imap/src/main/java/org/apache/james/imap/decode/parser/ImapParserFactory.java
----------------------------------------------------------------------
diff --git a/protocols/imap/src/main/java/org/apache/james/imap/decode/parser/ImapParserFactory.java
b/protocols/imap/src/main/java/org/apache/james/imap/decode/parser/ImapParserFactory.java
index ec89b13..ea57de6 100644
--- a/protocols/imap/src/main/java/org/apache/james/imap/decode/parser/ImapParserFactory.java
+++ b/protocols/imap/src/main/java/org/apache/james/imap/decode/parser/ImapParserFactory.java
@@ -107,6 +107,9 @@ public class ImapParserFactory implements ImapCommandParserFactory {
         _imapCommands.put(ImapConstants.GETQUOTA_COMMAND_NAME, GetQuotaCommandParser.class);
         _imapCommands.put(ImapConstants.SETQUOTA_COMMAND_NAME, SetQuotaCommandParser.class);
 
+        //RFC5464
+        //SETMETADATA
+        _imapCommands.put(ImapConstants.SETANNOTATION_COMMAND_NAME, SetAnnotationCommandParser.class);
     }
 
     /**

http://git-wip-us.apache.org/repos/asf/james-project/blob/ecaaf3bf/protocols/imap/src/main/java/org/apache/james/imap/decode/parser/SetAnnotationCommandParser.java
----------------------------------------------------------------------
diff --git a/protocols/imap/src/main/java/org/apache/james/imap/decode/parser/SetAnnotationCommandParser.java
b/protocols/imap/src/main/java/org/apache/james/imap/decode/parser/SetAnnotationCommandParser.java
new file mode 100644
index 0000000..fb66888
--- /dev/null
+++ b/protocols/imap/src/main/java/org/apache/james/imap/decode/parser/SetAnnotationCommandParser.java
@@ -0,0 +1,83 @@
+/****************************************************************
+ * 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.james.imap.api.ImapCommand;
+import org.apache.james.imap.api.ImapConstants;
+import org.apache.james.imap.api.ImapMessage;
+import org.apache.james.imap.api.display.HumanReadableText;
+import org.apache.james.imap.api.process.ImapSession;
+import org.apache.james.imap.decode.ImapRequestLineReader;
+import org.apache.james.imap.decode.base.AbstractImapCommandParser;
+import org.apache.james.imap.message.request.SetAnnotationRequest;
+import org.apache.james.mailbox.model.MailboxAnnotation;
+import org.apache.james.protocols.imap.DecodingException;
+
+import com.google.common.base.Function;
+import com.google.common.base.Optional;
+import com.google.common.collect.ImmutableList;
+
+public class SetAnnotationCommandParser extends AbstractImapCommandParser {
+    public SetAnnotationCommandParser() {
+        super(ImapCommand.authenticatedStateCommand(ImapConstants.SETANNOTATION_COMMAND_NAME));
+    }
+
+    @Override
+    protected ImapMessage decode(ImapCommand command, ImapRequestLineReader request, String
tag, ImapSession session)
+            throws DecodingException {
+        String mailboxName = request.mailbox();
+        ImmutableList.Builder<MailboxAnnotation> listMailboxAnnotations = ImmutableList.<MailboxAnnotation>builder();
+
+        if (request.nextWordChar() == '(') {
+            request.consumeChar('(');
+
+            do {
+                listMailboxAnnotations.add(readNextAnnotation(request));
+            } while (request.nextWordChar() != ')');
+
+            request.consumeChar(')');
+        }
+        request.eol();
+
+        return new SetAnnotationRequest(tag, command, mailboxName, listMailboxAnnotations.build());
+    }
+
+    private MailboxAnnotation readNextAnnotation(ImapRequestLineReader request) throws DecodingException
{
+        try {
+            String key = request.atom();
+            String value = request.nstring();
+
+            return Optional.fromNullable(value)
+                .transform(transforMailboxAnnotation(key))
+                .or(MailboxAnnotation.nil(key));
+        } catch (IllegalArgumentException e) {
+            throw new DecodingException(HumanReadableText.ILLEGAL_ARGUMENTS, "The key is
not valid: " + e.getMessage());
+        }
+    }
+
+    private Function<String, MailboxAnnotation> transforMailboxAnnotation(final String
key) {
+        return new Function<String, MailboxAnnotation>() {
+            public MailboxAnnotation apply(String value) {
+                return MailboxAnnotation.newInstance(key, value);
+            }
+        };
+    }
+
+}

http://git-wip-us.apache.org/repos/asf/james-project/blob/ecaaf3bf/protocols/imap/src/main/java/org/apache/james/imap/message/request/SetAnnotationRequest.java
----------------------------------------------------------------------
diff --git a/protocols/imap/src/main/java/org/apache/james/imap/message/request/SetAnnotationRequest.java
b/protocols/imap/src/main/java/org/apache/james/imap/message/request/SetAnnotationRequest.java
new file mode 100644
index 0000000..fdd82b0
--- /dev/null
+++ b/protocols/imap/src/main/java/org/apache/james/imap/message/request/SetAnnotationRequest.java
@@ -0,0 +1,47 @@
+/****************************************************************
+ * 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 java.util.List;
+
+import org.apache.james.imap.api.ImapCommand;
+import org.apache.james.mailbox.model.MailboxAnnotation;
+
+import com.google.common.collect.ImmutableList;
+
+public class SetAnnotationRequest extends AbstractImapRequest {
+    private final String mailboxName;
+    private final List<MailboxAnnotation> mailboxAnnotations;
+
+    public SetAnnotationRequest(String tag, ImapCommand command, String mailboxName, List<MailboxAnnotation>
mailboxAnnotations) {
+        super(tag, command);
+        this.mailboxName = mailboxName;
+        this.mailboxAnnotations = ImmutableList.copyOf(mailboxAnnotations);
+    }
+
+    public String getMailboxName() {
+        return mailboxName;
+    }
+
+    public List<MailboxAnnotation> getMailboxAnnotations() {
+        return mailboxAnnotations;
+    }
+
+}

http://git-wip-us.apache.org/repos/asf/james-project/blob/ecaaf3bf/protocols/imap/src/main/java/org/apache/james/imap/processor/DefaultProcessorChain.java
----------------------------------------------------------------------
diff --git a/protocols/imap/src/main/java/org/apache/james/imap/processor/DefaultProcessorChain.java
b/protocols/imap/src/main/java/org/apache/james/imap/processor/DefaultProcessorChain.java
index edd71ac..c8a8ceb 100644
--- a/protocols/imap/src/main/java/org/apache/james/imap/processor/DefaultProcessorChain.java
+++ b/protocols/imap/src/main/java/org/apache/james/imap/processor/DefaultProcessorChain.java
@@ -55,7 +55,14 @@ public class DefaultProcessorChain {
         final CreateProcessor createProcessor = new CreateProcessor(deleteProcessor, mailboxManager,
statusResponseFactory);
         final CloseProcessor closeProcessor = new CloseProcessor(createProcessor, mailboxManager,
statusResponseFactory);
         final UnsubscribeProcessor unsubscribeProcessor = new UnsubscribeProcessor(closeProcessor,
mailboxManager, subscriptionManager, statusResponseFactory);
-        final SubscribeProcessor subscribeProcessor = new SubscribeProcessor(unsubscribeProcessor,
mailboxManager, subscriptionManager, statusResponseFactory);
+        final SubscribeProcessor subscribeProcessor;
+        if (mailboxManager.hasCapability(MailboxManager.MailboxCapabilities.Annotation))
{
+            final SetAnnotationProcessor setAnnotationProcessor = new SetAnnotationProcessor(unsubscribeProcessor,
mailboxManager, statusResponseFactory);
+            capabilityProcessor.addProcessor(setAnnotationProcessor);
+            subscribeProcessor = new SubscribeProcessor(setAnnotationProcessor, mailboxManager,
subscriptionManager, statusResponseFactory);
+        } else {
+            subscribeProcessor = new SubscribeProcessor(unsubscribeProcessor, mailboxManager,
subscriptionManager, statusResponseFactory);
+        }
         final CopyProcessor copyProcessor = new CopyProcessor(subscribeProcessor, mailboxManager,
statusResponseFactory);
         AuthenticateProcessor authenticateProcessor;
         if (mailboxManager.hasCapability(MailboxManager.MailboxCapabilities.Move)) {

http://git-wip-us.apache.org/repos/asf/james-project/blob/ecaaf3bf/protocols/imap/src/main/java/org/apache/james/imap/processor/SetAnnotationProcessor.java
----------------------------------------------------------------------
diff --git a/protocols/imap/src/main/java/org/apache/james/imap/processor/SetAnnotationProcessor.java
b/protocols/imap/src/main/java/org/apache/james/imap/processor/SetAnnotationProcessor.java
new file mode 100644
index 0000000..feb5d68
--- /dev/null
+++ b/protocols/imap/src/main/java/org/apache/james/imap/processor/SetAnnotationProcessor.java
@@ -0,0 +1,71 @@
+/****************************************************************
+ * 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 java.util.List;
+
+import org.apache.james.imap.api.ImapCommand;
+import org.apache.james.imap.api.ImapConstants;
+import org.apache.james.imap.api.ImapSessionUtils;
+import org.apache.james.imap.api.display.HumanReadableText;
+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.SetAnnotationRequest;
+import org.apache.james.mailbox.MailboxManager;
+import org.apache.james.mailbox.MailboxSession;
+import org.apache.james.mailbox.exception.MailboxException;
+import org.apache.james.mailbox.exception.MailboxNotFoundException;
+import org.apache.james.mailbox.model.MailboxPath;
+import org.slf4j.Logger;
+
+import com.google.common.collect.ImmutableList;
+
+public class SetAnnotationProcessor extends AbstractMailboxProcessor<SetAnnotationRequest>
implements CapabilityImplementingProcessor {
+
+    public SetAnnotationProcessor(ImapProcessor next, MailboxManager mailboxManager, StatusResponseFactory
factory) {
+        super(SetAnnotationRequest.class, next, mailboxManager, factory);
+    }
+
+    public List<String> getImplementedCapabilities(ImapSession session) {
+        return ImmutableList.of(ImapConstants.SUPPORTS_ANNOTATION);
+    }
+
+    protected void doProcess(SetAnnotationRequest message, ImapSession session, String tag,
ImapCommand command,
+            Responder responder) {
+        final MailboxManager mailboxManager = getMailboxManager();
+        final MailboxSession mailboxSession = ImapSessionUtils.getMailboxSession(session);
+        final String mailboxName = message.getMailboxName();
+        try {
+            MailboxPath mailboxPath = buildFullPath(session, mailboxName);
+
+            mailboxManager.updateAnnotations(mailboxPath, mailboxSession, message.getMailboxAnnotations());
+
+            okComplete(command, tag, responder);
+        } catch (MailboxNotFoundException e) {
+            session.getLog().info(command.getName() + " failed for mailbox " + mailboxName,
e);
+            no(command, tag, responder, HumanReadableText.FAILURE_NO_SUCH_MAILBOX, StatusResponse.ResponseCode.tryCreate());
+        } catch (MailboxException e) {
+            session.getLog().info(command.getName() + " failed for mailbox " + mailboxName,
e);
+            no(command, tag, responder, HumanReadableText.GENERIC_FAILURE_DURING_PROCESSING);
+        }
+    }
+}

http://git-wip-us.apache.org/repos/asf/james-project/blob/ecaaf3bf/protocols/imap/src/test/java/org/apache/james/imap/decode/parser/SetAnnotationCommandParserTest.java
----------------------------------------------------------------------
diff --git a/protocols/imap/src/test/java/org/apache/james/imap/decode/parser/SetAnnotationCommandParserTest.java
b/protocols/imap/src/test/java/org/apache/james/imap/decode/parser/SetAnnotationCommandParserTest.java
new file mode 100644
index 0000000..9a793c6
--- /dev/null
+++ b/protocols/imap/src/test/java/org/apache/james/imap/decode/parser/SetAnnotationCommandParserTest.java
@@ -0,0 +1,163 @@
+/****************************************************************
+ * 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 static org.assertj.core.api.Assertions.assertThat;
+import static org.assertj.guava.api.Assertions.assertThat;
+
+import java.io.ByteArrayInputStream;
+import java.io.ByteArrayOutputStream;
+import java.io.InputStream;
+
+import org.apache.james.imap.api.ImapCommand;
+import org.apache.james.imap.decode.ImapRequestStreamLineReader;
+import org.apache.james.imap.message.request.SetAnnotationRequest;
+import org.apache.james.mailbox.model.MailboxAnnotation;
+import org.apache.james.protocols.imap.DecodingException;
+import org.junit.Test;
+
+public class SetAnnotationCommandParserTest {
+
+    private static final String INBOX = "anyMailboxName";
+    private static final String TAG = "A1";
+    private static final MailboxAnnotation PRIVATE_ANNOTATION = MailboxAnnotation.newInstance("/private/comment",
"This is my comment");
+    private static final MailboxAnnotation SHARED_ANNOTATION = MailboxAnnotation.newInstance("/shared/comment",
"This one is for you!");
+    private static final MailboxAnnotation NIL_ANNOTATION = MailboxAnnotation.nil("/private/comment");
+    private SetAnnotationCommandParser parser = new SetAnnotationCommandParser();
+    private ImapCommand command = ImapCommand.anyStateCommand("Command");
+
+    @Test
+    public void decodeMessageShouldReturnRequestContainsOneAnnotation() throws DecodingException
{
+        InputStream inputStream = new ByteArrayInputStream((INBOX + " (/private/comment \"This
is my comment\") \n").getBytes());
+        ImapRequestStreamLineReader lineReader = new ImapRequestStreamLineReader(inputStream,
null);
+        SetAnnotationRequest request = (SetAnnotationRequest) parser.decode(command, lineReader,
TAG, null);
+
+        assertThat(request.getMailboxName()).isEqualTo(INBOX);
+        assertThat(request.getMailboxAnnotations()).containsOnly(PRIVATE_ANNOTATION);
+    }
+
+    @Test(expected = DecodingException.class)
+    public void decodeMessageShouldThrowDecodingExceptionWhenContainsInvalidAnnotationKey()
throws DecodingException {
+        InputStream inputStream = new ByteArrayInputStream((INBOX + " (/pri*vate/comment
\"This is my comment\") \n").getBytes());
+        ImapRequestStreamLineReader lineReader = new ImapRequestStreamLineReader(inputStream,
null);
+
+        parser.decode(command, lineReader, TAG, null);
+    }
+
+    @Test
+    public void decodeMessageShouldReturnRequestContainsOneNilAnnotation() throws DecodingException
{
+        InputStream inputStream = new ByteArrayInputStream((INBOX + " (/private/comment NIL)
\n").getBytes());
+        ImapRequestStreamLineReader lineReader = new ImapRequestStreamLineReader(inputStream,
null);
+        SetAnnotationRequest request = (SetAnnotationRequest) parser.decode(command, lineReader,
TAG, null);
+
+        assertThat(request.getMailboxName()).isEqualTo(INBOX);
+        assertThat(request.getMailboxAnnotations()).containsOnly(NIL_ANNOTATION);
+    }
+
+    @Test
+    public void decodeMessageShouldReturnRequestContainsOneAnnotationWithMultiLinesValue()
throws DecodingException {
+        InputStream inputStream = new ByteArrayInputStream((INBOX + " (/private/comment {32}\nMy
new comment across two lines.) \n").getBytes());
+        ImapRequestStreamLineReader lineReader = new ImapRequestStreamLineReader(inputStream,
new ByteArrayOutputStream());
+        SetAnnotationRequest request = (SetAnnotationRequest) parser.decode(command, lineReader,
TAG, null);
+
+        assertThat(request.getMailboxName()).isEqualTo(INBOX);
+        assertThat(request.getMailboxAnnotations()).containsOnly(MailboxAnnotation.newInstance("/private/comment",
"My new comment across two lines."));
+    }
+
+    @Test
+    public void decodeMessageShouldReturnRequestContainsMultiAnnotations() throws DecodingException
{
+        InputStream inputStream = new ByteArrayInputStream((INBOX + " (/private/comment \"This
is my comment\" /shared/comment \"This one is for you!\") \n").getBytes());
+        ImapRequestStreamLineReader lineReader = new ImapRequestStreamLineReader(inputStream,
new ByteArrayOutputStream());
+        SetAnnotationRequest request = (SetAnnotationRequest) parser.decode(command, lineReader,
TAG, null);
+
+        assertThat(request.getMailboxName()).isEqualTo(INBOX);
+        assertThat(request.getMailboxAnnotations()).containsExactly(PRIVATE_ANNOTATION, SHARED_ANNOTATION);
+    }
+
+    @Test
+    public void decodeMessageShouldReturnRequestContainsMultiAnnotationsWithNil() throws
DecodingException {
+        InputStream inputStream = new ByteArrayInputStream((INBOX + " (/private/comment NIL
/shared/comment \"This one is for you!\") \n").getBytes());
+        ImapRequestStreamLineReader lineReader = new ImapRequestStreamLineReader(inputStream,
new ByteArrayOutputStream());
+        SetAnnotationRequest request = (SetAnnotationRequest) parser.decode(command, lineReader,
TAG, null);
+
+        assertThat(request.getMailboxName()).isEqualTo(INBOX);
+        assertThat(request.getMailboxAnnotations()).containsExactly(NIL_ANNOTATION, SHARED_ANNOTATION);
+    }
+
+    @Test(expected = DecodingException.class)
+    public void decodeMessageShouldThrowDecodingExceptionWhenCommandDoesNotStartWithSlash()
throws DecodingException {
+        InputStream inputStream = new ByteArrayInputStream("INBOX /private/comment \"This
is my comment\") \n".getBytes());
+        ImapRequestStreamLineReader lineReader = new ImapRequestStreamLineReader(inputStream,
null);
+
+        parser.decode(command, lineReader, TAG, null);
+    }
+
+    @Test(expected = DecodingException.class)
+    public void decodeMessageShouldThrowDecodingExceptionWhenCommandDoesNotEndWithSlash()
throws DecodingException {
+        InputStream inputStream = new ByteArrayInputStream((INBOX + " (/private/comment \"This
is my comment\" \n").getBytes());
+        ImapRequestStreamLineReader lineReader = new ImapRequestStreamLineReader(inputStream,
null);
+
+        parser.decode(command, lineReader, TAG, null);
+    }
+
+    @Test(expected = DecodingException.class)
+    public void decodeMessageShouldThrowDecodingExceptionWhenCommandDoesNotHaveAnnotationValue()
throws DecodingException {
+        InputStream inputStream = new ByteArrayInputStream((INBOX + " (/private/comment)
\n").getBytes());
+        ImapRequestStreamLineReader lineReader = new ImapRequestStreamLineReader(inputStream,
null);
+
+        parser.decode(command, lineReader, TAG, null);
+    }
+
+    @Test
+    public void decodeMessageShouldReturnRequestWhenCommandHasEmptyAnnotationValue() throws
DecodingException {
+        InputStream inputStream = new ByteArrayInputStream((INBOX + " (/private/comment \"
  \") \n").getBytes());
+        ImapRequestStreamLineReader lineReader = new ImapRequestStreamLineReader(inputStream,
null);
+
+        SetAnnotationRequest request = (SetAnnotationRequest) parser.decode(command, lineReader,
TAG, null);
+
+        assertThat(request.getMailboxAnnotations().get(0).getValue()).isPresent();
+    }
+
+    @Test(expected = DecodingException.class)
+    public void decodeMessageShouldThrowDecodingExceptionWhenCommandAnnotationValueNotInQuote()
throws DecodingException {
+        InputStream inputStream = new ByteArrayInputStream((INBOX + " (/private/comment This
is my comment) \n").getBytes());
+        ImapRequestStreamLineReader lineReader = new ImapRequestStreamLineReader(inputStream,
null);
+
+        parser.decode(command, lineReader, TAG, null);
+    }
+
+    @Test
+    public void decodeMessageShouldReturnRequestWhenCommandAnnotationValueIsNILString() throws
DecodingException {
+        InputStream inputStream = new ByteArrayInputStream((INBOX + " (/private/comment \"NIL\")
\n").getBytes());
+        ImapRequestStreamLineReader lineReader = new ImapRequestStreamLineReader(inputStream,
null);
+
+        SetAnnotationRequest request = (SetAnnotationRequest) parser.decode(command, lineReader,
TAG, null);
+
+        assertThat(request.getMailboxAnnotations().get(0).getValue()).isPresent();
+    }
+
+    @Test(expected = DecodingException.class)
+    public void decodeMessageShouldThrowDecodingExceptionWhenCommandMissingAnnotations()
throws DecodingException {
+        InputStream inputStream = new ByteArrayInputStream((INBOX + " () \n").getBytes());
+        ImapRequestStreamLineReader lineReader = new ImapRequestStreamLineReader(inputStream,
null);
+
+        parser.decode(command, lineReader, TAG, null);
+    }
+}

http://git-wip-us.apache.org/repos/asf/james-project/blob/ecaaf3bf/protocols/imap/src/test/java/org/apache/james/imap/processor/SetAnnotationProcessorTest.java
----------------------------------------------------------------------
diff --git a/protocols/imap/src/test/java/org/apache/james/imap/processor/SetAnnotationProcessorTest.java
b/protocols/imap/src/test/java/org/apache/james/imap/processor/SetAnnotationProcessorTest.java
new file mode 100644
index 0000000..65d62ea
--- /dev/null
+++ b/protocols/imap/src/test/java/org/apache/james/imap/processor/SetAnnotationProcessorTest.java
@@ -0,0 +1,160 @@
+/****************************************************************
+ * 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.assertj.core.api.Assertions.assertThat;
+import static org.mockito.Matchers.any;
+import static org.mockito.Matchers.eq;
+import static org.mockito.Mockito.doThrow;
+import static org.mockito.Mockito.mock;
+import static org.mockito.Mockito.times;
+import static org.mockito.Mockito.verify;
+import static org.mockito.Mockito.when;
+
+import java.util.List;
+
+import org.apache.james.imap.api.ImapCommand;
+import org.apache.james.imap.api.ImapConstants;
+import org.apache.james.imap.api.ImapSessionState;
+import org.apache.james.imap.api.ImapSessionUtils;
+import org.apache.james.imap.api.display.HumanReadableText;
+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.encode.FakeImapSession;
+import org.apache.james.imap.message.request.SetAnnotationRequest;
+import org.apache.james.mailbox.MailboxManager;
+import org.apache.james.mailbox.MailboxSession;
+import org.apache.james.mailbox.exception.MailboxException;
+import org.apache.james.mailbox.exception.MailboxNotFoundException;
+import org.apache.james.mailbox.mock.MockMailboxSession;
+import org.apache.james.mailbox.model.MailboxAnnotation;
+import org.apache.james.mailbox.model.MailboxPath;
+import org.junit.After;
+import org.junit.Before;
+import org.junit.Test;
+import org.mockito.ArgumentCaptor;
+import org.mockito.InjectMocks;
+import org.mockito.MockitoAnnotations;
+import org.slf4j.Logger;
+
+import com.google.common.collect.ImmutableList;
+
+public class SetAnnotationProcessorTest {
+
+    private static final String TAG = "TAG";
+
+    @InjectMocks
+    private SetAnnotationProcessor processor;
+
+    private ImapProcessor mockNextProcessor;
+    private MailboxManager mockMailboxManager;
+    private StatusResponseFactory mockStatusResponseFactory;
+    private ImapProcessor.Responder mockResponder;
+    private ImapSession mockImapSession;
+    private MailboxSession mockMailboxSession;
+
+    private List<MailboxAnnotation> MAILBOX_ANNOTATIONS;
+    private StatusResponse okResponse;
+    private Logger log;
+
+    private MailboxPath inbox; 
+
+    private SetAnnotationRequest request;
+    private ArgumentCaptor<HumanReadableText> humanTextCaptor;
+    
+    private void initAndMockData() {
+        okResponse = mock(StatusResponse.class);
+        mockNextProcessor = mock(ImapProcessor.class);
+        mockMailboxManager = mock(MailboxManager.class);
+        mockStatusResponseFactory = mock(StatusResponseFactory.class);
+        mockResponder = mock(ImapProcessor.Responder.class);
+        mockImapSession = mock(ImapSession.class);
+        log = mock(Logger.class);;
+
+        mockMailboxSession = new MockMailboxSession("username");
+        inbox = MailboxPath.inbox(mockMailboxSession);
+        MAILBOX_ANNOTATIONS = ImmutableList.of(MailboxAnnotation.newInstance("/private/key",
"anyValue"));
+        request = new SetAnnotationRequest(TAG, ImapCommand.anyStateCommand("Name"), ImapConstants.INBOX_NAME,
MAILBOX_ANNOTATIONS);
+        humanTextCaptor = ArgumentCaptor.forClass(HumanReadableText.class);
+
+        when(mockImapSession.getState()).thenReturn(ImapSessionState.SELECTED);
+        when(mockImapSession.getAttribute(ImapSessionUtils.MAILBOX_SESSION_ATTRIBUTE_SESSION_KEY)).thenReturn(mockMailboxSession);
+    }
+
+    @Before
+    public void setUp() {
+        MockitoAnnotations.initMocks(this);
+        initAndMockData();
+        processor = new SetAnnotationProcessor(mockNextProcessor, mockMailboxManager, mockStatusResponseFactory);
+    }
+    @After
+    public void tearDown() {
+        processor = null;
+    }
+
+    @Test
+    public void getImplementedCapabilitiesShouldContainSupportAnnotationWhenMailboxManagerHasAnnotationCapability()
{
+        assertThat(processor.getImplementedCapabilities(new FakeImapSession())).containsExactly(ImapConstants.SUPPORTS_ANNOTATION);
+    }
+
+    @Test
+    public void processShouldResponseNoWithNoSuchMailboxWhenManagerThrowMailboxNotFoundException()
throws Exception {
+        when(mockImapSession.getLog()).thenReturn(log);
+
+        doThrow(MailboxNotFoundException.class).when(mockMailboxManager).updateAnnotations(eq(inbox),
+            eq(mockMailboxSession), eq(MAILBOX_ANNOTATIONS));
+
+        processor.process(request, mockResponder, mockImapSession);
+
+        verify(mockStatusResponseFactory, times(1)).taggedNo(any(String.class), any(ImapCommand.class),
+                humanTextCaptor.capture(), any(StatusResponse.ResponseCode.class));
+
+        assertThat(humanTextCaptor.getAllValues()).containsOnly(HumanReadableText.FAILURE_NO_SUCH_MAILBOX);
+    }
+
+    @Test
+    public void processShouldResponseNoWithGenericFailureWhenManagerThrowMailboxException()
throws Exception {
+        when(mockImapSession.getLog()).thenReturn(log);
+
+        doThrow(MailboxException.class).when(mockMailboxManager).updateAnnotations(eq(inbox),
eq(mockMailboxSession), eq(MAILBOX_ANNOTATIONS));
+
+        processor.process(request, mockResponder, mockImapSession);
+
+        verify(mockStatusResponseFactory, times(1)).taggedNo(any(String.class), any(ImapCommand.class),
humanTextCaptor.capture());
+
+        assertThat(humanTextCaptor.getAllValues()).containsOnly(HumanReadableText.GENERIC_FAILURE_DURING_PROCESSING);
+    }
+
+    @Test
+    public void processShouldWorkWithCompleteResponse() throws Exception {
+        when(mockStatusResponseFactory.taggedOk(any(String.class), any(ImapCommand.class),
any(HumanReadableText.class)))
+            .thenReturn(okResponse);
+
+        processor.process(request, mockResponder, mockImapSession);
+
+        verify(mockMailboxManager).updateAnnotations(inbox, mockMailboxSession, MAILBOX_ANNOTATIONS);
+        verify(mockResponder).respond(okResponse);
+        verify(mockStatusResponseFactory, times(1)).taggedOk(any(String.class), any(ImapCommand.class),
humanTextCaptor.capture());
+
+        assertThat(humanTextCaptor.getAllValues()).containsOnly(HumanReadableText.COMPLETED);
+    }
+}
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/james-project/blob/ecaaf3bf/protocols/pom.xml
----------------------------------------------------------------------
diff --git a/protocols/pom.xml b/protocols/pom.xml
index 470cb72..ee5d7d2 100644
--- a/protocols/pom.xml
+++ b/protocols/pom.xml
@@ -251,6 +251,11 @@
                 <version>1.4.4</version>
             </dependency>
             <dependency>
+                <groupId>org.assertj</groupId>
+                <artifactId>assertj-guava</artifactId>
+                <version>1.3.1</version>
+            </dependency>
+            <dependency>
                 <groupId>org.mockito</groupId>
                 <artifactId>mockito-core</artifactId>
                 <version>${mockito-core.version}</version>


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


Mime
View raw message