polygene-commits mailing list archives

Site index · List index
Message view « Date » · « Thread »
Top « Date » · « Thread »
From nic...@apache.org
Subject [07/11] polygene-java git commit: Committing an intermediate state of the JOOQ ES, to dig into the classloading issue in the Service composition.
Date Sun, 11 Jun 2017 03:43:43 GMT
Committing an intermediate state of the JOOQ ES, to dig into the classloading issue in the Service composition.

Signed-off-by: niclas <niclas@hedhman.org>


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

Branch: refs/heads/es-jooq
Commit: 60d2eebd709dc2eb7078b04a305aaba2e4485299
Parents: c2a30f7
Author: niclas <niclas@hedhman.org>
Authored: Fri Jun 9 11:40:09 2017 +0800
Committer: niclas <niclas@hedhman.org>
Committed: Fri Jun 9 11:40:09 2017 +0800

----------------------------------------------------------------------
 .../org/apache/polygene/api/PolygeneAPI.java    |   1 +
 .../api/association/AssociationDescriptor.java  |   8 +-
 .../api/property/PropertyDescriptor.java        |   8 +-
 .../runtime/methods/AccessibleTest.java         |  99 +++++
 .../polygene/entitystore/jooq/BaseEntity.java   |  17 +
 .../entitystore/jooq/EntitiesTable.java         | 247 +++++++++++
 .../entitystore/jooq/JooqDslContext.java        |  24 +-
 .../jooq/JooqEntityStoreConfiguration.java      |  11 +
 .../entitystore/jooq/JooqEntityStoreMixin.java  |  67 ++-
 .../jooq/JooqEntityStoreService.java            |   2 +-
 .../polygene/entitystore/jooq/MixinTable.java   | 214 ++++++++++
 .../polygene/entitystore/jooq/SqlTable.java     | 416 +++++++------------
 .../polygene/entitystore/jooq/SqlType.java      | 185 ++++-----
 .../polygene/entitystore/jooq/TableFields.java  |  69 +++
 .../polygene/entitystore/jooq/TypesTable.java   | 187 +++++++++
 .../jooq/assembly/JooqEntityStoreAssembler.java |   7 +-
 .../entitystore/jooq/JooqEntityStoreTest.java   |  66 ++-
 .../sql/dbcp/DBCPDataSourceServiceImporter.java |   3 +-
 18 files changed, 1218 insertions(+), 413 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/polygene-java/blob/60d2eebd/core/api/src/main/java/org/apache/polygene/api/PolygeneAPI.java
----------------------------------------------------------------------
diff --git a/core/api/src/main/java/org/apache/polygene/api/PolygeneAPI.java b/core/api/src/main/java/org/apache/polygene/api/PolygeneAPI.java
index 2823cb6..15d104e 100644
--- a/core/api/src/main/java/org/apache/polygene/api/PolygeneAPI.java
+++ b/core/api/src/main/java/org/apache/polygene/api/PolygeneAPI.java
@@ -143,6 +143,7 @@ public interface PolygeneAPI
      * @return true if the given object is a Composite type.
      */
     boolean isComposite( Object object );
+
     /**
      * Function that returns the CompositeInstance of a Composite.
      */

http://git-wip-us.apache.org/repos/asf/polygene-java/blob/60d2eebd/core/api/src/main/java/org/apache/polygene/api/association/AssociationDescriptor.java
----------------------------------------------------------------------
diff --git a/core/api/src/main/java/org/apache/polygene/api/association/AssociationDescriptor.java b/core/api/src/main/java/org/apache/polygene/api/association/AssociationDescriptor.java
index e7a1c01..09cd2c4 100644
--- a/core/api/src/main/java/org/apache/polygene/api/association/AssociationDescriptor.java
+++ b/core/api/src/main/java/org/apache/polygene/api/association/AssociationDescriptor.java
@@ -59,11 +59,11 @@ public interface AssociationDescriptor extends MetaInfoHolder
      */
     Type type();
 
-    boolean isImmutable();
-
-    boolean isAggregated();
-
     AccessibleObject accessor();
 
     boolean queryable();
+
+    boolean isImmutable();
+
+    boolean isAggregated();
 }

