/* * Copyright 2015 Samppa Saarela * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package org.javersion.store.jdbc; import com.google.common.collect.ImmutableMap; import com.querydsl.core.types.Path; import com.querydsl.sql.SQLQueryFactory; import org.javersion.core.VersionNode; import org.javersion.object.ObjectVersionGraph; import org.javersion.path.PropertyPath; import org.javersion.util.Check; import javax.annotation.Nullable; import javax.annotation.concurrent.Immutable; import java.util.concurrent.ArrayBlockingQueue; import java.util.concurrent.Executor; import java.util.concurrent.Executors; import java.util.concurrent.ThreadPoolExecutor; import java.util.function.Function; import java.util.function.Predicate; import static com.google.common.base.MoreObjects.firstNonNull; import static java.util.concurrent.TimeUnit.MILLISECONDS; @Immutable public abstract class StoreOptions<Id, M, V extends JVersion<Id>> extends GraphOptions<Id, M> { public final V version; public final V sinceVersion; public final JVersionParent parent; public final JVersionProperty property; public final ImmutableMap<PropertyPath, Path<?>> versionTableProperties; public final Transactions transactions; public final Executor optimizer; public final Executor publisher; public final Function<VersionStore<Id, M>, GraphCache<Id, M>> cacheBuilder; public final SQLQueryFactory queryFactory; protected StoreOptions(AbstractBuilder<Id, M, V, ?, ?> builder) { super(builder.optimizeWhen, builder.optimizeKeep); this.version = Check.notNull(builder.version, "versionTable"); this.sinceVersion = Check.notNull(builder.versionTableSince, "versionTableSince"); this.parent = Check.notNull(builder.parentTable, "parentTable"); this.property = Check.notNull(builder.propertyTable, "propertyTable"); this.versionTableProperties = builder.versionTableProperties != null ? ImmutableMap.copyOf(builder.versionTableProperties) : ImmutableMap.of(); this.transactions = Check.notNull(builder.transactions, "transactions"); this.optimizer = builder.optimizer; this.publisher = builder.publisher; this.cacheBuilder = firstNonNull(builder.cacheBuilder, store -> null); this.queryFactory = Check.notNull(builder.queryFactory, "queryFactory"); } public abstract AbstractBuilder<Id, M, V, ?, ?> toBuilder(); public abstract static class AbstractBuilder<Id, M, V extends JVersion<Id>, Options extends StoreOptions<Id, M, V>, This extends AbstractBuilder<Id, M, V, Options,This>> { private static final Executor SYNCHRONOUS_EXECUTOR = Runnable::run; protected V version; protected V versionTableSince; protected JVersionParent parentTable; protected JVersionProperty propertyTable; protected Predicate<ObjectVersionGraph<M>> optimizeWhen; protected Function<ObjectVersionGraph<M>, Predicate<VersionNode<PropertyPath, Object, M>>> optimizeKeep; protected Transactions transactions; protected Executor optimizer; protected Executor publisher; @Nullable protected ImmutableMap<PropertyPath, Path<?>> versionTableProperties; protected Function<VersionStore<Id, M>, GraphCache<Id, M>> cacheBuilder; protected SQLQueryFactory queryFactory; public AbstractBuilder() {} public AbstractBuilder(StoreOptions<Id, M, V> options) { this.version = options.version; this.versionTableSince = options.sinceVersion; this.parentTable = options.parent; this.propertyTable = options.property; this.optimizeWhen = options.optimizeWhen; this.optimizeKeep = options.optimizeKeep; this.transactions = options.transactions; this.optimizer = options.optimizer; this.publisher = options.publisher; this.versionTableProperties = options.versionTableProperties; this.queryFactory = options.queryFactory; } public This versionTableSince(V sinceVersion) { this.versionTableSince = sinceVersion; return self(); } public This versionTable(V version) { this.version = version; return self(); } public This parentTable(JVersionParent jParent) { this.parentTable = jParent; return self(); } public This propertyTable(JVersionProperty jProperty) { this.propertyTable = jProperty; return self(); } public This graphOptions(GraphOptions<Id, M> graphOptions) { return optimizeWhen(graphOptions.optimizeWhen).optimizeKeep(graphOptions.optimizeKeep); } public This optimizeWhen(Predicate<ObjectVersionGraph<M>> optimizeWhen) { this.optimizeWhen = optimizeWhen; return self(); } public This optimizeKeep(Function<ObjectVersionGraph<M>, Predicate<VersionNode<PropertyPath, Object, M>>> optimizeKeep) { this.optimizeKeep = optimizeKeep; return self(); } public This publisherType(ExecutorType type) { switch (type) { case ASYNC: return publisher(new ThreadPoolExecutor(1, 1, 0L, MILLISECONDS, new ArrayBlockingQueue<>(2), new ThreadPoolExecutor.DiscardPolicy())); case SYNC: return publisher(SYNCHRONOUS_EXECUTOR); default: return publisher(null); } } public This optimizerType(ExecutorType type) { switch (type) { case ASYNC: return optimizer(Executors.newFixedThreadPool(Runtime.getRuntime().availableProcessors())); case SYNC: return optimizer(SYNCHRONOUS_EXECUTOR); default: return optimizer(null); } } public This transactions(Transactions transactions) { this.transactions = transactions; return self(); } public This optimizer(Executor optimizer) { this.optimizer = optimizer; return self(); } public This publisher(Executor publisher) { this.publisher = publisher; return self(); } public This versionTableProperties(ImmutableMap<PropertyPath, Path<?>> versionTableProperties) { this.versionTableProperties = versionTableProperties; return self(); } public This cacheBuilder(Function<VersionStore<Id, M>, GraphCache<Id, M>> cacheBuilder) { this.cacheBuilder = cacheBuilder; return self(); } public This defaultsFor(String repositoryName) { return parentTable(new JVersionParent(repositoryName)) .propertyTable(new JVersionProperty(repositoryName)); } public This queryFactory(SQLQueryFactory queryFactory) { this.queryFactory = queryFactory; return self(); } public abstract Options build(); public Options build(SQLQueryFactory queryFactory) { return queryFactory(queryFactory).build(); } @SuppressWarnings("unchecked") public This self() { return (This) this; } } }