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/07/01 19:14:10 UTC

svn commit: r959725 - in /james/imap/trunk/jcr/src/main/java/org/apache/james/imap/jcr: ./ mail/ user/

Author: norman
Date: Thu Jul  1 17:14:10 2010
New Revision: 959725

URL: http://svn.apache.org/viewvc?rev=959725&view=rev
Log:
Handle the construction of the node path for the username in a protected method + make it configurable how the scaling is constructed (IMAP-173)

Added:
    james/imap/trunk/jcr/src/main/java/org/apache/james/imap/jcr/AbstractJCRScalingMapper.java
Modified:
    james/imap/trunk/jcr/src/main/java/org/apache/james/imap/jcr/AbstractJCRMapper.java
    james/imap/trunk/jcr/src/main/java/org/apache/james/imap/jcr/JCRMailboxSessionMapperFactory.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/user/JCRSubscriptionMapper.java

Modified: james/imap/trunk/jcr/src/main/java/org/apache/james/imap/jcr/AbstractJCRMapper.java
URL: http://svn.apache.org/viewvc/james/imap/trunk/jcr/src/main/java/org/apache/james/imap/jcr/AbstractJCRMapper.java?rev=959725&r1=959724&r2=959725&view=diff
==============================================================================
--- james/imap/trunk/jcr/src/main/java/org/apache/james/imap/jcr/AbstractJCRMapper.java (original)
+++ james/imap/trunk/jcr/src/main/java/org/apache/james/imap/jcr/AbstractJCRMapper.java Thu Jul  1 17:14:10 2010
@@ -18,12 +18,10 @@
  ****************************************************************/
 package org.apache.james.imap.jcr;
 
-import javax.jcr.Node;
 import javax.jcr.RepositoryException;
 import javax.jcr.Session;
 
 import org.apache.commons.logging.Log;
-import org.apache.jackrabbit.commons.JcrUtils;
 import org.apache.james.imap.api.display.HumanReadableText;
 import org.apache.james.imap.mailbox.MailboxException;
 import org.apache.james.imap.mailbox.MailboxSession;
@@ -42,15 +40,13 @@ public abstract class AbstractJCRMapper 
     private final MailboxSessionJCRRepository repository;
     private final MailboxSession mSession;
     private final NodeLocker locker;
-    private final int scaling;
-    private final static char PAD ='_';
+
     
