Skip to content

Commit 6e1d3b0

Browse files
committed
Implement DI with Guice (Close #22)
1 parent 7d3b515 commit 6e1d3b0

File tree

189 files changed

+1542
-985
lines changed

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

189 files changed

+1542
-985
lines changed

api/build.gradle

+7-5
Original file line numberDiff line numberDiff line change
@@ -7,15 +7,17 @@ dependencies {
77
implementation project(':scale')
88
implementation project(':transport')
99

10+
implementation 'com.google.inject:guice:5.1.0'
11+
1012
annotationProcessor project(':pallet:pallet-codegen')
1113
annotationProcessor project(':rpc:rpc-codegen')
1214

1315
testImplementation project(':tests')
1416

15-
testAnnotationProcessor project(':pallet:pallet-codegen')
16-
1717
testImplementation 'ch.qos.logback:logback-classic:1.2.11'
18-
testImplementation 'org.testcontainers:testcontainers:1.17.1'
19-
testImplementation 'org.testcontainers:junit-jupiter:1.17.1'
18+
testImplementation 'org.testcontainers:testcontainers:1.17.2'
19+
testImplementation 'org.testcontainers:junit-jupiter:1.17.2'
2020
testImplementation 'org.awaitility:awaitility:4.2.0'
21-
}
21+
22+
testAnnotationProcessor project(':pallet:pallet-codegen')
23+
}
Original file line numberDiff line numberDiff line change
@@ -1,32 +1,27 @@
11
package com.strategyobject.substrateclient.api;
22

3-
import com.strategyobject.substrateclient.pallet.GeneratedPalletResolver;
4-
import com.strategyobject.substrateclient.pallet.PalletResolver;
5-
import com.strategyobject.substrateclient.rpc.RpcGeneratedSectionFactory;
6-
import com.strategyobject.substrateclient.rpc.api.section.State;
3+
import com.google.inject.Module;
4+
import com.strategyobject.substrateclient.pallet.PalletFactory;
5+
import com.strategyobject.substrateclient.rpc.RpcSectionFactory;
76
import com.strategyobject.substrateclient.transport.ProviderInterface;
87
import lombok.NonNull;
9-
import lombok.val;
8+
import lombok.RequiredArgsConstructor;
109

1110
import java.util.Map;
1211
import java.util.concurrent.ConcurrentHashMap;
12+
import java.util.function.Supplier;
1313

