polygene-commits mailing list archives

Site index · List index
Message view « Date » · « Thread »
Top « Date » · « Thread »
From nic...@apache.org
Subject [07/15] polygene-java git commit: POLYGENE-225 - Cassandra entitystore implemented.
Date Sat, 18 Feb 2017 00:43:33 GMT
POLYGENE-225 - Cassandra entitystore implemented.


Project: http://git-wip-us.apache.org/repos/asf/polygene-java/repo
Commit: http://git-wip-us.apache.org/repos/asf/polygene-java/commit/c86b1154
Tree: http://git-wip-us.apache.org/repos/asf/polygene-java/tree/c86b1154
Diff: http://git-wip-us.apache.org/repos/asf/polygene-java/diff/c86b1154

Branch: refs/heads/develop
Commit: c86b1154e820d197516ace8da63d077d2f79f5b8
Parents: 96d03df
Author: niclas <niclas@spicter.com>
Authored: Tue Feb 14 12:44:48 2017 +0800
Committer: niclas <niclas@spicter.com>
Committed: Tue Feb 14 12:44:48 2017 +0800

----------------------------------------------------------------------
 dependencies.gradle                             |   3 +
 extensions/entitystore-cassandra/build.gradle   |  38 ++
 extensions/entitystore-cassandra/dev-status.xml |  38 ++
 .../entitystore/cassandra/CassandraCluster.java | 213 ++++++++++
 .../CassandraEntityStoreConfiguration.java      |  50 +++
 .../cassandra/CassandraEntityStoreMixin.java    | 425 +++++++++++++++++++
 .../cassandra/CassandraEntityStoreService.java  |  48 +++
 .../cassandra/CassandraMigration.java           |  28 ++
 .../CassandraDBEntityStoreAssembler.java        |  46 ++
 .../polygene/entitystore/cassandra/package.html |  43 ++
 .../cassandra/CassandraMapEntityStoreTest.java  |  89 ++++
 .../cassandra/EmptyCassandraTableMixin.java     |  20 +
 .../src/main/docker/cassandra/Dockerfile        |  16 +
 settings.gradle                                 |   4 +-
 tools/shell/build.gradle                        |  39 --
 tools/shell/dev-status.xml                      |  38 --
 .../create/project/NullProjectCreator.java      |  37 --
 17 files changed, 1059 insertions(+), 116 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/polygene-java/blob/c86b1154/dependencies.gradle
