/** * Copyright 2014 Sunny Gleason and original author or authors * * 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 io.kazuki.v0.store.guice; import io.kazuki.v0.internal.helper.LockManager; import io.kazuki.v0.store.guice.impl.DataSourceModuleH2Impl; import io.kazuki.v0.store.guice.impl.JournalStoreModulePartitionedImpl; import io.kazuki.v0.store.guice.impl.KeyValueStoreModuleJdbiH2Impl; import io.kazuki.v0.store.guice.impl.LifecycleModuleDefaultImpl; import io.kazuki.v0.store.guice.impl.LockManagerModuleImpl; import io.kazuki.v0.store.guice.impl.SequenceServiceModuleJdbiH2Impl; import io.kazuki.v0.store.jdbi.JdbiDataSourceConfiguration; import io.kazuki.v0.store.keyvalue.KeyValueStoreConfiguration; import io.kazuki.v0.store.lifecycle.Lifecycle; import io.kazuki.v0.store.management.ComponentRegistrar; import io.kazuki.v0.store.management.KazukiManager; import io.kazuki.v0.store.management.impl.KazukiManagerImpl; import io.kazuki.v0.store.sequence.SequenceService; import io.kazuki.v0.store.sequence.SequenceServiceConfiguration; import javax.sql.DataSource; import com.google.common.base.Preconditions; import com.google.inject.AbstractModule; import com.google.inject.Key; import com.google.inject.Provider; import com.google.inject.Scopes; import com.google.inject.name.Names; public class KazukiModule extends AbstractModule { private final String name; private final String managerName; private final BindingConfig jdbiConfig; private final BindingConfig seqConfig; private final BindingConfig kvConfig; private final BindingConfig jsConfig; private KazukiModule(String name, String managerName, BindingConfig jdbiConfig, BindingConfig seqConfig, BindingConfig kvConfig, BindingConfig jsConfig) { Preconditions.checkNotNull(name, "name"); Preconditions.checkNotNull(jdbiConfig, "jdbiConfig"); Preconditions.checkNotNull(seqConfig, "seqConfig"); Preconditions.checkArgument(kvConfig == null || jsConfig == null, "must specify one KeyValueStore, one JournalStore, or neither"); this.name = name; this.jdbiConfig = jdbiConfig; this.seqConfig = seqConfig; this.kvConfig = kvConfig; this.jsConfig = jsConfig; this.managerName = managerName; } @Override protected void configure() { // TODO: re-enable ASAP // binder().requireExplicitBindings(); Key<Lifecycle> lifecycleKey = Key.get(Lifecycle.class, Names.named(name)); Key<LockManager> lockManagerKey = Key.get(LockManager.class, Names.named(name)); Key<JdbiDataSourceConfiguration> jdbiConfigKey = Key.get(JdbiDataSourceConfiguration.class, Names.named(jdbiConfig.getName())); Key<DataSource> dataSourceKey = Key.get(DataSource.class, Names.named(jdbiConfig.getName())); Key<SequenceService> sequenceServiceKey = Key.get(SequenceService.class, Names.named(seqConfig.getName())); // bind the manager & component registrar Key<KazukiManager> managerKey = null; Key<ComponentRegistrar> registrarKey = null; if (this.managerName != null) { managerKey = Key.get(KazukiManager.class, Names.named(this.managerName)); registrarKey = Key.get(ComponentRegistrar.class, Names.named(this.managerName)); bindObject(new BindingConfig(this.managerName, KazukiManager.class, managerKey)); bindObject(new BindingConfig(this.managerName, ComponentRegistrar.class, registrarKey)); } else { managerKey = Key.get(KazukiManager.class, Names.named(this.name)); registrarKey = Key.get(ComponentRegistrar.class, Names.named(this.name)); KazukiManagerImpl manager = new KazukiManagerImpl(); bindObject(new BindingConfig(this.name, KazukiManager.class, manager)); bindObject(new BindingConfig(this.name, ComponentRegistrar.class, manager)); } // install Lifecycle install(new LifecycleModuleDefaultImpl(name, registrarKey)); // bind lock manager install(new LockManagerModuleImpl(name, registrarKey)); // bind JDBI config bindObject(jdbiConfig); install(new DataSourceModuleH2Impl(name, registrarKey, lifecycleKey, jdbiConfigKey)); // bind SequenceService bindObject(seqConfig); install(new SequenceServiceModuleJdbiH2Impl(seqConfig.getName(), registrarKey, lifecycleKey, dataSourceKey, lockManagerKey)); // bind KeyValueStore (if applicable) if (kvConfig != null) { bindObject(kvConfig); install(new KeyValueStoreModuleJdbiH2Impl(name, registrarKey, lifecycleKey, lockManagerKey, dataSourceKey, sequenceServiceKey)); } // bind JournalStore (if applicable) if (jsConfig != null) { bindObject(jsConfig); install(new JournalStoreModulePartitionedImpl(name, registrarKey, lifecycleKey, lockManagerKey, dataSourceKey, sequenceServiceKey)); } } @SuppressWarnings({"rawtypes", "unchecked"}) protected void bindObject(BindingConfig config) { Key bindKey = Key.get(config.getClazz(), Names.named(config.getName())); Object instance = config.getInstance(); if (instance instanceof Key) { // sweet - it's already bound } else if (instance instanceof Provider) { bind(bindKey).toProvider((Provider) instance).in(Scopes.SINGLETON); } else { bind(bindKey).toInstance(instance); } } public static class Builder { private final String name; private String managerName; private BindingConfig jdbiConfig; private BindingConfig seqConfig; private BindingConfig kvConfig; private BindingConfig jsConfig; public Builder(String name) { this.name = name; } public Builder withComponentManager(String managerName) { this.managerName = managerName; return this; } public Builder withJdbiConfiguration(String name, JdbiDataSourceConfiguration jdbiConfig) { this.jdbiConfig = new BindingConfig(name, JdbiDataSourceConfiguration.class, jdbiConfig); return this; } public Builder withJdbiConfiguration(String name, Provider<JdbiDataSourceConfiguration> jdbiConfig, boolean exposed) { this.jdbiConfig = new BindingConfig(name, JdbiDataSourceConfiguration.class, jdbiConfig); return this; } public Builder withJdbiConfiguration(String name, Key<JdbiDataSourceConfiguration> jdbiConfig) { this.jdbiConfig = new BindingConfig(name, JdbiDataSourceConfiguration.class, jdbiConfig); return this; } public Builder withSequenceServiceConfiguration(String name, SequenceServiceConfiguration seqConfig) { this.seqConfig = new BindingConfig(name, SequenceServiceConfiguration.class, seqConfig); return this; } public Builder withSequenceServiceConfiguration(String name, Provider<SequenceServiceConfiguration> seqConfig) { this.seqConfig = new BindingConfig(name, SequenceServiceConfiguration.class, seqConfig); return this; } public Builder withSequenceServiceConfiguration(String name, Key<SequenceServiceConfiguration> seqConfig) { this.seqConfig = new BindingConfig(name, SequenceServiceConfiguration.class, seqConfig); return this; } public Builder withKeyValueStoreConfiguration(String name, KeyValueStoreConfiguration kvConfig) { this.kvConfig = new BindingConfig(name, KeyValueStoreConfiguration.class, kvConfig); return this; } public Builder withKeyValueStoreConfiguration(String name, Provider<KeyValueStoreConfiguration> kvConfig) { this.kvConfig = new BindingConfig(name, KeyValueStoreConfiguration.class, kvConfig); return this; } public Builder withKeyValueStoreConfiguration(String name, Key<KeyValueStoreConfiguration> kvConfig) { this.kvConfig = new BindingConfig(name, KeyValueStoreConfiguration.class, kvConfig); return this; } public Builder withJournalStoreConfiguration(String name, KeyValueStoreConfiguration jsConfig) { this.jsConfig = new BindingConfig(name, KeyValueStoreConfiguration.class, jsConfig); return this; } public Builder withJournalStoreConfiguration(String name, Provider<KeyValueStoreConfiguration> jsConfig) { this.jsConfig = new BindingConfig(name, KeyValueStoreConfiguration.class, jsConfig); return this; } public Builder withJournalStoreConfiguration(String name, Key<KeyValueStoreConfiguration> jsConfig) { this.jsConfig = new BindingConfig(name, KeyValueStoreConfiguration.class, jsConfig); return this; } public KazukiModule build() { return new KazukiModule(this.name, this.managerName, this.jdbiConfig, this.seqConfig, this.kvConfig, this.jsConfig); } } public static class BindingConfig { private final String name; private final Class<?> clazz; private final Object instance; public BindingConfig(String name, Class<?> clazz, Object instance) { this.name = name; this.clazz = clazz; this.instance = instance; } public String getName() { return name; } public Class<?> getClazz() { return clazz; } public Object getInstance() { return instance; } } }