Committing an intermediate state of the JOOQ ES, to dig into the classloading issue in the Service composition.
Signed-off-by: niclas <[email protected]> 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/develop Commit: 60d2eebd709dc2eb7078b04a305aaba2e4485299 Parents: c2a30f7 Author: niclas <[email protected]> Authored: Fri Jun 9 11:40:09 2017 +0800 Committer: niclas <[email protected]> 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<String> registration(); + * } + * <p> + * public interface Person extends LegalEntity + * { + * Property<String> name(); + * <p> + * @Optional + * Association<Person> spouse(); + * <p> + * ManyAssocation<Person> 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 <mixintable>_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<String> registration(); - * } - * <p> - * public interface Person extends LegalEntity - * { - * Property<String> name(); - * <p> - * @Optional - * Association<Person> spouse(); - * <p> - * ManyAssocation<Person> 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() )
