You are viewing a plain text version of this content. The canonical link for it is here.
Posted to server-dev@james.apache.org by no...@apache.org on 2010/03/12 20:56:12 UTC

svn commit: r922406 [1/2] - in /james/imap/trunk: deployment/ deployment/src/test/java/org/apache/james/imap/functional/jcr/ deployment/src/test/resources/ jcr/src/main/java/org/apache/james/imap/jcr/ jcr/src/main/java/org/apache/james/imap/jcr/mail/ j...

Author: norman
Date: Fri Mar 12 19:56:11 2010
New Revision: 922406

URL: http://svn.apache.org/viewvc?rev=922406&view=rev
Log:
More work on JCR.. Not tested yet (IMAP-93)

Added:
    james/imap/trunk/deployment/src/test/java/org/apache/james/imap/functional/jcr/
    james/imap/trunk/deployment/src/test/java/org/apache/james/imap/functional/jcr/JCRHostSystem.java
    james/imap/trunk/deployment/src/test/resources/log4j.properties
    james/imap/trunk/deployment/src/test/resources/test-repository.xml
    james/imap/trunk/jcr/src/main/java/org/apache/james/imap/jcr/Persistent.java
    james/imap/trunk/jcr/src/main/java/org/apache/james/imap/jcr/mail/model/JCRMailboxMembership.java
    james/imap/trunk/jcr/src/main/java/org/apache/james/imap/jcr/mail/model/JCRMessage.java
    james/imap/trunk/store/src/main/java/org/apache/james/imap/store/mail/model/AbstractDocument.java
Removed:
    james/imap/trunk/jcr/src/main/java/org/apache/james/imap/jcr/IsPersistent.java
Modified:
    james/imap/trunk/deployment/pom.xml
    james/imap/trunk/jcr/src/main/java/org/apache/james/imap/jcr/JCRMailbox.java
    james/imap/trunk/jcr/src/main/java/org/apache/james/imap/jcr/JCRMailboxManager.java
    james/imap/trunk/jcr/src/main/java/org/apache/james/imap/jcr/mail/JCRMailboxMapper.java
    james/imap/trunk/jcr/src/main/java/org/apache/james/imap/jcr/mail/JCRMessageMapper.java
    james/imap/trunk/jcr/src/main/java/org/apache/james/imap/jcr/mail/model/JCRHeader.java
    james/imap/trunk/jcr/src/main/java/org/apache/james/imap/jcr/mail/model/JCRMailbox.java
    james/imap/trunk/jcr/src/main/java/org/apache/james/imap/jcr/mail/model/JCRProperty.java
    james/imap/trunk/jcr/src/main/java/org/apache/james/imap/jcr/user/JCRSubscriptionMapper.java
    james/imap/trunk/jcr/src/main/java/org/apache/james/imap/jcr/user/model/JCRSubscription.java
    james/imap/trunk/jpa/src/main/java/org/apache/james/imap/jpa/mail/model/JPAMessage.java
    james/imap/trunk/parent/pom.xml
    james/imap/trunk/store/src/main/java/org/apache/james/imap/store/StoreMailbox.java

Modified: james/imap/trunk/deployment/pom.xml
URL: http://svn.apache.org/viewvc/james/imap/trunk/deployment/pom.xml?rev=922406&r1=922405&r2=922406&view=diff
==============================================================================
--- james/imap/trunk/deployment/pom.xml (original)
+++ james/imap/trunk/deployment/pom.xml Fri Mar 12 19:56:11 2010
@@ -90,7 +90,11 @@
       <artifactId>apache-james-imap-protocol-tester</artifactId>
       <scope>test</scope>
     </dependency>
-
+    <dependency>
+      <groupId>org.apache.james</groupId>
+      <artifactId>apache-james-imap-jcr</artifactId>
+      <scope>test</scope>
+    </dependency>
     <dependency>
       <groupId>commons-collections</groupId>
       <artifactId>commons-collections</artifactId>
@@ -141,6 +145,22 @@
       <scope>test</scope>
     </dependency> 
 
+      <dependency>
+        <groupId>javax.jcr</groupId>
+        <artifactId>jcr</artifactId>
+        <scope>test</scope>
+      </dependency>
+      
+      <dependency>
+      <groupId>org.apache.jackrabbit</groupId>
+      <artifactId>jackrabbit-core</artifactId>
+      <scope>test</scope>
+    </dependency>
+    <dependency>
+      <groupId>org.slf4j</groupId>
+      <artifactId>slf4j-log4j12</artifactId>
+      <scope>test</scope>
+    </dependency>
     <dependency>
       <groupId>org.apache.james</groupId>
       <artifactId>apache-james-imap-seda</artifactId>