http://git-wip-us.apache.org/repos/asf/polygene-java/blob/60d2eebd/core/api/src/main/java/org/apache/polygene/api/property/PropertyDescriptor.java
----------------------------------------------------------------------
diff --git a/core/api/src/main/java/org/apache/polygene/api/property/PropertyDescriptor.java b/core/api/src/main/java/org/apache/polygene/api/property/PropertyDescriptor.java
index 6c7df05..4a21920 100644
--- a/core/api/src/main/java/org/apache/polygene/api/property/PropertyDescriptor.java
+++ b/core/api/src/main/java/org/apache/polygene/api/property/PropertyDescriptor.java
@@ -32,8 +32,6 @@ import org.apache.polygene.api.type.ValueType;
  */
 public interface PropertyDescriptor extends MetaInfoHolder
 {
-    boolean isImmutable();
-
     /**
      * Get the qualified name of the property which is equal to:
      * <pre><code>
@@ -54,9 +52,11 @@ public interface PropertyDescriptor extends MetaInfoHolder
 
     AccessibleObject accessor();
 
-    Object resolveInitialValue(ModuleDescriptor moduleDescriptor);
+    boolean isImmutable();
+
+    boolean queryable();
 
     ValueType valueType();
 
-    boolean queryable();
+    Object resolveInitialValue(ModuleDescriptor moduleDescriptor);
 }

http://git-wip-us.apache.org/repos/asf/polygene-java/blob/60d2eebd/core/runtime/src/test/java/org/apache/polygene/runtime/methods/AccessibleTest.java
----------------------------------------------------------------------
diff --git a/core/runtime/src/test/java/org/apache/polygene/runtime/methods/AccessibleTest.java b/core/runtime/src/test/java/org/apache/polygene/runtime/methods/AccessibleTest.java
new file mode 100644
index 0000000..0d3ccb4
--- /dev/null
+++ b/core/runtime/src/test/java/org/apache/polygene/runtime/methods/AccessibleTest.java
@@ -0,0 +1,99 @@
+/*
+ *  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.runtime.methods;
+
+import org.apache.polygene.api.injection.scope.This;
+import org.apache.polygene.api.mixin.Mixins;
+import org.apache.polygene.bootstrap.AssemblyException;
+import org.apache.polygene.bootstrap.ModuleAssembly;
+import org.apache.polygene.test.AbstractPolygeneTest;
+import org.junit.Test;
+
+import static org.hamcrest.core.IsEqual.equalTo;
+import static org.junit.Assert.assertThat;
+
+public class AccessibleTest extends AbstractPolygeneTest
+{
+
+    @Override
+    public void assemble( ModuleAssembly module )
+        throws AssemblyException
+    {
+        module.transients( MyComposite.class );
+    }
+
+    @Test
+    public void givenPrivateMixinWhenCallingFromWithinExpectSuccess()
+    {
+        MyComposite myComposite = transientBuilderFactory.newTransient( MyComposite.class );
+        assertThat(myComposite.doSomething(), equalTo("Hello"));
+    }
+
+    @Mixins( MyCompositeMixin.class)
+    public interface MyComposite
+    {
+        String doSomething();
+    }
+
+    @Mixins( MyFunctionMixin.class )
+    public interface MyFunction
+    {
+        String doSomething();
+    }
+
+
+    public class MyCompositeMixin
+        implements MyComposite
+    {
+        @This
+        private MyFunction function;
+
+        @Override
+        public String doSomething()
+        {
+            return new MyObject( function ).doSomething() + " ---- " + getClass().getClassLoader();
+        }
+    }
+
+    public class MyFunctionMixin
+        implements MyFunction
+    {
+        @Override
+        public String doSomething()
+        {
+            return "Hello " + getClass().getClassLoader();
+        }
+    }
+
+    public class MyObject
+    {
+        private MyFunction fn;
+
+        public MyObject( MyFunction fn )
+        {
+            this.fn = fn;
+        }
+
+        String doSomething()
+        {
+            return fn.doSomething();
+        }
+    }
+}

http://git-wip-us.apache.org/repos/asf/polygene-java/blob/60d2eebd/extensions/entitystore-jooq/src/main/java/org/apache/polygene/entitystore/jooq/BaseEntity.java
----------------------------------------------------------------------
diff --git a/extensions/entitystore-jooq/src/main/java/org/apache/polygene/entitystore/jooq/BaseEntity.java b/extensions/entitystore-jooq/src/main/java/org/apache/polygene/entitystore/jooq/BaseEntity.java
index 07fb05c..e4eaa40 100644
--- a/extensions/entitystore-jooq/src/main/java/org/apache/polygene/entitystore/jooq/BaseEntity.java
+++ b/extensions/entitystore-jooq/src/main/java/org/apache/polygene/entitystore/jooq/BaseEntity.java
@@ -1,3 +1,20 @@
+/*
+ *  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.jooq;
 
 import java.time.Instant;

http://git-wip-us.apache.org/repos/asf/polygene-java/blob/60d2eebd/extensions/entitystore-jooq/src/main/java/org/apache/polygene/entitystore/jooq/EntitiesTable.java
----------------------------------------------------------------------
diff --git a/extensions/entitystore-jooq/src/main/java/org/apache/polygene/entitystore/jooq/EntitiesTable.java b/extensions/entitystore-jooq/src/main/java/org/apache/polygene/entitystore/jooq/EntitiesTable.java
new file mode 100644
index 0000000..dc765a9
--- /dev/null
+++ b/extensions/entitystore-jooq/src/main/java/org/apache/polygene/entitystore/jooq/EntitiesTable.java
@@ -0,0 +1,247 @@
+/*
+ *  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.jooq;
+
+import java.lang.reflect.Method;
+import java.sql.Timestamp;
+import java.time.Instant;
+import java.util.List;
+import java.util.Map;
+import java.util.Set;
+import java.util.UUID;
+import java.util.concurrent.ConcurrentHashMap;
+import java.util.function.Consumer;
+import java.util.stream.Collectors;
+import java.util.stream.Stream;
+import org.apache.polygene.api.association.AssociationDescriptor;
+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.property.PropertyDescriptor;
+import org.apache.polygene.api.structure.ModuleDescriptor;
+import org.apache.polygene.api.type.EntityCompositeType;
+import org.apache.polygene.api.unitofwork.NoSuchEntityTypeException;
+import org.apache.polygene.api.util.Classes;
+import org.apache.polygene.spi.entitystore.EntityNotFoundException;
+import org.apache.polygene.spi.entitystore.EntityStoreUnitOfWork;
+import org.apache.polygene.spi.entitystore.helpers.DefaultEntityState;
+import org.jooq.Condition;
+import org.jooq.Field;
+import org.jooq.Record;
+import org.jooq.Result;
+import org.jooq.Schema;
+import org.jooq.SelectJoinStep;
+import org.jooq.SelectQuery;
+import org.jooq.Table;
+
+public class EntitiesTable
+    implements TableFields
+{
+    private Map<EntityCompositeType, Set<Class<?>>> mixinTypeCache = new ConcurrentHashMap<>();
+    private Map<Class<?>, MixinTable> mixinTablesCache = new ConcurrentHashMap<>();
+
+    private final Table<Record> entitiesTable;
+    private JooqDslContext dsl;
+    private final TypesTable types;
+    private final Schema schema;
+    private String applicationVersion;
+
+    EntitiesTable( JooqDslContext dsl, Schema schema, TypesTable types, String applicationVersion, String entitiesTableName )
+    {
+        this.dsl = dsl;
+        this.types = types;
+        this.schema = schema;
+        this.applicationVersion = applicationVersion;
+        entitiesTable = types.tableOf( entitiesTableName );
+    }
+
+    public BaseEntity fetchEntity( EntityReference reference, ModuleDescriptor module )
+    {
+        BaseEntity result = new BaseEntity();
+
+        Result<Record> baseEntityResult = dsl
+            .selectFrom( entitiesTable )
+            .where( identityColumn.eq( reference.identity().toString() ) )
+            .fetch();
+
+        if( baseEntityResult.isEmpty() )
+        {
+            throw new EntityNotFoundException( reference );
+        }
+        Record baseEntity = baseEntityResult.get( 0 );
+        String typeName = baseEntity.field( typeNameColumn ).get( baseEntity );
+        result.type = findEntityDescriptor( typeName, module );
+        result.version = baseEntity.field( versionColumn ).get( baseEntity );
+        result.applicationVersion = baseEntity.field( applicationVersionColumn ).get( baseEntity );
+        result.identity = EntityReference.parseEntityReference( baseEntity.field( identityColumn ).get( baseEntity ) ).identity();
+        result.currentValueIdentity = EntityReference.parseEntityReference( baseEntity.field( valueIdentityColumn ).get( baseEntity ) ).identity();
+        result.modifedAt = Instant.ofEpochMilli( baseEntity.field( modifiedColumn ).get( baseEntity ).getTime() );
+        result.createdAt = Instant.ofEpochMilli( baseEntity.field( createdColumn ).get( baseEntity ).getTime() );
+        return result;
+    }
+
+    private EntityDescriptor findEntityDescriptor( String typeName, ModuleDescriptor module )
+    {
+        try
+        {
+            Class<?> type = getClass().getClassLoader().loadClass( typeName );
+            return module.typeLookup().lookupEntityModel( type );
+        }
+        catch( ClassNotFoundException e )
+        {
+            throw new NoSuchEntityTypeException( typeName, module.name(), module.typeLookup() );
+        }
+    }
+
+    void insertEntity( DefaultEntityState state )
+    {
+        EntityCompositeType compositeType = state.entityDescriptor().valueType();
+        Set<Class<?>> mixinTypes = mixinTypeCache.computeIfAbsent( compositeType, type ->
+        {
+            Set<Class<?>> mixins = compositeType
+                .properties()
+                .map( PropertyDescriptor::accessor )
+                .filter( Classes.instanceOf( Method.class ) )
+                .map( accessor -> (Method) accessor )
+                .map( Method::getDeclaringClass )
+                .collect( Collectors.toSet() );
+            Set<Class<?>> mixinsWithAssociations = mixinsOf( compositeType.associations() );
+            Set<Class<?>> mixinsWithManyAssociations = mixinsOf( compositeType.manyAssociations() );
+            Set<Class<?>> mixinsWithNamedAssociations = mixinsOf( compositeType.namedAssociations() );
+            mixins.addAll( mixinsWithAssociations );
+            mixins.addAll( mixinsWithManyAssociations );
+            mixins.addAll( mixinsWithNamedAssociations );
+            return mixins;
+        } );
+        String valueIdentity = UUID.randomUUID().toString();
+        mixinTypes.forEach( type ->
+                            {
+                                MixinTable table = findMixinTable( type, state.entityDescriptor() );
+                                table.insertMixinState( state, valueIdentity );
+                            } );
+    }
+
+    private MixinTable findMixinTable( Class<?> type, EntityDescriptor entityDescriptor )
+    {
+        return mixinTablesCache.computeIfAbsent( type, t -> new MixinTable( dsl, schema, types, type, entityDescriptor ) );
+    }
+
+    private Set<Class<?>> mixinsOf( Stream<? extends AssociationDescriptor> stream )
+    {
+        return stream
+            .map( AssociationDescriptor::accessor )
+            .filter( Classes.instanceOf( Method.class ) )
+            .map( accessor -> (Method) accessor )
+            .map( Method::getDeclaringClass )
+            .collect( Collectors.toSet() );
+    }
+
+    private String columnNameOf( QualifiedName propertyName )
+    {
+        return null;
+    }
+
+    void modifyEntity( Class<?> mixinType, DefaultEntityState state )
+    {
+
+    }
+
+    void createNewBaseEntity( EntityReference reference, EntityDescriptor descriptor, EntityStoreUnitOfWork uow )
+    {
+        String valueIdentity = UUID.randomUUID().toString();
+        dsl.insertInto( entitiesTable )
+           .set( identityColumn, reference.identity().toString() )
+           .set( createdColumn, new Timestamp( uow.currentTime().toEpochMilli() ) )
+           .set( modifiedColumn, new Timestamp( uow.currentTime().toEpochMilli() ) )
+           .set( valueIdentityColumn, valueIdentity )
+           .set( typeNameColumn, descriptor.primaryType().getName() )
+           .set( versionColumn, "1" )
+           .set( applicationVersionColumn, applicationVersion )
+           .execute();
+    }
+
+    /**
+     * Builds the SELECT statement for a given entity.
+     * <p>
+     * Example; If we have the following entity
+     * </p>
+     * <code><pre>
+     *     public interface LegalEntity
+     *     {
+     *         Property&lt;String&gt; registration();
+     *     }
+     * <p>
+     *     public interface Person extends LegalEntity
+     *     {
+     *         Property&lt;String&gt; name();
+     * <p>
+     *         &#64;Optional
+     *         Association&lt;Person&gt; spouse();
+     * <p>
+     *         ManyAssocation&lt;Person&gt; children();
+     *     }
+     * </pre></code>
+     * <p>
+     * and we do a simple;
+     * <code><pre>
+     *     Person p = uow.get( Person.class, "niclas" );
+     * </pre></code>
+     * <p>
+     * then the generated query will be
+     * </p>
+     * <code><pre>
+     *     SELECT * FROM ENTITIES
+     *     JOIN Person ON identity = ENTITIES.value_id
+     *     JOIN LegalEntity ON identity = ENTITIES.value_id
+     *     JOIN Person_Assoc ON identity = ENTITIES.value_id
+     *     WHERE ENTITIES.identity = '123'
+     * </pre></code>
+     *
+     * @param entityDescriptor The descriptor of the entity type to be built.
+     * @return The SELECT query that can be executed to retrieve the entity.
+     */
+    public SelectQuery<Record> createGetEntityQuery( EntityDescriptor entityDescriptor, EntityReference reference )
+    {
+        SelectJoinStep<Record> from = dsl.select().from( entitiesTable );
+        List<Table<Record>> joins = getTableJoins( entityDescriptor );
+        for( Table<Record> joinedTable : joins )
+        {
+            Field<String> joinedField = joinedTable.field( identityColumn );
+            Condition joinCondition = joinedField.eq( entitiesTable.field( valueIdentityColumn ) );
+            from = from.join( joinedTable ).on( joinCondition );
+        }
+        return from.where( identityColumn.eq( reference.identity().toString() ) ).getQuery();
+    }
+
+    public void fetchAssociations( Record record, Consumer<AssociationValue> consume )
+    {
+        AssociationValue value = new AssociationValue();
+        value.name = record.getValue( nameColumn );
+        value.position = record.getValue( indexColumn );
+        value.reference = record.getValue( referenceColumn );
+        consume.accept( value );
+    }
+
+    public List<Table<Record>> getTableJoins( EntityDescriptor entityDescriptor )
+    {
+        return entityDescriptor
+            .mixinTypes()
+            .map( ( Class<?> type ) -> types.tableFor( type, entityDescriptor ) )
+            .collect( Collectors.toList() );
+    }
+}