1414
/**
1515
* Provides the ability to query a node and interact with the Polkadot or Substrate chains.
1616
* It allows interacting with blockchain in various ways: using RPC's queries directly or
1717
* accessing Pallets and its APIs, such as storages, transactions, etc.
1818
*/
19+
@RequiredArgsConstructor
1920
public class Api implements AutoCloseable {
20-
private final @NonNull ProviderInterface providerInterface;
21-
private final @NonNull PalletResolver palletResolver;
21+
private final @NonNull RpcSectionFactory rpcSectionFactory;
22+
private final @NonNull PalletFactory palletFactory;
2223
private final Map<Class<?>, Object> resolvedCache = new ConcurrentHashMap<>();
2324

24-
private Api(@NonNull ProviderInterface providerInterface) {
25-
this.providerInterface = providerInterface;
26-
27-
val state = RpcGeneratedSectionFactory.create(State.class, providerInterface);
28-
this.palletResolver = GeneratedPalletResolver.with(state);
29-
}
3025

3126
/**
3227
* Resolves the instance of a rpc by its definition.
@@ -35,9 +30,8 @@ private Api(@NonNull ProviderInterface providerInterface) {
3530
* @param <T> the type of the rpc
3631
* @return appropriate instance of the rpc
3732
*/
38-
public <T> T rpc(Class<T> clazz) {
39-
return clazz.cast(resolvedCache
40-
.computeIfAbsent(clazz, x -> RpcGeneratedSectionFactory.create(x, providerInterface)));
33+
public <T> T rpc(@NonNull Class<T> clazz) {
34+
return clazz.cast(resolvedCache.computeIfAbsent(clazz, rpcSectionFactory::create));
4135
}
4236

4337
/**
@@ -48,18 +42,21 @@ public <T> T rpc(Class<T> clazz) {
4842
* @return appropriate instance of the pallet
4943
*/
5044
public <T> T pallet(@NonNull Class<T> clazz) {
51-
return clazz.cast(resolvedCache
52-
.computeIfAbsent(clazz, palletResolver::resolve));
53-
}
54-
55-
public static Api with(ProviderInterface providerInterface) {
56-
return new Api(providerInterface);
45+
return clazz.cast(resolvedCache.computeIfAbsent(clazz, palletFactory::create));
5746
}
5847

5948
@Override
6049
public void close() throws Exception {
61-
if (providerInterface instanceof AutoCloseable) {
62-
((AutoCloseable) providerInterface).close();
50+
if (rpcSectionFactory instanceof AutoCloseable) {
51+
((AutoCloseable) rpcSectionFactory).close();
6352
}
6453
}
54+
55+
public static ApiBuilder<DefaultModule> with(@NonNull Supplier<ProviderInterface> providerInterface) {
56+
return with(new DefaultModule(providerInterface.get()));
57+
}
58+
59+
public static <M extends Module> ApiBuilder<M> with(@NonNull M module) {
60+
return new ApiBuilder<>(module);
61+
}
6562
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,36 @@
1+
package com.strategyobject.substrateclient.api;
2+
3+
import com.google.inject.Guice;
4+
import com.google.inject.Module;
5+
import com.strategyobject.substrateclient.transport.ProviderInterface;
6+
import lombok.NonNull;
7+
import lombok.RequiredArgsConstructor;
8+
import lombok.val;
9+
10+
import java.util.concurrent.CompletableFuture;
11+
import java.util.function.Consumer;
12+
import java.util.function.Function;
13+
14+
@RequiredArgsConstructor
15+
public class ApiBuilder<M extends Module> {
16+
private final @NonNull M module;
17+
18+
public ApiBuilder<M> configure(@NonNull Consumer<M> configuration) {
19+
configuration.accept(module);
20+
return this;
21+
}
22+
23+
public <N extends Module> ApiBuilder<N> reconfigure(@NonNull Function<M, N> configuration) {
24+
return new ApiBuilder<>(configuration.apply(this.module));
25+
}
26+
27+
public CompletableFuture<Api> build() {
28+
val injector = Guice.createInjector(new RequireModule(), module);
29+
val provider = injector.getInstance(ProviderInterface.class);
30+
val result = provider.isConnected() ?
31+
CompletableFuture.<Void>completedFuture(null) :
32+
provider.connect();
33+
34+
return result.thenApply(ignored -> injector.getInstance(Api.class));
35+
}
36+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,125 @@
1+
package com.strategyobject.substrateclient.api;
2+
3+
import com.google.inject.AbstractModule;
4+
import com.google.inject.Provides;
5+
import com.google.inject.Singleton;
6+
import com.strategyobject.substrateclient.common.types.AutoRegistry;
7+
import com.strategyobject.substrateclient.pallet.GeneratedPalletFactory;
8+
import com.strategyobject.substrateclient.pallet.PalletFactory;
9+
import com.strategyobject.substrateclient.rpc.GeneratedRpcSectionFactory;
10+
import com.strategyobject.substrateclient.rpc.RpcSectionFactory;
11+
import com.strategyobject.substrateclient.rpc.api.section.State;
12+
import com.strategyobject.substrateclient.rpc.registries.RpcDecoderRegistry;
13+
import com.strategyobject.substrateclient.rpc.registries.RpcEncoderRegistry;
14+
import com.strategyobject.substrateclient.scale.registries.ScaleReaderRegistry;
15+
import com.strategyobject.substrateclient.scale.registries.ScaleWriterRegistry;
16+
import com.strategyobject.substrateclient.transport.ProviderInterface;
17+
import lombok.NonNull;
18+
import lombok.RequiredArgsConstructor;
19+
import lombok.val;
20+
21+
import java.util.function.Consumer;
22+
23+
@RequiredArgsConstructor
24+
public class DefaultModule extends AbstractModule {
25+
private final @NonNull ProviderInterface providerInterface;
26+
27+
private Consumer<ScaleReaderRegistry> configureScaleReaderRegistry = this::autoRegister;
28+
private Consumer<ScaleWriterRegistry> configureScaleWriterRegistry = this::autoRegister;
29+
private Consumer<RpcDecoderRegistry> configureRpcDecoderRegistry = this::autoRegister;
30+
private Consumer<RpcEncoderRegistry> configureRpcEncoderRegistry = this::autoRegister;
31+
32+
private void autoRegister(AutoRegistry registry) {
33+
registry.registerAnnotatedFrom("com.strategyobject.substrateclient");
34+
}
35+
36+
public DefaultModule configureScaleReaderRegistry(Consumer<ScaleReaderRegistry> configure) {
37+
configureScaleReaderRegistry = configureScaleReaderRegistry.andThen(configure);
38+
return this;
39+
}
40+
41+
public DefaultModule configureScaleWriterRegistry(Consumer<ScaleWriterRegistry> configure) {
42+
configureScaleWriterRegistry = configureScaleWriterRegistry.andThen(configure);
43+
return this;
44+
}
45+
46+
public DefaultModule configureRpcDecoderRegistry(Consumer<RpcDecoderRegistry> configure) {
47+
configureRpcDecoderRegistry = configureRpcDecoderRegistry.andThen(configure);
48+
return this;
49+
}
50+
51+
public DefaultModule configureRpcEncoderRegistry(Consumer<RpcEncoderRegistry> configure) {
52+
configureRpcEncoderRegistry = configureRpcEncoderRegistry.andThen(configure);
53+
return this;
54+
}
55+
56+
@Override
57+
protected void configure() {
58+
try {
59+
bind(ProviderInterface.class).toInstance(providerInterface);
60+
bind(RpcSectionFactory.class)
61+
.toConstructor(
62+
GeneratedRpcSectionFactory.class.getConstructor(
63+
ProviderInterface.class,
64+
RpcEncoderRegistry.class,
65+
ScaleWriterRegistry.class,
66+
RpcDecoderRegistry.class,
67+
ScaleReaderRegistry.class))
68+
.asEagerSingleton();
69+
bind(PalletFactory.class)
70+
.toConstructor(
71+
GeneratedPalletFactory.class.getConstructor(
72+
ScaleReaderRegistry.class,
73+
ScaleWriterRegistry.class,
74+
State.class
75+
))
76+
.asEagerSingleton();
77+
bind(Api.class)
78+
.toConstructor(
79+
Api.class.getConstructor(
80+
RpcSectionFactory.class,
81+
PalletFactory.class))
82+
.asEagerSingleton();
83+
} catch (NoSuchMethodException e) {
84+
throw new RuntimeException(e);
85+
}
86+
}
87+
88+
@Provides
89+
@Singleton
90+
public ScaleReaderRegistry provideScaleReaderRegistry() {
91+
val registry = new ScaleReaderRegistry();
92+
configureScaleReaderRegistry.accept(registry);
93+
return registry;
94+
}
95+
96+
@Provides
97+
@Singleton
98+
public ScaleWriterRegistry provideScaleWriterRegistry() {
99+
val registry = new ScaleWriterRegistry();
100+
configureScaleWriterRegistry.accept(registry);
101+
return registry;
102+
}
103+
104+
@Provides
105+
@Singleton
106+
public RpcDecoderRegistry provideRpcDecoderRegistry(ScaleReaderRegistry scaleReaderRegistry) {
107+
val registry = new RpcDecoderRegistry(scaleReaderRegistry);
108+
configureRpcDecoderRegistry.accept(registry);
109+
return registry;
110+
}
111+
112+
@Provides
113+
@Singleton
114+
public RpcEncoderRegistry provideRpcEncoderRegistry(ScaleWriterRegistry scaleWriterRegistry) {
115+
val registry = new RpcEncoderRegistry(scaleWriterRegistry);
116+
configureRpcEncoderRegistry.accept(registry);
117+
return registry;
118+
}
119+
120+
@Provides
121+
@Singleton
122+
public State provideState(RpcSectionFactory rpcSectionFactory) {
123+
return rpcSectionFactory.create(State.class);
124+
}
125+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,24 @@
1+
package com.strategyobject.substrateclient.api;
2+
3+
import com.google.inject.AbstractModule;
4+
import com.strategyobject.substrateclient.pallet.PalletFactory;
5+
import com.strategyobject.substrateclient.rpc.RpcSectionFactory;
6+
import com.strategyobject.substrateclient.rpc.registries.RpcDecoderRegistry;
7+
import com.strategyobject.substrateclient.rpc.registries.RpcEncoderRegistry;
8+
import com.strategyobject.substrateclient.scale.registries.ScaleReaderRegistry;
9+
import com.strategyobject.substrateclient.scale.registries.ScaleWriterRegistry;
10+
import com.strategyobject.substrateclient.transport.ProviderInterface;
11+
12+
public class RequireModule extends AbstractModule {
13+
@Override
14+
protected void configure() {
15+
requireBinding(ProviderInterface.class);
16+
requireBinding(ScaleReaderRegistry.class);
17+
requireBinding(ScaleWriterRegistry.class);
18+
requireBinding(RpcDecoderRegistry.class);
19+
requireBinding(RpcEncoderRegistry.class);
20+
requireBinding(RpcSectionFactory.class);
21+
requireBinding(PalletFactory.class);
22+
requireBinding(Api.class);
23+
}
24+
}

0 commit comments

Comments
 (0)