-    public AbstractJCRMapper(final MailboxSessionJCRRepository repository, MailboxSession mSession, NodeLocker locker, int scaling, Log logger) {
+    public AbstractJCRMapper(final MailboxSessionJCRRepository repository, MailboxSession mSession, NodeLocker locker, Log logger) {
         this.repository = repository;
         this.mSession = mSession;
         this.logger = logger;
         this.locker = locker;
-        this.scaling = scaling;
     }
 
     public NodeLocker getNodeLocker() {
@@ -118,71 +114,5 @@ public abstract class AbstractJCRMapper 
     public void endRequest() {
        repository.logout(mSession);
     }
-        
-    /**
-     * Construct the user node path part, using the specified scaling factor.
-     * If the username is not long enough it will fill it with {@link #PAD}
-     * 
-     * So if you use a scaling of 2 it will look like:
-     * 
-     * foo:
-     *     f/fo/foo
-     *     
-     * fo:
-     *     f/fo/fo
-     * 
-     * f: 
-     *    f/f_/fo
-     * 
-     * @param username
-     * @return path
-     */
-    protected String constructUserPathPart(String username) {
-        StringBuffer sb = new StringBuffer();
-        for (int i = 0 ; i < scaling; i++) {
-            if (username.length() > i) {
-                sb.append(username.substring(0,i+1));
-            } else {
-                sb.append(username);
-                int a = i - username.length();
-                for (int b = 0; b < a; b++) {
-                    sb.append(PAD);
-                }
-            }
-            sb.append(NODE_DELIMITER);
-        }
-        sb.append(username);
-        return sb.toString();
-
-    }
-
-    /**
-     * Create the needed Node structure for the given username using the given Node as parent.
-     * 
-     * The method will use {@link #constructUserPathPart(String)} for create the needed node path and split
-     * it when a NODE_DELIMITER was found
-     * 
-     * @param parent
-     * @param username
-     * @return userNode
-     * @throws RepositoryException
-     */
-    protected Node createUserPathStructure(Node parent, String username)
-            throws RepositoryException {
-        String userpath = constructUserPathPart(username);
-
-        String[] userPathParts = userpath.split(NODE_DELIMITER);
-        for (int a = 0; a < userPathParts.length; a++) {
-            parent = JcrUtils.getOrAddNode(parent, userPathParts[a],
-                    "nt:unstructured");
-
-            // thats the last user node so add the right mixin type
-            if (a + 1 == userPathParts.length)
-                parent.addMixin("jamesMailbox:user");
-        }
-
-        return parent;
-
-    }
 
 }

Added: james/imap/trunk/jcr/src/main/java/org/apache/james/imap/jcr/AbstractJCRScalingMapper.java
URL: http://svn.apache.org/viewvc/james/imap/trunk/jcr/src/main/java/org/apache/james/imap/jcr/AbstractJCRScalingMapper.java?rev=959725&view=auto
==============================================================================
--- james/imap/trunk/jcr/src/main/java/org/apache/james/imap/jcr/AbstractJCRScalingMapper.java (added)
+++ james/imap/trunk/jcr/src/main/java/org/apache/james/imap/jcr/AbstractJCRScalingMapper.java Thu Jul  1 17:14:10 2010
@@ -0,0 +1,107 @@
+/****************************************************************
+ * 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;
+
+import org.apache.commons.logging.Log;
+import org.apache.jackrabbit.commons.JcrUtils;
+import org.apache.james.imap.mailbox.MailboxSession;
+
+/**
+ * Abstract base class for Mapper's which support scaling 
+ *
+ */
+public abstract class AbstractJCRScalingMapper extends AbstractJCRMapper{
+
+    private final int scaling;
+    private final static char PAD ='_';
+    
+    public AbstractJCRScalingMapper(MailboxSessionJCRRepository repository, MailboxSession mSession, NodeLocker locker, int scaling, Log logger) {
+        super(repository, mSession, locker, logger);
+        this.scaling = scaling;
+    }
+
+    /**
+     * Construct the user node path part, using the specified scaling factor.
+     * If the username is not long enough it will fill it with {@link #PAD}
+     * 
+     * So if you use a scaling of 2 it will look like:
+     * 
+     * foo:
+     *     f/fo/foo
+     *     
+     * fo:
+     *     f/fo/fo
+     * 
+     * f: 
+     *    f/f_/f
+     * 
+     * @param username
+     * @return path
+     */
+    protected String constructUserPathPart(String username) {
+        StringBuffer sb = new StringBuffer();
+        for (int i = 0 ; i < scaling; i++) {
+            if (username.length() > i) {
+                sb.append(username.substring(0,i+1));
+            } else {
+                sb.append(username);
+                int a = i - username.length();
+                for (int b = 0; b < a; b++) {
+                    sb.append(PAD);
+                }
+            }
+            sb.append(NODE_DELIMITER);
+        }
+        sb.append(username);
+        return sb.toString();
+
+    }
+
+    /**
+     * Create the needed Node structure for the given username using the given Node as parent.
+     * 
+     * The method will use {@link #constructUserPathPart(String)} for create the needed node path and split
+     * it when a NODE_DELIMITER was found
+     * 
+     * @param parent
+     * @param username
+     * @return userNode
+     * @throws RepositoryException
+     */
+    protected Node createUserPathStructure(Node parent, String username)
+            throws RepositoryException {
+        String userpath = constructUserPathPart(username);
+
+        String[] userPathParts = userpath.split(NODE_DELIMITER);
+        for (int a = 0; a < userPathParts.length; a++) {
+            parent = JcrUtils.getOrAddNode(parent, userPathParts[a],
+                    "nt:unstructured");
+
+            // thats the last user node so add the right mixin type
+            if (a + 1 == userPathParts.length)
+                parent.addMixin("jamesMailbox:user");
+        }
+
+        return parent;
+
+    }
+}

Modified: james/imap/trunk/jcr/src/main/java/org/apache/james/imap/jcr/JCRMailboxSessionMapperFactory.java
URL: http://svn.apache.org/viewvc/james/imap/trunk/jcr/src/main/java/org/apache/james/imap/jcr/JCRMailboxSessionMapperFactory.java?rev=959725&r1=959724&r2=959725&view=diff
==============================================================================
--- james/imap/trunk/jcr/src/main/java/org/apache/james/imap/jcr/JCRMailboxSessionMapperFactory.java (original)
+++ james/imap/trunk/jcr/src/main/java/org/apache/james/imap/jcr/JCRMailboxSessionMapperFactory.java Thu Jul  1 17:14:10 2010
@@ -54,7 +54,7 @@ public class JCRMailboxSessionMapperFact
         this.repository = repository;
         this.logger = LogFactory.getLog(JCRSubscriptionManager.class);
         this.delimiter = delimiter;
-        this.locker = locker;;
+        this.locker = locker;
     }
 
     