http://git-wip-us.apache.org/repos/asf/polygene-java/blob/60d2eebd/extensions/entitystore-jooq/src/main/java/org/apache/polygene/entitystore/jooq/JooqDslContext.java
----------------------------------------------------------------------
diff --git a/extensions/entitystore-jooq/src/main/java/org/apache/polygene/entitystore/jooq/JooqDslContext.java b/extensions/entitystore-jooq/src/main/java/org/apache/polygene/entitystore/jooq/JooqDslContext.java
index 8737936..95a0fd5 100644
--- a/extensions/entitystore-jooq/src/main/java/org/apache/polygene/entitystore/jooq/JooqDslContext.java
+++ b/extensions/entitystore-jooq/src/main/java/org/apache/polygene/entitystore/jooq/JooqDslContext.java
@@ -1,3 +1,20 @@
+/*
+ *  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.jooq;
 
 import java.lang.reflect.InvocationHandler;
@@ -6,7 +23,6 @@ import javax.sql.DataSource;
 import org.apache.polygene.api.injection.scope.Service;
 import org.apache.polygene.api.injection.scope.Uses;
 import org.apache.polygene.api.mixin.Mixins;
-import org.apache.polygene.api.service.ServiceDescriptor;
 import org.jooq.Configuration;
 import org.jooq.DSLContext;
 import org.jooq.SQLDialect;
@@ -23,13 +39,11 @@ public interface JooqDslContext extends DSLContext
     {
         private DSLContext dsl;
 
-        public Mixin( @Service DataSource dataSource, @Uses ServiceDescriptor serviceDescriptor )
+        public Mixin( @Service DataSource dataSource, @Uses Settings settings, @Uses SQLDialect dialect )
         {
-            Settings settings = serviceDescriptor.metaInfo( Settings.class );
-            SQLDialect sqlDialect = serviceDescriptor.metaInfo( SQLDialect.class );
             Configuration configuration = new DefaultConfiguration()
                 .set( dataSource )
-                .set( sqlDialect )
+                .set( dialect )
                 .set( settings );
             dsl = DSL.using( configuration );
         }

http://git-wip-us.apache.org/repos/asf/polygene-java/blob/60d2eebd/extensions/entitystore-jooq/src/main/java/org/apache/polygene/entitystore/jooq/JooqEntityStoreConfiguration.java
----------------------------------------------------------------------
diff --git a/extensions/entitystore-jooq/src/main/java/org/apache/polygene/entitystore/jooq/JooqEntityStoreConfiguration.java b/extensions/entitystore-jooq/src/main/java/org/apache/polygene/entitystore/jooq/JooqEntityStoreConfiguration.java
index e3a79f6..7d27cdf 100644
--- a/extensions/entitystore-jooq/src/main/java/org/apache/polygene/entitystore/jooq/JooqEntityStoreConfiguration.java
+++ b/extensions/entitystore-jooq/src/main/java/org/apache/polygene/entitystore/jooq/JooqEntityStoreConfiguration.java
@@ -58,5 +58,16 @@ public interface JooqEntityStoreConfiguration extends SQLConfiguration
      */
     @UseDefaults( "true" )
     Property<Boolean> createIfMissing();
+
+    /**
+     * The SQL dialect that is being used.
+     * <p>
+     * Typically that is matching a supporting dialect in JOOQ.
+     * See {@link org.jooq.SQLDialect} for supported values.
+     * </p>
+     * @return The property with the dialect value.
+     */
+    @UseDefaults( "" )
+    Property<String> dialect();
 }
 // END SNIPPET: config

http://git-wip-us.apache.org/repos/asf/polygene-java/blob/60d2eebd/extensions/entitystore-jooq/src/main/java/org/apache/polygene/entitystore/jooq/JooqEntityStoreMixin.java
----------------------------------------------------------------------
diff --git a/extensions/entitystore-jooq/src/main/java/org/apache/polygene/entitystore/jooq/JooqEntityStoreMixin.java b/extensions/entitystore-jooq/src/main/java/org/apache/polygene/entitystore/jooq/JooqEntityStoreMixin.java
index 8974181..a22354b 100644
--- a/extensions/entitystore-jooq/src/main/java/org/apache/polygene/entitystore/jooq/JooqEntityStoreMixin.java
+++ b/extensions/entitystore-jooq/src/main/java/org/apache/polygene/entitystore/jooq/JooqEntityStoreMixin.java
@@ -30,11 +30,9 @@ import org.apache.polygene.api.entity.EntityDescriptor;
 import org.apache.polygene.api.entity.EntityReference;
 import org.apache.polygene.api.identity.IdentityGenerator;
 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.structure.ModuleDescriptor;
 import org.apache.polygene.api.usecase.Usecase;
-import org.apache.polygene.spi.PolygeneSPI;
 import org.apache.polygene.spi.entity.EntityState;
 import org.apache.polygene.spi.entity.EntityStatus;
 import org.apache.polygene.spi.entitystore.DefaultEntityStoreUnitOfWork;
@@ -53,19 +51,9 @@ import static org.apache.polygene.api.entity.EntityReference.parseEntityReferenc
 public class JooqEntityStoreMixin
     implements EntityStore, EntityStoreSPI
 {
-
-    @Structure
-    private PolygeneSPI spi;
-
-    @This
-    private SqlType sqlType;
-
     @This
     private SqlTable sqlTable;
 
-    @This
-    private JooqDslContext jooqDslContext;
-
     @Service
     private IdentityGenerator identityGenerator;
 
@@ -103,7 +91,6 @@ public class JooqEntityStoreMixin
         Map<QualifiedName, List<EntityReference>> manyAssocs = new HashMap<>();
         Map<QualifiedName, Map<String, EntityReference>> namedAssocs = new HashMap<>();
         result.forEach( record ->
-                        {
                             sqlTable.fetchAssociations( record, associationValue ->
                             {
                                 // TODO: Perhaps introduce "preserveManyAssociationOrder" option which would have an additional column, separating 'ordinal position' and 'name position'
@@ -115,8 +102,7 @@ public class JooqEntityStoreMixin
                                 {
                                     addNamedAssociation( stateDescriptor, namedAssocs, associationValue );
                                 }
-                            } );
-                        } );
+                            } ) );
 
         return new DefaultEntityState( baseEntity.version,
                                        baseEntity.modifedAt,
@@ -155,7 +141,7 @@ public class JooqEntityStoreMixin
     @Override
     public StateCommitter applyChanges( EntityStoreUnitOfWork unitOfWork, Iterable<EntityState> state )
     {
-        return new JooqStateCommitter( unitOfWork, state );
+        return new JooqStateCommitter( unitOfWork, state, sqlTable.jooqDslContext() );
     }
 
     @Override
@@ -175,24 +161,65 @@ public class JooqEntityStoreMixin
         return null;
     }
 
-    private static class JooqStateCommitter
+    private class JooqStateCommitter
         implements StateCommitter
     {
-        public JooqStateCommitter( EntityStoreUnitOfWork unitOfWork, Iterable<EntityState> state )
-        {
+        private final EntityStoreUnitOfWork unitOfWork;
+        private final Iterable<EntityState> states;
+        private final JooqDslContext dslContext;
 
+        JooqStateCommitter( EntityStoreUnitOfWork unitOfWork, Iterable<EntityState> states, JooqDslContext dslContext )
+        {
+            this.unitOfWork = unitOfWork;
+            this.states = states;
+            this.dslContext = dslContext;
         }
 
         @Override
         public void commit()
         {
+            dslContext.transaction( configuration ->
+                                    {
+                                        for( EntityState es : this.states )
+                                        {
+                                            DefaultEntityState state = (DefaultEntityState) es;
+                                            if( state.status() == EntityStatus.NEW )
+                                            {
+                                                newState( state );
+                                            }
+                                            if( state.status() == EntityStatus.UPDATED )
+                                            {
+                                                updateState( state );
+                                            }
+                                            if( state.status() == EntityStatus.REMOVED )
+                                            {
+                                                removeState( state );
+                                            }
+                                        }
+                                    } );
+        }
+
+        private void newState( DefaultEntityState state )
+        {
+            EntityReference ref = state.entityReference();
+            EntityDescriptor descriptor = state.entityDescriptor();
+            sqlTable.createNewBaseEntity( ref, descriptor, unitOfWork );
+            sqlTable.insertEntity( state );
+        }
+
+        private void updateState( DefaultEntityState state )
+        {
 
         }
 
+        private void removeState( DefaultEntityState state )
+        {
+            EntityReference reference = state.entityReference();
+        }
+
         @Override
         public void cancel()
         {
-
         }
     }
 }

http://git-wip-us.apache.org/repos/asf/polygene-java/blob/60d2eebd/extensions/entitystore-jooq/src/main/java/org/apache/polygene/entitystore/jooq/JooqEntityStoreService.java
----------------------------------------------------------------------
diff --git a/extensions/entitystore-jooq/src/main/java/org/apache/polygene/entitystore/jooq/JooqEntityStoreService.java b/extensions/entitystore-jooq/src/main/java/org/apache/polygene/entitystore/jooq/JooqEntityStoreService.java
index 0259151..511f2f0 100644
--- a/extensions/entitystore-jooq/src/main/java/org/apache/polygene/entitystore/jooq/JooqEntityStoreService.java
+++ b/extensions/entitystore-jooq/src/main/java/org/apache/polygene/entitystore/jooq/JooqEntityStoreService.java
@@ -31,6 +31,6 @@ import org.apache.polygene.spi.entitystore.StateChangeNotificationConcern;
 @Concerns( { StateChangeNotificationConcern.class, ConcurrentModificationCheckConcern.class } )
 @Mixins( { JooqEntityStoreMixin.class } )
 public interface JooqEntityStoreService
-    extends EntityStore, EntityStateVersions, Configuration
+    extends EntityStore, EntityStateVersions, Configuration, SqlTable
 {
 }

