Author: [email protected]
Date: Mon Sep 19 14:35:42 2011
New Revision: 1398
Log:
[AMDATUCASSANDRA-70] Implemented OAuth nonce store, using expiring columns
Added:
trunk/amdatu-cassandra/cassandra-store-nonce/
trunk/amdatu-cassandra/cassandra-store-nonce/pom.xml
trunk/amdatu-cassandra/cassandra-store-nonce/src/
trunk/amdatu-cassandra/cassandra-store-nonce/src/main/
trunk/amdatu-cassandra/cassandra-store-nonce/src/main/java/
trunk/amdatu-cassandra/cassandra-store-nonce/src/main/java/org/
trunk/amdatu-cassandra/cassandra-store-nonce/src/main/java/org/amdatu/
trunk/amdatu-cassandra/cassandra-store-nonce/src/main/java/org/amdatu/cassandra/
trunk/amdatu-cassandra/cassandra-store-nonce/src/main/java/org/amdatu/cassandra/store/
trunk/amdatu-cassandra/cassandra-store-nonce/src/main/java/org/amdatu/cassandra/store/nonce/
trunk/amdatu-cassandra/cassandra-store-nonce/src/main/java/org/amdatu/cassandra/store/nonce/osgi/
trunk/amdatu-cassandra/cassandra-store-nonce/src/main/java/org/amdatu/cassandra/store/nonce/osgi/Activator.java
trunk/amdatu-cassandra/cassandra-store-nonce/src/main/java/org/amdatu/cassandra/store/nonce/service/
trunk/amdatu-cassandra/cassandra-store-nonce/src/main/java/org/amdatu/cassandra/store/nonce/service/CassandraNonceStorageProviderImpl.java
trunk/amdatu-cassandra/cassandra-store-nonce/src/main/java/org/amdatu/cassandra/store/nonce/service/NonceColumnFamilyProvider.java
trunk/amdatu-cassandra/cassandra-store-nonce/src/test/
trunk/amdatu-cassandra/cassandra-store-nonce/src/test/java/
trunk/amdatu-cassandra/cassandra-store-nonce/src/test/java/org/
trunk/amdatu-cassandra/cassandra-store-nonce/src/test/java/org/amdatu/
trunk/amdatu-cassandra/cassandra-store-nonce/src/test/java/org/amdatu/cassandra/
trunk/amdatu-cassandra/cassandra-store-nonce/src/test/java/org/amdatu/cassandra/test/
trunk/amdatu-cassandra/cassandra-store-nonce/src/test/java/org/amdatu/cassandra/test/unit/
trunk/amdatu-cassandra/cassandra-store-nonce/src/test/java/org/amdatu/cassandra/test/unit/CassandraNonceStoreTest.java
Modified:
trunk/amdatu-cassandra/cassandra-persistencemanager/src/main/java/org/amdatu/cassandra/persistencemanager/CassandraPersistenceManager.java
trunk/amdatu-cassandra/cassandra-persistencemanager/src/main/java/org/amdatu/cassandra/persistencemanager/service/HectorCassandraPersistenceManagerImpl.java
trunk/amdatu-cassandra/pom.xml
trunk/amdatu-cassandra/test-unit/src/main/java/org/amdatu/cassandra/test/unit/framework/mock/CassandraPersistenceManagerMock.java
trunk/amdatu-cassandra/test-unit/src/main/java/org/amdatu/cassandra/test/unit/framework/mock/ColumnFamily.java
Modified:
trunk/amdatu-cassandra/cassandra-persistencemanager/src/main/java/org/amdatu/cassandra/persistencemanager/CassandraPersistenceManager.java
==============================================================================
---
trunk/amdatu-cassandra/cassandra-persistencemanager/src/main/java/org/amdatu/cassandra/persistencemanager/CassandraPersistenceManager.java
(original)
+++
trunk/amdatu-cassandra/cassandra-persistencemanager/src/main/java/org/amdatu/cassandra/persistencemanager/CassandraPersistenceManager.java
Mon Sep 19 14:35:42 2011
@@ -173,6 +173,32 @@
* The value to set on the column
*/
void setValue(String columnFamily, String rowKey, String superColumn,
String column, Object value);
+
+ /**
+ * Sets a single value on the specified column. The ColumnFamily may be
either of type "Super" or
+ * of type "Standard". In case the ColumnFamily is of type "Super", the
provided superColumn and column should both
+ * not be null. In case the ColumnFamily is of type "Standard", the
superColumn should be null and the column should
+ * not be null. When illegal arguments are provided (as described above)
or the specified ColumnFamily does not
+ * exist, an unchecked exception will be thrown.
+ * The provided value can be one of the following types: String, byte[],
Double or double, java.util.Date,
+ * Long or long, int or Integer, java.util.UUID or java.lang.Object (must
be Serializable though).
+ *
+ * @param columnFamily
+ * The name of the ColumnFamily to set the column for.
+ * @param rowKey
+ * The key of the row to set the column for.
+ * @param superColumn
+ * The name of the super column to set the column for (must be null
in case the ColumnFamily is
+ * of type "Standard").
+ * @param column
+ * The name of the column to set the value.
+ * @param value
+ * The value to set on the column
+ * @param ttl
+ * The time to live of the value, expressed in seconds. For
example if ttl=60, the the value is removed
+ * (expires) automatically after 60 seconds.
+ */
+ void setValue(String columnFamily, String rowKey, String superColumn,
String column, Object value, int ttl);
/**
* Returns a single value from the specified column. The ColumnFamily may
be either of type "Super" or
Modified:
trunk/amdatu-cassandra/cassandra-persistencemanager/src/main/java/org/amdatu/cassandra/persistencemanager/service/HectorCassandraPersistenceManagerImpl.java
==============================================================================
---
trunk/amdatu-cassandra/cassandra-persistencemanager/src/main/java/org/amdatu/cassandra/persistencemanager/service/HectorCassandraPersistenceManagerImpl.java
(original)
+++
trunk/amdatu-cassandra/cassandra-persistencemanager/src/main/java/org/amdatu/cassandra/persistencemanager/service/HectorCassandraPersistenceManagerImpl.java
Mon Sep 19 14:35:42 2011
@@ -252,7 +252,11 @@
public void setValue(final String columnFamily, final String rowKey, final
String superColumn, final String column,
final Object value) {
- internalsetValue(columnFamily, rowKey, superColumn, column, value);
+ internalsetValue(columnFamily, rowKey, superColumn, column, value, 0);
+ }
+
+ public void setValue(String columnFamily, String rowKey, String
superColumn, String column, Object value, int ttl) {
+ internalsetValue(columnFamily, rowKey, superColumn, column, value,
ttl);
}
public <T> T getValue(final String columnFamilyName, final String rowKey,
final String superColumnName,
@@ -377,19 +381,25 @@
}
private <T extends Object> void internalsetValue(final String
columnFamilyName, final String rowKey,
- final String superColumnName, final String columnName, final T value) {
+ final String superColumnName, final String columnName, final T value,
final int ttl) {
StringSerializer stringSerializer = StringSerializer.get();
Serializer<T> valueSerializer = getSerializer(value);
Mutator<String> mutator = HFactory.createMutator(getHectorKeyspace(),
stringSerializer);
if (isSuper(columnFamilyName, superColumnName, columnName)) {
- List<HColumn<String, T>> column =
- toList(HFactory.createColumn(columnName, value,
stringSerializer, valueSerializer));
- mutator.insert(rowKey, columnFamilyName,
HFactory.createSuperColumn(superColumnName, column,
+ HColumn<String, T> column = HFactory.createColumn(columnName,
value, stringSerializer, valueSerializer);
+ if (ttl > 0) {
+ column.setTtl(ttl);
+ }
+ List<HColumn<String, T>> columnList = toList(column);
+ mutator.insert(rowKey, columnFamilyName,
HFactory.createSuperColumn(superColumnName, columnList,
stringSerializer, stringSerializer, valueSerializer));
}
else {
- mutator.insert(rowKey, columnFamilyName,
- HFactory.createColumn(columnName, value, stringSerializer,
valueSerializer));
+ HColumn<String, T> column = HFactory.createColumn(columnName,
value, stringSerializer, valueSerializer);
+ if (ttl > 0) {
+ column.setTtl(ttl);
+ }
+ mutator.insert(rowKey, columnFamilyName, column);
}
}
Added: trunk/amdatu-cassandra/cassandra-store-nonce/pom.xml
==============================================================================
--- (empty file)
+++ trunk/amdatu-cassandra/cassandra-store-nonce/pom.xml Mon Sep 19
14:35:42 2011
@@ -0,0 +1,141 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--
+ Copyright (c) 2010, 2011 The Amdatu Foundation
+
+ Licensed 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.verning permissions and limitations
+ under the License.
+-->
+<project xmlns="http://maven.apache.org/POM/4.0.0"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0
http://maven.apache.org/maven-v4_0_0.xsd">
+ <modelVersion>4.0.0</modelVersion>
+ <parent>
+ <groupId>org.amdatu.cassandra</groupId>
+ <artifactId>org.amdatu.cassandra</artifactId>
+ <version>0.2.1-SNAPSHOT</version>
+ </parent>
+ <artifactId>org.amdatu.cassandra.store.nonce</artifactId>
+ <packaging>bundle</packaging>
+ <name>Amdatu Cassandra - OAuth nonce Store</name>
+ <description>Provides an implementation of the OAuth nonce
store</description>
+
+ <properties>
+ <amdatu.auth.version>0.2.0-RC1</amdatu.auth.version>
+ </properties>
+
+ <dependencies>
+ <dependency>
+ <groupId>org.amdatu.cassandra</groupId>
+ <artifactId>org.amdatu.cassandra.listener</artifactId>
+ <type>bundle</type>
+ </dependency>
+ <dependency>
+ <groupId>org.amdatu.cassandra</groupId>
+ <artifactId>org.amdatu.cassandra.application</artifactId>
+ <type>bundle</type>
+ </dependency>
+ <dependency>
+ <groupId>org.amdatu.cassandra</groupId>
+ <artifactId>org.amdatu.cassandra.persistencemanager</artifactId>
+ <type>bundle</type>
+ </dependency>
+ <dependency>
+ <groupId>org.amdatu.core</groupId>
+ <artifactId>org.amdatu.core.tenant</artifactId>
+ <type>bundle</type>
+ </dependency>
+ <dependency>
+ <groupId>org.amdatu.auth</groupId>
+ <artifactId>org.amdatu.auth.oauth.api</artifactId>
+ <version>${amdatu.auth.version}</version>
+ <scope>provided</scope>
+ <type>bundle</type>
+ </dependency>
+ <dependency>
+ <groupId>org.amdatu.auth</groupId>
+ <artifactId>org.amdatu.auth.oauth.server</artifactId>
+ <version>${amdatu.auth.version}</version>
+ <scope>provided</scope>
+ <type>bundle</type>
+ </dependency>
+ <dependency>
+ <groupId>org.codehaus.jackson</groupId>
+ <artifactId>jackson-core-asl</artifactId>
+ <version>1.4.0</version>
+ <scope>compile</scope>
+ </dependency>
+ <dependency>
+ <groupId>org.codehaus.jackson</groupId>
+ <artifactId>jackson-mapper-asl</artifactId>
+ <version>1.4.0</version>
+ <scope>compile</scope>
+ </dependency>
+ <dependency>
+ <groupId>org.json</groupId>
+ <artifactId>json</artifactId>
+ <version>20090211</version>
+ <scope>compile</scope>
+ </dependency>
+ <dependency>
+ <groupId>org.amdatu.cassandra</groupId>
+ <artifactId>org.amdatu.cassandra.test.unit</artifactId>
+ <type>jar</type>
+ </dependency>
+ </dependencies>
+
+ <build>
+ <plugins>
+ <plugin>
+ <artifactId>maven-source-plugin</artifactId>
+ </plugin>
+ <plugin>
+ <groupId>org.apache.felix</groupId>
+ <artifactId>maven-bundle-plugin</artifactId>
+ <configuration>
+ <instructions>
+
<Bundle-Activator>org.amdatu.cassandra.store.nonce.osgi.Activator</Bundle-Activator>
+
<Bundle-SymbolicName>org.amdatu.cassandra.store.nonce</Bundle-SymbolicName>
+ <Embed-Dependency>*;scope=compile</Embed-Dependency>
+ <Embed-Transitive>true</Embed-Transitive>
+ <Import-Package>
+ !org.joda.time,
+ org.amdatu.cassandra.application;version="[1.0,2.0)",
+ org.amdatu.cassandra.listener;version="[1.0,2.0)",
+ org.amdatu.cassandra.persistencemanager;version="[1.0,2.0)",
+ me.prettyprint.hector.api.beans;version="[1.0,2.0)",
+ *
+ </Import-Package>
+ </instructions>
+ </configuration>
+ </plugin>
+ </plugins>
+ </build>
+
+ <profiles>
+ <profile>
+ <!-- Profile that will copy the jar to the configured
amdatu.deploy.directory when
+ the deploy profile is activated -->
+ <id>deploy</id>
+ <activation>
+ <activeByDefault>false</activeByDefault>
+ </activation>
+ <build>
+ <defaultGoal>install</defaultGoal>
+ <plugins>
+ <plugin>
+ <groupId>org.apache.maven.plugins</groupId>
+ <artifactId>maven-antrun-plugin</artifactId>
+ </plugin>
+ </plugins>
+ </build>
+ </profile>
+ </profiles>
+</project>
Added:
trunk/amdatu-cassandra/cassandra-store-nonce/src/main/java/org/amdatu/cassandra/store/nonce/osgi/Activator.java
==============================================================================
--- (empty file)
+++
trunk/amdatu-cassandra/cassandra-store-nonce/src/main/java/org/amdatu/cassandra/store/nonce/osgi/Activator.java
Mon Sep 19 14:35:42 2011
@@ -0,0 +1,55 @@
+/*
+ * Copyright (c) 2010, 2011 The Amdatu Foundation
+ *
+ * Licensed 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.amdatu.cassandra.store.nonce.osgi;
+
+import org.amdatu.auth.oauth.server.OAuthNonceStorageProvider;
+import org.amdatu.cassandra.listener.ColumnFamilyAvailable;
+import org.amdatu.cassandra.listener.ColumnFamilyProvider;
+import org.amdatu.cassandra.persistencemanager.CassandraPersistenceManager;
+import
org.amdatu.cassandra.store.nonce.service.CassandraNonceStorageProviderImpl;
+import org.amdatu.cassandra.store.nonce.service.NonceColumnFamilyProvider;
+import org.apache.felix.dm.DependencyActivatorBase;
+import org.apache.felix.dm.DependencyManager;
+import org.osgi.framework.BundleContext;
+
+/**
+ * This is the bundle activator for the Cassandra nonce store bundle.
+ */
+public class Activator extends DependencyActivatorBase {
+
+ public void init(final BundleContext context, final DependencyManager
manager) {
+ // First define a service that provides the Service consumer
ColumnFamily we need
+ manager.add(createComponent()
+ .setInterface(new String[]{ColumnFamilyProvider.class.getName()},
null)
+ .setImplementation(NonceColumnFamilyProvider.class));
+
+ // Create and register the Cassandra Service consumer storage provider
+ String keyspaceFilter = "(" +
CassandraPersistenceManager.KEYSPACE_AWARE_KEY + "="
+ + CassandraPersistenceManager.DEFAULT_KEYSPACE + ")";
+ String nonceCFFilter = "(&" + keyspaceFilter + "(" +
ColumnFamilyAvailable.FILTER_NAME
+ + "=" + NonceColumnFamilyProvider.CF_NONCE + "))";
+ manager.add(
+ createComponent()
+ .setImplementation(CassandraNonceStorageProviderImpl.class)
+ .setInterface(OAuthNonceStorageProvider.class.getName(), null)
+
.add(createServiceDependency().setService(CassandraPersistenceManager.class,
keyspaceFilter).setRequired(true))
+
.add(createServiceDependency().setService(ColumnFamilyAvailable.class,
nonceCFFilter).setRequired(true)));
+ }
+
+ @Override
+ public void destroy(final BundleContext context, final DependencyManager
manager) throws Exception {
+ }
+}
Added:
trunk/amdatu-cassandra/cassandra-store-nonce/src/main/java/org/amdatu/cassandra/store/nonce/service/CassandraNonceStorageProviderImpl.java
==============================================================================
--- (empty file)
+++
trunk/amdatu-cassandra/cassandra-store-nonce/src/main/java/org/amdatu/cassandra/store/nonce/service/CassandraNonceStorageProviderImpl.java
Mon Sep 19 14:35:42 2011
@@ -0,0 +1,89 @@
+/*
+ * Copyright (c) 2010, 2011 The Amdatu Foundation
+ *
+ * Licensed 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.amdatu.cassandra.store.nonce.service;
+
+import org.amdatu.auth.oauth.server.OAuthNonceStorageProvider;
+import org.amdatu.cassandra.persistencemanager.CassandraPersistenceManager;
+
+/**
+ * This class provides a Cassandra based implementation of a OAuth nonce store.
+ * The implementation is primarily focussed on performance. Nonces are created
for each
+ * (OAuth protected) HTTP request so potentially, the nonce store may hold
many nonces.
+ *
+ * @author ivol
+ */
+public class CassandraNonceStorageProviderImpl implements
OAuthNonceStorageProvider {
+ // NB: the time to live of nonces is up to the implementation of the Nonce
store.
+ // We use time to live of 5 minutes
+ public static final int DEFAULT_NONCE_TTL = 5 * 60;
+
+ // Service dependencies, injected by the dependency manager
+ private volatile CassandraPersistenceManager m_pm;
+
+ // The time to live of nonces
+ private int m_ttl;
+
+ // Column names
+ private static final String COLNAME = "n";
+
+ /**
+ * Default constructor.
+ */
+ public CassandraNonceStorageProviderImpl() {
+ m_ttl = DEFAULT_NONCE_TTL;
+ }
+
+ /**
+ * Constructor used by the Unit test.
+ *
+ * @param pm
+ * @param logService
+ */
+ public CassandraNonceStorageProviderImpl(CassandraPersistenceManager pm,
int ttl) {
+ m_pm = pm;
+ m_ttl = ttl;
+ }
+
+ public boolean addNonce(long timestamp, String nonce, String[]
requestParams) {
+ String rowKey = getRowKey(timestamp, nonce, requestParams);
+ if (m_pm.getValue(NonceColumnFamilyProvider.CF_NONCE, rowKey, null,
COLNAME, String.class) != null) {
+ return false;
+ }
+ m_pm.setValue(NonceColumnFamilyProvider.CF_NONCE, rowKey, null,
COLNAME, "1", m_ttl);
+ return true;
+ }
+
+ // NB: this method has an empty implementation, since we handle nonce
expiration in this
+ // Cassandra implementation in a different way, by using the "expiring
columns" function.
+ public void removeExpiredNonces(long timestamp) {
+ }
+
+ // NB: there may be special cases in which two different
timestamp/nonce/requestParams
+ // combinations are mapped to the same row key, but this store is
primarily focused on
+ // performance rather then a 100% guarantee of unique nonces. In this very
rare case
+ // a hacker could perform a replay attack with this specific request, but
what would be
+ // the odds?
+ private String getRowKey(long timestamp, String nonce, String[]
requestParams) {
+ String rowkey = nonce + "&";
+ if (requestParams != null) {
+ for (String param : requestParams) {
+ rowkey += param + "&";
+ }
+ }
+ rowkey += timestamp;
+ return rowkey;
+ }
+}
Added:
trunk/amdatu-cassandra/cassandra-store-nonce/src/main/java/org/amdatu/cassandra/store/nonce/service/NonceColumnFamilyProvider.java
==============================================================================
--- (empty file)
+++
trunk/amdatu-cassandra/cassandra-store-nonce/src/main/java/org/amdatu/cassandra/store/nonce/service/NonceColumnFamilyProvider.java
Mon Sep 19 14:35:42 2011
@@ -0,0 +1,41 @@
+/*
+ * Copyright (c) 2010, 2011 The Amdatu Foundation
+ *
+ * Licensed 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.amdatu.cassandra.store.nonce.service;
+
+import org.amdatu.cassandra.listener.ColumnFamilyDefinition;
+import org.amdatu.cassandra.listener.ColumnFamilyDefinition.ColumnType;
+import org.amdatu.cassandra.listener.ColumnFamilyDefinition.CompareType;
+import org.amdatu.cassandra.listener.ColumnFamilyProvider;
+import org.amdatu.cassandra.persistencemanager.CassandraPersistenceManager;
+
+public class NonceColumnFamilyProvider implements ColumnFamilyProvider {
+ /**
+ * ColumnFamily that stores the nonces.
+ */
+ public static final String CF_NONCE = "OAuthNonce";
+
+ @Override
+ public ColumnFamilyDefinition[] getColumnFamilies() {
+ return new ColumnFamilyDefinition[] {
+ new ColumnFamilyDefinition(
+ CF_NONCE,
+ new String[]
{CassandraPersistenceManager.DEFAULT_KEYSPACE},
+ ColumnType.STANDARD,
+ CompareType.BYTESTYPE,
+ CompareType.BYTESTYPE)};
+ }
+
+}
Added:
trunk/amdatu-cassandra/cassandra-store-nonce/src/test/java/org/amdatu/cassandra/test/unit/CassandraNonceStoreTest.java
==============================================================================
--- (empty file)
+++
trunk/amdatu-cassandra/cassandra-store-nonce/src/test/java/org/amdatu/cassandra/test/unit/CassandraNonceStoreTest.java
Mon Sep 19 14:35:42 2011
@@ -0,0 +1,77 @@
+/*
+ * Copyright (c) 2010, 2011 The Amdatu Foundation
+ *
+ * Licensed 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.amdatu.cassandra.test.unit;
+
+import junit.framework.Assert;
+
+import org.amdatu.auth.oauth.api.ConsumerAlreadyExistsException;
+import org.amdatu.auth.oauth.api.ConsumerNotFoundException;
+import org.amdatu.auth.oauth.api.ConsumerRegistryStorageException;
+import org.amdatu.cassandra.listener.ColumnFamilyDefinition;
+import
org.amdatu.cassandra.store.nonce.service.CassandraNonceStorageProviderImpl;
+import org.amdatu.cassandra.store.nonce.service.NonceColumnFamilyProvider;
+import
org.amdatu.cassandra.test.unit.framework.mock.CassandraPersistenceManagerMock;
+import org.amdatu.cassandra.test.unit.framework.mock.LogServiceMock;
+import org.junit.Test;
+
+public class CassandraNonceStoreTest {
+ @Test
+ public void test() throws ConsumerRegistryStorageException,
ConsumerAlreadyExistsException,
+ ConsumerNotFoundException {
+ // Create the mock objects
+ LogServiceMock logService = new LogServiceMock();
+ CassandraPersistenceManagerMock<String, String, Object> pm = new
CassandraPersistenceManagerMock<String, String, Object>("Default");
+ ColumnFamilyDefinition[] colDefs = new
NonceColumnFamilyProvider().getColumnFamilies();
+ pm.addColumnFamily(colDefs);
+
+ // And the store under test itself, define a TTL of 5 seconds
+ int ttl = 1;
+ CassandraNonceStorageProviderImpl store = new
CassandraNonceStorageProviderImpl(pm, ttl);
+
+ String nonce = "A";
+ long timestamp1 = 10000; // second 10
+ long timestamp2 = 10001;
+ long timestamp3 = 10002;
+ long timestamp4 = 20000;
+ long timestamp5 = 2435436;
+
+ // Validate that the same nonce can be added only once
+ Assert.assertTrue(store.addNonce(timestamp1, nonce, null));
+ Assert.assertFalse(store.addNonce(timestamp1, nonce, null));
+ Assert.assertTrue(store.addNonce(timestamp2, nonce, null));
+ Assert.assertFalse(store.addNonce(timestamp2, nonce, null));
+ Assert.assertTrue(store.addNonce(timestamp3, nonce, new
String[]{"arg1"}));
+ Assert.assertFalse(store.addNonce(timestamp3, nonce, new
String[]{"arg1"}));
+ Assert.assertTrue(store.addNonce(timestamp4, nonce, new
String[]{"arg2"}));
+ Assert.assertFalse(store.addNonce(timestamp4, nonce, new
String[]{"arg2"}));
+ Assert.assertTrue(store.addNonce(timestamp5, nonce, new
String[]{"arg1", "arg2"}));
+ Assert.assertFalse(store.addNonce(timestamp5, nonce, new
String[]{"arg1", "arg2"}));
+
+ // Now wait for 5 seconds and verify that the nonces have been removed
(TTL is 5 seconds)
+ try {
+ Thread.sleep(ttl*1000);
+ }
+ catch (InterruptedException e) {
+ }
+ Assert.assertTrue(store.addNonce(timestamp1, nonce, null));
+ Assert.assertTrue(store.addNonce(timestamp2, nonce, null));
+ Assert.assertTrue(store.addNonce(timestamp3, nonce, new
String[]{"arg1"}));
+ Assert.assertTrue(store.addNonce(timestamp4, nonce, new
String[]{"arg2"}));
+ Assert.assertTrue(store.addNonce(timestamp5, nonce, new
String[]{"arg1", "arg2"}));
+
+
+ }
+}
Modified: trunk/amdatu-cassandra/pom.xml
==============================================================================
--- trunk/amdatu-cassandra/pom.xml (original)
+++ trunk/amdatu-cassandra/pom.xml Mon Sep 19 14:35:42 2011
@@ -274,6 +274,7 @@
<module>cassandra-persistencemanager</module>
<module>cassandra-store-consumer</module>
<module>cassandra-store-gadget</module>
+ <module>cassandra-store-nonce</module>
<module>cassandra-store-token</module>
<module>cassandra-store-tenant</module>
<module>cassandra-store-useradmin</module>
Modified:
trunk/amdatu-cassandra/test-unit/src/main/java/org/amdatu/cassandra/test/unit/framework/mock/CassandraPersistenceManagerMock.java
==============================================================================
---
trunk/amdatu-cassandra/test-unit/src/main/java/org/amdatu/cassandra/test/unit/framework/mock/CassandraPersistenceManagerMock.java
(original)
+++
trunk/amdatu-cassandra/test-unit/src/main/java/org/amdatu/cassandra/test/unit/framework/mock/CassandraPersistenceManagerMock.java
Mon Sep 19 14:35:42 2011
@@ -163,6 +163,10 @@
@SuppressWarnings("unchecked")
public void setValue(String columnFamily, String rowKey, String
superColumn, String column, Object value) {
+ setValue(columnFamily, rowKey, superColumn, column, value, 0);
+ }
+
+ public void setValue(String columnFamily, String rowKey, String
superColumn, String column, Object value, int ttl) {
if (!exists(columnFamily)) {
throw new HInvalidRequestException("ColumnFamily '" + columnFamily
+ "' does not exist");
}
@@ -187,6 +191,9 @@
else {
hColumn.setValue((V) value);
}
+ if (ttl > 0) {
+ HectorUtil.getColumn(hSuperColumn, column).setTtl(ttl);
+ }
}
else {
// Column case
@@ -203,6 +210,9 @@
else {
col.setValue((V) value);
}
+ if (ttl > 0) {
+ row.getColumn(column).setTtl(ttl);
+ }
}
}
Modified:
trunk/amdatu-cassandra/test-unit/src/main/java/org/amdatu/cassandra/test/unit/framework/mock/ColumnFamily.java
==============================================================================
---
trunk/amdatu-cassandra/test-unit/src/main/java/org/amdatu/cassandra/test/unit/framework/mock/ColumnFamily.java
(original)
+++
trunk/amdatu-cassandra/test-unit/src/main/java/org/amdatu/cassandra/test/unit/framework/mock/ColumnFamily.java
Mon Sep 19 14:35:42 2011
@@ -182,7 +182,7 @@
if (m_type == ColumnType.STANDARD) {
for (RowImpl<SN, N, V> row : m_rows) {
if (row.getKey().equals(rowKey)) {
- return row.getColumns();
+ return filterExpiredColumns(row.getColumns());
}
}
return null;
@@ -192,4 +192,14 @@
"Cannot retrieve columns from a ColumnFamily of type super,
retrieve super columns instead");
}
}
+
+ private List<HColumn<N, V>> filterExpiredColumns(List<HColumn<N, V>>
columns) {
+ List<HColumn<N, V>> filteredColumns = new ArrayList<HColumn<N, V>>();
+ for (HColumn<N, V> column : columns) {
+ if (column.getTtl() == 0 || column.getClock() +
1000*column.getTtl() > System.currentTimeMillis()) {
+ filteredColumns.add(column);
+ }
+ }
+ return filteredColumns;
+ }
}
_______________________________________________
Amdatu-commits mailing list
[email protected]
http://lists.amdatu.org/mailman/listinfo/amdatu-commits