Author: eric Date: Thu May 28 15:51:11 2015 New Revision: 1682267 URL: http://svn.apache.org/r1682267 Log: Add missing files to support Cassandra table creation, patch contributed by Benoit Tellier (MAILBOX-226)
Added: james/mailbox/trunk/cassandra/README.txt james/mailbox/trunk/cassandra/src/main/java/org/apache/james/mailbox/cassandra/CassandraConstants.java james/mailbox/trunk/cassandra/src/main/java/org/apache/james/mailbox/cassandra/CassandraTableManager.java james/mailbox/trunk/cassandra/src/main/java/org/apache/james/mailbox/cassandra/ClusterFactory.java james/mailbox/trunk/cassandra/src/main/java/org/apache/james/mailbox/cassandra/ClusterWithKeyspaceCreatedFactory.java james/mailbox/trunk/cassandra/src/main/java/org/apache/james/mailbox/cassandra/SessionFactory.java Removed: james/mailbox/trunk/cassandra/src/main/java/org/apache/james/mailbox/cassandra/CassandraSession.java Added: james/mailbox/trunk/cassandra/README.txt URL: http://svn.apache.org/viewvc/james/mailbox/trunk/cassandra/README.txt?rev=1682267&view=auto ============================================================================== --- james/mailbox/trunk/cassandra/README.txt (added) +++ james/mailbox/trunk/cassandra/README.txt Thu May 28 15:51:11 2015 @@ -0,0 +1,18 @@ += Cassandra Mailbox implementation + +This Mailbox sub-project is about providing a scalable mailbox implementation relying on Cassandra database. + +Concurrency is handled by this implementation while performing writes using Lightweight transactions. You do not need to lock anything, or provide utils to lock anything, when using this implementation. + +== Configuration + +The configuration is achieved through Spring. The file is 'src/main/resources/META-INF/spring/mailbox-cassandra.xml' . + +The components are instanciated and wired together. + +What might interest you the most is the way you want to connect your Cassandra cluster. + +Factories are used. You have : + * ClusterFactory : you specify which Cassandra servers you want to connect, with ( optional ) which user name and password to use. + * ClusterWithKeyspaceCreatedFactory : This ( optional ) component creates a Keyspace if it does not already exists. You may want to skip this step in production environment. + * SessionFactory : Connect the appropriated Keyspace, to create a Session our application can work with. \ No newline at end of file Added: james/mailbox/trunk/cassandra/src/main/java/org/apache/james/mailbox/cassandra/CassandraConstants.java URL: http://svn.apache.org/viewvc/james/mailbox/trunk/cassandra/src/main/java/org/apache/james/mailbox/cassandra/CassandraConstants.java?rev=1682267&view=auto ============================================================================== --- james/mailbox/trunk/cassandra/src/main/java/org/apache/james/mailbox/cassandra/CassandraConstants.java (added) +++ james/mailbox/trunk/cassandra/src/main/java/org/apache/james/mailbox/cassandra/CassandraConstants.java Thu May 28 15:51:11 2015 @@ -0,0 +1,24 @@ +/**************************************************************** + * 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.mailbox.cassandra; + +public interface CassandraConstants { + int LIGHTWEIGHT_TRANSACTION_APPLIED = 0; +} Added: james/mailbox/trunk/cassandra/src/main/java/org/apache/james/mailbox/cassandra/CassandraTableManager.java URL: http://svn.apache.org/viewvc/james/mailbox/trunk/cassandra/src/main/java/org/apache/james/mailbox/cassandra/CassandraTableManager.java?rev=1682267&view=auto ============================================================================== --- james/mailbox/trunk/cassandra/src/main/java/org/apache/james/mailbox/cassandra/CassandraTableManager.java (added) +++ james/mailbox/trunk/cassandra/src/main/java/org/apache/james/mailbox/cassandra/CassandraTableManager.java Thu May 28 15:51:11 2015 @@ -0,0 +1,149 @@ +/**************************************************************** + * 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.mailbox.cassandra; + +import static com.datastax.driver.core.DataType.*; + +import com.datastax.driver.core.querybuilder.QueryBuilder; +import com.datastax.driver.core.schemabuilder.Create; + +import com.datastax.driver.core.Session; +import com.datastax.driver.core.schemabuilder.SchemaBuilder; +import com.datastax.driver.core.schemabuilder.SchemaStatement; +import org.apache.james.mailbox.cassandra.table.CassandraACLTable; +import org.apache.james.mailbox.cassandra.table.CassandraMailboxCountersTable; +import org.apache.james.mailbox.cassandra.table.CassandraMailboxTable; +import org.apache.james.mailbox.cassandra.table.CassandraMessageTable; +import org.apache.james.mailbox.cassandra.table.CassandraMessageUidTable; +import org.apache.james.mailbox.cassandra.table.CassandraSubscriptionTable; + +import java.util.Arrays; + +public class CassandraTableManager { + + private Session session; + + enum TABLE { + Mailbox(CassandraMailboxTable.TABLE_NAME, + SchemaBuilder.createTable(CassandraMailboxTable.TABLE_NAME) + .ifNotExists() + .addPartitionKey(CassandraMailboxTable.ID, uuid()) + .addColumn(CassandraMailboxTable.NAMESPACE, text()) + .addColumn(CassandraMailboxTable.USER, text()) + .addColumn(CassandraMailboxTable.NAME, text()) + .addColumn(CassandraMailboxTable.PATH, text()) + .addColumn(CassandraMailboxTable.UIDVALIDITY, bigint())), + MailboxCounter(CassandraMailboxCountersTable.TABLE_NAME, + SchemaBuilder.createTable(CassandraMailboxCountersTable.TABLE_NAME) + .ifNotExists() + .addPartitionKey(CassandraMailboxCountersTable.MAILBOX_ID, uuid()) + .addColumn(CassandraMailboxCountersTable.COUNT, counter()) + .addColumn(CassandraMailboxCountersTable.UNSEEN, counter()) + .addColumn(CassandraMailboxCountersTable.NEXT_MOD_SEQ, counter())), + MessageUid(CassandraMessageUidTable.TABLE_NAME, + SchemaBuilder.createTable(CassandraMessageUidTable.TABLE_NAME) + .ifNotExists() + .addPartitionKey(CassandraMessageUidTable.MAILBOX_ID, uuid()) + .addColumn(CassandraMessageUidTable.NEXT_UID, bigint())), + Message(CassandraMessageTable.TABLE_NAME, + SchemaBuilder.createTable(CassandraMessageTable.TABLE_NAME) + .ifNotExists() + .addPartitionKey(CassandraMessageTable.MAILBOX_ID, uuid()) + .addClusteringColumn(CassandraMessageTable.IMAP_UID, bigint()) + .addColumn(CassandraMessageTable.INTERNAL_DATE, timestamp()) + .addColumn(CassandraMessageTable.BODY_START_OCTET, cint()) + .addColumn(CassandraMessageTable.BODY_OCTECTS, cint()) + .addColumn(CassandraMessageTable.TEXTUAL_LINE_COUNT, bigint()) + .addColumn(CassandraMessageTable.MOD_SEQ, bigint()) + .addColumn(CassandraMessageTable.MEDIA_TYPE, text()) + .addColumn(CassandraMessageTable.SUB_TYPE, text()) + .addColumn(CassandraMessageTable.FULL_CONTENT_OCTETS, cint()) + .addColumn(CassandraMessageTable.BODY_CONTENT, blob()) + .addColumn(CassandraMessageTable.HEADER_CONTENT, blob()) + .addColumn(CassandraMessageTable.Flag.ANSWERED, cboolean()) + .addColumn(CassandraMessageTable.Flag.DELETED, cboolean()) + .addColumn(CassandraMessageTable.Flag.DRAFT, cboolean()) + .addColumn(CassandraMessageTable.Flag.FLAGGED, cboolean()) + .addColumn(CassandraMessageTable.Flag.RECENT, cboolean()) + .addColumn(CassandraMessageTable.Flag.SEEN, cboolean()) + .addColumn(CassandraMessageTable.Flag.USER, cboolean()) + .addColumn(CassandraMessageTable.FLAG_VERSION, bigint())), + Subscription(CassandraSubscriptionTable.TABLE_NAME, + SchemaBuilder.createTable(CassandraSubscriptionTable.TABLE_NAME) + .ifNotExists() + .addPartitionKey(CassandraSubscriptionTable.MAILBOX, text()) + .addClusteringColumn(CassandraSubscriptionTable.USER, text()) + ), + Acl(CassandraACLTable.TABLE_NAME, + SchemaBuilder.createTable(CassandraACLTable.TABLE_NAME) + .ifNotExists() + .addPartitionKey(CassandraACLTable.ID, uuid()) + .addColumn(CassandraACLTable.ACL, text()) + .addColumn(CassandraACLTable.VERSION, bigint()) + ) + ; + private Create createStatement; + private String name; + + TABLE(String name, Create createStatement) { + this.createStatement = createStatement; + this.name = name; + } + } + + enum INDEX { + MailboxPath(SchemaBuilder.createIndex(CassandraMailboxTable.TABLE_NAME) + .ifNotExists() + .onTable(CassandraMailboxTable.TABLE_NAME) + .andColumn(CassandraMailboxTable.PATH)); + private SchemaStatement createIndexStatement; + + INDEX(SchemaStatement createIndexStatement) { + this.createIndexStatement = createIndexStatement; + } + } + + public CassandraTableManager(Session session) { + this.session = session; + } + + public CassandraTableManager ensureAllTables() { + Arrays.asList(TABLE.values()) + .forEach( + (table) -> session.execute(table.createStatement) + ); + Arrays.asList(INDEX.values()) + .forEach( + (table) -> session.execute(table.createIndexStatement) + ); + return this; + } + + public void clearAllTables() { + Arrays.asList(TABLE.values()) + .forEach( + (table) -> clearTable(table.name) + ); + } + + private void clearTable(String tableName) { + session.execute(QueryBuilder.truncate(tableName)); + } +} Added: james/mailbox/trunk/cassandra/src/main/java/org/apache/james/mailbox/cassandra/ClusterFactory.java URL: http://svn.apache.org/viewvc/james/mailbox/trunk/cassandra/src/main/java/org/apache/james/mailbox/cassandra/ClusterFactory.java?rev=1682267&view=auto ============================================================================== --- james/mailbox/trunk/cassandra/src/main/java/org/apache/james/mailbox/cassandra/ClusterFactory.java (added) +++ james/mailbox/trunk/cassandra/src/main/java/org/apache/james/mailbox/cassandra/ClusterFactory.java Thu May 28 15:51:11 2015 @@ -0,0 +1,69 @@ +/**************************************************************** + * 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.mailbox.cassandra; + +import com.datastax.driver.core.Cluster; +import com.google.common.base.Strings; +import com.google.common.collect.ImmutableList; + +import java.util.List; + +public class ClusterFactory { + + public static class CassandraServer { + private String ip; + private int port; + + public CassandraServer(String ip, int port) { + this.ip = ip; + this.port = port; + } + } + + private final static String DEFAULT_CLUSTER_IP = "localhost"; + private final static int DEFAULT_CLUSTER_PORT = 9042; + + public Cluster createClusterForClusterWithPassWord(List<CassandraServer> servers, String userName, String password) { + Cluster.Builder clusterBuilder = Cluster.builder(); + servers.forEach( + (server) -> clusterBuilder.addContactPoint(server.ip).withPort(server.port) + ); + if(!Strings.isNullOrEmpty(userName) && !Strings.isNullOrEmpty(password)) { + clusterBuilder.withCredentials(userName, password); + } + return clusterBuilder.build(); + } + + public Cluster createClusterForClusterWithoutPassWord(List<CassandraServer> servers) { + return createClusterForClusterWithPassWord(servers, null, null); + } + + public Cluster createClusterForSingleServerWithPassWord(String ip, int port, String userName, String password) { + return createClusterForClusterWithPassWord(ImmutableList.of(new CassandraServer(ip, port)), userName, password); + } + + public Cluster createClusterForSingleServerWithoutPassWord(String ip, int port) { + return createClusterForClusterWithPassWord(ImmutableList.of(new CassandraServer(ip, port)), null, null); + } + + public Cluster createDefaultSession() { + return createClusterForSingleServerWithoutPassWord(DEFAULT_CLUSTER_IP, DEFAULT_CLUSTER_PORT); + } +} Added: james/mailbox/trunk/cassandra/src/main/java/org/apache/james/mailbox/cassandra/ClusterWithKeyspaceCreatedFactory.java URL: http://svn.apache.org/viewvc/james/mailbox/trunk/cassandra/src/main/java/org/apache/james/mailbox/cassandra/ClusterWithKeyspaceCreatedFactory.java?rev=1682267&view=auto ============================================================================== --- james/mailbox/trunk/cassandra/src/main/java/org/apache/james/mailbox/cassandra/ClusterWithKeyspaceCreatedFactory.java (added) +++ james/mailbox/trunk/cassandra/src/main/java/org/apache/james/mailbox/cassandra/ClusterWithKeyspaceCreatedFactory.java Thu May 28 15:51:11 2015 @@ -0,0 +1,32 @@ +package org.apache.james.mailbox.cassandra; + +import com.datastax.driver.core.Cluster; +import com.datastax.driver.core.Session; + +public class ClusterWithKeyspaceCreatedFactory { + + private final static int DEFAULT_REPLICATION_FACTOR = 1; + + public Cluster clusterWithInitializedKeyspace(Cluster cluster, String keyspace, int replicationFactor) { + if (isKeyspacePresent(cluster, keyspace)) { + createKeyspace(cluster, keyspace, replicationFactor); + } + return cluster; + } + + public Cluster clusterWithInitializedKeyspace(Cluster cluster, String keyspace) { + return clusterWithInitializedKeyspace(cluster, keyspace, DEFAULT_REPLICATION_FACTOR); + } + + private boolean isKeyspacePresent(Cluster cluster, String keyspace) { + return cluster.getMetadata().getKeyspace(keyspace) == null; + } + + private void createKeyspace(Cluster cluster, String keyspace, int replicationFactor) { + try (Session session = cluster.connect()) { + session.execute("CREATE KEYSPACE IF NOT EXISTS " + keyspace + + " WITH replication = {'class':'SimpleStrategy', 'replication_factor':" + replicationFactor + "};"); + } + } + +} Added: james/mailbox/trunk/cassandra/src/main/java/org/apache/james/mailbox/cassandra/SessionFactory.java URL: http://svn.apache.org/viewvc/james/mailbox/trunk/cassandra/src/main/java/org/apache/james/mailbox/cassandra/SessionFactory.java?rev=1682267&view=auto ============================================================================== --- james/mailbox/trunk/cassandra/src/main/java/org/apache/james/mailbox/cassandra/SessionFactory.java (added) +++ james/mailbox/trunk/cassandra/src/main/java/org/apache/james/mailbox/cassandra/SessionFactory.java Thu May 28 15:51:11 2015 @@ -0,0 +1,39 @@ +/**************************************************************** + * 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.mailbox.cassandra; + +import com.datastax.driver.core.Cluster; +import com.datastax.driver.core.Session; + +public class SessionFactory { + private final static String DEFAULT_KEYSPACE_NAME = "apache_james"; + + public Session createSession(Cluster cluster, String keyspace) { + Session session = cluster.connect(keyspace); + new CassandraTableManager(session) + .ensureAllTables(); + return session; + } + + public Session createSession(Cluster cluster) { + return createSession(cluster, DEFAULT_KEYSPACE_NAME); + } + +} --------------------------------------------------------------------- To unsubscribe, e-mail: server-dev-unsubscr...@james.apache.org For additional commands, e-mail: server-dev-h...@james.apache.org