http://git-wip-us.apache.org/repos/asf/polygene-java/blob/60d2eebd/extensions/entitystore-jooq/src/main/java/org/apache/polygene/entitystore/jooq/MixinTable.java
----------------------------------------------------------------------
diff --git a/extensions/entitystore-jooq/src/main/java/org/apache/polygene/entitystore/jooq/MixinTable.java b/extensions/entitystore-jooq/src/main/java/org/apache/polygene/entitystore/jooq/MixinTable.java
new file mode 100644
index 0000000..fee95ef
--- /dev/null
+++ b/extensions/entitystore-jooq/src/main/java/org/apache/polygene/entitystore/jooq/MixinTable.java
@@ -0,0 +1,214 @@
+/*
+ *  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.jooq;
+
+import java.lang.reflect.AccessibleObject;
+import java.lang.reflect.Method;
+import java.sql.Timestamp;
+import java.util.Map;
+import java.util.function.Consumer;
+import org.apache.polygene.api.association.AssociationDescriptor;
+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.property.PropertyDescriptor;
+import org.apache.polygene.spi.entity.ManyAssociationState;
+import org.apache.polygene.spi.entity.NamedAssociationState;
+import org.apache.polygene.spi.entitystore.helpers.DefaultEntityState;
+import org.jooq.Field;
+import org.jooq.InsertSetMoreStep;
+import org.jooq.Name;
+import org.jooq.Record;
+import org.jooq.Schema;
+import org.jooq.Table;
+import org.jooq.impl.DSL;
+
+class MixinTable
+    implements TableFields
+{
+
+    private final Table<Record> mixinTable;
+    private final Table<Record> mixinAssocsTable;
+
+    private final JooqDslContext dsl;
+    private TypesTable types;
+    private final Class<?> mixinType;
+
+    MixinTable( JooqDslContext dsl, Schema schema, TypesTable types, Class<?> mixinType,
+                EntityDescriptor descriptor )
+    {
+        this.dsl = dsl;
+        this.types = types;
+        this.mixinType = mixinType;
+        mixinTable = types.tableFor( mixinType, descriptor );
+        mixinAssocsTable = getAssocsTable( descriptor, schema );
+    }
+
+    void insertMixinState( DefaultEntityState state, String valueIdentity )
+    {
+        InsertSetMoreStep<Record> primaryTable =
+            dsl.insertInto( mixinTable )
+               .set( identityColumn, valueIdentity )
+               .set( createdColumn, new Timestamp( System.currentTimeMillis() ) )
+               .set( modifiedColumn, new Timestamp( System.currentTimeMillis() ) );
+
+        EntityDescriptor entityDescriptor = state.entityDescriptor();
+        entityDescriptor.valueType().properties()
+                        .filter( this::isThisMixin )
+                        .forEach( propDescriptor ->
+                                  {
+                                      QualifiedName propertyName = propDescriptor.qualifiedName();
+                                      Field<Object> propertyField = types.fieldOf( propDescriptor );
+                                      primaryTable.set( propertyField, state.propertyValueOf( propertyName ) );
+                                  }
+                                );
+        entityDescriptor.valueType().associations()
+                        .filter( this::isThisMixin )
+                        .forEach( assocDescriptor ->
+                                  {
+                                      QualifiedName assocName = assocDescriptor.qualifiedName();
+                                      Field<String> assocField = types.fieldOf( assocDescriptor );
+                                      EntityReference reference = state.associationValueOf( assocName );
+                                      String identity = null;
+                                      if( reference != null )
+                                      {
+                                          identity = reference.identity().toString();
+                                      }
+                                      primaryTable.set( assocField, identity );
+                                  }
+                                );
+
+        if( mixinAssocsTable != null )
+        {
+            entityDescriptor.valueType().manyAssociations()
+                            .filter( this::isThisMixin )
+                            .forEach( setManyAssociations( state, valueIdentity ) );
+
+            entityDescriptor.valueType().namedAssociations()
+                            .filter( this::isThisMixin )
+                            .forEach( setNamedAssociations( state, valueIdentity ) );
+        }
+    }
+
+    private Consumer<? super AssociationDescriptor> setManyAssociations( DefaultEntityState state, String valueIdentity )
+    {
+        return assocDescriptor ->
+        {
+            QualifiedName assocName = assocDescriptor.qualifiedName();
+            ManyAssociationState entityReferences = state.manyAssociationValueOf( assocName );
+            entityReferences.stream().forEach( setManyAssociation( state, assocDescriptor, valueIdentity ) );
+        };
+    }
+
+    private Consumer<? super EntityReference> setManyAssociation( DefaultEntityState state,
+                                                                  AssociationDescriptor assocDescriptor,
+                                                                  String valueIdentity )
+    {
+        QualifiedName assocName = assocDescriptor.qualifiedName();
+        Field<String> assocField = types.fieldOf( assocDescriptor );
+        InsertSetMoreStep<Record> assocsTable = dsl.insertInto( mixinAssocsTable ).set( identityColumn, valueIdentity );
+        return ref ->
+        {
+            assocsTable.newRecord();
+            assocsTable.set( assocField, state.associationValueOf( assocName ).identity().toString() );
+        };
+    }
+
+    private Consumer<? super AssociationDescriptor> setNamedAssociations( DefaultEntityState state,
+                                                                          String valueIdentity )
+    {
+        return assocDescriptor ->
+        {
+            QualifiedName assocName = assocDescriptor.qualifiedName();
+            NamedAssociationState entityReferences = state.namedAssociationValueOf( assocName );
+            entityReferences.stream().forEach( setNamedAssociation( state, assocDescriptor, valueIdentity ) );
+        };
+    }
+
+    private Consumer<? super Map.Entry<String, EntityReference>> setNamedAssociation( DefaultEntityState state,
+                                                                                      AssociationDescriptor assocDescriptor,
+                                                                                      String valueIdentity )
+    {
+        QualifiedName assocName = assocDescriptor.qualifiedName();
+        Field<String> assocField = types.fieldOf( assocDescriptor );
+        InsertSetMoreStep<Record> assocsTable = dsl.insertInto( mixinAssocsTable ).set( identityColumn, valueIdentity );
+        return ref ->
+        {
+            assocsTable.newRecord();
+            assocsTable.set( assocField, state.associationValueOf( assocName ).identity().toString() );
+        };
+    }
+
+    private boolean isThisMixin( PropertyDescriptor descriptor )
+    {
+        Class<?> declaringClass = declaredIn( descriptor );
+        return mixinType.equals( declaringClass );
+    }
+
+    private boolean isThisMixin( AssociationDescriptor descriptor )
+    {
+        Class<?> declaringClass = declaredIn( descriptor );
+        return mixinType.equals( declaringClass );
+    }
+
+    private Class<?> declaredIn( PropertyDescriptor descriptor )
+    {
+        AccessibleObject accessor = descriptor.accessor();
+        if( accessor instanceof Method )
+        {
+            return ( (Method) accessor ).getDeclaringClass();
+        }
+        throw new UnsupportedOperationException( "Property declared as " + accessor.getClass() + " is not supported in this Entity Store yet." );
+    }
+
+    private Class<?> declaredIn( AssociationDescriptor descriptor )
+    {
+        AccessibleObject accessor = descriptor.accessor();
+        if( accessor instanceof Method )
+        {
+            return ( (Method) accessor ).getDeclaringClass();
+        }
+        throw new UnsupportedOperationException( "Property declared as " + accessor.getClass() + " is not supported in this Entity Store yet." );
+    }
+
+    void modifyMixinState( Class<?> mixinType, DefaultEntityState state )
+    {
+
+    }
+
+    private Table<Record> getAssocsTable( EntityDescriptor descriptor, Schema schema )
+    {
+        if( descriptor.state().manyAssociations().count() > 0
+            || descriptor.state().namedAssociations().count() > 0 )
+        {
+            Name tableName = DSL.name( schema.getName(), mixinTable.getName() + ASSOCS_TABLE_POSTFIX );
+            Table<Record> table = DSL.table( tableName );
+            int result2 = dsl.createTableIfNotExists( table )
+                             .column( identityColumn )
+                             .column( nameColumn )
+                             .column( indexColumn )
+                             .column( referenceColumn )
+                             .execute();
+            return table;
+        }
+        else
+        {
+            return null;
+        }
+    }
+}

http://git-wip-us.apache.org/repos/asf/polygene-java/blob/60d2eebd/extensions/entitystore-jooq/src/main/java/org/apache/polygene/entitystore/jooq/SqlTable.java
----------------------------------------------------------------------
diff --git a/extensions/entitystore-jooq/src/main/java/org/apache/polygene/entitystore/jooq/SqlTable.java b/extensions/entitystore-jooq/src/main/java/org/apache/polygene/entitystore/jooq/SqlTable.java
index 1cf0c1c..2801f57 100644
--- a/extensions/entitystore-jooq/src/main/java/org/apache/polygene/entitystore/jooq/SqlTable.java
+++ b/extensions/entitystore-jooq/src/main/java/org/apache/polygene/entitystore/jooq/SqlTable.java
@@ -17,340 +17,236 @@
  */
 package org.apache.polygene.entitystore.jooq;
 
-import java.lang.reflect.Method;
-import java.time.Instant;
-import java.util.Arrays;
-import java.util.List;
-import java.util.Map;
 import java.util.function.Consumer;
-import java.util.stream.Collectors;
+import javax.sql.DataSource;
+import org.apache.polygene.api.PolygeneAPI;
+import org.apache.polygene.api.composite.TransientBuilderFactory;
 import org.apache.polygene.api.configuration.Configuration;
 import org.apache.polygene.api.entity.EntityDescriptor;
 import org.apache.polygene.api.entity.EntityReference;
+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.injection.scope.Uses;
 import org.apache.polygene.api.mixin.Mixins;
-import org.apache.polygene.api.property.Property;
-import org.apache.polygene.api.property.PropertyDescriptor;
+import org.apache.polygene.api.object.ObjectFactory;
 import org.apache.polygene.api.service.ServiceActivation;
 import org.apache.polygene.api.service.ServiceDescriptor;
+import org.apache.polygene.api.structure.Application;
 import org.apache.polygene.api.structure.ModuleDescriptor;
