DefaultPersisterBuilder.java
package org.codefilarete.stalactite.engine.configurer.builder;
import java.util.function.Function;
import org.codefilarete.stalactite.dsl.entity.EntityMappingConfiguration;
import org.codefilarete.stalactite.dsl.entity.EntityMappingConfigurationProvider;
import org.codefilarete.stalactite.engine.EntityPersister;
import org.codefilarete.stalactite.engine.PersistenceContext;
import org.codefilarete.stalactite.engine.PersisterRegistry;
import org.codefilarete.stalactite.engine.PersisterRegistry.DefaultPersisterRegistry;
import org.codefilarete.stalactite.engine.runtime.ConfiguredRelationalPersister;
import org.codefilarete.stalactite.engine.runtime.EntityIsManagedByPersisterAsserter;
import org.codefilarete.stalactite.engine.runtime.OptimizedUpdatePersister;
import org.codefilarete.stalactite.sql.ConnectionConfiguration;
import org.codefilarete.stalactite.sql.Dialect;
public class DefaultPersisterBuilder {
private final Dialect dialect;
private final ConnectionConfiguration connectionConfiguration;
private final PersisterRegistry persisterRegistry;
public DefaultPersisterBuilder(PersistenceContext persistenceContext) {
this(persistenceContext.getDialect(), persistenceContext.getConnectionConfiguration(), new DefaultPersisterRegistry(persistenceContext.getPersisters()));
}
/**
*
* @param dialect the dialect to use to adapt SQL to the database
* @param connectionConfiguration connection information to adapt SQL or create Sequence for identifier generation
* @param persisterRegistry any existing {@link PersisterRegistry} that can provide any existing {@link org.codefilarete.stalactite.engine.EntityPersister}
* to be reused
*/
public DefaultPersisterBuilder(Dialect dialect, ConnectionConfiguration connectionConfiguration, PersisterRegistry persisterRegistry) {
this.dialect = dialect;
this.connectionConfiguration = connectionConfiguration;
this.persisterRegistry = persisterRegistry;
}
public <C, I> ConfiguredRelationalPersister<C, I> build(EntityMappingConfigurationProvider<C, I> entityMappingConfiguration) {
return build(entityMappingConfiguration.getConfiguration());
}
public <C, I> ConfiguredRelationalPersister<C, I> build(EntityMappingConfiguration<C, I> entityMappingConfiguration) {
// If a persister already exists for the type, then we return it : case of graph that declares twice / several times same mapped type
// WARN : this does not take mapping configuration differences into account, so if configuration is different from previous one, since
// no check is done, then the very first persister is returned
EntityPersister<C, Object> existingPersister = persisterRegistry.getPersister(entityMappingConfiguration.getEntityType());
if (existingPersister != null) {
// we can cast because all persisters we registered implement the interface
return (ConfiguredRelationalPersister<C, I>) existingPersister;
} else {
return doBuild(entityMappingConfiguration);
}
}
private <C, I> ConfiguredRelationalPersister<C, I> doBuild(EntityMappingConfiguration<C, I> entityMappingConfiguration) {
ConfiguredRelationalPersister<C, I> result;
result = decorateWithUpdateOptimization((adaptedConnectionConfiguration) -> {
PersisterBuilderPipeline<C, I> persisterBuilderPipeline = new PersisterBuilderPipeline<>(dialect, adaptedConnectionConfiguration, persisterRegistry);
ConfiguredRelationalPersister<C, I> persister = persisterBuilderPipeline.build(entityMappingConfiguration);
return persister;
});
result = decorateWithEntityManagementAsserter(result);
return result;
}
private <C, I> OptimizedUpdatePersister<C, I> decorateWithUpdateOptimization(Function<ConnectionConfiguration, ConfiguredRelationalPersister<C, I>> builderDelegate) {
// we wrap final result with some transversal features
// NB: Order of wrap is important due to invocation of instance methods with code like "this.doSomething(..)" in particular with OptimizedUpdatePersister
// which internally calls update(C, C, boolean) on update(id, Consumer): the latter method is not listened by EntityIsManagedByPersisterAsserter
// (because it has no purpose since entity is not given as argument) but update(C, C, boolean) is and should be, that is not the case if
// EntityIsManagedByPersisterAsserter is done first since OptimizedUpdatePersister invokes itself with "this.update(C, C, boolean)"
ConfiguredRelationalPersister<C, I> concretePersister = builderDelegate.apply(OptimizedUpdatePersister.wrapWithQueryCache(connectionConfiguration));
return new OptimizedUpdatePersister<>(concretePersister);
}
private <C, I> ConfiguredRelationalPersister<C, I> decorateWithEntityManagementAsserter(ConfiguredRelationalPersister<C, I> concretePersister) {
return new EntityIsManagedByPersisterAsserter<>(concretePersister);
}
}