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