-import org.apache.polygene.api.type.ValueType;
-import org.apache.polygene.api.unitofwork.NoSuchEntityTypeException;
-import org.apache.polygene.spi.entitystore.EntityNotFoundException;
-import org.jooq.Condition;
-import org.jooq.CreateTableAsStep;
-import org.jooq.Field;
+import org.apache.polygene.spi.entitystore.EntityStoreUnitOfWork;
+import org.apache.polygene.spi.entitystore.helpers.DefaultEntityState;
 import org.jooq.Record;
-import org.jooq.Result;
 import org.jooq.SQLDialect;
 import org.jooq.Schema;
-import org.jooq.SelectJoinStep;
 import org.jooq.SelectQuery;
-import org.jooq.Table;
+import org.jooq.conf.RenderNameStyle;
+import org.jooq.conf.Settings;
 import org.jooq.impl.DSL;
 
+/**
+ * This class handles all the Jooq interactions.
+ * <p>
+ * <p>
+ * <p>
+ * <h1>Tables</h1>
+ * <h2>Types Table</h2>
+ * <ul>
+ * <li>identity</li>
+ * <li>table_name</li>
+ * <li>created_at</li>
+ * <li>modified_at</li>
+ * </ul>
+ * <h2>Entities Table</h2>
+ * <ul>
+ * <li>identity</li>
+ * <li>app_version</li>
+ * <li>value_id</li>
+ * <li>version</li>
+ * <li>type</li>
+ * <li>modified_at</li>
+ * <li>created_at</li>
+ * </ul>
+ * <h2>Mixin Tables</h2>
+ * <p>
+ * Each Mixin is stored in its own table. Only the following column is always present;
+ * <ul>
+ * <li>identity - this is not entity identity but the UUID of the value_id in the Entities Table above.</li>
+ * </ul>
+ * </p>
+ * <p>
+ * Each Property of the Mixin (as defined by QualifiedName of the Property, will reside in its own column.
+ * All values in columns are (for now) serialized using a ValueSerialization service.
+ * </p>
+ * <p>
+ * Associations also has their own columns in the table, with the EntityReference.identity() stored in them.
+ * </p>
+ * <p>
+ * ManyAssociations and NamedAssociations are stored in a separate table, named &lt;mixintable&gt;_ASSOCS, see below.
+ * </p>
+ * <h2>Mixin_ASSOCS Table</h2>
+ * <ul>
+ * <li>identity - the value_id of the mixin value</li>
+ * <li>name - the name of the ManyAssociation or NamedAssociation</li>
+ * <li>position - for NamedAssociation this is the 'name' (i.e key) and for ManyAssociation this is the index into the list.</li>
+ * <li>reference - EntityReference.identity of that association</li>
+ * </ul>
+ */
 @Mixins( SqlTable.Mixin.class )