@@ -66,7 +66,7 @@ public class JCRMailboxSessionMapperFact
 
     @Override
     public MessageMapper<String> createMessageMapper(MailboxSession session) throws MailboxException {
-        JCRMessageMapper messageMapper = new JCRMessageMapper(repository, session, locker, DEFAULT_SCALING, logger);
+        JCRMessageMapper messageMapper = new JCRMessageMapper(repository, session, locker, logger);
         return messageMapper;
     }
 

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=959725&r1=959724&r2=959725&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 Thu Jul  1 17:14:10 2010
@@ -33,7 +33,7 @@ import org.apache.commons.logging.Log;
 import org.apache.jackrabbit.JcrConstants;
 import org.apache.jackrabbit.commons.JcrUtils;
 import org.apache.james.imap.api.display.HumanReadableText;
-import org.apache.james.imap.jcr.AbstractJCRMapper;
+import org.apache.james.imap.jcr.AbstractJCRScalingMapper;
 import org.apache.james.imap.jcr.MailboxSessionJCRRepository;
 import org.apache.james.imap.jcr.NodeLocker;
 import org.apache.james.imap.jcr.NodeLocker.NodeLockedExecution;
@@ -49,7 +49,7 @@ import org.apache.james.imap.store.mail.
  * 
  * 
  */