Added: james/imap/trunk/deployment/src/test/java/org/apache/james/imap/functional/jcr/JCRHostSystem.java
URL: http://svn.apache.org/viewvc/james/imap/trunk/deployment/src/test/java/org/apache/james/imap/functional/jcr/JCRHostSystem.java?rev=922406&view=auto
==============================================================================
--- james/imap/trunk/deployment/src/test/java/org/apache/james/imap/functional/jcr/JCRHostSystem.java (added)
+++ james/imap/trunk/deployment/src/test/java/org/apache/james/imap/functional/jcr/JCRHostSystem.java Fri Mar 12 19:56:11 2010
@@ -0,0 +1,101 @@
+/****************************************************************
+ * 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.functional.jcr;
+
+import java.io.File;
+
+import org.apache.commons.io.FileUtils;
+import org.apache.jackrabbit.core.RepositoryImpl;
+import org.apache.jackrabbit.core.config.RepositoryConfig;
+import org.apache.james.imap.encode.main.DefaultImapEncoderFactory;
+import org.apache.james.imap.functional.ImapHostSystem;
+import org.apache.james.imap.functional.jpa.user.InMemoryUserManager;
+import org.apache.james.imap.jcr.JCRGlobalUserMailboxManager;
+import org.apache.james.imap.jcr.JCRGlobalUserSubscriptionManager;
+import org.apache.james.imap.main.DefaultImapDecoderFactory;
+import org.apache.james.imap.processor.main.DefaultImapProcessorFactory;
+import org.apache.james.test.functional.HostSystem;
+import org.xml.sax.InputSource;
+
+public class JCRHostSystem extends ImapHostSystem{
+
+
+    public static final String META_DATA_DIRECTORY = "target/user-meta-data";
+
+    public static HostSystem build() throws Exception {        
+        JCRHostSystem host =  new JCRHostSystem();
+        return host;
+    }
+    
+    private final JCRGlobalUserMailboxManager mailboxManager;
+    private final InMemoryUserManager userManager; 
+
+ private static final String JACKRABBIT_HOME = "target/jackrabbit";
+    
+    private RepositoryImpl repository;
+    
+    public JCRHostSystem() throws Exception {
+        
+        userManager = new InMemoryUserManager();
+        File home = new File(JACKRABBIT_HOME);
+        if (home.exists()) {
+            delete(home);
+        } 
+        home.mkdir();
+        
+        RepositoryConfig config = RepositoryConfig.create(new InputSource(this.getClass().getClassLoader().getResourceAsStream("test-repository.xml")), JACKRABBIT_HOME);
+        repository = RepositoryImpl.create(config);
+        mailboxManager = new JCRGlobalUserMailboxManager(userManager, new JCRGlobalUserSubscriptionManager(repository, null, null, null), repository, null, null, null);
+        
+        final DefaultImapProcessorFactory defaultImapProcessorFactory = new DefaultImapProcessorFactory();
+        resetUserMetaData();
+        defaultImapProcessorFactory.configure(mailboxManager);
+        configure(new DefaultImapDecoderFactory().buildImapDecoder(),
+                new DefaultImapEncoderFactory().buildImapEncoder(),
+                defaultImapProcessorFactory.buildImapProcessor());
+    }
+
+    private void delete(File file) {
+        if (file.isDirectory()) {
+            File[] contents = file.listFiles();
+            for (int i = 0; i < contents.length; i++) {
+                delete(contents[i]);
+            }
+        } 
+        file.delete();
+    }
+    public boolean addUser(String user, String password) {
+        userManager.addUser(user, password);
+        return true;
+    }
+
+    public void resetData() throws Exception {
+        resetUserMetaData();
+        mailboxManager.deleteEverything();
+    }
+    
+    public void resetUserMetaData() throws Exception {
+        File dir = new File(META_DATA_DIRECTORY);
+        if (dir.exists()) {
+            FileUtils.deleteDirectory(dir);
+        }
+        dir.mkdirs();
+    }
+
+}

Added: james/imap/trunk/deployment/src/test/resources/log4j.properties
URL: http://svn.apache.org/viewvc/james/imap/trunk/deployment/src/test/resources/log4j.properties?rev=922406&view=auto
==============================================================================
--- james/imap/trunk/deployment/src/test/resources/log4j.properties (added)
+++ james/imap/trunk/deployment/src/test/resources/log4j.properties Fri Mar 12 19:56:11 2010
@@ -0,0 +1,9 @@
+log4j.rootLogger=DEBUG, A1
+log4j.appender.A1=org.apache.log4j.ConsoleAppender
+log4j.appender.A1.layout=org.apache.log4j.PatternLayout
+
+# Print the date in ISO 8601 format
+log4j.appender.A1.layout.ConversionPattern=%d [%t] %-5p %c - %m%n
+
+
+org.apache.jackrabbit.core.config.ConfigurationErrorHandler=DEBUG,CONS
\ No newline at end of file

Added: james/imap/trunk/deployment/src/test/resources/test-repository.xml
URL: http://svn.apache.org/viewvc/james/imap/trunk/deployment/src/test/resources/test-repository.xml?rev=922406&view=auto
==============================================================================
--- james/imap/trunk/deployment/src/test/resources/test-repository.xml (added)
+++ james/imap/trunk/deployment/src/test/resources/test-repository.xml Fri Mar 12 19:56:11 2010
@@ -0,0 +1,94 @@
+<?xml version="1.0"?>
+<!--
+   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.
+-->
+<!DOCTYPE Repository PUBLIC "-//The Apache Software Foundation//DTD Jackrabbit 1.6//EN"
+                            "http://jackrabbit.apache.org/dtd/repository-1.6.dtd">
+<!-- Example Repository Configuration File
+     Used by
+     - org.apache.jackrabbit.core.config.RepositoryConfigTest.java
+     -
+-->
+<Repository>
+    <!--
+        virtual file system where the repository stores global state
+        (e.g. registered namespaces, custom node types, etc.)
+    -->
+    <FileSystem class="org.apache.jackrabbit.core.fs.local.LocalFileSystem">
+        <param name="path" value="target/repository"/>
+    </FileSystem>
+
+    <!--
+        security configuration
+    -->
+    <Security appName="Jackrabbit">
+        <SecurityManager class="org.apache.jackrabbit.core.security.simple.SimpleSecurityManager" workspaceName="default">
+        </SecurityManager>
+
+        <AccessManager class="org.apache.jackrabbit.core.security.simple.SimpleAccessManager">
+        </AccessManager>
+
+        <LoginModule class="org.apache.jackrabbit.core.security.simple.SimpleLoginModule">
+           <param name="adminId" value="admin"/>
+        </LoginModule>
+    </Security>
+    <!--
+        location of workspaces root directory and name of default workspace
+    -->
+    <Workspaces rootPath="target/repository/workspaces" defaultWorkspace="default"/>
+    <!--
+        workspace configuration template:
+        used to create the initial workspace if there's no workspace yet
+    -->
+    <Workspace name="default">
+        <!--
+            virtual file system of the workspace:
+            class: FQN of class implementing the FileSystem interface
+        -->
+        <FileSystem class="org.apache.jackrabbit.core.fs.local.LocalFileSystem">
+            <param name="path" value="default"/>
+        </FileSystem>
+        <!--
+            persistence manager of the workspace:
+            class: FQN of class implementing the PersistenceManager interface
+        -->
+        <PersistenceManager  class="org.apache.jackrabbit.core.persistence.db.SimpleDbPersistenceManager">
+                        <param name="url" value="jdbc:h2:target/wsp_name/db"/>
+                        <param name="driver" value="org.h2.Driver"/>
+                        <param name="schema" value="h2"/>
+                        <param name="schemaObjectPrefix" value="default_"/>
+        </PersistenceManager>
+        
+    </Workspace>
+
+    <!--
+        Configures the versioning
+    -->
+    <Versioning rootPath="target/repository/version">
+
+        <FileSystem class="org.apache.jackrabbit.core.fs.local.LocalFileSystem">
+            <param name="path" value="target/repository/version" />
+        </FileSystem>
+
+        <PersistenceManager  class="org.apache.jackrabbit.core.persistence.db.SimpleDbPersistenceManager">
+                        <param name="url" value="jdbc:h2:target/wsp_name/db"/>
+                        <param name="driver" value="org.h2.Driver"/>
+                        <param name="schema" value="h2"/>
+          				<param name="schemaObjectPrefix" value="version_"/>
+        </PersistenceManager>
+    </Versioning>
+
+</Repository>

Modified: james/imap/trunk/jcr/src/main/java/org/apache/james/imap/jcr/JCRMailbox.java
URL: http://svn.apache.org/viewvc/james/imap/trunk/jcr/src/main/java/org/apache/james/imap/jcr/JCRMailbox.java?rev=922406&r1=922405&r2=922406&view=diff
==============================================================================
--- james/imap/trunk/jcr/src/main/java/org/apache/james/imap/jcr/JCRMailbox.java (original)
+++ james/imap/trunk/jcr/src/main/java/org/apache/james/imap/jcr/JCRMailbox.java Fri Mar 12 19:56:11 2010
@@ -1,15 +1,45 @@
+/****************************************************************
+ * 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.jcr;
 
+import java.util.ArrayList;
 import java.util.Date;
 import java.util.List;
 
+import javax.jcr.LoginException;
+import javax.jcr.NoSuchWorkspaceException;
 import javax.jcr.Repository;
+import javax.jcr.RepositoryException;
+import javax.jcr.Session;
+import javax.jcr.SimpleCredentials;
 import javax.mail.Flags;
 
 import org.apache.commons.logging.Log;
+import org.apache.james.imap.api.display.HumanReadableText;
+import org.apache.james.imap.jcr.mail.JCRMailboxMapper;
+import org.apache.james.imap.jcr.mail.JCRMessageMapper;
 import org.apache.james.imap.jcr.mail.model.JCRHeader;
+import org.apache.james.imap.jcr.mail.model.JCRMailboxMembership;
 import org.apache.james.imap.mailbox.MailboxException;
 import org.apache.james.imap.mailbox.MailboxSession;
+import org.apache.james.imap.mailbox.SubscriptionException;
+import org.apache.james.imap.store.PasswordAwareUser;
 import org.apache.james.imap.store.StoreMailbox;
 import org.apache.james.imap.store.mail.MessageMapper;
 import org.apache.james.imap.store.mail.model.Header;
@@ -19,48 +49,104 @@ import org.apache.james.imap.store.mail.
 
 public class JCRMailbox extends StoreMailbox{
 
-    private final Repository repos;
+    private final Repository repository;
     private final String workspace;
     private final Log log;
-    public JCRMailbox(final Mailbox mailbox, final MailboxSession session, final Repository repos, final String workspace, final Log log) {
+    private String uuid;
+    
+    public JCRMailbox(final org.apache.james.imap.jcr.mail.model.JCRMailbox mailbox, final MailboxSession session, final Repository repository, final String workspace, final Log log) {
         super(mailbox, session );
-        this.repos = repos;
+        this.repository = repository;
         this.workspace = workspace;
         this.log = log;
+        this.uuid = mailbox.getUUID();
+        
     }
 
     @Override
+    public long getMailboxId() {
+        throw new UnsupportedOperationException("Please use getMailboxUUID for this implementation");
+    }
+
+    public String getMailboxUUID() {
+        return uuid;
+    }
+    
+    @Override
     protected MailboxMembership copyMessage(MailboxMembership originalMessage, long uid) {
-        // TODO Auto-generated method stub
-        return null;
+        MailboxMembership newRow = new JCRMailboxMembership(uuid, uid, (JCRMailboxMembership) originalMessage, log);
+        return newRow;
     }
 
     @Override
     protected Header createHeader(int lineNumber, String name, String value) {
-        return new JCRHeader(name, value, lineNumber, log);
+        return new JCRHeader(lineNumber, name, value, log);
     }
 
     @Override
     protected MailboxMembership createMessage(Date internalDate, long uid, int size, int bodyStartOctet, byte[] document, Flags flags, List<Header> headers, PropertyBuilder propertyBuilder) {
-        // TODO Auto-generated method stub
-        return null;
+        final List<JCRHeader> jcrHeaders = new ArrayList<JCRHeader>(headers.size());
+        for (Header header: headers) {
+            jcrHeaders.add((JCRHeader) header);
+        }
+        final MailboxMembership message = new JCRMailboxMembership(getMailboxUUID(), uid, internalDate, 
+                size, flags, document, bodyStartOctet, jcrHeaders, propertyBuilder, log);
+        return message;       
+        
     }
 
     @Override
-    protected MessageMapper createMessageMapper(MailboxSession session) {
-        
-        return null;
+    protected MessageMapper createMessageMapper(MailboxSession session) throws MailboxException {
+        PasswordAwareUser user = (PasswordAwareUser)getMailboxSession().getUser();
+
+        JCRMessageMapper messageMapper = new JCRMessageMapper(getSession(user), getMailboxUUID(), log);
+        return messageMapper;
     }
 
     @Override
     protected Mailbox getMailboxRow() throws MailboxException {
-        // TODO Auto-generated method stub
-        return null;
+        PasswordAwareUser user = (PasswordAwareUser)getMailboxSession().getUser();
+        final JCRMailboxMapper mapper = new JCRMailboxMapper(getSession(user), log);
+        return mapper.findMailboxByUUID(getMailboxUUID());
     }
 
     @Override
     protected Mailbox reserveNextUid() throws MailboxException {
-        return null;
+        PasswordAwareUser user = (PasswordAwareUser)getMailboxSession().getUser();
+        final JCRMailboxMapper mapper = new JCRMailboxMapper(getSession(user), log);
+        return mapper.consumeNextUid(getMailboxUUID());
+    }
+
+    /**
+     * Return a new JCR Session for the given MailboxSession
+     * 
+     * @param s
+     * @return session
+     * @throws MailboxException
+     */
+    protected Session getSession(PasswordAwareUser user) throws SubscriptionException {
+        try {
+            return repository.login(new SimpleCredentials(user.getUserName(), user.getPassword().toCharArray()), getWorkspace());
+        } catch (LoginException e) {
+            throw new SubscriptionException(HumanReadableText.INVALID_LOGIN, e);
+        } catch (NoSuchWorkspaceException e) {
+            throw new SubscriptionException(HumanReadableText.GENERIC_FAILURE_DURING_PROCESSING, e);
+        } catch (RepositoryException e) {
+            throw new SubscriptionException(HumanReadableText.GENERIC_FAILURE_DURING_PROCESSING, e);
+
+        }
+    }
+
+    /**
+     * Return the JCR workspace
+     * 
+     * @return workspace
+     */
+    protected String getWorkspace() {
+        return workspace;
     }
 
+    protected Repository getRepository() {
+        return repository;
+    }
 }

Modified: james/imap/trunk/jcr/src/main/java/org/apache/james/imap/jcr/JCRMailboxManager.java
URL: http://svn.apache.org/viewvc/james/imap/trunk/jcr/src/main/java/org/apache/james/imap/jcr/JCRMailboxManager.java?rev=922406&r1=922405&r2=922406&view=diff
==============================================================================
--- james/imap/trunk/jcr/src/main/java/org/apache/james/imap/jcr/JCRMailboxManager.java (original)
+++ james/imap/trunk/jcr/src/main/java/org/apache/james/imap/jcr/JCRMailboxManager.java Fri Mar 12 19:56:11 2010
@@ -35,6 +35,7 @@ import org.apache.james.imap.jcr.mail.JC
 import org.apache.james.imap.mailbox.BadCredentialsException;
 import org.apache.james.imap.mailbox.MailboxException;
 import org.apache.james.imap.mailbox.MailboxSession;
+import org.apache.james.imap.mailbox.StorageException;
 import org.apache.james.imap.store.Authenticator;
 import org.apache.james.imap.store.PasswordAwareMailboxSession;
 import org.apache.james.imap.store.PasswordAwareUser;
@@ -97,7 +98,7 @@ public class JCRMailboxManager extends S
 
     @Override
     protected void doCreate(String namespaceName, MailboxSession session) throws MailboxException {
-        final Mailbox mailbox = new org.apache.james.imap.jcr.mail.model.JCRMailbox(namespaceName, randomUidValidity());
+        final Mailbox mailbox = new org.apache.james.imap.jcr.mail.model.JCRMailbox(namespaceName, randomUidValidity(), logger);
         final MailboxMapper mapper = createMailboxMapper(session);
         mapper.execute(new TransactionalMapper.Transaction() {
 
@@ -122,6 +123,14 @@ public class JCRMailboxManager extends S
             throw new BadCredentialsException();
         }
     }
+    
+    public void deleteEverything() throws StorageException {
+        try {
+            repository.login().getRootNode().remove();
+        } catch (RepositoryException e) {
+            throw new StorageException(HumanReadableText.DELETED_FAILED, e);
+        }
+    }
 
     /**
      * Return the JCR workspace

Added: james/imap/trunk/jcr/src/main/java/org/apache/james/imap/jcr/Persistent.java
URL: http://svn.apache.org/viewvc/james/imap/trunk/jcr/src/main/java/org/apache/james/imap/jcr/Persistent.java?rev=922406&view=auto
==============================================================================
--- james/imap/trunk/jcr/src/main/java/org/apache/james/imap/jcr/Persistent.java (added)
+++ james/imap/trunk/jcr/src/main/java/org/apache/james/imap/jcr/Persistent.java Fri Mar 12 19:56:11 2010
@@ -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.jcr;
+
+import javax.jcr.Node;
+import javax.jcr.RepositoryException;
+
+public interface Persistent {
+
+	/**
+	 * Merge the object with the node
+	 * 
+	 * @param node
+	 */
+	public void merge(Node node) throws RepositoryException;
+
+	/**
+	 * Return underlying Node
+	 * 
+	 * @return node
+	 */
+	public Node getNode();
+
+	/**
+	 * Return if the object is persistent
+	 * 
+	 * @return
+	 */
+	public boolean isPersistent();
+
+}