-public interface SqlTable
+public interface SqlTable extends ServiceActivation
 {
-    String IDENTITY_COLUMN_NAME = "identity";
-    String VALUEID_COLUMN_NAME = "value_id";
-    String VERSION_COLUMN_NAME = "version";
-    String APPLICATIONVERSION_COLUMN_NAME = "app_version";
-    String TYPE_COLUMN_NAME = "type";
-    String LASTMODIFIED_COLUMN_NAME = "modified_at";
-    String CREATED_COLUMN_NAME = "created_at";
-    String TABLENAME_COLUMN_NAME = "table_name";
-    String ASSOCIATIONS_COLUMN_NAME = "assocations";
-    String POSITION_COLUMN_NAME = "position";
-
-    String createNewTableName( Class<?> type );
-
-    Result<Record> createNewTable( Class<?> mixinType, EntityDescriptor descriptor );
-
-    boolean isProperty( Method method );
-
-    Table<Record> findTable( Class<?> type, EntityDescriptor descriptor );
-
-    Table<Record> createTable( Class<?> type, EntityDescriptor descriptor );
-
-    String findTableName( Class<?> type, EntityDescriptor descriptor );
-
-    List<Table<Record>> getTableJoins( EntityDescriptor entityDescriptor );
-
-    Result<Record> fetchTypeInfoFromTable( Class<?> entityType );
-
     BaseEntity fetchBaseEntity( EntityReference reference, ModuleDescriptor module );
 
-    EntityDescriptor findEntityDescriptor( String typeName, ModuleDescriptor module );
+    SelectQuery<Record> createGetEntityQuery( EntityDescriptor descriptor, EntityReference reference );
 
-    Record createNewBaseEntity( EntityReference reference, EntityDescriptor descriptor );
+    void fetchAssociations( Record record, Consumer<AssociationValue> consume );
 
-    SelectQuery<Record> createGetEntityQuery( EntityDescriptor entityDescriptor, EntityReference reference );
+    void createNewBaseEntity( EntityReference ref, EntityDescriptor descriptor, EntityStoreUnitOfWork unitOfWork );
 
-    void fetchAssociations( Record record, Consumer<AssociationValue> consume );
+    void insertEntity( DefaultEntityState state );
+
+    JooqDslContext jooqDslContext();
 
     class Mixin
-        implements SqlTable, ServiceActivation
+        implements SqlTable, TableFields, ServiceActivation
     {
+        @Structure
+        private Application application;
 
-        @This
-        JooqDslContext dsl;
+        @Structure
+        private PolygeneAPI api;
+
+        @Structure
+        private TransientBuilderFactory tbf;
+
+        @Structure
+        private ObjectFactory objectFactory;
 
         @This
         private Configuration<JooqEntityStoreConfiguration> configuration;
 
-        @This
-        private SqlType sqlType;
+        @Service
+        private DataSource datasource;
 
         @Uses
         private ServiceDescriptor serviceDescriptor;
 
-        private Table<Record> typesTable;
-        private Table<Record> entitiesTable;
-        private Map<Class, Table<Record>> entityTables;
-        private Field<String> identityColumn;
-        private Field<String> valueIdentityColumn;
-        private Field<String> typeColumn;
-        private Field<String> versionColumn;
-        private Field<String> applicationVersionColumn;
-        private Field<Instant> modifiedColumn;
-        private Field<Instant> createdColumn;
-        private Field<String> tableNameColumn;
-        private Field<String> assocationsColumn;
-        private Field<String> positionColumn;
-
-        private Schema schema;
-
-        private SQLDialect dialect;
-
-        @Override
-        public void activateService()
-            throws Exception
-        {
-            configuration.refresh();
-            JooqEntityStoreConfiguration config = configuration.get();
-
-            // Prepare jooq DSL
-            dialect = serviceDescriptor.metaInfo( SQLDialect.class );
-
-            String schemaName = config.schemaName().get();
-            String typesTableName = config.typesTableName().get();
-            String entitiesTableName = config.entitiesTableName().get();
-            schema = DSL.schema( DSL.name( schemaName ) );
-            typesTable = DSL.table(
-                dialect.equals( SQLDialect.SQLITE )
-                ? DSL.name( typesTableName )
-                : DSL.name( schema.getName(), typesTableName )
-                                  );
-            entitiesTable = DSL.table(
-                dialect.equals( SQLDialect.SQLITE )
-                ? DSL.name( entitiesTableName )
-                : DSL.name( schema.getName(), entitiesTableName ) );
+        private EntitiesTable entitiesTable;
 
-            identityColumn = DSL.field( DSL.name( IDENTITY_COLUMN_NAME ), String.class );
-            valueIdentityColumn = DSL.field( DSL.name( VALUEID_COLUMN_NAME ), String.class );
-            versionColumn = DSL.field( DSL.name( VERSION_COLUMN_NAME ), String.class );
-            applicationVersionColumn = DSL.field( DSL.name( APPLICATIONVERSION_COLUMN_NAME ), String.class );
-            typeColumn = DSL.field( DSL.name( TYPE_COLUMN_NAME ), String.class );
-            modifiedColumn = DSL.field( DSL.name( LASTMODIFIED_COLUMN_NAME ), Instant.class );
-            createdColumn = DSL.field( DSL.name( CREATED_COLUMN_NAME ), Instant.class );
-            tableNameColumn = DSL.field( DSL.name( TABLENAME_COLUMN_NAME ), String.class );
-            assocationsColumn = DSL.field( DSL.name( ASSOCIATIONS_COLUMN_NAME ), String.class );
-            positionColumn = DSL.field( DSL.name( POSITION_COLUMN_NAME ), String.class );
-
-            // Eventually create schema
-            if( config.createIfMissing().get() )
-            {
-                if( !dialect.equals( SQLDialect.SQLITE )
-                    && dsl.meta().getSchemas().stream().noneMatch( s -> schema.getName().equalsIgnoreCase( s.getName() ) ) )
-                {
-                    dsl.createSchema( schema ).execute();
-                }
-            }
-        }
+        private TypesTable types;
+        private JooqDslContext dsl;
 
         @Override
         public BaseEntity fetchBaseEntity( EntityReference reference, ModuleDescriptor module )
         {
-            BaseEntity result = new BaseEntity();
-
-            Result<Record> baseEntityResult = dsl
-                .select()
-                .from( entitiesTable )
-                .where( identityColumn.eq( reference.toURI() ) )
-                .fetch();
-
-            if( baseEntityResult.isEmpty() )
-            {
-                throw new EntityNotFoundException( reference );
-            }
-            Record baseEntity = baseEntityResult.get( 0 );
-            String typeName = baseEntity.field( typeColumn ).get( baseEntity );
-            result.type = findEntityDescriptor( typeName, module );
-            result.version = baseEntity.field( versionColumn ).get( baseEntity );
-            result.applicationVersion = baseEntity.field( applicationVersionColumn ).get( baseEntity );
-            result.identity = EntityReference.parseEntityReference( baseEntity.field( identityColumn ).get( baseEntity ) ).identity();
-            result.currentValueIdentity = EntityReference.parseEntityReference( baseEntity.field( valueIdentityColumn ).get( baseEntity ) ).identity();
-            result.modifedAt = baseEntity.field( modifiedColumn ).get( baseEntity );
-            result.createdAt = baseEntity.field( createdColumn ).get( baseEntity );
-            return result;
+            return entitiesTable.fetchEntity( reference, module );
         }
 
         @Override
-        public void passivateService()
-            throws Exception
+        public SelectQuery<Record> createGetEntityQuery( EntityDescriptor descriptor, EntityReference reference )
         {
-            schema = null;
+            return entitiesTable.createGetEntityQuery( descriptor, reference );
         }
 
-        public Result<Record> fetchTypeInfoFromTable( Class<?> entityType )
-        {
-            return dsl
-                .select()
-                .from( typesTable )
-                .where( identityColumn.eq( entityType.getName() ) )
-                .fetch();
-        }
-
-        public List<Table<Record>> getTableJoins( EntityDescriptor entityDescriptor )
-        {
-            return entityDescriptor
-                .mixinTypes()
-                .map( ( Class<?> type ) -> findTable( type, entityDescriptor ) )
-                .collect( Collectors.toList() );
-        }
-
-        public Table<Record> findTable( Class<?> type, EntityDescriptor descriptor )
+        @Override
+        public void fetchAssociations( Record record, Consumer<AssociationValue> consume )
         {
-            return entityTables.computeIfAbsent( type, t -> createTable( t, descriptor ) );
+            entitiesTable.fetchAssociations( record, consume );
         }
 
-        public Table<Record> createTable( Class<?> type, EntityDescriptor descriptor )
+        @Override
+        public void createNewBaseEntity( EntityReference ref, EntityDescriptor descriptor, EntityStoreUnitOfWork unitOfWork )
         {
-            String tableName = findTableName( type, descriptor );
-            return null;
+            entitiesTable.createNewBaseEntity( ref, descriptor, unitOfWork );
         }
 
-        public String findTableName( Class<?> type, EntityDescriptor descriptor )
+        @Override
+        public void insertEntity( DefaultEntityState state )
         {
-            Result<Record> typeInfo = fetchTypeInfoFromTable( type );
-            if( typeInfo.isEmpty() )
-            {
-                typeInfo = createNewTable( type, descriptor );
-            }
-            return typeInfo.getValue( 0, tableNameColumn );
+            entitiesTable.insertEntity( state );
         }
 
         @Override
-        public String createNewTableName( Class<?> type )
+        public JooqDslContext jooqDslContext()
         {
-            return null;
+            return dsl;
         }
 
-        public Result<Record> createNewTable( Class<?> mixinType, EntityDescriptor descriptor )
+        @Override
+        public void activateService()
+            throws Exception
         {
-            String tableName = createNewTableName( mixinType );
-            CreateTableAsStep<Record> table = dsl.createTable( tableName );
-            Arrays.stream( mixinType.getDeclaredMethods() )
-                  .filter( this::isProperty )
-                  .forEach( method ->
-                            {
-                                PropertyDescriptor propertyDescriptor = descriptor.state().findPropertyModelByName( method.getName() );
-                                ValueType valueType = propertyDescriptor.valueType();
-                                Class<?> propertyType = valueType.primaryType();
-                                String propertyName = method.getName();
-                                table.column( propertyName, sqlType.getSqlDataTypeFor( propertyType ) );
-                            } );
+            JooqEntityStoreConfiguration config = this.configuration.get();
+            SQLDialect dialect = getSqlDialect( config );
 
-            return fetchTypeInfoFromTable( mixinType );
-        }
+            Settings settings = serviceDescriptor
+                .metaInfo( Settings.class )
+                .withRenderNameStyle( RenderNameStyle.QUOTED );
+            dsl = tbf.newTransient( JooqDslContext.class, settings, dialect );
 
-        public boolean isProperty( Method method )
-        {
-            return Property.class.isAssignableFrom( method.getReturnType() ) && method.getParameterCount() == 0;
-        }
+            String schemaName = config.schemaName().get();
+            String typesTableName = config.typesTableName().get();
+            String entitiesTableName = config.entitiesTableName().get();
+            Schema schema = DSL.schema( DSL.name( schemaName ) );
+            types = new TypesTable( dsl, schema, dialect, typesTableName );
+            entitiesTable = new EntitiesTable( dsl, schema, types, application.version(), entitiesTableName );
 
-        public EntityDescriptor findEntityDescriptor( String typeName, ModuleDescriptor module )
-        {
-            try
-            {
-                Class<?> type = getClass().getClassLoader().loadClass( typeName );
-                return module.typeLookup().lookupEntityModel( type );
-            }
-            catch( ClassNotFoundException e )
+            // Eventually create schema
+            if( config.createIfMissing().get() )
             {
-                throw new NoSuchEntityTypeException( typeName, module.name(), module.typeLookup() );
+                if( !dialect.equals( SQLDialect.SQLITE )
+                    && dsl.meta().getSchemas().stream().noneMatch( s -> schema.getName().equalsIgnoreCase( s.getName() ) ) )
+                {
+                    dsl.createSchema( schema ).execute();
+                }
+
+                dsl.createTableIfNotExists( DSL.name( schemaName, typesTableName ) )
+                   .column( identityColumn )
+                   .column( tableNameColumn )
+                   .column( createdColumn )
+                   .column( modifiedColumn )
+                   .execute();
+
+                dsl.createTableIfNotExists( DSL.name( schemaName, entitiesTableName ) )
+                   .column( identityColumn )
+                   .column( applicationVersionColumn )
+                   .column( valueIdentityColumn )
+                   .column( versionColumn )
+                   .column( typeNameColumn )
+                   .column( modifiedColumn )
+                   .column( createdColumn )
+                   .execute();
             }
+            datasource.getConnection().commit();
         }
 
         @Override
-        public Record createNewBaseEntity( EntityReference reference, EntityDescriptor descriptor )
+        public void passivateService()
+            throws Exception
         {
-            return null;
+
         }
 
-        /**
-         * Builds the SELECT statement for a given entity.
-         * <p>
-         * Example; If we have the following entity
-         * </p>
-         * <code><pre>
-         *     public interface LegalEntity
-         *     {
-         *         Property&lt;String&gt; registration();
-         *     }
-         * <p>
-         *     public interface Person extends LegalEntity
-         *     {
-         *         Property&lt;String&gt; name();
-         * <p>
-         *         &#64;Optional
-         *         Association&lt;Person&gt; spouse();
-         * <p>
-         *         ManyAssocation&lt;Person&gt; children();
-         *     }
-         * </pre></code>
-         * <p>
-         * and we do a simple;
-         * <code><pre>
-         *     Person p = uow.get( Person.class, "niclas" );
-         * </pre></code>
-         * <p>
-         * then the generated query will be
-         * </p>
-         * <code><pre>
-         *     SELECT * FROM ENTITIES
-         *     JOIN Person ON identity = ENTITIES.value_id
-         *     JOIN LegalEntity ON identity = ENTITIES.value_id
-         *     JOIN Person_Assoc ON identity = ENTITIES.value_id
-         *     WHERE ENTITIES.identity = '123'
-         * </pre></code>
-         *
-         * @param entityDescriptor The descriptor of the entity type to be built.
-         * @return The SELECT query that can be executed to retrieve the entity.
-         */
-        public SelectQuery<Record> createGetEntityQuery( EntityDescriptor entityDescriptor, EntityReference reference )
+        private SQLDialect getSqlDialect( JooqEntityStoreConfiguration config )
         {
-            SelectJoinStep<Record> from = dsl.select().from( entitiesTable );
-            List<Table<Record>> joins = getTableJoins( entityDescriptor );
-            for( Table<Record> joinedTable : joins )
+            SQLDialect dialect = null;
+            String dialectString = config.dialect().get();
+            if( dialectString.length() == 0 )
             {
-                Field<String> joinedField = joinedTable.field( identityColumn );
-                Condition joinCondition = joinedField.eq( entitiesTable.field( valueIdentityColumn ) );
-                from = from.join( joinedTable ).on( joinCondition );
+                dialect = SQLDialect.DEFAULT;
             }
-            return from.where( identityColumn.eq( reference.identity().toString() ) ).getQuery();
-        }
-
-        @Override
-        public void fetchAssociations( Record record, Consumer<AssociationValue> consume )
-        {
-            AssociationValue value = new AssociationValue();
-            value.name = record.getValue( assocationsColumn );
-            value.position = record.getValue( positionColumn );
-            value.reference = record.getValue( this.assocationsColumn );
-            consume.accept( value );
+            else
+            {
+                try
+                {
+                    dialect = SQLDialect.valueOf( dialectString );
+                }
+                catch( IllegalArgumentException e )
+                {
+                    throw new IllegalArgumentException( "Invalid SQLDialect: '" + dialectString + "'" );
+                }
+            }
+            return dialect;
         }
     }
 }

http://git-wip-us.apache.org/repos/asf/polygene-java/blob/60d2eebd/extensions/entitystore-jooq/src/main/java/org/apache/polygene/entitystore/jooq/SqlType.java
----------------------------------------------------------------------
diff --git a/extensions/entitystore-jooq/src/main/java/org/apache/polygene/entitystore/jooq/SqlType.java b/extensions/entitystore-jooq/src/main/java/org/apache/polygene/entitystore/jooq/SqlType.java
index c872d62..6b6dfdd 100644
--- a/extensions/entitystore-jooq/src/main/java/org/apache/polygene/entitystore/jooq/SqlType.java
+++ b/extensions/entitystore-jooq/src/main/java/org/apache/polygene/entitystore/jooq/SqlType.java
@@ -24,125 +24,118 @@ import java.time.LocalTime;
 import java.time.OffsetDateTime;
 import java.time.Period;
 import java.time.ZonedDateTime;
-import org.apache.polygene.api.mixin.Mixins;
 import org.jooq.DataType;
 import org.jooq.impl.SQLDataType;
 import org.jooq.types.Interval;
 
