Skip to content

Commit 784c954

Browse files
authored
Added option channelInitializer (#137)
2 parents 9292be3 + 8cc58f4 commit 784c954

File tree

5 files changed

+238
-42
lines changed

5 files changed

+238
-42
lines changed

jdbc/src/main/java/tech/ydb/jdbc/settings/YdbConnectionProperties.java

Lines changed: 97 additions & 29 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@
33
import java.lang.reflect.InvocationTargetException;
44
import java.sql.SQLException;
55
import java.util.Properties;
6+
import java.util.function.Consumer;
67
import java.util.function.Supplier;
78
import java.util.logging.Level;
89
import java.util.logging.Logger;
@@ -54,6 +55,10 @@ public class YdbConnectionProperties {
5455
static final YdbProperty<String> METADATA_URL = YdbProperty.content("metadataURL",
5556
"Custom URL for the metadata service authentication");
5657

58+
static final YdbProperty<Object> CHANNEL_INITIALIZER = YdbProperty.object("channelInitializer",
59+
"Custom GRPC channel initilizer, use object instance or class full name impementing"
60+
+ " Consumer<ManagedChannelBuilder>");
61+
5762
static final YdbProperty<Object> TOKEN_PROVIDER = YdbProperty.object("tokenProvider",
5863
"Custom token provider, use object instance or class full name impementing Supplier<String>");
5964

@@ -75,6 +80,7 @@ public class YdbConnectionProperties {
7580
private final YdbValue<String> iamEndpoint;
7681
private final YdbValue<String> metadataUrl;
7782
private final YdbValue<Object> tokenProvider;
83+
private final YdbValue<Object> channelInitializer;
7884
private final YdbValue<String> grpcCompression;
7985

8086
public YdbConnectionProperties(String username, String password, Properties props) throws SQLException {
@@ -92,6 +98,7 @@ public YdbConnectionProperties(String username, String password, Properties prop
9298
this.iamEndpoint = IAM_ENDPOINT.readValue(props);
9399
this.metadataUrl = METADATA_URL.readValue(props);
94100
this.tokenProvider = TOKEN_PROVIDER.readValue(props);
101+
this.channelInitializer = CHANNEL_INITIALIZER.readValue(props);
95102
this.grpcCompression = GRPC_COMPRESSION.readValue(props);
96103
}
97104

@@ -203,36 +210,12 @@ public GrpcTransportBuilder applyToGrpcTransport(GrpcTransportBuilder builder) t
203210
}
204211

205212
Object provider = tokenProvider.getValue();
206-
if (provider instanceof Supplier) {
207-
Supplier<?> prov = (Supplier<?>) provider;
208-
builder = builder.withAuthProvider((rpc) -> () -> prov.get().toString());
209-
} else if (provider instanceof AuthProvider) {
210-
AuthProvider prov = (AuthProvider) provider;
211-
builder = builder.withAuthProvider(prov);
212-
} else if (provider instanceof String) {
213-
String className = (String) provider;
214-
if (!FQCN.matcher(className).matches()) {
215-
throw new SQLException("tokenProvider must be full class name or instance of Supplier<String>");
216-
}
213+
builder = applyTokenProvider(builder, provider);
214+
}
217215

218-
try {
219-
Class<?> clazz = Class.forName(className);
220-
if (!Supplier.class.isAssignableFrom(clazz)) {
221-
throw new SQLException("tokenProvider " + className + " is not implement Supplier<String>");
222-
}
223-
Supplier<?> prov = clazz.asSubclass(Supplier.class)
224-
.getConstructor(new Class<?>[0])
225-
.newInstance(new Object[0]);
226-
builder = builder.withAuthProvider((rpc) -> () -> prov.get().toString());
227-
} catch (ClassNotFoundException ex) {
228-
throw new SQLException("tokenProvider " + className + " not found", ex);
229-
} catch (NoSuchMethodException | SecurityException | InstantiationException | IllegalAccessException
230-
| IllegalArgumentException | InvocationTargetException ex) {
231-
throw new SQLException("Cannot construct tokenProvider " + className, ex);
232-
}
233-
} else if (provider != null) {
234-
throw new SQLException("Cannot parse tokenProvider " + provider.getClass().getName());
235-
}
216+
if (channelInitializer.hasValue()) {
217+
Object initializer = channelInitializer.getValue();
218+
builder = applyChannelInitializer(builder, initializer);
236219
}
237220

238221
if (grpcCompression.hasValue()) {
@@ -248,4 +231,89 @@ public GrpcTransportBuilder applyToGrpcTransport(GrpcTransportBuilder builder) t
248231

249232
return builder;
250233
}
234+
235+
private GrpcTransportBuilder applyTokenProvider(GrpcTransportBuilder builder, Object provider) throws SQLException {
236+
if (provider instanceof Supplier) {
237+
Supplier<?> prov = (Supplier<?>) provider;
238+
builder = builder.withAuthProvider((rpc) -> () -> prov.get().toString());
239+
} else if (provider instanceof AuthProvider) {
240+
AuthProvider prov = (AuthProvider) provider;
241+
builder = builder.withAuthProvider(prov);
242+
} else if (provider instanceof String) {
243+
String className = (String) provider;
244+
if (!FQCN.matcher(className).matches()) {
245+
throw new SQLException("tokenProvider must be full class name or instance of Supplier<String>");
246+
}
247+
248+
try {
249+
Class<?> clazz = Class.forName(className);
250+
if (!Supplier.class.isAssignableFrom(clazz)) {
251+
throw new SQLException("tokenProvider " + className + " is not implement Supplier<String>");
252+
}
253+
Supplier<?> prov = clazz.asSubclass(Supplier.class)
254+
.getConstructor(new Class<?>[0])
255+
.newInstance(new Object[0]);
256+
builder = builder.withAuthProvider((rpc) -> () -> prov.get().toString());
257+
} catch (ClassNotFoundException ex) {
258+
throw new SQLException("tokenProvider " + className + " not found", ex);
259+
} catch (NoSuchMethodException | SecurityException | InstantiationException | IllegalAccessException
260+
| IllegalArgumentException | InvocationTargetException ex) {
261+
throw new SQLException("Cannot construct tokenProvider " + className, ex);
262+
}
263+
} else if (provider != null) {
264+
throw new SQLException("Cannot parse tokenProvider " + provider.getClass().getName());
265+
}
266+
return builder;
267+
}
268+
269+
private GrpcTransportBuilder applyChannelInitializer(GrpcTransportBuilder builder, Object initializer)
270+
throws SQLException {
271+
if (initializer instanceof Consumer) {
272+
@SuppressWarnings("unchecked")
273+
Consumer<Object> prov = (Consumer<Object>) initializer;
274+
builder = builder.addChannelInitializer(prov);
275+
} else if (initializer instanceof String) {
276+
String className = (String) initializer;
277+
278+
if (FQCN.matcher(className.trim()).matches()) {
279+
builder.addChannelInitializer(newInitializerInstance(className.trim()));
280+
} else {
281+
String[] classNames = className.split(",");
282+
if (classNames.length < 2) {
283+
throw new SQLException("channelInitializer must be full class name or instance of "
284+
+ "Consumer<ManagedChannelBuilder>");
285+
}
286+
287+
for (String name: classNames) {
288+
if (!FQCN.matcher(name.trim()).matches()) {
289+
throw new SQLException("channelInitializer must be full class name or instance of "
290+
+ "Consumer<ManagedChannelBuilder>");
291+
}
292+
builder.addChannelInitializer(newInitializerInstance(name.trim()));
293+
}
294+
}
295+
} else if (initializer != null) {
296+
throw new SQLException("Cannot parse channelInitializer " + initializer.getClass().getName());
297+
}
298+
return builder;
299+
}
300+
301+
@SuppressWarnings("unchecked")
302+
private Consumer<Object> newInitializerInstance(String className) throws SQLException {
303+
try {
304+
Class<?> clazz = Class.forName(className);
305+
if (!Consumer.class.isAssignableFrom(clazz)) {
306+
throw new SQLException("channelInitializer " + className + " is not implement "
307+
+ "Consumer<ManagedChannelBuilder>");
308+
}
309+
return clazz.asSubclass(Consumer.class)
310+
.getConstructor(new Class<?>[0])
311+
.newInstance(new Object[0]);
312+
} catch (ClassNotFoundException ex) {
313+
throw new SQLException("channelInitializer " + className + " not found", ex);
314+
} catch (NoSuchMethodException | SecurityException | InstantiationException | IllegalAccessException
315+
| IllegalArgumentException | InvocationTargetException ex) {
316+
throw new SQLException("Cannot construct channelInitializer " + className, ex);
317+
}
318+
}
251319
}
Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,22 @@
1+
package tech.ydb.jdbc.settings;
2+
3+
import java.util.function.Consumer;
4+
5+
import io.grpc.ManagedChannelBuilder;
6+
7+
/**
8+
*
9+
* @author Aleksandr Gorshenin
10+
*/
11+
public class BadChannelInitilizer implements Consumer<ManagedChannelBuilder<?>> {
12+
private final String authority;
13+
14+
public BadChannelInitilizer(String authority) {
15+
this.authority = authority;
16+
}
17+
18+
@Override
19+
public void accept(ManagedChannelBuilder<?> t) {
20+
t.overrideAuthority(authority);
21+
}
22+
}
Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,16 @@
1+
package tech.ydb.jdbc.settings;
2+
3+
import java.util.function.Consumer;
4+
5+
import io.grpc.ManagedChannelBuilder;
6+
7+
/**
8+
*
9+
* @author Aleksandr Gorshenin
10+
*/
11+
public class CustomChannelInitilizer implements Consumer<ManagedChannelBuilder<?>> {
12+
@Override
13+
public void accept(ManagedChannelBuilder<?> t) {
14+
t.usePlaintext();
15+
}
16+
}

jdbc/src/test/java/tech/ydb/jdbc/settings/NonSupplierTokenProvider.java

Lines changed: 0 additions & 11 deletions
This file was deleted.

jdbc/src/test/java/tech/ydb/jdbc/settings/YdbConnectionPropertiesTest.java

Lines changed: 103 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -2,8 +2,10 @@
22

33
import java.sql.SQLException;
44
import java.util.Properties;
5+
import java.util.function.Consumer;
56
import java.util.function.Supplier;
67

8+
import io.grpc.ManagedChannelBuilder;
79
import org.junit.jupiter.api.Assertions;
810
import org.junit.jupiter.api.Test;
911

@@ -100,10 +102,10 @@ public void tokenProviderInvalidClassTest() throws SQLException {
100102
@Test
101103
public void tokenProviderNonSupplierClassTest() throws SQLException {
102104
Properties props = new Properties();
103-
props.put("tokenProvider", "tech.ydb.jdbc.settings.NonSupplierTokenProvider");
105+
props.put("tokenProvider", "tech.ydb.jdbc.settings.CustomChannelInitilizer");
104106
YdbConnectionProperties cp = new YdbConnectionProperties(null, null, props);
105107
ExceptionAssert.sqlException(
106-
"tokenProvider tech.ydb.jdbc.settings.NonSupplierTokenProvider is not implement Supplier<String>",
108+
"tokenProvider tech.ydb.jdbc.settings.CustomChannelInitilizer is not implement Supplier<String>",
107109
() -> cp.applyToGrpcTransport(GrpcTransport.forConnectionString(YDB_URL))
108110
);
109111
}
@@ -119,4 +121,103 @@ public void tokenProviderWrongObjectTest() throws SQLException {
119121
() -> cp.applyToGrpcTransport(GrpcTransport.forConnectionString(YDB_URL))
120122
);
121123
}
124+
125+
@Test
126+
public void channelInitializerConsumerTest() throws SQLException {
127+
Properties props = new Properties();
128+
props.put("channelInitializer", (Consumer<ManagedChannelBuilder<?>>) (ManagedChannelBuilder<?> t) -> {
129+
t.maxTraceEvents(0);
130+
});
131+
YdbConnectionProperties cp = new YdbConnectionProperties(null, null, props);
132+
GrpcTransportBuilder builder = cp.applyToGrpcTransport(GrpcTransport.forConnectionString(YDB_URL));
133+
Assertions.assertFalse(builder.getChannelInitializers().isEmpty());
134+
}
135+
136+
@Test
137+
public void channelInitializerClassTest() throws SQLException {
138+
Properties props = new Properties();
139+
props.put("channelInitializer", "tech.ydb.jdbc.settings.CustomChannelInitilizer");
140+
YdbConnectionProperties cp = new YdbConnectionProperties(null, null, props);
141+
GrpcTransportBuilder builder = cp.applyToGrpcTransport(GrpcTransport.forConnectionString(YDB_URL));
142+
Assertions.assertEquals(1, builder.getChannelInitializers().size());
143+
}
144+
145+
@Test
146+
public void channelInitializerClassListTest() throws SQLException {
147+
Properties props = new Properties();
148+
props.put("channelInitializer", "tech.ydb.jdbc.settings.CustomChannelInitilizer, "
149+
+ "tech.ydb.jdbc.settings.CustomChannelInitilizer");
150+
YdbConnectionProperties cp = new YdbConnectionProperties(null, null, props);
151+
GrpcTransportBuilder builder = cp.applyToGrpcTransport(GrpcTransport.forConnectionString(YDB_URL));
152+
Assertions.assertEquals(2, builder.getChannelInitializers().size());
153+
}
154+
155+
@Test
156+
public void channelInitializerWrongClassNameTest() throws SQLException {
157+
Properties props = new Properties();
158+
props.put("channelInitializer", "1tech.ydb.jdbc.settings.StaticTokenProvider");
159+
YdbConnectionProperties cp = new YdbConnectionProperties(null, null, props);
160+
ExceptionAssert.sqlException(
161+
"channelInitializer must be full class name or instance of Consumer<ManagedChannelBuilder>",
162+
() -> cp.applyToGrpcTransport(GrpcTransport.forConnectionString(YDB_URL))
163+
);
164+
}
165+
166+
@Test
167+
public void channelInitializerWrongClassNameListTest() throws SQLException {
168+
Properties props = new Properties();
169+
props.put("channelInitializer", "tech.ydb.jdbc.settings.CustomChannelInitilizer, "
170+
+ "1tech.ydb.jdbc.settings.StaticTokenProvider");
171+
YdbConnectionProperties cp = new YdbConnectionProperties(null, null, props);
172+
ExceptionAssert.sqlException(
173+
"channelInitializer must be full class name or instance of Consumer<ManagedChannelBuilder>",
174+
() -> cp.applyToGrpcTransport(GrpcTransport.forConnectionString(YDB_URL))
175+
);
176+
}
177+
178+
@Test
179+
public void channelInitializerUnknownClassTest() throws SQLException {
180+
Properties props = new Properties();
181+
props.put("channelInitializer", "tech.ydb.jdbc.settings.TestTokenProvider");
182+
YdbConnectionProperties cp = new YdbConnectionProperties(null, null, props);
183+
ExceptionAssert.sqlException(
184+
"channelInitializer tech.ydb.jdbc.settings.TestTokenProvider not found",
185+
() -> cp.applyToGrpcTransport(GrpcTransport.forConnectionString(YDB_URL))
186+
);
187+
}
188+
189+
@Test
190+
public void channelInitializerInvalidClassTest() throws SQLException {
191+
Properties props = new Properties();
192+
props.put("channelInitializer", "tech.ydb.jdbc.settings.BadChannelInitilizer");
193+
YdbConnectionProperties cp = new YdbConnectionProperties(null, null, props);
194+
ExceptionAssert.sqlException(
195+
"Cannot construct channelInitializer tech.ydb.jdbc.settings.BadChannelInitilizer",
196+
() -> cp.applyToGrpcTransport(GrpcTransport.forConnectionString(YDB_URL))
197+
);
198+
}
199+
200+
@Test
201+
public void channelInitializerNonConsumerClassTest() throws SQLException {
202+
Properties props = new Properties();
203+
props.put("channelInitializer", "tech.ydb.jdbc.settings.StaticTokenProvider");
204+
YdbConnectionProperties cp = new YdbConnectionProperties(null, null, props);
205+
ExceptionAssert.sqlException(
206+
"channelInitializer tech.ydb.jdbc.settings.StaticTokenProvider is not implement "
207+
+ "Consumer<ManagedChannelBuilder>",
208+
() -> cp.applyToGrpcTransport(GrpcTransport.forConnectionString(YDB_URL))
209+
);
210+
}
211+
212+
@Test
213+
public void channelInitializerWrongObjectTest() throws SQLException {
214+
Properties props = new Properties();
215+
props.put("channelInitializer", new Object());
216+
YdbConnectionProperties cp = new YdbConnectionProperties(null, null, props);
217+
218+
ExceptionAssert.sqlException(
219+
"Cannot parse channelInitializer java.lang.Object",
220+
() -> cp.applyToGrpcTransport(GrpcTransport.forConnectionString(YDB_URL))
221+
);
222+
}
122223
}

0 commit comments

Comments
 (0)