Modified: james/imap/trunk/jcr/src/main/java/org/apache/james/imap/jcr/mail/JCRMailboxMapper.java
URL: http://svn.apache.org/viewvc/james/imap/trunk/jcr/src/main/java/org/apache/james/imap/jcr/mail/JCRMailboxMapper.java?rev=922406&r1=922405&r2=922406&view=diff
==============================================================================
--- james/imap/trunk/jcr/src/main/java/org/apache/james/imap/jcr/mail/JCRMailboxMapper.java (original)
+++ james/imap/trunk/jcr/src/main/java/org/apache/james/imap/jcr/mail/JCRMailboxMapper.java Fri Mar 12 19:56:11 2010
@@ -26,10 +26,9 @@ import javax.jcr.NodeIterator;
 import javax.jcr.PathNotFoundException;
 import javax.jcr.RepositoryException;
 import javax.jcr.Session;
-import javax.jcr.query.Query;
-import javax.jcr.query.QueryManager;
 
 import org.apache.commons.logging.Log;
+import org.apache.jackrabbit.JcrConstants;
 import org.apache.jackrabbit.util.Text;
 import org.apache.james.imap.api.display.HumanReadableText;
 import org.apache.james.imap.jcr.JCRImapConstants;
@@ -137,6 +136,7 @@ public class JCRMailboxMapper extends No
      * @see org.apache.james.imap.store.mail.MailboxMapper#findMailboxById(long)
      */
     public Mailbox findMailboxById(long mailboxId) throws StorageException, MailboxNotFoundException {
+        /*
         try {
             QueryManager manager = session.getWorkspace().getQueryManager();
             String queryString = JCRUtils.createPath(session.getRootNode().getPath(), PATH) + "//element(" + mailboxId + ")," + JCRMailbox.ID_PROPERTY + ")";
@@ -146,15 +146,27 @@ public class JCRMailboxMapper extends No
             if (nodes.hasNext() == false) {
                 throw new MailboxNotFoundException(mailboxId);
             } else {
-                return JCRMailbox.from(nodes.nextNode());
+                return new JCRMailbox(nodes.nextNode(),logger);
             }
         } catch (PathNotFoundException e) {
             throw new MailboxNotFoundException(mailboxId);
         } catch (RepositoryException e) {
             throw new StorageException(HumanReadableText.SEARCH_FAILED, e);
         }
+        */
+        throw new StorageException(HumanReadableText.UNSUPPORTED,null);
     }
 
+    public Mailbox findMailboxByUUID(String uuid) throws StorageException, MailboxNotFoundException {
+        try {
+            return new JCRMailbox(session.getNodeByUUID(uuid),logger);
+        } catch (PathNotFoundException e) {
+            throw new MailboxNotFoundException(uuid);
+        } catch (RepositoryException e) {
+            throw new StorageException(HumanReadableText.SEARCH_FAILED, e);
+        }
+    }
+    
     /*
      * (non-Javadoc)
      * 
@@ -165,7 +177,7 @@ public class JCRMailboxMapper extends No
     public Mailbox findMailboxByName(String name) throws StorageException, MailboxNotFoundException {
         try {
             Node node = session.getRootNode().getNode(JCRUtils.createPath(PATH, name));
-            return JCRMailbox.from(node);
+            return new JCRMailbox(node, logger);
         } catch (PathNotFoundException e) {
             throw new MailboxNotFoundException(name);
         } catch (RepositoryException e) {
@@ -185,7 +197,7 @@ public class JCRMailboxMapper extends No
         try {
             NodeIterator it = session.getRootNode().getNodes(PATH + NODE_DELIMITER + WILDCARD + name + WILDCARD);
             while (it.hasNext()) {
-                mailboxList.add(JCRMailbox.from(it.nextNode()));
+                mailboxList.add(new JCRMailbox(it.nextNode(), logger));
             }
         } catch (PathNotFoundException e) {
             // nothing todo
@@ -209,13 +221,28 @@ public class JCRMailboxMapper extends No
             if (session.getRootNode().hasNode(nodePath)) {
                 node = session.getRootNode().getNode(PATH);
             } else {
-                node = session.getRootNode().addNode(PATH);
+                node = session.getRootNode().addNode(PATH, JcrConstants.MIX_REFERENCEABLE);
             }
-            JCRMailbox.copy(node, mailbox);
+            ((JCRMailbox)mailbox).merge(node);
             session.save();
         } catch (RepositoryException e) {
             throw new StorageException(HumanReadableText.SAVE_FAILED, e);
         }
     }
+    
+    public Mailbox consumeNextUid(String uuid) throws StorageException, MailboxNotFoundException {
+
+        JCRMailbox mailbox = (JCRMailbox) findMailboxByUUID(uuid);
+        mailbox.consumeUid();
+        try {
+            session.save();
+        } catch (PathNotFoundException e) {
+            throw new MailboxNotFoundException(uuid);
+        } catch (RepositoryException e) {
+            throw new StorageException(HumanReadableText.SAVE_FAILED, e);
+        }
+        return mailbox;
+
+    }
 
 }

Modified: james/imap/trunk/jcr/src/main/java/org/apache/james/imap/jcr/mail/JCRMessageMapper.java
URL: http://svn.apache.org/viewvc/james/imap/trunk/jcr/src/main/java/org/apache/james/imap/jcr/mail/JCRMessageMapper.java?rev=922406&r1=922405&r2=922406&view=diff
==============================================================================
--- james/imap/trunk/jcr/src/main/java/org/apache/james/imap/jcr/mail/JCRMessageMapper.java (original)
+++ james/imap/trunk/jcr/src/main/java/org/apache/james/imap/jcr/mail/JCRMessageMapper.java Fri Mar 12 19:56:11 2010
@@ -18,107 +18,335 @@
  ****************************************************************/
 package org.apache.james.imap.jcr.mail;
 
+import java.util.ArrayList;
 import java.util.List;
 
+import javax.jcr.Node;
+import javax.jcr.NodeIterator;
+import javax.jcr.RepositoryException;
 import javax.jcr.Session;
+import javax.jcr.query.Query;
+import javax.jcr.query.QueryManager;
+import javax.jcr.query.QueryResult;
 
 import org.apache.commons.logging.Log;
+import org.apache.james.imap.api.display.HumanReadableText;
+import org.apache.james.imap.jcr.JCRImapConstants;
+import org.apache.james.imap.jcr.JCRUtils;
+import org.apache.james.imap.jcr.mail.model.JCRMailboxMembership;
 import org.apache.james.imap.mailbox.MessageRange;
 import org.apache.james.imap.mailbox.SearchQuery;
 import org.apache.james.imap.mailbox.StorageException;
+import org.apache.james.imap.mailbox.MessageRange.Type;
+import org.apache.james.imap.mailbox.SearchQuery.Criterion;
+import org.apache.james.imap.mailbox.SearchQuery.NumericRange;
 import org.apache.james.imap.store.mail.MessageMapper;
 import org.apache.james.imap.store.mail.model.MailboxMembership;
 import org.apache.james.imap.store.transaction.NonTransactionalMapper;
 