-@Mixins( SqlType.Mixin.class )
-public interface SqlType
+class SqlType
 {
-    DataType<?> getSqlDataTypeFor( Class<?> propertyType );
-
-    class Mixin
-        implements SqlType
+    @SuppressWarnings( "unchecked" )
+    static <T> DataType<T> getSqlDataTypeFor( Class<?> propertyType )
     {
-        public DataType<?> getSqlDataTypeFor( Class<?> propertyType )
+        if( String.class.isAssignableFrom( propertyType ) )
         {
-            if( String.class.isAssignableFrom( propertyType ) )
-            {
-                return SQLDataType.VARCHAR;
-            }
-            if( Integer.class.isAssignableFrom( propertyType ) )
-            {
-                return SQLDataType.INTEGER;
-            }
-            if( Long.class.isAssignableFrom( propertyType ) )
-            {
-                return SQLDataType.BIGINT;
-            }
-            if( Boolean.class.isAssignableFrom( propertyType ) )
-            {
-                return SQLDataType.BOOLEAN;
-            }
-            if( Float.class.isAssignableFrom( propertyType ) )
-            {
-                return SQLDataType.FLOAT;
-            }
-            if( Double.class.isAssignableFrom( propertyType ) )
-            {
-                return SQLDataType.DOUBLE;
-            }
-            if( Instant.class.isAssignableFrom( propertyType ) )
-            {
-                return SQLDataType.TIMESTAMPWITHTIMEZONE;
-            }
-            if( Interval.class.isAssignableFrom( propertyType ) )
-            {
-                return SQLDataType.VARCHAR;
-            }
-            if( Period.class.isAssignableFrom( propertyType ) )
-            {
-                return SQLDataType.VARCHAR;
-            }
-            if( LocalDate.class.isAssignableFrom( propertyType ) )
-            {
-                return SQLDataType.LOCALDATE;
-            }
-            if( LocalTime.class.isAssignableFrom( propertyType ) )
+            return (DataType<T>) SQLDataType.VARCHAR;
+        }
+        if( Integer.class.isAssignableFrom( propertyType ) )
+        {
+            return (DataType<T>) SQLDataType.INTEGER;
+        }
+        if( Long.class.isAssignableFrom( propertyType ) )
+        {
+            return (DataType<T>) SQLDataType.BIGINT;
+        }
+        if( Boolean.class.isAssignableFrom( propertyType ) )
+        {
+            return (DataType<T>) SQLDataType.BOOLEAN;
+        }
+        if( Float.class.isAssignableFrom( propertyType ) )
+        {
+            return (DataType<T>) SQLDataType.FLOAT;
+        }
+        if( Double.class.isAssignableFrom( propertyType ) )
+        {
+            return (DataType<T>) SQLDataType.DOUBLE;
+        }
+        if( Instant.class.isAssignableFrom( propertyType ) )
+        {
+            return (DataType<T>) SQLDataType.TIMESTAMPWITHTIMEZONE;
+        }
+        if( Interval.class.isAssignableFrom( propertyType ) )
+        {
+            return (DataType<T>) SQLDataType.VARCHAR;
+        }
+        if( Period.class.isAssignableFrom( propertyType ) )
+        {
+            return (DataType<T>) SQLDataType.VARCHAR;
+        }
+        if( LocalDate.class.isAssignableFrom( propertyType ) )
+        {
+            return (DataType<T>) SQLDataType.LOCALDATE;
+        }
+        if( LocalTime.class.isAssignableFrom( propertyType ) )
+        {
+            return (DataType<T>) SQLDataType.LOCALTIME;
+        }
+        if( LocalDateTime.class.isAssignableFrom( propertyType ) )
+        {
+            return (DataType<T>) SQLDataType.LOCALDATETIME;
+        }
+        if( ZonedDateTime.class.isAssignableFrom( propertyType ) )
+        {
+            return (DataType<T>) SQLDataType.OFFSETDATETIME;
+        }
+        if( OffsetDateTime.class.isAssignableFrom( propertyType ) )
+        {
+            return (DataType<T>) SQLDataType.OFFSETDATETIME;
+        }
+        if( Character.class.isAssignableFrom( propertyType ) )
+        {
+            return (DataType<T>) SQLDataType.CHAR( 1 );
+        }
+        if( Short.class.isAssignableFrom( propertyType ) )
+        {
+            return (DataType<T>) SQLDataType.INTEGER;
+        }
+        if( Byte.class.isAssignableFrom( propertyType ) )
+        {
+            return (DataType<T>) SQLDataType.INTEGER;
+        }
+        if( propertyType.isPrimitive() )
+        {
+            if( propertyType.equals( Integer.TYPE ) )
             {
-                return SQLDataType.LOCALTIME;
+                return (DataType<T>) SQLDataType.INTEGER;
             }
-            if( LocalDateTime.class.isAssignableFrom( propertyType ) )
+            if( propertyType.equals( Long.TYPE ) )
             {
-                return SQLDataType.LOCALDATETIME;
+                return (DataType<T>) SQLDataType.BIGINT;
             }
-            if( ZonedDateTime.class.isAssignableFrom( propertyType ) )
+            if( propertyType.equals( Boolean.TYPE ) )
             {
-                return SQLDataType.OFFSETDATETIME;
+                return (DataType<T>) SQLDataType.BOOLEAN;
             }
-            if( OffsetDateTime.class.isAssignableFrom( propertyType ) )
+            if( propertyType.equals( Float.TYPE ) )
             {
-                return SQLDataType.OFFSETDATETIME;
+                return (DataType<T>) SQLDataType.FLOAT;
             }
-            if( Character.class.isAssignableFrom( propertyType ) )
+            if( propertyType.equals( Double.TYPE ) )
             {
-                return SQLDataType.CHAR( 1 );
+                return (DataType<T>) SQLDataType.DOUBLE;
             }
-            if( Short.class.isAssignableFrom( propertyType ) )
+            if( propertyType.equals( Character.TYPE ) )
             {
-                return SQLDataType.INTEGER;
+                return (DataType<T>) SQLDataType.CHAR( 1 );
             }
-            if( Byte.class.isAssignableFrom( propertyType ) )
+            if( propertyType.equals( Short.TYPE ) )
             {
-                return SQLDataType.INTEGER;
+                return (DataType<T>) SQLDataType.INTEGER;
             }
-            if( propertyType.isPrimitive() )
+            if( propertyType.equals( Byte.TYPE ) )
             {
-                if( propertyType.equals( Integer.TYPE ) )
-                {
-                    return SQLDataType.INTEGER;
-                }
-                if( propertyType.equals( Long.TYPE ) )
-                {
-                    return SQLDataType.BIGINT;
-                }
-                if( propertyType.equals( Boolean.TYPE ) )
-                {
-                    return SQLDataType.BOOLEAN;
-                }
-                if( propertyType.equals( Float.TYPE ) )
-                {
-                    return SQLDataType.FLOAT;
-                }
-                if( propertyType.equals( Double.TYPE ) )
-                {
-                    return SQLDataType.DOUBLE;
-                }
-                if( propertyType.equals( Character.TYPE ) )
-                {
-                    return SQLDataType.CHAR( 1 );
-                }
-                if( propertyType.equals( Short.TYPE ) )
-                {
-                    return SQLDataType.INTEGER;
-                }
-                if( propertyType.equals( Byte.TYPE ) )
-                {
-                    return SQLDataType.INTEGER;
-                }
+                return (DataType<T>) SQLDataType.INTEGER;
             }
-            return SQLDataType.VARCHAR;
         }
+        return (DataType<T>) SQLDataType.VARCHAR;
     }
 }

http://git-wip-us.apache.org/repos/asf/polygene-java/blob/60d2eebd/extensions/entitystore-jooq/src/main/java/org/apache/polygene/entitystore/jooq/TableFields.java
----------------------------------------------------------------------
diff --git a/extensions/entitystore-jooq/src/main/java/org/apache/polygene/entitystore/jooq/TableFields.java b/extensions/entitystore-jooq/src/main/java/org/apache/polygene/entitystore/jooq/TableFields.java
new file mode 100644
index 0000000..2454ae4
--- /dev/null
+++ b/extensions/entitystore-jooq/src/main/java/org/apache/polygene/entitystore/jooq/TableFields.java
@@ -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.polygene.entitystore.jooq;
+
+import java.sql.Timestamp;
+import org.jooq.Field;
+
+import static org.apache.polygene.entitystore.jooq.TypesTable.makeField;
+
+public interface TableFields
+{
+    // Common in all tables
+    String IDENTITY_COLUMN_NAME = "identity";
+    String CREATED_COLUMN_NAME = "created_at";
+    String LASTMODIFIED_COLUMN_NAME = "modified_at";
+
+    // Types Table
+    String TABLENAME_COLUMN_NAME = "table_name";
+
+    // Entities Table
+    String VALUEID_COLUMN_NAME = "value_id";
+    String TYPE_COLUMN_NAME = "type";
+    String VERSION_COLUMN_NAME = "version";
+    String APPLICATIONVERSION_COLUMN_NAME = "app_version";
+
+    // Mixin Tables
+    String NAME_COLUMN_NAME = "name";
+    String INDEX_COLUMN_NAME = "index";    // either index in ManyAssociation or name in NamedAssociation
+    String REFERENCE_COLUMN_NAME = "reference";
+    String ASSOCS_TABLE_POSTFIX = "_ASSOCS";
+
+
+    // Common Fields
+    Field<String> identityColumn = makeField( IDENTITY_COLUMN_NAME, String.class );
+    Field<Timestamp> createdColumn = makeField( CREATED_COLUMN_NAME, Timestamp.class );
+    Field<Timestamp> modifiedColumn = makeField( LASTMODIFIED_COLUMN_NAME, Timestamp.class );
+
+    // Types Table
+    Field<String> tableNameColumn = makeField( TABLENAME_COLUMN_NAME, String.class );
+
+    // Entities Table
+    Field<String> valueIdentityColumn = makeField( VALUEID_COLUMN_NAME, String.class );
+    Field<String> typeNameColumn = makeField( TYPE_COLUMN_NAME, String.class );
+    Field<String> versionColumn = makeField( VERSION_COLUMN_NAME, String.class );
+    Field<String> applicationVersionColumn = makeField( APPLICATIONVERSION_COLUMN_NAME, String.class );
+
+    // Mixin Tables
+
+    // The _ASSOCS table
+    Field<String> nameColumn = makeField( NAME_COLUMN_NAME, String.class );
+    Field<String> referenceColumn = makeField( REFERENCE_COLUMN_NAME, String.class );
+    Field<String> indexColumn = makeField( INDEX_COLUMN_NAME, String.class );
+
+}