----------------------------------------------------------------------
diff --git a/dependencies.gradle b/dependencies.gradle
index 6f6f0b9..4a00547 100644
--- a/dependencies.gradle
+++ b/dependencies.gradle
@@ -41,6 +41,7 @@ dependencies.libraries << [
 // Extensions, Libraries and Tools dependencies
 def bonecpVersion = '0.8.0.RELEASE'
 def bouncyVersion = '1.55'
+def cassandraClientVersion = '3.1.3'
 def codahaleMetricsVersion = '3.1.2'
 def commonsDbcpVersion = '2.1.1'
 def commonsLangVersion = '3.5'
@@ -77,6 +78,8 @@ def velocityVersion = '1.7'
 dependencies.libraries << [
   bonecp              : "com.jolbox:bonecp:$bonecpVersion",
   bouncy_castle       : "org.bouncycastle:bcprov-jdk15on:$bouncyVersion",
+  cassandra_client    : [ "com.datastax.cassandra:cassandra-driver-core:$cassandraClientVersion",
+          ],
   codahale_metrics    : [ "io.dropwizard.metrics:metrics-core:$codahaleMetricsVersion",
                           "io.dropwizard.metrics:metrics-healthchecks:$codahaleMetricsVersion" ],
   commons_dbcp        : "org.apache.commons:commons-dbcp2:$commonsDbcpVersion",

http://git-wip-us.apache.org/repos/asf/polygene-java/blob/c86b1154/extensions/entitystore-cassandra/build.gradle
----------------------------------------------------------------------
diff --git a/extensions/entitystore-cassandra/build.gradle b/extensions/entitystore-cassandra/build.gradle
new file mode 100644
index 0000000..2fb41a2
--- /dev/null
+++ b/extensions/entitystore-cassandra/build.gradle
@@ -0,0 +1,38 @@
+/*
+ *  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.
+ *
+ *
+ */
+
+apply plugin: 'polygene-extension'
+
+description = "Apache Polygene™ Cassandra EntityStore Extension"
+
+jar { manifest { name = "Apache Polygene™ Extension - EntityStore - Cassandra" } }
+
+dependencies {
+  compile polygene.core.bootstrap
+  compile polygene.library( 'locking' )
+  compile libraries.cassandra_client
+
+  runtime polygene.core.runtime
+
+  testCompile polygene.internals.testsupport
+  testCompile polygene.extension( 'valueserialization-orgjson' )
+
+  testRuntime libraries.logback
+}

http://git-wip-us.apache.org/repos/asf/polygene-java/blob/c86b1154/extensions/entitystore-cassandra/dev-status.xml
----------------------------------------------------------------------
diff --git a/extensions/entitystore-cassandra/dev-status.xml b/extensions/entitystore-cassandra/dev-status.xml
new file mode 100644
index 0000000..fcc2930
--- /dev/null
+++ b/extensions/entitystore-cassandra/dev-status.xml
@@ -0,0 +1,38 @@
+<?xml version="1.0" encoding="UTF-8" ?>
+<!--
+  ~  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.
+  ~
+  ~
+  -->
+<module xmlns="http://polygene.apache.org/schemas/2008/dev-status/1"
+        xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
+        xsi:schemaLocation="http://polygene.apache.org/schemas/2008/dev-status/1
+        http://polygene.apache.org/schemas/2008/dev-status/1/dev-status.xsd">
+  <status>
+        <!--none,early,beta,stable,mature-->
+        <codebase>beta</codebase>
+
+        <!-- none, brief, good, complete -->
+        <documentation>none</documentation>
+
+        <!-- none, some, good, complete -->
+        <unittests>good</unittests>
+    </status>
+    <licenses>
+        <license>ALv2</license>
+    </licenses>
+</module>

http://git-wip-us.apache.org/repos/asf/polygene-java/blob/c86b1154/extensions/entitystore-cassandra/src/main/java/org/apache/polygene/entitystore/cassandra/CassandraCluster.java
----------------------------------------------------------------------
diff --git a/extensions/entitystore-cassandra/src/main/java/org/apache/polygene/entitystore/cassandra/CassandraCluster.java b/extensions/entitystore-cassandra/src/main/java/org/apache/polygene/entitystore/cassandra/CassandraCluster.java
new file mode 100644
index 0000000..c5bcf72
--- /dev/null
+++ b/extensions/entitystore-cassandra/src/main/java/org/apache/polygene/entitystore/cassandra/CassandraCluster.java
@@ -0,0 +1,213 @@
+/*
+ *  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.polygene.entitystore.cassandra;
+
+import com.datastax.driver.core.Cluster;
+import com.datastax.driver.core.KeyspaceMetadata;
+import com.datastax.driver.core.PreparedStatement;
+import com.datastax.driver.core.Session;
+import org.apache.polygene.api.configuration.Configuration;
+import org.apache.polygene.api.injection.scope.This;
+import org.apache.polygene.api.mixin.Mixins;
+import org.apache.polygene.api.service.ServiceActivation;
+
+@Mixins( CassandraCluster.Mixin.class )
+public interface CassandraCluster
+{
+    String CURRENT_STORAGE_VERSION = "1";
+    String DEFAULT_KEYSPACE_NAME = "polygene:entitystore";
+    String DEFAULT_TABLE_NAME = "polygene:entitystore:entities";
+    String IDENTITY_COLUMN = "_id";
+    String VERSION_COLUMN = "_version";
+    String USECASE_COLUMN = "_usecase";
+    String LASTMODIFIED_COLUMN = "_modified";
+    String APP_VERSION_COLUMN = "_appversion";
+    String STORE_VERSION_COLUMN = "_storeversion";
+    String TYPE_COLUMN = "_type";
+    String PROPERTIES_COLUMN = "_props";
+    String ASSOCIATIONS_COLUMN = "_assocs";
+    String MANYASSOCIATIONS_COLUMN = "_manyassocs";
+    String NAMEDASSOCIATIONS_COLUMN = "_namedassocs";
+
+    Session session();
+
+    String tableName();
+
+    PreparedStatement entityRetrieveStatement();
+    PreparedStatement versionRetrieveStatement();
+    PreparedStatement entityUpdateStatement();
+
+    String keyspaceName();
+
+    class Mixin
+        implements ServiceActivation, CassandraCluster
+    {
+        @This
+        private Configuration<CassandraEntityStoreConfiguration> configuration;
+
+        private Cluster cluster;
+        private Session session;
+        private String keyspaceName;
+        private PreparedStatement getEntityStatement;
+        private PreparedStatement updateEntityStatement;
+        private PreparedStatement getVersionStatement;
+
+        @Override
+        public Session session()
+        {
+            return session;
+        }
+
+        @Override
+        public PreparedStatement entityRetrieveStatement()
+        {
+            return getEntityStatement;
+        }
+
+        @Override
+        public PreparedStatement versionRetrieveStatement()
+        {
+            return getVersionStatement;
+        }
+
+        @Override
+        public PreparedStatement entityUpdateStatement()
+        {
+            return updateEntityStatement;
+        }
+
+        @Override
+        public String keyspaceName()
+        {
+            return keyspaceName;
+        }
+
+        public  String tableName(  )
+        {
+            CassandraEntityStoreConfiguration config = configuration.get();
+            String tableName = config.table().get();
+            if( tableName == null )
+            {
+                tableName = DEFAULT_TABLE_NAME;
+            }
+            return tableName;
+        }
+
+        @Override
+        public void activateService()
+            throws Exception
+        {
+            configuration.refresh();
+            CassandraEntityStoreConfiguration config = configuration.get();
+
+            String[] hostNames = config.hostnames().get().split( "," );
+            Cluster.Builder builder =
+                Cluster.builder()
+                       .withClusterName( "myCluster" )
+                       .addContactPoints( hostNames )
+                       .withCredentials( config.username().get(), config.password().get() );
+            cluster = builder.build();
+            keyspaceName = config.keySpace().get();
+            if( keyspaceName == null )
+            {
+                keyspaceName = DEFAULT_KEYSPACE_NAME;
+            }
+            String tableName = tableName();
+            KeyspaceMetadata keyspace = cluster.getMetadata().getKeyspace( keyspaceName );
+            if( keyspace == null )
+            {
+                createKeyspace( keyspaceName, config.replicationFactor().get() );
+                session = cluster.connect( keyspaceName );
+                createPolygeneStateTable( tableName );
+            }
+            else
+            {
+                session = cluster.connect( keyspaceName );
+            }
+            session.init();
+
+            getEntityStatement = session.prepare( "SELECT "
+                                                  + IDENTITY_COLUMN + ", "
+                                                  + VERSION_COLUMN + ", "
+                                                  + APP_VERSION_COLUMN + ", "
+                                                  + STORE_VERSION_COLUMN + ", "
+                                                  + LASTMODIFIED_COLUMN + ", "
+                                                  + USECASE_COLUMN + ", "
+                                                  + PROPERTIES_COLUMN + ", "
+                                                  + ASSOCIATIONS_COLUMN + ", "
+                                                  + MANYASSOCIATIONS_COLUMN + ", "
+                                                  + NAMEDASSOCIATIONS_COLUMN
+                                                  + " FROM " + tableName
+                                                  + " WHERE "
+                                                  + IDENTITY_COLUMN + " = ?" );
+
+            getVersionStatement = session.prepare( "SELECT "
+                                                   + VERSION_COLUMN + ", "
+                                                   + " FROM " + tableName
+                                                   + " WHERE "
+                                                   + IDENTITY_COLUMN + " = ?" );
+
+            updateEntityStatement = session.prepare( "INSERT INTO " + tableName + "( "
+                                                     + IDENTITY_COLUMN + ", "
+                                                     + VERSION_COLUMN + ", "
+                                                     + APP_VERSION_COLUMN + ", "
+                                                     + STORE_VERSION_COLUMN + ", "
+                                                     + LASTMODIFIED_COLUMN + ", "
+                                                     + USECASE_COLUMN + ", "
+                                                     + PROPERTIES_COLUMN + ", "
+                                                     + ASSOCIATIONS_COLUMN + ", "
+                                                     + MANYASSOCIATIONS_COLUMN + ", "
+                                                     + NAMEDASSOCIATIONS_COLUMN
+                                                     + " ) VALUES (?,?,?," + CURRENT_STORAGE_VERSION + "?,?,?,?,?,?)" );
+        }
+
+        private void createPolygeneStateTable( String tableName )
+        {
+            session.execute( "CREATE TABLE " + tableName + "(\n"
+                             + "   " + IDENTITY_COLUMN + " text PRIMARYKEY,\n"
+                             + "   " + VERSION_COLUMN + " text,\n"
+                             + "   " + APP_VERSION_COLUMN + " text,\n"
+                             + "   " + STORE_VERSION_COLUMN + " text,\n"
+                             + "   " + LASTMODIFIED_COLUMN + " timestamp,\n"
+                             + "   " + USECASE_COLUMN + " text,\n"
+                             + "   " + PROPERTIES_COLUMN + " map,\n"
+                             + "   " + ASSOCIATIONS_COLUMN + " map,\n"
+                             + "   " + MANYASSOCIATIONS_COLUMN + " map,\n"
+                             + "   " + NAMEDASSOCIATIONS_COLUMN + " map,\n"
+                             + "   )" );
+        }
+
+        private void createKeyspace( String keyspaceName, int replication )
+        {
+            try( Session defaultSession = cluster.connect() )
+            {
+                String query = "CREATE KEYSPACE " + keyspaceName + "WITH replication = {'class':'SimpleStrategy', 'replication_factor' : " + replication + "};";
+                defaultSession.execute( query );
+            }
+        }
+
+        @Override
+        public void passivateService()
+            throws Exception
+        {
+            cluster.close();
+        }
+    }
+}
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/polygene-java/blob/c86b1154/extensions/entitystore-cassandra/src/main/java/org/apache/polygene/entitystore/cassandra/CassandraEntityStoreConfiguration.java
----------------------------------------------------------------------
diff --git a/extensions/entitystore-cassandra/src/main/java/org/apache/polygene/entitystore/cassandra/CassandraEntityStoreConfiguration.java b/extensions/entitystore-cassandra/src/main/java/org/apache/polygene/entitystore/cassandra/CassandraEntityStoreConfiguration.java
new file mode 100644
index 0000000..4a5e512
--- /dev/null
+++ b/extensions/entitystore-cassandra/src/main/java/org/apache/polygene/entitystore/cassandra/CassandraEntityStoreConfiguration.java
@@ -0,0 +1,50 @@
+/*
+ *  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.polygene.entitystore.cassandra;
+
+import org.apache.polygene.api.common.Optional;
+import org.apache.polygene.api.common.UseDefaults;
+import org.apache.polygene.api.configuration.ConfigurationComposite;
+import org.apache.polygene.api.property.Property;
+
+// START SNIPPET: config
+public interface CassandraEntityStoreConfiguration
+    extends ConfigurationComposite
+{
+
+    @Optional
+    Property<String> hostnames();
+
+    @Optional
+    Property<Integer> replicationFactor();
+
+    @UseDefaults
+    Property<String> username();
+
+    @UseDefaults
+    Property<String> password();
+
+    @Optional
+    Property<String> keySpace();
+
+    @Optional
+    Property<String> table();
+}
+// END SNIPPET: config
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/polygene-java/blob/c86b1154/extensions/entitystore-cassandra/src/main/java/org/apache/polygene/entitystore/cassandra/CassandraEntityStoreMixin.java
----------------------------------------------------------------------
diff --git a/extensions/entitystore-cassandra/src/main/java/org/apache/polygene/entitystore/cassandra/CassandraEntityStoreMixin.java b/extensions/entitystore-cassandra/src/main/java/org/apache/polygene/entitystore/cassandra/CassandraEntityStoreMixin.java
new file mode 100644
index 0000000..159bc9c
--- /dev/null
+++ b/extensions/entitystore-cassandra/src/main/java/org/apache/polygene/entitystore/cassandra/CassandraEntityStoreMixin.java
@@ -0,0 +1,425 @@
+/*
+ *  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.polygene.entitystore.cassandra;
+
+import com.datastax.driver.core.BoundStatement;
+import com.datastax.driver.core.ResultSet;
+import com.datastax.driver.core.Row;
+import com.datastax.driver.core.TypeTokens;
+import com.google.common.reflect.TypeToken;
+import java.time.Instant;
+import java.util.ArrayList;
+import java.util.Date;
+import java.util.HashMap;
+import java.util.LinkedHashMap;
+import java.util.List;
+import java.util.Map;
+import java.util.UUID;
+import java.util.stream.Collectors;
+import java.util.stream.Stream;
+import org.apache.polygene.api.association.AssociationDescriptor;
+import org.apache.polygene.api.common.Optional;
+import org.apache.polygene.api.common.QualifiedName;
+import org.apache.polygene.api.entity.EntityDescriptor;
+import org.apache.polygene.api.entity.EntityReference;
+import org.apache.polygene.api.identity.HasIdentity;
+import org.apache.polygene.api.identity.Identity;
+import org.apache.polygene.api.identity.IdentityGenerator;
+import org.apache.polygene.api.identity.StringIdentity;
+import org.apache.polygene.api.injection.scope.Service;
+import org.apache.polygene.api.injection.scope.Structure;
+import org.apache.polygene.api.injection.scope.This;
+import org.apache.polygene.api.property.PropertyDescriptor;
+import org.apache.polygene.api.service.ServiceActivation;
+import org.apache.polygene.api.service.qualifier.Tagged;
+import org.apache.polygene.api.structure.Application;
+import org.apache.polygene.api.structure.ModuleDescriptor;
+import org.apache.polygene.api.unitofwork.NoSuchEntityTypeException;
+import org.apache.polygene.api.unitofwork.UnitOfWork;
+import org.apache.polygene.api.usecase.Usecase;
+import org.apache.polygene.api.value.ValueSerialization;
+import org.apache.polygene.spi.entity.EntityState;
+import org.apache.polygene.spi.entity.EntityStatus;
+import org.apache.polygene.spi.entity.ManyAssociationState;
+import org.apache.polygene.spi.entity.NamedAssociationState;
+import org.apache.polygene.spi.entitystore.DefaultEntityStoreUnitOfWork;
+import org.apache.polygene.spi.entitystore.EntityStore;
+import org.apache.polygene.spi.entitystore.EntityStoreSPI;
+import org.apache.polygene.spi.entitystore.EntityStoreUnitOfWork;
+import org.apache.polygene.spi.entitystore.StateCommitter;
+import org.apache.polygene.spi.entitystore.helpers.DefaultEntityState;
+
+import static java.util.stream.StreamSupport.stream;
+import static org.apache.polygene.entitystore.cassandra.CassandraCluster.APP_VERSION_COLUMN;
+import static org.apache.polygene.entitystore.cassandra.CassandraCluster.ASSOCIATIONS_COLUMN;
+import static org.apache.polygene.entitystore.cassandra.CassandraCluster.IDENTITY_COLUMN;
+import static org.apache.polygene.entitystore.cassandra.CassandraCluster.LASTMODIFIED_COLUMN;
+import static org.apache.polygene.entitystore.cassandra.CassandraCluster.MANYASSOCIATIONS_COLUMN;
+import static org.apache.polygene.entitystore.cassandra.CassandraCluster.NAMEDASSOCIATIONS_COLUMN;
+import static org.apache.polygene.entitystore.cassandra.CassandraCluster.PROPERTIES_COLUMN;
+import static org.apache.polygene.entitystore.cassandra.CassandraCluster.STORE_VERSION_COLUMN;
+import static org.apache.polygene.entitystore.cassandra.CassandraCluster.TYPE_COLUMN;
+import static org.apache.polygene.entitystore.cassandra.CassandraCluster.USECASE_COLUMN;
+import static org.apache.polygene.entitystore.cassandra.CassandraCluster.VERSION_COLUMN;
+
+/**
+ * MongoDB implementation of MapEntityStore.
+ */
+public class CassandraEntityStoreMixin
+    implements EntityStore, EntityStoreSPI
+{
+
+    @This
+    private CassandraCluster cluster;
+
+    @Structure
+    private Application application;
+
+    @Optional
+    @Service
+    private CassandraMigration migration;
+
+    @Service
+    @Tagged( ValueSerialization.Formats.JSON )
+    private ValueSerialization valueSerialization;
+
+
+    @Optional
+    @Service
+    private IdentityGenerator idGenerator;
+
+    @Override
+    public EntityState newEntityState( EntityStoreUnitOfWork unitOfWork, EntityReference reference, EntityDescriptor entityDescriptor )
+    {
+        return new DefaultEntityState( unitOfWork.currentTime(), reference, entityDescriptor );
+    }
+
+    @Override
+    public EntityState entityStateOf( EntityStoreUnitOfWork unitOfWork, ModuleDescriptor module, EntityReference reference )
+    {
+        return queryFor( cluster.entityRetrieveStatement().bind( reference.toURI() ), module, reference  );
+    }
+
+    private EntityState queryFor( BoundStatement statement, ModuleDescriptor module, EntityReference reference )
+    {
+        ResultSet result = cluster.session().execute( statement );
+        Row row = result.one();
+        return deserialize( row, module);
+    }
+
+    private EntityState deserialize( Row row, ModuleDescriptor module )
+    {
+        String version = row.getString( VERSION_COLUMN );
+        Instant lastModifed = row.getTimestamp( LASTMODIFIED_COLUMN ).toInstant();
+        EntityStatus[] status = new EntityStatus[ 1 ];
+        status[ 0 ] = EntityStatus.LOADED;
+
+        // Check if version is correct
+        String currentAppVersion = row.getString( APP_VERSION_COLUMN );
+        if( !currentAppVersion.equals( application.version() ) )
+        {
+            if( migration != null )
+            {
+                migration.migrate( row, application.version(), cluster.session() );
+                // State may have changed
+                status[ 0 ] = EntityStatus.UPDATED;
+            }
+//            else
+//            {
+            // Do nothing ?? Should we update to newer version? Probably not...
+//            }
+        }
+        String type = row.getString( TYPE_COLUMN );
+
+        EntityDescriptor entityDescriptor = module.entityDescriptor( type );
+        if( entityDescriptor == null )
+        {
+            throw new NoSuchEntityTypeException( type, module.name(), module.typeLookup() );
+        }
+        Map<String, String> storedProperties = row.getMap( PROPERTIES_COLUMN, String.class, String.class );
+        Map<String, String> storedAssociations = row.getMap( ASSOCIATIONS_COLUMN, String.class, String.class );
+
+        TypeToken<String> stringToken = TypeToken.of( String.class );
+        TypeToken<List<String>> listOfStringsToken = TypeTokens.listOf( String.class );
+        TypeToken<Map<String, String>> mapOfStringsToken = TypeTokens.mapOf( String.class, String.class );
+        Map<String, List<String>> storedManyassociation = row.getMap( MANYASSOCIATIONS_COLUMN, stringToken, listOfStringsToken );
+        Map<String, Map<String, String>> storedNamedassociation = row.getMap( NAMEDASSOCIATIONS_COLUMN, stringToken, mapOfStringsToken );
+
+        Map<QualifiedName, Object> properties = new HashMap<>();
+        entityDescriptor
+            .state()
+            .properties()
+            .forEach(
+                propertyDescriptor ->
+                {
+                    String storedValue;
+                    try
+                    {
+                        storedValue = storedProperties.get( propertyDescriptor.qualifiedName().name() );
+                        if( storedValue == null )
+                        {
+                            properties.put( propertyDescriptor.qualifiedName(), null );
+                        }
+                        else
+                        {
+                            Object deserialized = valueSerialization.deserialize( module, propertyDescriptor.valueType(), storedValue );
+                            properties.put( propertyDescriptor.qualifiedName(), deserialized );
+                        }
+                    }
+                    catch( RuntimeException e )
+                    {
+                        // Value not found, or value is corrupt, default it. Is this correct behavior?
+                        Object initialValue = propertyDescriptor.resolveInitialValue( module );
+                        properties.put( propertyDescriptor.qualifiedName(), initialValue );
+                        status[ 0 ] = EntityStatus.UPDATED;
+                    }
+                } );
+
+        Map<QualifiedName, EntityReference> associations = new HashMap<>();
+        entityDescriptor
+            .state()
+            .associations()
+            .forEach(
+                associationType ->
+                {
+                    try
+                    {
+                        String storedValue = storedAssociations.get( associationType.qualifiedName().name() );
+                        EntityReference value = storedValue == null
+                                                ? null
+                                                : EntityReference.parseEntityReference( storedValue );
+                        associations.put( associationType.qualifiedName(), value );
+                    }
+                    catch( RuntimeException e )
+                    {
+                        // Association not found, default it to null
+                        associations.put( associationType.qualifiedName(), null );
+                        status[ 0 ] = EntityStatus.UPDATED;
+                    }
+                } );
+
+        Map<QualifiedName, List<EntityReference>> manyAssociations = new HashMap<>();
+        entityDescriptor
+            .state()
+            .manyAssociations()
+            .forEach(
+                manyAssociationType ->
+                {
+                    List<EntityReference> references = new ArrayList<>();
+                    try
+                    {
+                        List<String> storedValue = storedManyassociation.get( manyAssociationType.qualifiedName().name() );
+                        if( storedValue != null )
+                        {
+                            for( String value : storedValue )
+                            {
+                                EntityReference ref = value == null
+                                                      ? null
+                                                      : EntityReference.parseEntityReference( value );
+                                references.add( ref );
+                            }
+                            manyAssociations.put( manyAssociationType.qualifiedName(), references );
+                        }
+                    }
+                    catch( RuntimeException e )
+                    {
+                        // ManyAssociation not found, default to empty one
+                        manyAssociations.put( manyAssociationType.qualifiedName(), references );
+                    }
+                } );
+
+        Map<QualifiedName, Map<String, EntityReference>> namedAssociations = new HashMap<>();
+        entityDescriptor
+            .state()
+            .namedAssociations()
+            .forEach(
+                namedAssociationType ->
+                {
+                    Map<String, EntityReference> references = new LinkedHashMap<>();
+                    try
+                    {
+                        Map<String, String> storedValues = storedNamedassociation.get( namedAssociationType.qualifiedName().name() );
+                        if( storedValues != null )
+                        {
+                            for( Map.Entry<String, String> entry : storedValues.entrySet() )
+                            {
+                                String name = entry.getKey();
+                                String value = entry.getValue();
+                                EntityReference ref = value == null
+                                                      ? null
+                                                      : EntityReference.parseEntityReference( value );
+                                references.put( name, ref );
+                            }
+                            namedAssociations.put( namedAssociationType.qualifiedName(), references );
+                        }
+                    }
+                    catch( RuntimeException e )
+                    {
+                        // NamedAssociation not found, default to empty one
+                        namedAssociations.put( namedAssociationType.qualifiedName(), references );
+                    }
+                } );
+
+        EntityReference reference = EntityReference.parseEntityReference( storedProperties.get( "identity" ) );
+        return new DefaultEntityState( version,
+                                       lastModifed,
+                                       reference,
+                                       status[ 0 ],
+                                       entityDescriptor,
+                                       properties,
+                                       associations,
+                                       manyAssociations,
+                                       namedAssociations
+        );
+    }
+
+    @Override
+    public String versionOf( EntityStoreUnitOfWork unitOfWork, EntityReference reference )
+    {
+        ResultSet result = cluster.session().execute( cluster.entityRetrieveStatement().bind( reference.toURI() ) );
+        Row row = result.one();
+        return row.getString( VERSION_COLUMN );
+    }
+
+    @Override
+    public StateCommitter applyChanges( EntityStoreUnitOfWork unitOfWork, Iterable<EntityState> state )
+    {
+        return new StateCommitter()
+        {
+            @Override
+            public void commit()
+            {
+
+                stream( state.spliterator(), false )
+                    .filter( entity -> entity.status() == EntityStatus.UPDATED || entity.status() == EntityStatus.NEW )
+                    .forEach(
+                        entityState ->
+                        {
+                            Map<String, String> props = new HashMap<>();
+                            Map<String, String> assocs = new HashMap<>();
+                            Map<String, List<String>> many = new HashMap<>();
+                            Map<String, Map<String, String>> named = new HashMap<>();
+                            serializeProperties( entityState, props );
+                            serializeAssociations( entityState, assocs );
+                            serializeManyAssociations( entityState, many );
+                            serializeNamedAssociations( entityState, named );
+                            Identity identity = (Identity) entityState.propertyValueOf( HasIdentity.IDENTITY_STATE_NAME );
+                            String ver = entityState.version();
+                            String appVersion = application.version();
+                            Date lastModified = new Date( entityState.lastModified().toEpochMilli() );
+                            String usecase = unitOfWork.usecase().name();
+                            BoundStatement statement = cluster.entityUpdateStatement().bind( identity.toString(), ver, appVersion, lastModified, usecase, props, assocs, many, named );
+                            ResultSet result = cluster.session().execute( statement );
+                            System.out.println( result );
+                        } );
+            }
+
+            private void serializeProperties( EntityState entityState, Map<String, String> props )
+            {
+                Stream<? extends PropertyDescriptor> properties = entityState.entityDescriptor().state().properties();
+                properties.forEach(
+                    descriptor ->
+                    {
+                        Object value = entityState.propertyValueOf( descriptor.qualifiedName() );
+                        String serialized = valueSerialization.serialize( value );
+                        props.put( descriptor.qualifiedName().name(), serialized );
+                    } );
+            }
+
+            private void serializeAssociations( EntityState entityState, Map<String, String> assocs )
+            {
+                Stream<? extends AssociationDescriptor> associations = entityState.entityDescriptor().state().associations();
+                associations.forEach(
+                    descriptor ->
+                    {
+                        EntityReference ref = entityState.associationValueOf( descriptor.qualifiedName() );
+                        assocs.put( descriptor.qualifiedName().name(), ref.toString() );
+                    } );
+            }
+
+            private void serializeManyAssociations( EntityState entityState, Map<String, List<String>> many )
+            {
+                Stream<? extends AssociationDescriptor> associations = entityState.entityDescriptor().state().associations();
+                associations.forEach(
+                    descriptor ->
+                    {
+                        ManyAssociationState references = entityState.manyAssociationValueOf( descriptor.qualifiedName() );
+                        List<String> refs = references.stream().map( EntityReference::toString ).collect( Collectors.toList() );
+                        many.put( descriptor.qualifiedName().name(), refs );
+                    } );
+            }
+
+            private void serializeNamedAssociations( EntityState entityState, Map<String, Map<String, String>> named )
+            {
+                Stream<? extends AssociationDescriptor> associations = entityState.entityDescriptor().state().associations();
+                associations.forEach(
+                    descriptor ->
+                    {
+                        NamedAssociationState references = entityState.namedAssociationValueOf( descriptor.qualifiedName() );
+                        Map<String, String> refs =
+                            references.stream()
+                                      .collect(
+                                          Collectors.toMap( Map.Entry::getKey,
+                                                            entry -> entry.getValue().toString() ) );
+                        named.put( descriptor.qualifiedName().name(), refs );
+                    } );
+            }
+
+            @Override
+            public void cancel()
+            {
+            }
+        };
+    }
+
+    @Override
+    public EntityStoreUnitOfWork newUnitOfWork( ModuleDescriptor module, Usecase usecase, Instant currentTime )
+    {
+        Identity newIdentity;
+        if( idGenerator == null )
+        {
+            newIdentity = new StringIdentity( UUID.randomUUID().toString() );
+        }
+        else
+        {
+            newIdentity= idGenerator.generate( UnitOfWork.class );
+        }
+        return new DefaultEntityStoreUnitOfWork( module, this, newIdentity, usecase, currentTime );
+    }
+
+    @Override
+    public Stream<EntityState> entityStates( ModuleDescriptor module )
+    {
+        ResultSet resultSet = cluster.session().execute( "SELECT "
+                                             + IDENTITY_COLUMN + ", "
+                                             + VERSION_COLUMN + ", "
+                                             + APP_VERSION_COLUMN + ", "
+                                             + STORE_VERSION_COLUMN + ", "
+                                             + LASTMODIFIED_COLUMN + ", "
+                                             + USECASE_COLUMN + ", "
+                                             + PROPERTIES_COLUMN + ", "
+                                             + ASSOCIATIONS_COLUMN + ", "
+                                             + MANYASSOCIATIONS_COLUMN + ", "
+                                             + NAMEDASSOCIATIONS_COLUMN
+                                             + " FROM " + cluster.tableName() );
+        return stream(resultSet.spliterator(), false).map( row -> deserialize( row, module ));
+    }
+
+}

http://git-wip-us.apache.org/repos/asf/polygene-java/blob/c86b1154/extensions/entitystore-cassandra/src/main/java/org/apache/polygene/entitystore/cassandra/CassandraEntityStoreService.java
----------------------------------------------------------------------
diff --git a/extensions/entitystore-cassandra/src/main/java/org/apache/polygene/entitystore/cassandra/CassandraEntityStoreService.java b/extensions/entitystore-cassandra/src/main/java/org/apache/polygene/entitystore/cassandra/CassandraEntityStoreService.java
new file mode 100644
index 0000000..e7531ce
--- /dev/null
+++ b/extensions/entitystore-cassandra/src/main/java/org/apache/polygene/entitystore/cassandra/CassandraEntityStoreService.java
@@ -0,0 +1,48 @@
+/*
+ *  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.polygene.entitystore.cassandra;
+
+import org.apache.polygene.api.concern.Concerns;
+import org.apache.polygene.api.configuration.Configuration;
+import org.apache.polygene.api.mixin.Mixins;
+import org.apache.polygene.api.service.ServiceActivation;
+import org.apache.polygene.api.service.ServiceComposite;
+import org.apache.polygene.library.locking.LockingAbstractComposite;
+import org.apache.polygene.spi.entitystore.ConcurrentModificationCheckConcern;
+import org.apache.polygene.spi.entitystore.EntityStateVersions;
+import org.apache.polygene.spi.entitystore.EntityStore;
+import org.apache.polygene.spi.entitystore.StateChangeNotificationConcern;
+import org.apache.polygene.spi.entitystore.helpers.JSONMapEntityStoreActivation;
+import org.apache.polygene.spi.entitystore.helpers.JSONMapEntityStoreMixin;
+
+/**
+ * Cassandra EntityStore service.
+ */
+@Concerns( { StateChangeNotificationConcern.class, ConcurrentModificationCheckConcern.class } )
+@Mixins( { CassandraEntityStoreMixin.class } )
+public interface CassandraEntityStoreService
+    extends EntityStore,
+            EntityStateVersions,
+            ServiceComposite,
+            ServiceActivation,
+            LockingAbstractComposite,
+            Configuration
+{
+}

http://git-wip-us.apache.org/repos/asf/polygene-java/blob/c86b1154/extensions/entitystore-cassandra/src/main/java/org/apache/polygene/entitystore/cassandra/CassandraMigration.java
----------------------------------------------------------------------
diff --git a/extensions/entitystore-cassandra/src/main/java/org/apache/polygene/entitystore/cassandra/CassandraMigration.java b/extensions/entitystore-cassandra/src/main/java/org/apache/polygene/entitystore/cassandra/CassandraMigration.java
new file mode 100644
index 0000000..72b4060
--- /dev/null
+++ b/extensions/entitystore-cassandra/src/main/java/org/apache/polygene/entitystore/cassandra/CassandraMigration.java
@@ -0,0 +1,28 @@
+/*
+ *  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.polygene.entitystore.cassandra;
+
+import com.datastax.driver.core.Row;
+import com.datastax.driver.core.Session;
+
+public interface CassandraMigration
+{
+    Row migrate( Row existingRow, String toVersion, Session session );
+}

http://git-wip-us.apache.org/repos/asf/polygene-java/blob/c86b1154/extensions/entitystore-cassandra/src/main/java/org/apache/polygene/entitystore/cassandra/assembly/CassandraDBEntityStoreAssembler.java
----------------------------------------------------------------------
diff --git a/extensions/entitystore-cassandra/src/main/java/org/apache/polygene/entitystore/cassandra/assembly/CassandraDBEntityStoreAssembler.java b/extensions/entitystore-cassandra/src/main/java/org/apache/polygene/entitystore/cassandra/assembly/CassandraDBEntityStoreAssembler.java
new file mode 100644
index 0000000..15b3c60
--- /dev/null
+++ b/extensions/entitystore-cassandra/src/main/java/org/apache/polygene/entitystore/cassandra/assembly/CassandraDBEntityStoreAssembler.java
@@ -0,0 +1,46 @@
+/*
+ *  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.polygene.entitystore.cassandra.assembly;
+
+import org.apache.polygene.bootstrap.Assemblers;
+import org.apache.polygene.bootstrap.AssemblyException;
+import org.apache.polygene.bootstrap.ModuleAssembly;
+import org.apache.polygene.bootstrap.ServiceDeclaration;
+import org.apache.polygene.entitystore.cassandra.CassandraEntityStoreConfiguration;
+import org.apache.polygene.entitystore.cassandra.CassandraEntityStoreService;
+
+public class CassandraDBEntityStoreAssembler
+    extends Assemblers.VisibilityIdentityConfig<CassandraDBEntityStoreAssembler>
+{
+    @Override
+    public void assemble( ModuleAssembly module )
+        throws AssemblyException
+    {
+        ServiceDeclaration service = module.services( CassandraEntityStoreService.class ).visibleIn( visibility() );
+        if( hasIdentity() )
+        {
+            service.identifiedBy( identity() );
+        }
+        if( hasConfig() )
+        {
+            configModule().entities( CassandraEntityStoreConfiguration.class ).visibleIn( configVisibility() );
+        }
+    }
+}

http://git-wip-us.apache.org/repos/asf/polygene-java/blob/c86b1154/extensions/entitystore-cassandra/src/main/java/org/apache/polygene/entitystore/cassandra/package.html
----------------------------------------------------------------------
diff --git a/extensions/entitystore-cassandra/src/main/java/org/apache/polygene/entitystore/cassandra/package.html b/extensions/entitystore-cassandra/src/main/java/org/apache/polygene/entitystore/cassandra/package.html
new file mode 100644
index 0000000..2a0077e
--- /dev/null
+++ b/extensions/entitystore-cassandra/src/main/java/org/apache/polygene/entitystore/cassandra/package.html
@@ -0,0 +1,43 @@
+<!--
+  ~  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.
+  ~
+  ~
+  -->
+<html>
+<body>
+<h2>Casssandra EntityStore.</h2>
+    <p>
+        The Cassandra EntityStore leverages the CQL 'map' type, which is the "newer" way of doing variable-wdith rows.
+    </p>
+<p>
+    For properties, there is a map called '_props' with string key (the name of the property) and string value,
+    which is the serialized state of the property.
+</p>
+<p>
+    For associations, there is map called '_assocs' with string key (the name of the association) and string value,
+    which is the entity reference in toString() format.
+</p>
+<p>
+    For manyassociations, there is map called '_manyassocs' with string key (the name of the manyassociation) and
+    list of strings value, which is the list of entity references in toString() format.
+</p>
+<p>
+    For namedassociations, there is map called '_manyassocs' with string key (the name of the association) and
+    map of strings value, which is the name as the key and the value is the entity reference in toString() format.
+</p>
+</body>
+</html>

http://git-wip-us.apache.org/repos/asf/polygene-java/blob/c86b1154/extensions/entitystore-cassandra/src/test/java/org/apache/polygene/entitystore/cassandra/CassandraMapEntityStoreTest.java
----------------------------------------------------------------------
diff --git a/extensions/entitystore-cassandra/src/test/java/org/apache/polygene/entitystore/cassandra/CassandraMapEntityStoreTest.java b/extensions/entitystore-cassandra/src/test/java/org/apache/polygene/entitystore/cassandra/CassandraMapEntityStoreTest.java
new file mode 100644
index 0000000..3f5cc12
--- /dev/null
+++ b/extensions/entitystore-cassandra/src/test/java/org/apache/polygene/entitystore/cassandra/CassandraMapEntityStoreTest.java
@@ -0,0 +1,89 @@
+/*
+ *  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.polygene.entitystore.cassandra;
+
+import org.apache.polygene.entitystore.cassandra.assembly.CassandraDBEntityStoreAssembler;
+import org.apache.polygene.test.entity.CanRemoveAll;
+import org.junit.BeforeClass;
+import org.apache.polygene.api.common.Visibility;
+import org.apache.polygene.bootstrap.AssemblyException;
+import org.apache.polygene.bootstrap.ModuleAssembly;
+import org.apache.polygene.test.EntityTestAssembler;
+import org.apache.polygene.test.entity.AbstractEntityStoreTest;
+import org.apache.polygene.valueserialization.orgjson.OrgJsonValueSerializationAssembler;
+
+import static org.apache.polygene.test.util.Assume.assumeConnectivity;
+
+/**
+ * Test the CassandraEntityStoreService.
+ * <p>Installing Cassandra and starting it should suffice as the test use Cassandra defaults: 127.0.0.1:3000</p>
+ */
+public class CassandraMapEntityStoreTest
+    extends AbstractEntityStoreTest
+{
+
+
+    @BeforeClass
+    public static void beforeCassandraEntityStoreTests()
+    {
+        assumeConnectivity( "localhost", 9042 );
+    }
+
+    @Override
+    // START SNIPPET: assembly
+    public void assemble( ModuleAssembly module )
+        throws AssemblyException
+    {
+        // END SNIPPET: assembly
+        super.assemble( module );
+
+        ModuleAssembly config = module.layer().module( "config" );
+        new EntityTestAssembler().assemble( config );
+        module.services( CassandraEntityStoreService.class ).withTypes( CanRemoveAll.class ).withMixins( EmptyCassandraTableMixin.class );
+        new OrgJsonValueSerializationAssembler().assemble( module );
+
+        // START SNIPPET: assembly
+        new CassandraDBEntityStoreAssembler().withConfig( config, Visibility.layer ).assemble( module );
+        // END SNIPPET: assembly
+
+        CassandraEntityStoreConfiguration cassandraConfig = config.forMixin( CassandraEntityStoreConfiguration.class ).declareDefaults();
+        cassandraConfig.keySpace().set( "polygene:test" );
+        cassandraConfig.table().set( "polygene:test:entities" );
+        cassandraConfig.replicationFactor().set( 1 );
+        // START SNIPPET: assembly
+    }
+    // END SNIPPET: assembly
+
+    @Override
+    public void setUp()
+        throws Exception
+    {
+        super.setUp();
+    }
+
+    @Override
+    public void tearDown()
+        throws Exception
+    {
+        CanRemoveAll cleaner = serviceFinder.findService( CanRemoveAll.class ).get();
+        cleaner.removeAll();
+        super.tearDown();
+    }
+}

http://git-wip-us.apache.org/repos/asf/polygene-java/blob/c86b1154/extensions/entitystore-cassandra/src/test/java/org/apache/polygene/entitystore/cassandra/EmptyCassandraTableMixin.java
----------------------------------------------------------------------
diff --git a/extensions/entitystore-cassandra/src/test/java/org/apache/polygene/entitystore/cassandra/EmptyCassandraTableMixin.java b/extensions/entitystore-cassandra/src/test/java/org/apache/polygene/entitystore/cassandra/EmptyCassandraTableMixin.java
new file mode 100644
index 0000000..a620d32
--- /dev/null
+++ b/extensions/entitystore-cassandra/src/test/java/org/apache/polygene/entitystore/cassandra/EmptyCassandraTableMixin.java
@@ -0,0 +1,20 @@
+package org.apache.polygene.entitystore.cassandra;
+
+import com.datastax.driver.core.querybuilder.Delete;
+import com.datastax.driver.core.querybuilder.QueryBuilder;
+import org.apache.polygene.api.injection.scope.This;
+import org.apache.polygene.test.entity.CanRemoveAll;
+
+public class EmptyCassandraTableMixin
+    implements CanRemoveAll
+{
+    @This
+    private CassandraCluster cluster;
+
+    @Override
+    public void removeAll()
+    {
+        Delete delete = QueryBuilder.delete().from(cluster.keyspaceName(), cluster.tableName());
+        cluster.session().execute( delete );
+    }
+}

http://git-wip-us.apache.org/repos/asf/polygene-java/blob/c86b1154/internals/testsupport-internal/src/main/docker/cassandra/Dockerfile
----------------------------------------------------------------------
diff --git a/internals/testsupport-internal/src/main/docker/cassandra/Dockerfile b/internals/testsupport-internal/src/main/docker/cassandra/Dockerfile
new file mode 100644
index 0000000..e382cc1
--- /dev/null
+++ b/internals/testsupport-internal/src/main/docker/cassandra/Dockerfile
@@ -0,0 +1,16 @@
+# 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.
+
+FROM cassandra:3.9

http://git-wip-us.apache.org/repos/asf/polygene-java/blob/c86b1154/settings.gradle
----------------------------------------------------------------------
diff --git a/settings.gradle b/settings.gradle
index 6858c4c..67ec7c4 100644
--- a/settings.gradle
+++ b/settings.gradle
@@ -57,13 +57,14 @@ include 'core:api',
         'libraries:uowfile',
         'extensions:cache-ehcache',
         'extensions:cache-memcache',
-        'extensions:entitystore-memory',
+        'extensions:entitystore-cassandra',
         'extensions:entitystore-file',
         'extensions:entitystore-geode',
         'extensions:entitystore-hazelcast',
         'extensions:entitystore-jclouds',
         'extensions:entitystore-jdbm',
         'extensions:entitystore-leveldb',
+        'extensions:entitystore-memory',
         'extensions:entitystore-mongodb',
         'extensions:entitystore-preferences',
         'extensions:entitystore-redis',
@@ -81,7 +82,6 @@ include 'core:api',
         'extensions:valueserialization-stax',
         'tools:model-detail',
         'tools:envisage',
-        'tools:shell',
 //        'tools:qidea',
         'tests:regression',
         'tests:performance',

http://git-wip-us.apache.org/repos/asf/polygene-java/blob/c86b1154/tools/shell/build.gradle
----------------------------------------------------------------------
diff --git a/tools/shell/build.gradle b/tools/shell/build.gradle
deleted file mode 100644
index 1ec559f..0000000
--- a/tools/shell/build.gradle
+++ /dev/null
@@ -1,39 +0,0 @@
-/*
- *  Licensed to the Apache Software Foundation (ASF) under one
- *  or more contributor license agreements.  See the NOTICE file
- *  distributed with this work for additional information
- *  regarding copyright ownership.  The ASF licenses this file
- *  to you under the Apache License, Version 2.0 (the
- *  "License"); you may not use this file except in compliance
- *  with the License.  You may obtain a copy of the License at
- *
- *       http://www.apache.org/licenses/LICENSE-2.0
- *
- *  Unless required by applicable law or agreed to in writing, software
- *  distributed under the License is distributed on an "AS IS" BASIS,
- *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- *  See the License for the specific language governing permissions and
- *  limitations under the License.
- *
- *
- */
-
-apply plugin: 'polygene-tool'
-apply plugin: 'application'
-
-description = "Command line tools for building Apache Polygene™ applications."
-mainClassName = "org.apache.polygene.tools.shell.Main"
-
-jar {
-  manifest {
-    name = "Apache Polygene™ Command Line"
-    attributes("Main-Class": mainClassName )
-  }
-}
-
-[ distZip, distTar ].each { dist -> dist.classifier = 'bin' }
-distTar.compression = Compression.GZIP
-
-dependencies {
-  testRuntime libraries.logback
-}

http://git-wip-us.apache.org/repos/asf/polygene-java/blob/c86b1154/tools/shell/dev-status.xml
----------------------------------------------------------------------
diff --git a/tools/shell/dev-status.xml b/tools/shell/dev-status.xml
deleted file mode 100644
index 01d0c15..0000000
--- a/tools/shell/dev-status.xml
+++ /dev/null
@@ -1,38 +0,0 @@
-<?xml version="1.0" encoding="UTF-8" ?>
-<!--
-  ~  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.
-  ~
-  ~
-  -->
-<module xmlns="http://polygene.apache.org/schemas/2008/dev-status/1"
-        xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
-        xsi:schemaLocation="http://polygene.apache.org/schemas/2008/dev-status/1
-        http://polygene.apache.org/schemas/2008/dev-status/1/dev-status.xsd">
-  <status>
-    <!--none,early,beta,stable,mature-->
-    <codebase>beta</codebase>
-
-    <!-- none, brief, good, complete -->
-    <documentation>brief</documentation>
-
-    <!-- none, some, good, complete -->
-    <unittests>good</unittests>
-  </status>
-  <licenses>
-    <license>ALv2</license>
-  </licenses>
-</module>

http://git-wip-us.apache.org/repos/asf/polygene-java/blob/c86b1154/tools/shell/src/main/java/org/apache/polygene/tools/shell/create/project/NullProjectCreator.java
----------------------------------------------------------------------
diff --git a/tools/shell/src/main/java/org/apache/polygene/tools/shell/create/project/NullProjectCreator.java b/tools/shell/src/main/java/org/apache/polygene/tools/shell/create/project/NullProjectCreator.java
deleted file mode 100644
index 8018dc6..0000000
--- a/tools/shell/src/main/java/org/apache/polygene/tools/shell/create/project/NullProjectCreator.java
+++ /dev/null
@@ -1,37 +0,0 @@
-/*
- *  Licensed to the Apache Software Foundation (ASF) under one
- *  or more contributor license agreements.  See the NOTICE file
- *  distributed with this work for additional information
- *  regarding copyright ownership.  The ASF licenses this file
- *  to you under the Apache License, Version 2.0 (the
- *  "License"); you may not use this file except in compliance
- *  with the License.  You may obtain a copy of the License at
- *
- *       http://www.apache.org/licenses/LICENSE-2.0
- *
- *  Unless required by applicable law or agreed to in writing, software
- *  distributed under the License is distributed on an "AS IS" BASIS,
- *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- *  See the License for the specific language governing permissions and
- *  limitations under the License.
- *
- *
- */
-
-package org.apache.polygene.tools.shell.create.project;
-
-import java.io.File;
-import java.io.IOException;
-import java.util.Map;
-
-public class NullProjectCreator extends AbstractProjectCreator
-    implements ProjectCreator
-{
-
-    @Override
-    public void create( String projectName, File projectDir, Map<String, String> properties )
-        throws IOException
-    {
-        super.create( projectName, projectDir, properties );    // creates the directory structures.
-    }
-}


Mime
View raw message