-public class JCRMailboxMapper extends AbstractJCRMapper implements MailboxMapper<String> {
+public class JCRMailboxMapper extends AbstractJCRScalingMapper implements MailboxMapper<String> {
 
     private char delimiter;
 
@@ -214,7 +214,6 @@ public class JCRMailboxMapper extends Ab
            }
             
         } catch (RepositoryException e) {
-            e.printStackTrace();
             throw new StorageException(HumanReadableText.SAVE_FAILED, e);
         } catch (InterruptedException e) {
             throw new StorageException(HumanReadableText.SAVE_FAILED, e);

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=959725&r1=959724&r2=959725&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 Thu Jul  1 17:14:10 2010
@@ -58,11 +58,72 @@ import org.apache.james.imap.store.mail.
  */
 public class JCRMessageMapper extends AbstractJCRMapper implements MessageMapper<String> {
 
-    public JCRMessageMapper(final MailboxSessionJCRRepository repos, MailboxSession session, NodeLocker locker, final int scaling, final Log logger) {
-        super(repos, session, locker, scaling, logger);
+    /**
+     * Store the messages directly in the mailbox:
+     * .../mailbox/
+     */
+    public final static int MESSAGE_SCALE_NONE = 0;
+    
+    /**
+     * Store the messages under a year directory in the mailbox:
+     * .../mailbox/2010/
+     */
+    public final static int MESSAGE_SCALE_YEAR = 1;
+    
+    /**
+     * Store the messages under a year/month directory in the mailbox:
+     * .../mailbox/2010/05/
+     */
+    public final static int MESSAGE_SCALE_MONTH = 2;
+    
+    /**
+     * Store the messages under a year/month/day directory in the mailbox:
+     * .../mailbox/2010/05/01/
+     */
+    public final static int MESSAGE_SCALE_DAY = 3;
+    
+    /**
+     * Store the messages under a year/month/day/hour directory in the mailbox:
+     * .../mailbox/2010/05/02/11
+     */
+    public final static int MESSAGE_SCALE_HOUR = 4;
+    
+    
+    /**
+     * Store the messages under a year/month/day/hour/min directory in the mailbox:
+     * .../mailbox/2010/05/02/11/59
+     */
+    public final static int MESSAGE_SCALE_MINUTE = 5;
+
+    private final int scaleType;
+    
+
+    /**
+     * 
+     * @see #JCRMessageMapper(MailboxSessionJCRRepository, MailboxSession, NodeLocker, Log, int)
+     * 
+     * In this case {@link #MESSAGE_SCALE_DAY} is used
+     */
+    public JCRMessageMapper(final MailboxSessionJCRRepository repos, MailboxSession session, NodeLocker locker, final Log logger) {
+        this(repos, session, locker, logger, MESSAGE_SCALE_DAY);
     }
 
     /**
+     * Construct a new {@link JCRMessageMapper} instance
+     * 
+     * @param repos {@link MailboxSessionJCRRepository} to use
+     * @param session {@link MailboxSession} to which the mapper is bound
+     * @param locker {@link NodeLocker} for locking Nodes
+     * @param logger Lo
+     * @param scaleType the scale type to use when storing messages. See {@link #MESSAGE_SCALE_NONE}, {@link #MESSAGE_SCALE_YEAR}, {@link #MESSAGE_SCALE_MONTH}, {@link #MESSAGE_SCALE_DAY},
+     *                  {@link #MESSAGE_SCALE_HOUR}, {@link #MESSAGE_SCALE_MINUTE}  
+     */
+    public JCRMessageMapper(final MailboxSessionJCRRepository repos, MailboxSession session, NodeLocker locker, final Log logger, int scaleType) {
+        super(repos, session, locker, logger);
+        this.scaleType = scaleType;
+    }
+    
+    /**
      * Return the path to the mailbox. This path is escaped to be able to use it in xpath queries
      * 
      * See http://wiki.apache.org/jackrabbit/EncodingAndEscaping
@@ -413,9 +474,9 @@ public class JCRMessageMapper extends Ab
     public void save(String uuid, MailboxMembership<String> message) throws StorageException {
         final JCRMessage membership = (JCRMessage) message;
         try {
-            //JCRUtils.createNodeRecursive(getSession().getRootNode(), mailboxN);
+
             Node messageNode = null;
-            
+
             if (membership.isPersistent()) {
                 messageNode = getSession().getNodeByIdentifier(membership.getId());
             }
@@ -425,67 +486,82 @@ public class JCRMessageMapper extends Ab
                 if (date == null) {
                     date = new Date();
                 }
-                
-                // extracte the date from the message to create node structure later
+
+                // extracte the date from the message to create node structure
+                // later
                 Calendar cal = Calendar.getInstance();
                 cal.setTime(date);
-                final String year = String.valueOf(cal.get(Calendar.YEAR));
-                final String month = String.valueOf(cal.get(Calendar.MONTH) +1);
-                final String day = String.valueOf(cal.get(Calendar.DAY_OF_MONTH));
-               
-                Node dayNode = null;
+                final String year = convertIntToString(cal.get(Calendar.YEAR));
+                final String month = convertIntToString(cal.get(Calendar.MONTH) + 1);
+                final String day = convertIntToString(cal.get(Calendar.DAY_OF_MONTH));
+                final String hour = convertIntToString(cal.get(Calendar.HOUR_OF_DAY));
+                final String min = convertIntToString(cal.get(Calendar.MINUTE));
+
+                Node node = null;
                 Node mailboxNode = getSession().getNodeByIdentifier(uuid);
-                String dayNodePath = year + NODE_DELIMITER + month + NODE_DELIMITER + day;
-                boolean found = mailboxNode.hasNode(dayNodePath);
-                
+
                 NodeLocker locker = getNodeLocker();
-                
-                // check if the node for the day already exists. if not we need to create the structure
-                if (found == false) {
-                    
+
+                if (scaleType > MESSAGE_SCALE_NONE) {
                     // we lock the whole mailbox with all its childs while
                     // adding the folder structure for the date
-                    // TODO: Maybe we should just lock the last child folder to improve performance
-                    dayNode = locker.execute(new NodeLocker.NodeLockedExecution<Node>() {
+                    
+                    // TODO: Maybe we should just lock the last child folder to
+                    // improve performance
+                    node = locker.execute(new NodeLocker.NodeLockedExecution<Node>() {
 
                         public Node execute(Node node) throws RepositoryException {
 
-                            Node yearNode = JcrUtils.getOrAddFolder(node, year);
-                            yearNode.addMixin(JcrConstants.MIX_LOCKABLE);
-
-                            Node monthNode = JcrUtils.getOrAddFolder(yearNode, month);
-                            monthNode.addMixin(JcrConstants.MIX_LOCKABLE);
+                            if (scaleType >= MESSAGE_SCALE_YEAR) {
+                                node = JcrUtils.getOrAddFolder(node, year);
+                                node.addMixin(JcrConstants.MIX_LOCKABLE);
+
+                                if (scaleType >= MESSAGE_SCALE_MONTH) {
+                                    node = JcrUtils.getOrAddFolder(node, month);
+                                    node.addMixin(JcrConstants.MIX_LOCKABLE);
+
+                                    if (scaleType >= MESSAGE_SCALE_DAY) {
+                                        node = JcrUtils.getOrAddFolder(node, day);
+                                        node.addMixin(JcrConstants.MIX_LOCKABLE);
+
+                                        if (scaleType >= MESSAGE_SCALE_HOUR) {
+                                            node = JcrUtils.getOrAddFolder(node, hour);
+                                            node.addMixin(JcrConstants.MIX_LOCKABLE);
+
+                                            if (scaleType >= MESSAGE_SCALE_MINUTE) {
+                                                node = JcrUtils.getOrAddFolder(node, min);
+                                                node.addMixin(JcrConstants.MIX_LOCKABLE);
+                                            }
+                                        }
+                                    }
+                                }
+                            }
 
-                            Node dayNode = JcrUtils.getOrAddFolder(monthNode, day);
-                            dayNode.addMixin(JcrConstants.MIX_LOCKABLE);
                             // save the folders for now
                             getSession().save();
-                            return dayNode;
+                            return node;
                         }
 
                         public boolean isDeepLocked() {
                             return true;
                         }
                     }, mailboxNode, Node.class);
-                   
                 } else {
-                    
-                    dayNode = mailboxNode.getNode(dayNodePath);
+                    node = mailboxNode;
                 }
-                
-                
+
                 // lock the day node and add the message
                 locker.execute(new NodeLockedExecution<Void>() {
 
                     public Void execute(Node node) throws RepositoryException {
-                        Node messageNode = node.addNode(String.valueOf(membership.getUid()),"nt:file");
+                        Node messageNode = node.addNode(String.valueOf(membership.getUid()), "nt:file");
                         messageNode.addMixin("jamesMailbox:message");
                         try {
                             membership.merge(messageNode);
                         } catch (IOException e) {
                             throw new RepositoryException("Unable to merge message in to tree", e);
                         }
-                        // save the message 
+                        // save the message
                         getSession().save();
 
                         return null;
@@ -494,8 +570,8 @@ public class JCRMessageMapper extends Ab
                     public boolean isDeepLocked() {
                         return true;
                     }
-                }, dayNode, Void.class);
-                
+                }, node, Void.class);
+
             } else {
                 membership.merge(messageNode);
             }
@@ -509,6 +585,19 @@ public class JCRMessageMapper extends Ab
 
     }
 
+    /**
+     * Convert the given int value to a String. If the int value is smaller then 9 it will prefix the String with 0.
+     * 
+     * @param value
+     * @return stringValue
+     */
+    private String convertIntToString(int value) {
+        if (value <= 9) {
+            return "0" +String.valueOf(value);
+        } else {
+            return String.valueOf(value);
+        }
+    }
     /*
      * (non-Javadoc)
      * 

Modified: james/imap/trunk/jcr/src/main/java/org/apache/james/imap/jcr/user/JCRSubscriptionMapper.java
URL: http://svn.apache.org/viewvc/james/imap/trunk/jcr/src/main/java/org/apache/james/imap/jcr/user/JCRSubscriptionMapper.java?rev=959725&r1=959724&r2=959725&view=diff
==============================================================================
--- james/imap/trunk/jcr/src/main/java/org/apache/james/imap/jcr/user/JCRSubscriptionMapper.java (original)
+++ james/imap/trunk/jcr/src/main/java/org/apache/james/imap/jcr/user/JCRSubscriptionMapper.java Thu Jul  1 17:14:10 2010
@@ -34,12 +34,14 @@ import javax.jcr.query.QueryResult;
 import org.apache.commons.logging.Log;
 import org.apache.jackrabbit.commons.JcrUtils;
 import org.apache.james.imap.api.display.HumanReadableText;
-import org.apache.james.imap.jcr.AbstractJCRMapper;
+import org.apache.james.imap.jcr.AbstractJCRScalingMapper;
+import org.apache.james.imap.jcr.JCRImapConstants;
 import org.apache.james.imap.jcr.MailboxSessionJCRRepository;
 import org.apache.james.imap.jcr.NodeLocker;
 import org.apache.james.imap.jcr.user.model.JCRSubscription;
 import org.apache.james.imap.mailbox.MailboxSession;
 import org.apache.james.imap.mailbox.SubscriptionException;
+import org.apache.james.imap.store.StoreConstants;
 import org.apache.james.imap.store.user.SubscriptionMapper;
 import org.apache.james.imap.store.user.model.Subscription;
 
@@ -47,7 +49,7 @@ import org.apache.james.imap.store.user.
  * JCR implementation of a SubscriptionManager
  * 
  */
-public class JCRSubscriptionMapper extends AbstractJCRMapper implements SubscriptionMapper {
+public class JCRSubscriptionMapper extends AbstractJCRScalingMapper implements SubscriptionMapper, StoreConstants {
 
     public JCRSubscriptionMapper(final MailboxSessionJCRRepository repos, MailboxSession session, final NodeLocker locker, final int scaling, final Log log) {
         super(repos,session, locker, scaling, log);
@@ -172,10 +174,11 @@ public class JCRSubscriptionMapper exten
             
             // its a new subscription
             if (sub == null) {
-                Node subscriptionsNode = JcrUtils.getOrAddNode(getSession().getRootNode(), MAILBOXES_PATH);
-                
+                node = JcrUtils.getOrAddNode(getSession().getRootNode(), MAILBOXES_PATH);
+                node = JcrUtils.getOrAddNode(node, StoreConstants.USER_NAMESPACE_PREFIX);
+
                 // This is needed to minimize the child nodes a bit
-                node = createUserPathStructure(subscriptionsNode, username);
+                node = createUserPathStructure(node, username);
             } else {
                 node = sub.getNode();
             }



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