-public class JCRMessageMapper extends NonTransactionalMapper implements MessageMapper{
-
+public class JCRMessageMapper extends NonTransactionalMapper implements MessageMapper, JCRImapConstants {
 
+    private final static String PATH = PROPERTY_PREFIX + "mailboxMemberships";
     private final Session session;
     private final Log logger;
+    private String uuid;
 
-    public JCRMessageMapper(final Session session, final Log logger) {
+    public JCRMessageMapper(final Session session, final String uuid, final Log logger) {
         this.session = session;
         this.logger = logger;
+        this.uuid = uuid;
     }
 
     /*
      * (non-Javadoc)
-     * @see org.apache.james.imap.store.mail.MessageMapper#countMessagesInMailbox()
+     * 
+     * @see
+     * org.apache.james.imap.store.mail.MessageMapper#countMessagesInMailbox()
      */
     public long countMessagesInMailbox() throws StorageException {
-        // TODO Auto-generated method stub
-        return 0;
+       
+        try {
+            String queryString = "//" + PATH + "//element(*)[@" + JCRMailboxMembership.MAILBOX_UUID_PROPERTY +"==" + uuid +"]";
+            QueryManager manager = session.getWorkspace().getQueryManager();
+            QueryResult result = manager.createQuery(queryString, Query.XPATH).execute();
+            return result.getNodes().getSize();
+        } catch (RepositoryException e) {
+            throw new StorageException(HumanReadableText.COUNT_FAILED, e);
+        }
+       
     }
 
     /*
      * (non-Javadoc)
-     * @see org.apache.james.imap.store.mail.MessageMapper#countUnseenMessagesInMailbox()
+     * 
+     * @see
+     * org.apache.james.imap.store.mail.MessageMapper#countUnseenMessagesInMailbox
+     * ()
      */
     public long countUnseenMessagesInMailbox() throws StorageException {
-        // TODO Auto-generated method stub
-        return 0;
+        
+        try {
+            String queryString = "//" + PATH + "//element(*)[@" + JCRMailboxMembership.MAILBOX_UUID_PROPERTY +"='" + uuid +"'] && [@" + JCRMailboxMembership.SEEN_PROPERTY +"='" + false +"']";
+            QueryManager manager = session.getWorkspace().getQueryManager();
+            QueryResult result = manager.createQuery(queryString, Query.XPATH).execute();
+            return result.getNodes().getSize();
+        } catch (RepositoryException e) {
+            throw new StorageException(HumanReadableText.COUNT_FAILED, e);
+        }
     }
 
     /*
      * (non-Javadoc)
-     * @see org.apache.james.imap.store.mail.MessageMapper#delete(org.apache.james.imap.store.mail.model.MailboxMembership)
+     * 
+     * @see
+     * org.apache.james.imap.store.mail.MessageMapper#delete(org.apache.james
+     * .imap.store.mail.model.MailboxMembership)
      */
     public void delete(MailboxMembership message) throws StorageException {
-        // TODO Auto-generated method stub
-        
+        JCRMailboxMembership membership = (JCRMailboxMembership) message;
+        if (membership.isPersistent()) {
+            try {
+                session.getNodeByUUID(membership.getUUID()).remove();
+            } catch (RepositoryException e) {
+                throw new StorageException(HumanReadableText.DELETED_FAILED, e);
+            }
+        }
     }
 
     /*
      * (non-Javadoc)
-     * @see org.apache.james.imap.store.mail.MessageMapper#findInMailbox(org.apache.james.imap.mailbox.MessageRange)
+     * 
+     * @see
+     * org.apache.james.imap.store.mail.MessageMapper#findInMailbox(org.apache
+     * .james.imap.mailbox.MessageRange)
      */
     public List<MailboxMembership> findInMailbox(MessageRange set) throws StorageException {
-        // TODO Auto-generated method stub
-        return null;
+        try {
+            final List<MailboxMembership> results;
+            final long from = set.getUidFrom();
+            final long to = set.getUidTo();
+            final Type type = set.getType();
+            switch (type) {
+                default:
+                case ALL:
+                    results = findMessagesInMailbox(uuid);
+                    break;
+                case FROM:
+                    results = findMessagesInMailboxAfterUID(uuid, from);
+                    break;
+                case ONE:
+                    results = findMessagesInMailboxWithUID(uuid, from);
+                    break;
+                case RANGE:
+                    results = findMessagesInMailboxBetweenUIDs(uuid, from, to);
+                    break;       
+            }
+            return results;
+        } catch (RepositoryException e) {
+            throw new StorageException(HumanReadableText.SEARCH_FAILED, e);
+        }
+    }
+
+    private List<MailboxMembership> findMessagesInMailboxAfterUID(String uuid, long uid) throws RepositoryException {
+        List<MailboxMembership> list = new ArrayList<MailboxMembership>();
+        String queryString = "//" + PATH + "//element(*)[@" + JCRMailboxMembership.MAILBOX_UUID_PROPERTY + "='" + uuid + "'] && [@" + JCRMailboxMembership.UID_PROPERTY + ">" + uid + "]";
+        QueryManager manager = session.getWorkspace().getQueryManager();
+        QueryResult result = manager.createQuery(queryString, Query.XPATH).execute();
+
+        NodeIterator iterator = result.getNodes();
+        while (iterator.hasNext()) {
+            list.add(new JCRMailboxMembership(iterator.nextNode(), logger));
+        }
+        return list;
+    }
+
+    private List<MailboxMembership> findMessagesInMailboxWithUID(String uuid, long uid) throws RepositoryException  {
+        List<MailboxMembership> list = new ArrayList<MailboxMembership>();
+        String queryString = "//" + PATH + "//element(*)[@" + JCRMailboxMembership.MAILBOX_UUID_PROPERTY + "='" + uuid + "'] && [@" + JCRMailboxMembership.UID_PROPERTY + "=" + uid + "]";
+        QueryManager manager = session.getWorkspace().getQueryManager();
+        QueryResult result = manager.createQuery(queryString, Query.XPATH).execute();
+
+        NodeIterator iterator = result.getNodes();
+        while (iterator.hasNext()) {
+            list.add(new JCRMailboxMembership(iterator.nextNode(), logger));
+        }
+        return list;
+    }
+
+    private List<MailboxMembership> findMessagesInMailboxBetweenUIDs(String uuid, long from, long to) throws RepositoryException {
+        List<MailboxMembership> list = new ArrayList<MailboxMembership>();
+        String queryString = "//" + PATH + "//element(*)[@" + JCRMailboxMembership.MAILBOX_UUID_PROPERTY + "='" + uuid + "'] && [@" + JCRMailboxMembership.UID_PROPERTY + ">" + from + "] && [@" + JCRMailboxMembership.UID_PROPERTY + "<" + to + "]";
+        QueryManager manager = session.getWorkspace().getQueryManager();
+        QueryResult result = manager.createQuery(queryString, Query.XPATH).execute();
+
+        NodeIterator iterator = result.getNodes();
+        while (iterator.hasNext()) {
+            list.add(new JCRMailboxMembership(iterator.nextNode(), logger));
+        }
+        return list;
+    }
+
+    private List<MailboxMembership> findMessagesInMailbox(String uuid) throws RepositoryException {
+        List<MailboxMembership> list = new ArrayList<MailboxMembership>();
+        String queryString = "//" + PATH + "//element(*)[@" + JCRMailboxMembership.MAILBOX_UUID_PROPERTY + "='" + uuid + "']";
+        QueryManager manager = session.getWorkspace().getQueryManager();
+        QueryResult result = manager.createQuery(queryString, Query.XPATH).execute();
+
+        NodeIterator iterator = result.getNodes();
+        while (iterator.hasNext()) {
+            list.add(new JCRMailboxMembership(iterator.nextNode(), logger));
+        }
+        return list;
     }
 
     /*
      * (non-Javadoc)
-     * @see org.apache.james.imap.store.mail.MessageMapper#findMarkedForDeletionInMailbox(org.apache.james.imap.mailbox.MessageRange)
+     * 
+     * @see
+     * org.apache.james.imap.store.mail.MessageMapper#findMarkedForDeletionInMailbox
+     * (org.apache.james.imap.mailbox.MessageRange)
      */
     public List<MailboxMembership> findMarkedForDeletionInMailbox(MessageRange set) throws StorageException {
-        // TODO Auto-generated method stub
-        return null;
+        try {
+            List<MailboxMembership> list = new ArrayList<MailboxMembership>();
+            String queryString = "//" + PATH + "//element(*)[@" + JCRMailboxMembership.MAILBOX_UUID_PROPERTY +"='" + uuid +"'] && [@" + JCRMailboxMembership.DELETED_PROPERTY +"=" + true +"]";
+            QueryManager manager = session.getWorkspace().getQueryManager();
+            QueryResult result = manager.createQuery(queryString, Query.XPATH).execute();
+            
+            NodeIterator iterator = result.getNodes();
+            while(iterator.hasNext()) {
+                list.add(new JCRMailboxMembership(iterator.nextNode(), logger));
+            }
+            return list;
+        } catch (RepositoryException e) {
+            throw new StorageException(HumanReadableText.SEARCH_FAILED, e);
+        }
     }
 
     /*
      * (non-Javadoc)
-     * @see org.apache.james.imap.store.mail.MessageMapper#findRecentMessagesInMailbox()
+     * 
+     * @see
+     * org.apache.james.imap.store.mail.MessageMapper#findRecentMessagesInMailbox
+     * ()
      */
     public List<MailboxMembership> findRecentMessagesInMailbox() throws StorageException {
-        // TODO Auto-generated method stub
-        return null;
+        
+        try {
+            List<MailboxMembership> list = new ArrayList<MailboxMembership>();
+            String queryString = "//" + PATH + "//element(*)[@" + JCRMailboxMembership.MAILBOX_UUID_PROPERTY +"='" + uuid +"'] && [@" + JCRMailboxMembership.RECENT_PROPERTY +"=" + true +"]";
+            QueryManager manager = session.getWorkspace().getQueryManager();
+            QueryResult result = manager.createQuery(queryString, Query.XPATH).execute();
+            
+            NodeIterator iterator = result.getNodes();
+            while(iterator.hasNext()) {
+                list.add(new JCRMailboxMembership(iterator.nextNode(), logger));
+            }
+            return list;
+        } catch (RepositoryException e) {
+            throw new StorageException(HumanReadableText.SEARCH_FAILED, e);
+        }
     }
 
     /*
      * (non-Javadoc)
-     * @see org.apache.james.imap.store.mail.MessageMapper#findUnseenMessagesInMailboxOrderByUid()
+     * 
+     * @seeorg.apache.james.imap.store.mail.MessageMapper#
+     * findUnseenMessagesInMailboxOrderByUid()
      */
     public List<MailboxMembership> findUnseenMessagesInMailboxOrderByUid() throws StorageException {
-        // TODO Auto-generated method stub
-        return null;
+        try {
+            List<MailboxMembership> list = new ArrayList<MailboxMembership>();
+            String queryString = "//" + PATH + "//element(*)[@" + JCRMailboxMembership.MAILBOX_UUID_PROPERTY +"='" + uuid +"'] && [@" + JCRMailboxMembership.SEEN_PROPERTY +"=" + false +"] order by @" + JCRMailboxMembership.UID_PROPERTY;
+            QueryManager manager = session.getWorkspace().getQueryManager();
+            QueryResult result = manager.createQuery(queryString, Query.XPATH).execute();
+            
+            NodeIterator iterator = result.getNodes();
+            while(iterator.hasNext()) {
+                list.add(new JCRMailboxMembership(iterator.nextNode(), logger));
+            }
+            return list;
+        } catch (RepositoryException e) {
+            throw new StorageException(HumanReadableText.SEARCH_FAILED, e);
+        }
     }
 
     /*
      * (non-Javadoc)
-     * @see org.apache.james.imap.store.mail.MessageMapper#save(org.apache.james.imap.store.mail.model.MailboxMembership)
+     * 
+     * @see
+     * org.apache.james.imap.store.mail.MessageMapper#save(org.apache.james.
+     * imap.store.mail.model.MailboxMembership)
      */
     public void save(MailboxMembership message) throws StorageException {
-        // TODO Auto-generated method stub
-        
+        Node messageNode;
+        JCRMailboxMembership membership = (JCRMailboxMembership) message;
+        try {
+            if (membership.isPersistent()) {
+
+                messageNode = session.getNodeByUUID(membership.getUUID());
+
+            } else {
+                messageNode = session.getRootNode().addNode(JCRUtils.createPath(PATH, String.valueOf(membership.getUid())));
+            }
+            membership.merge(messageNode);
+            session.save();
+
+       
+        } catch (RepositoryException e) {
+            throw new StorageException(HumanReadableText.SAVE_FAILED, e);
+        }
+
     }
 
     /*
      * (non-Javadoc)
-     * @see org.apache.james.imap.store.mail.MessageMapper#searchMailbox(org.apache.james.imap.mailbox.SearchQuery)
+     * 
+     * @see
+     * org.apache.james.imap.store.mail.MessageMapper#searchMailbox(org.apache
+     * .james.imap.mailbox.SearchQuery)
      */
     public List<MailboxMembership> searchMailbox(SearchQuery query) throws StorageException {
-        // TODO Auto-generated method stub
-        return null;
+        try {
+            List<MailboxMembership> list = new ArrayList<MailboxMembership>();
+            final String xpathQuery = formulateXPath(uuid, query);
+            QueryManager manager = session.getWorkspace().getQueryManager();
+            QueryResult result = manager.createQuery(xpathQuery, Query.XPATH).execute();
+            
+            NodeIterator it = result.getNodes();
+            while (it.hasNext()) {
+                list.add(new JCRMailboxMembership(it.nextNode(), logger));
+            }
+            return list;
+        } catch (RepositoryException e) {
+            throw new StorageException(HumanReadableText.SEARCH_FAILED, e);
+        }
+    }
+
+    private String formulateXPath(String uuid, SearchQuery query) {
+        final StringBuilder queryBuilder = new StringBuilder(50);
+        queryBuilder.append("//" + PATH + "//element(*)[@" + JCRMailboxMembership.MAILBOX_UUID_PROPERTY +"='" + uuid +"'] ");
+        final List<Criterion> criteria = query.getCriterias();
+        if (criteria.size() == 1) {
+            final Criterion firstCriterion = criteria.get(0);
+            if (firstCriterion instanceof SearchQuery.UidCriterion) {
+                final SearchQuery.UidCriterion uidCriterion = (SearchQuery.UidCriterion) firstCriterion;
+                final NumericRange[] ranges = uidCriterion.getOperator().getRange();
+                for (int i = 0; i < ranges.length; i++) {
+                    final long low = ranges[i].getLowValue();
+                    final long high = ranges[i].getHighValue();
+
+                    if (low == Long.MAX_VALUE) {
+                        queryBuilder.append(" and [@" + JCRMailboxMembership.UID_PROPERTY +"<=").append(high).append("]");
+                    } else if (low == high) {
+                        queryBuilder.append(" and [@" + JCRMailboxMembership.UID_PROPERTY +"=").append(low).append("]");
+                    } else {
+                        queryBuilder.append(" and [@" + JCRMailboxMembership.UID_PROPERTY +"<").append(low).append("] and [@" + JCRMailboxMembership.UID_PROPERTY + ">").append(high).append("]");
+                    }
+                }
+            }
+        }
+        final String jql = queryBuilder.toString();
+        return jql;
     }
 }

Modified: james/imap/trunk/jcr/src/main/java/org/apache/james/imap/jcr/mail/model/JCRHeader.java
URL: http://svn.apache.org/viewvc/james/imap/trunk/jcr/src/main/java/org/apache/james/imap/jcr/mail/model/JCRHeader.java?rev=922406&r1=922405&r2=922406&view=diff
==============================================================================
--- james/imap/trunk/jcr/src/main/java/org/apache/james/imap/jcr/mail/model/JCRHeader.java (original)
+++ james/imap/trunk/jcr/src/main/java/org/apache/james/imap/jcr/mail/model/JCRHeader.java Fri Mar 12 19:56:11 2010
@@ -20,19 +20,19 @@ package org.apache.james.imap.jcr.mail.m
 
 import javax.jcr.Node;
 import javax.jcr.RepositoryException;
-import javax.mail.Header;
 
 import org.apache.commons.logging.Log;
-import org.apache.james.imap.jcr.IsPersistent;
+import org.apache.james.imap.jcr.Persistent;
 import org.apache.james.imap.jcr.JCRImapConstants;
 import org.apache.james.imap.store.mail.model.AbstractComparableHeader;
+import org.apache.james.imap.store.mail.model.Header;
 
 /**
  * JCR implementation of a {@link Header}
  * 
  *
  */
-public class JCRHeader extends AbstractComparableHeader implements JCRImapConstants, IsPersistent{
+public class JCRHeader extends AbstractComparableHeader implements JCRImapConstants, Persistent{
 
     public final static String FIELDNAME_PROPERTY = PROPERTY_PREFIX + "headerFieldName";
     public final static String VALUE_PROPERTY = PROPERTY_PREFIX + "headerFalue";
@@ -44,6 +44,14 @@ public class JCRHeader extends AbstractC
     private Log logger;
     private Node node;
     
+    /**
+     * Copies the content of an existing header.
+     * @param header
+     */
+    public JCRHeader(Header header, Log logger) {
+        this(header.getLineNumber(), header.getFieldName(), header.getValue(), logger);
+    }
+    
     public JCRHeader(Node node, Log logger) {
         this.node = node;
         this.logger = logger;
@@ -51,7 +59,7 @@ public class JCRHeader extends AbstractC
     
     
     
-    public JCRHeader(final String fieldName, final String value, final int lineNumber, Log logger) {
+    public JCRHeader(final int lineNumber, final String fieldName, final String value, Log logger) {
         this.fieldName = fieldName;
         this.value = value;
         this.lineNumber = lineNumber;
@@ -125,7 +133,12 @@ public class JCRHeader extends AbstractC
      * @see org.apache.james.imap.jcr.IsPersistent#merge(javax.jcr.Node)
      */
     public void merge(Node node) throws RepositoryException {
+        node.setProperty(FIELDNAME_PROPERTY, fieldName);
+        node.setProperty(LINENUMBER_PROPERTY, lineNumber);
+        node.setProperty(VALUE_PROPERTY, value);
+        
         this.node = node;
+        
         this.fieldName = null;
         this.lineNumber = 0;
         this.value = null;

Modified: james/imap/trunk/jcr/src/main/java/org/apache/james/imap/jcr/mail/model/JCRMailbox.java
URL: http://svn.apache.org/viewvc/james/imap/trunk/jcr/src/main/java/org/apache/james/imap/jcr/mail/model/JCRMailbox.java?rev=922406&r1=922405&r2=922406&view=diff
==============================================================================
--- james/imap/trunk/jcr/src/main/java/org/apache/james/imap/jcr/mail/model/JCRMailbox.java (original)
+++ james/imap/trunk/jcr/src/main/java/org/apache/james/imap/jcr/mail/model/JCRMailbox.java Fri Mar 12 19:56:11 2010
@@ -1,146 +1,198 @@
-/****************************************************************
- * 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.jcr.mail.model;
-
-import javax.jcr.Node;
-import javax.jcr.PathNotFoundException;
-import javax.jcr.RepositoryException;
-import javax.jcr.ValueFormatException;
-import javax.jcr.lock.LockException;
-import javax.jcr.nodetype.ConstraintViolationException;
-import javax.jcr.version.VersionException;
-
-import org.apache.james.imap.jcr.JCRImapConstants;
-import org.apache.james.imap.store.mail.model.Mailbox;
-
-
-/**
- * JCR implementation of a {@link Mailbox}
- */
-public class JCRMailbox implements Mailbox{
-
-    public final static String ID_PROPERTY = JCRImapConstants.PROPERTY_PREFIX + "mailboxId";
-    public final static String NAME_PROPERTY = JCRImapConstants.PROPERTY_PREFIX + "mailboxName";
-    public final static String UIDVALIDITY_PROPERTY = JCRImapConstants.PROPERTY_PREFIX + "mailboxUidValidity";
-    public final static String LASTUID_PROPERTY = JCRImapConstants.PROPERTY_PREFIX + "mailboxLastUid";
-
-    private long id = -1;
-    private String name;
-    private final long uidValidity;
-    private long lastUid = 0;
-    
-    public JCRMailbox(final long id, final String name, final long uidValidity, final long lastUid) {
-        this.id = id;
-        this.name = name;
-        this.uidValidity = uidValidity;
-        this.lastUid = lastUid;
-    }
-    
-    public JCRMailbox( final String name, final long uidValidity) {
-        this.name = name;
-        this.uidValidity = uidValidity;
-    }
-    
-    /*
-     * (non-Javadoc)
-     * @see org.apache.james.imap.store.mail.model.Mailbox#consumeUid()
-     */
-    public void consumeUid() {
-        lastUid++;
-    }
-
-    /*
-     * (non-Javadoc)
-     * @see org.apache.james.imap.store.mail.model.Mailbox#getLastUid()
-     */
-    public long getLastUid() {
-        return lastUid;
-    }
-
-    /*
-     * (non-Javadoc)
-     * @see org.apache.james.imap.store.mail.model.Mailbox#getMailboxId()
-     */
-    public long getMailboxId() {
-        return id;
-    }
-
-   
-    /*
-     * (non-Javadoc)
-     * @see org.apache.james.imap.store.mail.model.Mailbox#getName()
-     */
-    public String getName() {
-        return name;
-    }
-
-    /*
-     * (non-Javadoc)
-     * @see org.apache.james.imap.store.mail.model.Mailbox#getUidValidity()
-     */
-    public long getUidValidity() {
-        return uidValidity;
-    }
-
-    /*
-     * (non-Javadoc)
-     * @see org.apache.james.imap.store.mail.model.Mailbox#setName(java.lang.String)
-     */
-    public void setName(String name) {     
-        this.name = name;
-    }
-    
-    /**
-     * Create a JCRMailbox from the given Node
-     * 
-     * @param node
-     * @return jcrMailbox
-     * @throws ValueFormatException
-     * @throws PathNotFoundException
-     * @throws RepositoryException
-     */
-    public static JCRMailbox from(Node node) throws ValueFormatException, PathNotFoundException, RepositoryException {
-        long id = node.getProperty(ID_PROPERTY).getLong();
-        String name = node.getProperty(NAME_PROPERTY).getString();
-        long uidValidity = node.getProperty(UIDVALIDITY_PROPERTY).getLong();
-        long lastUid = node.getProperty(LASTUID_PROPERTY).getLong();
-
-        return new JCRMailbox(id, name, uidValidity, lastUid);
-    }
-
-    /**
-     * Copy the mailbox to the given Node
-     * 
-     * @param node
-     * @param mailbox
-     * @return node
-     * @throws ValueFormatException
-     * @throws VersionException
-     * @throws LockException
-     * @throws ConstraintViolationException
-     * @throws RepositoryException
-     */
-    public static Node copy(Node node, Mailbox mailbox) throws ValueFormatException, VersionException, LockException, ConstraintViolationException, RepositoryException {
-        node.setProperty(ID_PROPERTY, mailbox.getMailboxId());
-        node.setProperty(NAME_PROPERTY, mailbox.getName());
-        node.setProperty(UIDVALIDITY_PROPERTY, mailbox.getUidValidity());
-        node.setProperty(LASTUID_PROPERTY, mailbox.getLastUid());
-        return node;
-    }
-}
+/****************************************************************
+ * 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.jcr.mail.model;
+
+import javax.jcr.Node;
+import javax.jcr.RepositoryException;
+
+import org.apache.commons.logging.Log;
+import org.apache.jackrabbit.JcrConstants;
+import org.apache.james.imap.jcr.JCRImapConstants;
+import org.apache.james.imap.jcr.Persistent;
+import org.apache.james.imap.store.mail.model.Mailbox;
+
+
+/**
+ * JCR implementation of a {@link Mailbox}
+ */
+public class JCRMailbox implements Mailbox, JCRImapConstants, Persistent{
+
+    public final static String ID_PROPERTY = PROPERTY_PREFIX + "mailboxId";
+    public final static String NAME_PROPERTY = PROPERTY_PREFIX + "mailboxName";
+    public final static String UIDVALIDITY_PROPERTY = PROPERTY_PREFIX + "mailboxUidValidity";
+    public final static String LASTUID_PROPERTY = PROPERTY_PREFIX + "mailboxLastUid";
+
+    private long id = -1;
+    private String name;
+    private long uidValidity;
+    private long lastUid = 0;
+    private final Log logger;
+    private Node node;
+    
+    public JCRMailbox(final String name, final long uidValidity, final long lastUid, Log logger) {
+        this.name = name;
+        this.uidValidity = uidValidity;
+        this.lastUid = lastUid;
+        this.logger = logger;
+    }
+    
+    public JCRMailbox( final String name, final long uidValidity, Log logger) {
+        this.name = name;
+        this.uidValidity = uidValidity;
+        this.logger = logger;
+    }
+    
+    public JCRMailbox( final Node node, final Log logger) {
+        this.node = node;
+        this.logger = logger;
+    }
+    
+    
+    /*
+     * (non-Javadoc)
+     * @see org.apache.james.imap.store.mail.model.Mailbox#consumeUid()
+     */
+    public void consumeUid() {
+        if (isPersistent()) {
+            try {
+                long uid = node.getProperty(LASTUID_PROPERTY).getLong();
+                uid++;
+                node.setProperty(LASTUID_PROPERTY, uid);
+            } catch (RepositoryException e) {
+                logger.error("Unable to access property " + LASTUID_PROPERTY, e);
+            }
+        } else {
+            lastUid++;
+        }
+    }
+
+    /*
+     * (non-Javadoc)
+     * @see org.apache.james.imap.store.mail.model.Mailbox#getLastUid()
+     */
+    public long getLastUid() {
+        if (isPersistent()) {
+            try {
+                return node.getProperty(LASTUID_PROPERTY).getLong();
+            } catch (RepositoryException e) {
+                logger.error("Unable to access property " + ID_PROPERTY, e);
+            }
+        }
+        return lastUid;
+    }
+
+    /*
+     * (non-Javadoc)
+     * @see org.apache.james.imap.store.mail.model.Mailbox#getMailboxId()
+     */
+    public long getMailboxId() {
+        if (isPersistent()) {
+            try {
+                return node.getProperty(ID_PROPERTY).getLong();
+            } catch (RepositoryException e) {
+                logger.error("Unable to access property " + ID_PROPERTY, e);
+            }
+        }
+        return id;
+    }
+
+   
+    /*
+     * (non-Javadoc)
+     * @see org.apache.james.imap.store.mail.model.Mailbox#getName()
+     */
+    public String getName() {
+        if (isPersistent()) {
+            try {
+                return node.getProperty(NAME_PROPERTY).getString();
+            } catch (RepositoryException e) {
+                logger.error("Unable to access property " + NAME_PROPERTY, e);
+            }
+        }
+        return name;
+    }
+
+    /*
+     * (non-Javadoc)
+     * @see org.apache.james.imap.store.mail.model.Mailbox#getUidValidity()
+     */
+    public long getUidValidity() {
+        if (isPersistent()) {
+            try {
+                return node.getProperty(UIDVALIDITY_PROPERTY).getLong();
+            } catch (RepositoryException e) {
+                logger.error("Unable to access property " + UIDVALIDITY_PROPERTY, e);
+            }
+        }
+        return uidValidity;
+    }
+
+    /*
+     * (non-Javadoc)
+     * @see org.apache.james.imap.store.mail.model.Mailbox#setName(java.lang.String)
+     */
+    public void setName(String name) {     
+        this.name = name;
+    }
+
+
+    /*
+     * (non-Javadoc)
+     * @see org.apache.james.imap.jcr.Persistent#getNode()
+     */
+    public Node getNode() {
+        return node;
+    }
+
+    /*
+     * (non-Javadoc)
+     * @see org.apache.james.imap.jcr.Persistent#isPersistent()
+     */
+    public boolean isPersistent() {
+        return node != null;
+    }
+
+    /*
+     * (non-Javadoc)
+     * @see org.apache.james.imap.jcr.Persistent#merge(javax.jcr.Node)
+     */
+    public void  merge(Node node) throws RepositoryException {
+        node.setProperty(ID_PROPERTY,  getMailboxId());
+        node.setProperty(NAME_PROPERTY, getName());
+        node.setProperty(UIDVALIDITY_PROPERTY, getUidValidity());
+        node.setProperty(LASTUID_PROPERTY, getLastUid());   
+        
+        this.node = node;
+        id = 0;
+        lastUid = 0;
+        name = null;
+        uidValidity = 0;
+    }
+    
+    public String getUUID() {
+        if (isPersistent()) {
+            try {
+                return node.getProperty(JcrConstants.JCR_UUID).getString();
+            } catch (RepositoryException e) {
+                logger.error("Unable to access property " + JcrConstants.JCR_UUID, e);
+            }
+        }
+        return null;  
+    }
+}

Added: james/imap/trunk/jcr/src/main/java/org/apache/james/imap/jcr/mail/model/JCRMailboxMembership.java
URL: http://svn.apache.org/viewvc/james/imap/trunk/jcr/src/main/java/org/apache/james/imap/jcr/mail/model/JCRMailboxMembership.java?rev=922406&view=auto
==============================================================================
--- james/imap/trunk/jcr/src/main/java/org/apache/james/imap/jcr/mail/model/JCRMailboxMembership.java (added)
+++ james/imap/trunk/jcr/src/main/java/org/apache/james/imap/jcr/mail/model/JCRMailboxMembership.java Fri Mar 12 19:56:11 2010
@@ -0,0 +1,464 @@
+/****************************************************************
+ * 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.jcr.mail.model;
+
+import java.util.Calendar;
+import java.util.Date;
+import java.util.List;
+
+import javax.jcr.Node;
+import javax.jcr.RepositoryException;
+import javax.mail.Flags;
+
+import org.apache.commons.logging.Log;
+import org.apache.jackrabbit.JcrConstants;
+import org.apache.james.imap.jcr.JCRImapConstants;
+import org.apache.james.imap.jcr.Persistent;
+import org.apache.james.imap.store.mail.model.AbstractMailboxMembership;
+import org.apache.james.imap.store.mail.model.Document;
+import org.apache.james.imap.store.mail.model.PropertyBuilder;
+
+public class JCRMailboxMembership extends AbstractMailboxMembership implements
+		Persistent, JCRImapConstants {
+
+	public final static String MAILBOX_UUID_PROPERTY = PROPERTY_PREFIX
+			+ "mailboxUUID";
+	public final static String UID_PROPERTY = PROPERTY_PREFIX + "uid";
+	public final static String SIZE_PROPERTY = PROPERTY_PREFIX + "size";
+	public final static String ANSWERED_PROPERTY = PROPERTY_PREFIX
+			+ "flags:answered";
+	public final static String DELETED_PROPERTY = PROPERTY_PREFIX
+			+ "flags:deleted";
+	public final static String DRAFT_PROPERTY = PROPERTY_PREFIX + "flags:draft";
+	public final static String FLAGGED_PROPERTY = PROPERTY_PREFIX + "flagged";
+	public final static String RECENT_PROPERTY = PROPERTY_PREFIX
+			+ "flags:recent";
+	public final static String SEEN_PROPERTY = PROPERTY_PREFIX + "flags:seen";
+	public final static String INTERNAL_DATE_PROPERTY = PROPERTY_PREFIX
+			+ "internalDate";
+
+	private String mailboxUUID;
+	private long uid;
+	private Date internalDate;
+	private int size;
+	private JCRMessage message;
+	private String messageUUID;
+	private boolean answered;
+	private boolean deleted;
+	private boolean draft;
+	private boolean flagged;
+	private boolean recent;
+	private boolean seen;
+	private Log logger;
+	private Node node;
+
+	public JCRMailboxMembership(String mailboxUUID, long uid,
+			Date internalDate, int size, Flags flags, byte[] content,
+			int bodyStartOctet, final List<JCRHeader> headers,
+			final PropertyBuilder propertyBuilder, Log logger) {
+		super();
+		this.mailboxUUID = mailboxUUID;
+		this.uid = uid;
+		this.internalDate = internalDate;
+		this.size = size;
+		this.message = new JCRMessage(content, bodyStartOctet, headers,
+				propertyBuilder, logger);
+		this.logger = logger;
+		setFlags(flags);
+	}
+
+	/**
+	 * Constructs a copy of the given message. All properties are cloned except
+	 * mailbox and UID.
+	 * 
+	 * @param mailboxId
+	 *            new mailbox ID
+	 * @param uid
+	 *            new UID
+	 * @param original
+	 *            message to be copied, not null
+	 */
+	public JCRMailboxMembership(String mailboxUUID, long uid,
+			JCRMailboxMembership original, Log logger) {
+		super();
+		this.mailboxUUID = mailboxUUID;
+		this.uid = uid;
+		this.internalDate = original.getInternalDate();
+		this.size = original.getSize();
+		this.answered = original.isAnswered();
+		this.deleted = original.isDeleted();
+		this.draft = original.isDraft();
+		this.flagged = original.isFlagged();
+		this.recent = original.isRecent();
+		this.seen = original.isSeen();
+		this.message = new JCRMessage((JCRMessage) original.getDocument(),
+				logger);
+	}
+
+	public JCRMailboxMembership(Node node, Log logger) {
+		this.logger = logger;
+		this.node = node;
+	}
+
+	/*
+	 * (non-Javadoc)
+	 * 
+	 * @see
+	 * org.apache.james.imap.store.mail.model.MailboxMembership#getDocument()
+	 */
+	public Document getDocument() {
+		if (isPersistent()) {
+			try {
+				return new JCRMessage(node.getNode(messageUUID), logger);
+
+			} catch (RepositoryException e) {
+				logger
+						.error("Unable to access property " + FLAGGED_PROPERTY,
+								e);
+			}
+			return null;
+		}
+		return message;
+	}
+
+	/*
+	 * (non-Javadoc)
+	 * 
+	 * @see
+	 * org.apache.james.imap.store.mail.model.MailboxMembership#getInternalDate
+	 * ()
+	 */
+	public Date getInternalDate() {
+		if (isPersistent()) {
+			try {
+				return node.getProperty(INTERNAL_DATE_PROPERTY).getDate()
+						.getTime();
+
+			} catch (RepositoryException e) {
+				logger
+						.error("Unable to access property " + FLAGGED_PROPERTY,
+								e);
+			}
+			return null;
+		}
+		return internalDate;
+	}
+
+	/*
+	 * (non-Javadoc)
+	 * 
+	 * @see
+	 * org.apache.james.imap.store.mail.model.MailboxMembership#getMailboxId()
+	 */
+	public long getMailboxId() {
+		throw new UnsupportedOperationException("Not Supported. Use UUID");
+	}
+
+	public String getMailboxUUID() {
+		if (isPersistent()) {
+			try {
+				node.getProperty(MAILBOX_UUID_PROPERTY).getString();
+			} catch (RepositoryException e) {
+				logger.error("Unable to access property "
+						+ MAILBOX_UUID_PROPERTY, e);
+			}
+		}
+		return mailboxUUID;
+	}
+
+	/*
+	 * (non-Javadoc)
+	 * 
+	 * @see org.apache.james.imap.store.mail.model.MailboxMembership#getSize()
+	 */
+	public int getSize() {
+		if (isPersistent()) {
+			try {
+				return new Long(node.getProperty(SIZE_PROPERTY).getLong())
+						.intValue();
+
+			} catch (RepositoryException e) {
+				logger
+						.error("Unable to access property " + FLAGGED_PROPERTY,
+								e);
+			}
+			return 0;
+		}
+		return size;
+	}
+
+	/*
+	 * (non-Javadoc)
+	 * 
+	 * @see org.apache.james.imap.store.mail.model.MailboxMembership#getUid()
+	 */
+	public long getUid() {
+		if (isPersistent()) {
+			try {
+				return node.getProperty(UID_PROPERTY).getLong();
+
+			} catch (RepositoryException e) {
+				logger.error("Unable to access property " + UID_PROPERTY, e);
+			}
+			return 0;
+		}
+		return uid;
+	}
+
+	/*
+	 * (non-Javadoc)
+	 * 
+	 * @see
+	 * org.apache.james.imap.store.mail.model.MailboxMembership#isAnswered()
+	 */
+	public boolean isAnswered() {
+		if (isPersistent()) {
+			try {
+				return node.getProperty(ANSWERED_PROPERTY).getBoolean();
+
+			} catch (RepositoryException e) {
+				logger.error("Unable to access property " + ANSWERED_PROPERTY,
+						e);
+			}
+			return false;
+		}
+		return answered;
+	}
+
+	/*
+	 * (non-Javadoc)
+	 * 
+	 * @see org.apache.james.imap.store.mail.model.MailboxMembership#isDeleted()
+	 */
+	public boolean isDeleted() {
+		if (isPersistent()) {
+			try {
+				return node.getProperty(DELETED_PROPERTY).getBoolean();
+
+			} catch (RepositoryException e) {
+				logger
+						.error("Unable to access property " + DELETED_PROPERTY,
+								e);
+			}
+			return false;
+		}
+		return deleted;
+	}
+
+	/*
+	 * (non-Javadoc)
+	 * 
+	 * @see org.apache.james.imap.store.mail.model.MailboxMembership#isDraft()
+	 */
+	public boolean isDraft() {
+		if (isPersistent()) {
+			try {
+				return node.getProperty(DRAFT_PROPERTY).getBoolean();
+
+			} catch (RepositoryException e) {
+				logger.error("Unable to access property " + DRAFT_PROPERTY, e);
+			}
+			return false;
+		}
+		return draft;
+	}
+
+	/*
+	 * (non-Javadoc)
+	 * 
+	 * @see org.apache.james.imap.store.mail.model.MailboxMembership#isFlagged()
+	 */
+	public boolean isFlagged() {
+		if (isPersistent()) {
+			try {
+				return node.getProperty(FLAGGED_PROPERTY).getBoolean();
+
+			} catch (RepositoryException e) {
+				logger
+						.error("Unable to access property " + FLAGGED_PROPERTY,
+								e);
+			}
+			return false;
+		}
+		return flagged;
+	}
+
+	/*
+	 * (non-Javadoc)
+	 * 
+	 * @see org.apache.james.imap.store.mail.model.MailboxMembership#isRecent()
+	 */
+	public boolean isRecent() {
+		if (isPersistent()) {
+			try {
+				return node.getProperty(RECENT_PROPERTY).getBoolean();
+
+			} catch (RepositoryException e) {
+				logger.error("Unable to access property " + RECENT_PROPERTY, e);
+			}
+			return false;
+		}
+		return recent;
+	}
+
+	/*
+	 * (non-Javadoc)
+	 * 
+	 * @see org.apache.james.imap.store.mail.model.MailboxMembership#isSeen()
+	 */
+	public boolean isSeen() {
+		if (isPersistent()) {
+			try {
+				return node.getProperty(SEEN_PROPERTY).getBoolean();
+
+			} catch (RepositoryException e) {
+				logger.error("Unable to access property " + SEEN_PROPERTY, e);
+			}
+			return false;
+		}
+		return seen;
+	}
+
+	/*
+	 * (non-Javadoc)
+	 * 
+	 * @see
+	 * org.apache.james.imap.store.mail.model.MailboxMembership#setFlags(javax
+	 * .mail.Flags)
+	 */
+	public void setFlags(Flags flags) {
+		if (isPersistent()) {
+			try {
+				node.getProperty(ANSWERED_PROPERTY).setValue(
+						flags.contains(Flags.Flag.ANSWERED));
+				node.getProperty(DELETED_PROPERTY).setValue(
+						flags.contains(Flags.Flag.DELETED));
+				node.getProperty(DRAFT_PROPERTY).setValue(
+						flags.contains(Flags.Flag.DRAFT));
+				node.getProperty(FLAGGED_PROPERTY).setValue(
+						flags.contains(Flags.Flag.FLAGGED));
+				node.getProperty(RECENT_PROPERTY).setValue(
+						flags.contains(Flags.Flag.RECENT));
+				node.getProperty(SEEN_PROPERTY).setValue(
+						flags.contains(Flags.Flag.SEEN));
+
+			} catch (RepositoryException e) {
+				logger.error("Unable to set flags", e);
+			}
+		} else {
+			answered = flags.contains(Flags.Flag.ANSWERED);
+			deleted = flags.contains(Flags.Flag.DELETED);
+			draft = flags.contains(Flags.Flag.DRAFT);
+			flagged = flags.contains(Flags.Flag.FLAGGED);
+			recent = flags.contains(Flags.Flag.RECENT);
+			seen = flags.contains(Flags.Flag.SEEN);
+		}
+	}
+
+	/*
+	 * (non-Javadoc)
+	 * 
+	 * @see
+	 * org.apache.james.imap.store.mail.model.MailboxMembership#unsetRecent()
+	 */
+	public void unsetRecent() {
+		if (isPersistent()) {
+			try {
+				node.getProperty(RECENT_PROPERTY).setValue(false);
+
+			} catch (RepositoryException e) {
+				logger.error("Unable to access property " + RECENT_PROPERTY, e);
+			}
+		} else {
+			recent = false;
+		}
+	}
+
+	public String getUUID() {
+		if (isPersistent()) {
+			try {
+				return node.getProperty(JcrConstants.JCR_UUID).getString();
+			} catch (RepositoryException e) {
+				logger.error("Unable to access property "
+						+ JcrConstants.JCR_UUID, e);
+			}
+		}
+		return null;
+	}
+
+	/*
+	 * (non-Javadoc)
+	 * 
+	 * @see org.apache.james.imap.jcr.Persistent#getNode()
+	 */
+	public Node getNode() {
+		return node;
+	}
+
+	/*
+	 * (non-Javadoc)
+	 * 
+	 * @see org.apache.james.imap.jcr.Persistent#isPersistent()
+	 */
+	public boolean isPersistent() {
+		return node != null;
+	}
+
+	/*
+	 * (non-Javadoc)
+	 * 
+	 * @see org.apache.james.imap.jcr.Persistent#merge(javax.jcr.Node)
+	 */
+	public void merge(Node node) throws RepositoryException {
+		node.setProperty(MAILBOX_UUID_PROPERTY, mailboxUUID);
+		node.setProperty(UID_PROPERTY, uid);
+		node.setProperty(SIZE_PROPERTY, size);
+		node.setProperty(ANSWERED_PROPERTY, answered);
+		node.setProperty(DELETED_PROPERTY, deleted);
+		node.setProperty(DRAFT_PROPERTY, draft);
+		node.setProperty(FLAGGED_PROPERTY, flagged);
+		node.setProperty(RECENT_PROPERTY, recent);
+		;
+		node.setProperty(SEEN_PROPERTY, seen);
+		;
+		Calendar cal = Calendar.getInstance();
+		cal.setTime(internalDate);
+		node.setProperty(INTERNAL_DATE_PROPERTY, cal);
+
+		Node messageNode = node.addNode(messageUUID);
+		message.merge(messageNode);
+
+		this.node = node;
+
+		mailboxUUID = null;
+		answered = false;
+		deleted = false;
+		draft = false;
+		flagged = false;
+		internalDate = null;
+		mailboxUUID = null;
+		message = null;
+		messageUUID = null;
+		recent = false;
+		seen = false;
+		size = 0;
+		uid = 0;
+	}
+
+}

Added: james/imap/trunk/jcr/src/main/java/org/apache/james/imap/jcr/mail/model/JCRMessage.java
URL: http://svn.apache.org/viewvc/james/imap/trunk/jcr/src/main/java/org/apache/james/imap/jcr/mail/model/JCRMessage.java?rev=922406&view=auto
==============================================================================
--- james/imap/trunk/jcr/src/main/java/org/apache/james/imap/jcr/mail/model/JCRMessage.java (added)
+++ james/imap/trunk/jcr/src/main/java/org/apache/james/imap/jcr/mail/model/JCRMessage.java Fri Mar 12 19:56:11 2010
@@ -0,0 +1,337 @@
+/****************************************************************
+ * 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.jcr.mail.model;
+
+import java.io.ByteArrayInputStream;
+import java.io.ByteArrayOutputStream;
+import java.io.IOException;
+import java.io.InputStream;
+import java.nio.ByteBuffer;
+import java.util.ArrayList;
+import java.util.List;
+
+import javax.jcr.Node;
+import javax.jcr.NodeIterator;
+import javax.jcr.RepositoryException;
+
+import org.apache.commons.logging.Log;
+import org.apache.jackrabbit.JcrConstants;
+import org.apache.james.imap.jcr.JCRImapConstants;
+import org.apache.james.imap.jcr.JCRUtils;
+import org.apache.james.imap.jcr.Persistent;
+import org.apache.james.imap.store.mail.model.AbstractDocument;
+import org.apache.james.imap.store.mail.model.Header;
+import org.apache.james.imap.store.mail.model.Property;
+import org.apache.james.imap.store.mail.model.PropertyBuilder;
+
+public class JCRMessage extends AbstractDocument implements JCRImapConstants, Persistent{
+
+    private Node node;
+    private final Log logger;
+    private byte[] content;
+    private List<JCRHeader> headers;
+    private long fullContentOctets;
+    private String mediaType;
+    private Long textualLineCount;
+    private String subType;
+    private List<JCRProperty> properties;
+    private int bodyStartOctet;
+    
+    public final static String BODY_START_OCTET_PROPERTY = PROPERTY_PREFIX + "messageBodyStartOctet";
+    public final static String FULL_CONTENT_OCTETS_PROPERTY = PROPERTY_PREFIX + "messageFullContentOctets";
+    public final static String HEADERS_NODE = PROPERTY_PREFIX + "messageHeaders";
+    public final static String PROPERTIES_NODE = PROPERTY_PREFIX + "messageProperties";
+
+    public final static String TEXTUAL_LINE_COUNT_PROPERTY  = PROPERTY_PREFIX + "messageTextualLineCount";
+    public final static String SUBTYPE_PROPERTY  = PROPERTY_PREFIX + "messageSubType";
+
+    public JCRMessage(Node node, Log logger) {
+        this.logger= logger;
+        this.node = node;
+    }
+    
+    public JCRMessage(byte[] content, final int bodyStartOctet, final List<JCRHeader> headers, final PropertyBuilder propertyBuilder, Log logger) {
+        super();
+        this.logger = logger;
+        this.content = content;
+        this.fullContentOctets = content.length;
+        this.bodyStartOctet = bodyStartOctet;
+        this.headers = new ArrayList<JCRHeader>(headers);
+        textualLineCount = propertyBuilder.getTextualLineCount();
+        this.mediaType = propertyBuilder.getMediaType();
+        this.subType = propertyBuilder.getSubType();
+        final List<Property> properties = propertyBuilder.toProperties();
+        this.properties = new ArrayList<JCRProperty>(properties.size());
+        int order = 0;
+        for (final Property property:properties) {
+            this.properties.add(new JCRProperty(property, order++, logger));
+        }
+        
+    }
+
+
+    /**
+     * Create a copy of the given message
+     * 
+     * @param message
+     */
+    public JCRMessage(JCRMessage message, Log logger) {
+        this.logger = logger;
+        ByteBuffer buf = message.getFullContent().duplicate();
+        int a = 0;
+        this.content = new byte[buf.capacity()];
+        while(buf.hasRemaining()) {
+            content[a] = buf.get();
+            a++;
+        }
+        this.fullContentOctets = content.length;
+        this.bodyStartOctet = (int) (message.getFullContentOctets() - message.getBodyOctets());
+        this.headers = new ArrayList<JCRHeader>();
+        
+        List<Header> originalHeaders = message.getHeaders();
+        for (int i = 0; i < originalHeaders.size(); i++) {
+            headers.add(new JCRHeader(originalHeaders.get(i),logger));
+        }
+
+        PropertyBuilder pBuilder = new PropertyBuilder(message.getProperties());
+        this.textualLineCount = pBuilder.getTextualLineCount();
+        this.mediaType = pBuilder.getMediaType();
+        this.subType = pBuilder.getSubType();
+        final List<Property> properties = pBuilder.toProperties();
+        this.properties = new ArrayList<JCRProperty>(properties.size());
+        int order = 0;
+        for (final Property property:properties) {
+            this.properties.add(new JCRProperty(property, order++, logger));
+        }
+    }
+    
+    /*
+     * (non-Javadoc)
+     * @see org.apache.james.imap.store.mail.model.Document#getFullContent()
+     */
+    public ByteBuffer getFullContent() {
+        if (isPersistent()) {
+            try {
+                //TODO: Maybe we should cache this somehow...
+                InputStream contentStream = node.getNode(JcrConstants.JCR_CONTENT).getProperty(JcrConstants.JCR_DATA).getStream();
+                ByteArrayOutputStream out = new ByteArrayOutputStream();
+ 
+                    byte[] buf = new byte[1024];
+                    int i = 0;
+                    while ((i = contentStream.read(buf)) != -1) {
+                        out.write(buf, 0, i);
+                    }
+
+                return ByteBuffer.wrap(out.toByteArray());
+            } catch (RepositoryException e) {
+                logger.error("Unable to retrieve property " + JcrConstants.JCR_CONTENT, e);
+            } catch (IOException e) {
+                logger.error("Unable to retrieve property " + JcrConstants.JCR_CONTENT, e);
+            }
+            return null;
+        }
+        return ByteBuffer.wrap(content);
+    }
+
+    /*
+     * (non-Javadoc)
+     * @see org.apache.james.imap.store.mail.model.Document#getFullContentOctets()
+     */
+    public long getFullContentOctets() {
+        if (isPersistent()) {
+            try {
+                return node.getNode(JcrConstants.JCR_CONTENT).getProperty(FULL_CONTENT_OCTETS_PROPERTY).getLong();
+            } catch (RepositoryException e) {
+                logger.error("Unable to retrieve property " + FULL_CONTENT_OCTETS_PROPERTY, e);
+
+            }
+            return 0;
+        }
+        return fullContentOctets;
+    }
+
+    /*
+     * (non-Javadoc)
+     * @see org.apache.james.imap.store.mail.model.Document#getHeaders()
+     */
+    public List<Header> getHeaders() {
+        if (isPersistent()) {
+            try {
+                List<Header> headers = new ArrayList<Header>();
+                NodeIterator nodeIt = node.getNodes(HEADERS_NODE + NODE_DELIMITER +"*");
+                while (nodeIt.hasNext()) {
+                    headers.add(new JCRHeader(nodeIt.nextNode(), logger));
+                }
+                return headers;
+            } catch (RepositoryException e) {
+                logger.error("Unable to retrieve node " + HEADERS_NODE, e);
+            }
+        }
+        return new ArrayList<Header>(headers);
+    }
+
+    /*
+     * (non-Javadoc)
+     * @see org.apache.james.imap.store.mail.model.Document#getMediaType()
+     */
+    public String getMediaType() {
+        if (isPersistent()) {
+            try {
+                return node.getNode(JcrConstants.JCR_CONTENT).getProperty(JcrConstants.JCR_MIMETYPE).getString();
+            } catch (RepositoryException e) {
+                logger.error("Unable to retrieve node " + JcrConstants.JCR_MIMETYPE, e);
+            }
+            return null;
+        }
+        return mediaType;
+    }
+
+    /*
+     * (non-Javadoc)
+     * @see org.apache.james.imap.store.mail.model.Document#getProperties()
+     */
+    public List<Property> getProperties() {
+        if (isPersistent()) {
+            try {
+                List<Property> properties = new ArrayList<Property>();
+                NodeIterator nodeIt = node.getNodes(PROPERTIES_NODE + NODE_DELIMITER +"*");
+                while (nodeIt.hasNext()) {
+                    properties.add(new JCRProperty(nodeIt.nextNode(), logger));
+                }
+                return properties;
+            } catch (RepositoryException e) {
+                logger.error("Unable to retrieve node " + PROPERTIES_NODE, e);
+            }
+        }
+        return new ArrayList<Property>(properties);
+    }
+
+    /*
+     * (non-Javadoc)
+     * @see org.apache.james.imap.store.mail.model.Document#getSubType()
+     */
+    public String getSubType() {
+        if (isPersistent()) {
+            try {
+                return node.getNode(JcrConstants.JCR_CONTENT).getProperty(SUBTYPE_PROPERTY).getString();
+            } catch (RepositoryException e) {
+                logger.error("Unable to retrieve node " + JcrConstants.JCR_MIMETYPE, e);
+            }
+            return null;
+        }
+        return subType;
+    }
+
+    /*
+     * (non-Javadoc)
+     * @see org.apache.james.imap.store.mail.model.Document#getTextualLineCount()
+     */
+    public Long getTextualLineCount() {
+        if (isPersistent()) {
+            try {
+                return node.getNode(JcrConstants.JCR_CONTENT).getProperty(TEXTUAL_LINE_COUNT_PROPERTY).getLong();
+            } catch (RepositoryException e) {
+                logger.error("Unable to retrieve property " + TEXTUAL_LINE_COUNT_PROPERTY, e);
+
+            }
+            return null;
+        }
+        return textualLineCount;
+    }
+
+    /*
+     * (non-Javadoc)
+     * @see org.apache.james.imap.jcr.Persistent#getNode()
+     */
+    public Node getNode() {
+        return node;
+    }
+
+    /*
+     * (non-Javadoc)
+     * @see org.apache.james.imap.jcr.Persistent#isPersistent()
+     */
+    public boolean isPersistent() {
+        return node != null;
+    }
+
+    /*
+     * (non-Javadoc)
+     * @see org.apache.james.imap.jcr.Persistent#merge(javax.jcr.Node)
+     */
+    public void merge(Node node) throws RepositoryException {
+        Node contentNode;
+        if (node.hasNode(JcrConstants.JCR_CONTENT) == false) {
+            contentNode = node.addNode(JcrConstants.JCR_CONTENT, JcrConstants.NT_RESOURCE);
+        } else {
+            contentNode = node.getNode(JcrConstants.JCR_CONTENT);
+        }
+        contentNode.setProperty(JcrConstants.JCR_DATA, new ByteArrayInputStream(content));
+        contentNode.setProperty(JcrConstants.JCR_MIMETYPE, mediaType);
+
+        contentNode.setProperty(BODY_START_OCTET_PROPERTY, bodyStartOctet);
+        contentNode.setProperty(FULL_CONTENT_OCTETS_PROPERTY, fullContentOctets);
+        contentNode.setProperty(FULL_CONTENT_OCTETS_PROPERTY, fullContentOctets);
+        contentNode.setProperty(TEXTUAL_LINE_COUNT_PROPERTY, textualLineCount);
+        contentNode.setProperty(SUBTYPE_PROPERTY, subType);
+        
+        Node headersNode = contentNode.getNode(HEADERS_NODE);
+        headersNode.remove();
+        for (int i = 0; i < headers.size(); i++) {
+            JCRHeader header = (JCRHeader) headers.get(i);
+            Node headerNode = headersNode.addNode(header.getFieldName());
+            header.merge(headerNode);
+        }
+      
+        Node propertiesNode = contentNode.getNode(PROPERTIES_NODE);
+        propertiesNode.remove();
+        for (int i = 0; i < properties.size(); i++) {
+            JCRProperty prop = (JCRProperty) properties.get(i);
+            Node propNode = propertiesNode.addNode(JCRUtils.createPath(prop.getNamespace()+ "." + prop.getLocalName()));
+            prop.merge(propNode);
+        }
+      
+        this.node = node;
+
+        content = null;
+        headers = null;
+        fullContentOctets = 0;
+        mediaType = null;
+        textualLineCount = null;
+        subType = null;
+        properties = null;
+        bodyStartOctet = 0;
+
+    }
+    
+    @Override
+    protected int getBodyStartOctet() {
+        if (isPersistent()) {
+            try {
+                return new Long(node.getNode(JcrConstants.JCR_CONTENT).getProperty(BODY_START_OCTET_PROPERTY).getLong()).intValue();
+            } catch (RepositoryException e) {
+                logger.error("Unable to retrieve property " + TEXTUAL_LINE_COUNT_PROPERTY, e);
+
+            }
+            return 0;
+        }
+        return bodyStartOctet;
+    }
+
+}



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