I did not take the approach of implementing javax.sql.DataSource as this
causes implementation of java.sql.Connection and java.sql.Statement; and
I want to use Calcite framework for parsing and executing SQL in Statement.
So, the code I use now is as following:
public class MyDriver extends org.apache.calcite.jdbc.Driver {
public static final String CONNECT_STRING_PREFIX = "jdbc:my:";
static { new MyDriver().register(); }
public MyDriver() { super(); }
@Override protected String getConnectStringPrefix() { return
CONNECT_STRING_PREFIX; }
private static ThreadLocal<String> cached_username = new
ThreadLocal<String>();
private static ThreadLocal<String> cached_password = new
ThreadLocal<String>();
public static String getCachedUsername() { return
cached_username.get(); } // used by SchemaFactory.create()
public static String getCachedPassword() { return
cached_password.get(); } // used by SchemaFactory.create()
@Override
public java.sql.Connection connect(String url, Properties info)
throws SQLException {
if (info != null) {
// same properties as in DriverManager.getConnection(String
url, String username, String password)
String username = info.getProperty("user");
String password = info.getProperty("password");
if (username != null && password != null) {
cached_username.set(username);
cached_password.set(password);
}
}
return super.connect(url, info);
}
}
public class MySchemaFactory implements SchemaFactory {
public MySchemaFactory() {}
@Override
public Schema create(SchemaPlus schemaPlus, String s, Map<String,
Object> map) {
String url = (String)map.get("url");
String username = (String)map.get("username");
String password = (String)map.get("password");
if (username == null && password == null) {
username = MyDriver.getCachedUsername();
password = MyDriver.getCachedPassword();
}
// ... here we do some real work, but for simplicity we...
return null;
}
}
// and then in the main code...
String user;
String password;
String url;
// got user, password and url from somewhere...
// url= "jdbc:my:schemaFactory=MySchemaFactory;schema=demodb;schema.url=..."
Class.forName("MyDriver");
java.sql.Connection conn = DriverManager.getConnection(url, user,
password);
...
The questions are:
Q1. Is this approach too ugly?
Q2. Is this approach against the ideology of Calcite?
Q3. Can I have more then one schema just by url tags, without model
file/inline/Properties-argument?
- Alexey.
On 10/01/2017 03:06 PM, Alexey Roytman wrote:
Dear colleagues, I'm doing my first steps in creating custom
SchemaFactory for accessing some endpoint.
My question is as following:
if I do DriverManager.getConnection(url, user, password);
why then:
SchemaFactory.create(SchemaPlus, String, Map<String, Object>)
gets the map without user and password?
I shall not create a model file (because it's a plain text with
password); I shall not pass username and password in URL (e.g.
";schema.username=...;schema.password=..." or model inline) because
it's saved as plain text.
I cannot change the call from DriverManager.getConnection(url, user,
password) to DriverManager.getConnection(url, Properties info) with
custom Properties, as I don't control that code.
My test code basically does this:
String user;
String password;
String url;
...
// got user, password and url from somewhere
// the url is of form: "jdbc:calcite:schemaFactory=MySchemaFactory"
Class.forName("org.apache.calcite.jdbc.Driver");
java.sql.Connection conn = DriverManager.getConnection(url, user,
password);
And the MySchemaFactory.java looks like this:
---
public class MySchemaFactory implements
org.apache.calcite.schema.SchemaFactory {
public MySchemaFactory() {
System.out.println("Factory");
}
@Override
public Schema create(SchemaPlus schemaPlus, String s,
java.util.Map<String, Object> map) {
String url = (String)map.get("url");
String username = (String)map.get("username");
String password = (String)map.get("password");
// do something with url, username and password...
return null; // just for demonstration
}
}
---
Instead of MySchemaFactory I can use
org.apache.calcite.adapter.cassandra.CassandraSchemaFactory, with same
result: the map has no credentials.
Does anyone have any idea of a secure way of passing credentials?..
Maybe, I need to write my own class extending
org.apache.calcite.jdbc.Driver?
What the right Calcite's way?
- Alexey.