http://git-wip-us.apache.org/repos/asf/polygene-java/blob/60d2eebd/extensions/entitystore-jooq/src/main/java/org/apache/polygene/entitystore/jooq/TypesTable.java
----------------------------------------------------------------------
diff --git a/extensions/entitystore-jooq/src/main/java/org/apache/polygene/entitystore/jooq/TypesTable.java b/extensions/entitystore-jooq/src/main/java/org/apache/polygene/entitystore/jooq/TypesTable.java
new file mode 100644
index 0000000..4672d4f
--- /dev/null
+++ b/extensions/entitystore-jooq/src/main/java/org/apache/polygene/entitystore/jooq/TypesTable.java
@@ -0,0 +1,187 @@
+/*
+ *  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.jooq;
+
+import java.lang.reflect.Method;
+import java.lang.reflect.Type;
+import java.sql.Timestamp;
+import java.util.Map;
+import java.util.concurrent.ConcurrentHashMap;
+import org.apache.polygene.api.association.AssociationDescriptor;
+import org.apache.polygene.api.common.QualifiedName;
+import org.apache.polygene.api.entity.EntityDescriptor;
+import org.apache.polygene.api.property.Property;
+import org.apache.polygene.api.property.PropertyDescriptor;
+import org.apache.polygene.api.util.Classes;
+import org.jooq.CreateTableColumnStep;
+import org.jooq.DataType;
+import org.jooq.Field;
+import org.jooq.Record;
+import org.jooq.Result;
+import org.jooq.SQLDialect;
+import org.jooq.Schema;
+import org.jooq.Table;
+import org.jooq.impl.DSL;
+
+public class TypesTable
+    implements TableFields
+{
+    private final Map<Class<?>, Table<Record>> mixinTablesCache = new ConcurrentHashMap<>();
+    private final Map<Class<?>, Table<Record>> mixinAssocsTablesCache = new ConcurrentHashMap<>();
+
+    private final Table<Record> typesTable;
+    private final SQLDialect dialect;
+    private final Schema schema;
+
+    private final JooqDslContext dsl;
+
+    TypesTable( JooqDslContext dsl, Schema schema,
+                SQLDialect dialect,
+                String typesTablesName
+              )
+    {
+        this.schema = schema;
+        this.dialect = dialect;
+        typesTable = tableOf( typesTablesName );
+        this.dsl = dsl;
+    }
+
+    static <T> Field<T> makeField( String columnName, Class<T> type )
+    {
+        return DSL.field( DSL.name( columnName ), type );
+    }
+
+    Table<Record> tableOf( String tableName )
+    {
+        return DSL.table(
+            dialect.equals( SQLDialect.SQLITE )
+            ? DSL.name( tableName )
+            : DSL.name( schema.getName(), tableName ) );
+    }
+
+    String tableNameOf( Class<?> mixinType )
+    {
+        Result<Record> typeInfo = fetchTypeInfoFromTable( mixinType );
+        if( typeInfo.isEmpty() )
+        {
+            return null;
+        }
+        return typeInfo.getValue( 0, tableNameColumn );
+    }
+
+    Table<Record> tableFor( Class<?> type, EntityDescriptor descriptor )
+    {
+        return mixinTablesCache.computeIfAbsent( type, t ->
+        {
+            String tableName = tableNameOf( t );
+            if( tableName == null )
+            {
+                Result<Record> newMixinTable = createNewMixinTable( type, descriptor );
+                return tableOf( newMixinTable.getValue( 0, tableNameColumn ) );
+            }
+            return tableOf( tableName );
+        } );
+    }
+
+    private Result<Record> fetchTypeInfoFromTable( Class<?> mixinTableName )
+    {
+        return dsl.select()
+                  .from( typesTable )
+                  .where( identityColumn.eq( mixinTableName.getName() ) )
+                  .fetch();
+    }
+
+    private Result<Record> createNewMixinTable( Class<?> mixinType, EntityDescriptor descriptor )
+    {
+        String mixinTypeName = mixinType.getName();
+        String tableName = createNewTableName( mixinType );
+        CreateTableColumnStep primaryTable = dsl.createTable( tableName ).column( identityColumn );
+        descriptor.state().properties().forEach(
+            property ->
+            {
+                QualifiedName qualifiedName = property.qualifiedName();
+                if( qualifiedName.toNamespace().equals( mixinTypeName ) )
+                {
+                    primaryTable.column( fieldOf( property ) );
+                }
+            } );
+        descriptor.state().associations().forEach(
+            assoc ->
+            {
+                QualifiedName qualifiedName = assoc.qualifiedName();
+                if( qualifiedName.toNamespace().equals( mixinTypeName ) )
+                {
+                    primaryTable.column( fieldOf( assoc ) );
+                }
+            } );
+
+        int result3 = dsl.insertInto( typesTable )
+                         .set( identityColumn, mixinTypeName )
+                         .set( tableNameColumn, tableName )
+                         .set( createdColumn, new Timestamp( System.currentTimeMillis() ) )
+                         .set( modifiedColumn, new Timestamp( System.currentTimeMillis() ) )
+                         .execute();
+        return fetchTypeInfoFromTable( mixinType );
+    }
+
+    private String createNewTableName( Class<?> mixinType )
+    {
+        String typeName = mixinType.getSimpleName();
+        String postFix = "";
+        int counter = 0;
+        boolean found = false;
+        do
+        {
+            found = checkForTableNamed( typeName + postFix );
+            postFix = "_" + counter++;
+        } while( found );
+        return typeName;
+    }
+
+    private boolean checkForTableNamed( String tableName )
+    {
+        return dsl.select()
+                  .from( typesTable )
+                  .where( tableNameColumn.eq( tableName ) )
+                  .fetch().size() > 0;
+    }
+
+    private boolean isProperty( Method method )
+    {
+        return Property.class.isAssignableFrom( method.getReturnType() ) && method.getParameterCount() == 0;
+    }
+
+    Field<Object> fieldOf( PropertyDescriptor descriptor )
+    {
+        String propertyName = descriptor.qualifiedName().name();
+        return DSL.field( DSL.name( propertyName ), dataTypeOf( descriptor ) );
+    }
+
+    Field<String> fieldOf( AssociationDescriptor descriptor )
+    {
+        String propertyName = descriptor.qualifiedName().name();
+        return DSL.field( DSL.name( propertyName ), DSL.getDataType( String.class ) );
+    }
+
+    private <T> DataType<T> dataTypeOf( PropertyDescriptor property )
+    {
+        Type type = property.type();
+        Class<?> rawType = Classes.RAW_CLASS.apply( type );
+        return SqlType.getSqlDataTypeFor( rawType );
+    }
+}

http://git-wip-us.apache.org/repos/asf/polygene-java/blob/60d2eebd/extensions/entitystore-jooq/src/main/java/org/apache/polygene/entitystore/jooq/assembly/JooqEntityStoreAssembler.java
----------------------------------------------------------------------
diff --git a/extensions/entitystore-jooq/src/main/java/org/apache/polygene/entitystore/jooq/assembly/JooqEntityStoreAssembler.java b/extensions/entitystore-jooq/src/main/java/org/apache/polygene/entitystore/jooq/assembly/JooqEntityStoreAssembler.java
index 8a986a9..c251efe 100644
--- a/extensions/entitystore-jooq/src/main/java/org/apache/polygene/entitystore/jooq/assembly/JooqEntityStoreAssembler.java
+++ b/extensions/entitystore-jooq/src/main/java/org/apache/polygene/entitystore/jooq/assembly/JooqEntityStoreAssembler.java
@@ -25,6 +25,7 @@ import org.apache.polygene.bootstrap.Assembler;
 import org.apache.polygene.bootstrap.Assemblers;
 import org.apache.polygene.bootstrap.AssemblyException;
 import org.apache.polygene.bootstrap.ModuleAssembly;
+import org.apache.polygene.entitystore.jooq.JooqDslContext;
 import org.apache.polygene.entitystore.jooq.JooqEntityStoreConfiguration;
 import org.apache.polygene.entitystore.jooq.JooqEntityStoreService;
 import org.jooq.SQLDialect;
@@ -32,8 +33,9 @@ import org.jooq.conf.RenderNameStyle;
 import org.jooq.conf.Settings;
 
 /**
- * MySQL EntityStore assembly.
+ * JOOQ EntityStore assembly.
  */
+@SuppressWarnings( "WeakerAccess" )
 public class JooqEntityStoreAssembler extends Assemblers.VisibilityIdentityConfig<JooqEntityStoreAssembler>
     implements Assembler
 {
@@ -49,11 +51,12 @@ public class JooqEntityStoreAssembler extends Assemblers.VisibilityIdentityConfi
         }
 
         String identity = ( hasIdentity() ? identity() : DEFAULT_ENTITYSTORE_IDENTITY ).toString();
+        module.transients( JooqDslContext.class );
 
         module.services( JooqEntityStoreService.class )
               .identifiedBy( identity )
               .visibleIn( visibility() )
-              .setMetaInfo( getSQLDialect() )
+              .instantiateOnStartup()
               .setMetaInfo( settings );
 
         if( hasConfig() )


Mime
View raw message