33import java .lang .reflect .InvocationTargetException ;
44import java .sql .SQLException ;
55import java .util .Properties ;
6+ import java .util .function .Consumer ;
67import java .util .function .Supplier ;
78import java .util .logging .Level ;
89import 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}
0 commit comments