Skip to content

Commit 6253891

Browse files
committed
Add ojdbc-provider-pkl module
1 parent 4679521 commit 6253891

File tree

6 files changed

+2864
-0
lines changed

6 files changed

+2864
-0
lines changed

ojdbc-provider-pkl/pom.xml

Lines changed: 102 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,102 @@
1+
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
2+
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
3+
<modelVersion>4.0.0</modelVersion>
4+
5+
<name>Oracle JDBC Providers Pkl Module</name>
6+
7+
<artifactId>ojdbc-provider-pkl</artifactId>
8+
<packaging>jar</packaging>
9+
10+
<parent>
11+
<groupId>com.oracle.database.jdbc</groupId>
12+
<artifactId>ojdbc-extensions</artifactId>
13+
<version>${extensions-version}</version>
14+
</parent>
15+
16+
<properties>
17+
<pkl.version>0.27.0</pkl.version>
18+
<maven.compiler.source>17</maven.compiler.source>
19+
<maven.compiler.target>17</maven.compiler.target>
20+
</properties>
21+
22+
<dependencies>
23+
<dependency>
24+
<groupId>com.oracle.database.jdbc</groupId>
25+
<artifactId>ojdbc8</artifactId>
26+
</dependency>
27+
<dependency>
28+
<groupId>org.pkl-lang</groupId>
29+
<artifactId>pkl-core</artifactId>
30+
<version>${pkl.version}</version>
31+
</dependency>
32+
<dependency>
33+
<groupId>org.pkl-lang</groupId>
34+
<artifactId>pkl-config-java</artifactId>
35+
<version>${pkl.version}</version>
36+
</dependency>
37+
<dependency>
38+
<groupId>org.pkl-lang</groupId>
39+
<artifactId>pkl-codegen-java</artifactId>
40+
<version>${pkl.version}</version>
41+
</dependency>
42+
<dependency>
43+
<groupId>org.junit.jupiter</groupId>
44+
<artifactId>junit-jupiter-api</artifactId>
45+
</dependency>
46+
<dependency>
47+
<groupId>org.junit.jupiter</groupId>
48+
<artifactId>junit-jupiter-engine</artifactId>
49+
</dependency>
50+
</dependencies>
51+
52+
<build>
53+
<plugins>
54+
<plugin>
55+
<groupId>org.apache.maven.plugins</groupId>
56+
<artifactId>maven-jar-plugin</artifactId>
57+
<version>3.3.0</version>
58+
<executions>
59+
<execution>
60+
<goals>
61+
<!--
62+
The test classes of this module are used by test classes of
63+
the sibling modules (OCI and Azure).
64+
Maven's jar plugin is configured to generate a test-jar. The
65+
sibling modules then declare a dependency on it.
66+
-->
67+
<goal>test-jar</goal>
68+
</goals>
69+
</execution>
70+
</executions>
71+
</plugin>
72+
<!-- <plugin>-->
73+
<!-- &lt;!&ndash; Comment out this plugin for now. We only need to generate the Java class from pkl template only once. &ndash;&gt;-->
74+
<!-- &lt;!&ndash; There are some changes being made manually in the generated Java class. For example, replacing &ndash;&gt;-->
75+
<!-- &lt;!&ndash; dots (.) in variable names with double dollar sign ($$), since dot is illegal in Java variable names. &ndash;&gt;-->
76+
<!-- <groupId>org.codehaus.mojo</groupId>-->
77+
<!-- <artifactId>exec-maven-plugin</artifactId>-->
78+
<!-- <version>3.3.0</version>-->
79+
<!-- <executions>-->
80+
<!-- <execution>-->
81+
<!-- <goals>-->
82+
<!-- <goal>java</goal>-->
83+
<!-- </goals>-->
84+
<!-- <phase>initialize</phase>-->
85+
<!-- </execution>-->
86+
<!-- </executions>-->
87+
<!-- <configuration>-->
88+
<!-- <mainClass>org.pkl.codegen.java.Main</mainClass>-->
89+
<!-- <arguments>-->
90+
<!-- <argument>&#45;&#45;generate-javadoc</argument>-->
91+
<!-- <argument>-w</argument>-->
92+
<!-- <argument>${maven.multiModuleProjectDirectory}/ojdbc-provider-pkl</argument>-->
93+
<!-- <argument>-o</argument>-->
94+
<!-- <argument>${maven.multiModuleProjectDirectory}/ojdbc-provider-pkl/src/main</argument>-->
95+
<!-- <argument>src/main/resources/OjdbcConfig.pkl</argument>-->
96+
<!-- </arguments>-->
97+
<!-- </configuration>-->
98+
<!-- </plugin>-->
99+
</plugins>
100+
</build>
101+
102+
</project>
Lines changed: 174 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,174 @@
1+
package oracle.jdbc.provider.pkl.configuration.parser;
2+
3+
import oracle.jdbc.provider.pkl.configuration.parser.generated.OjdbcConfig;
4+
import oracle.jdbc.spi.OracleConfigurationParser;
5+
import oracle.jdbc.spi.OracleConfigurationSecretProvider;
6+
import org.pkl.config.java.Config;
7+
import org.pkl.config.java.ConfigEvaluator;
8+
import org.pkl.config.java.NoSuchChildException;
9+
import org.pkl.core.Duration;
10+
import org.pkl.core.ModuleSource;
11+
import org.pkl.core.PNull;
12+
13+
import java.io.IOException;
14+
import java.io.InputStream;
15+
import java.lang.reflect.Field;
16+
import java.nio.charset.StandardCharsets;
17+
import java.sql.SQLException;
18+
import java.util.Base64;
19+
import java.util.HashMap;
20+
import java.util.Map;
21+
import java.util.Properties;
22+
23+
import static oracle.jdbc.OracleConnection.CONNECTION_PROPERTY_PASSWORD;
24+
import static oracle.jdbc.OracleConnection.CONNECTION_PROPERTY_WALLET_LOCATION;
25+
26+
public class PklParser implements OracleConfigurationParser {
27+
@Override
28+
public Properties parse(
29+
InputStream inputStream, Map<String, String> options) throws SQLException {
30+
Properties properties = new Properties();
31+
Config pklConfig;
32+
33+
// Parse Pkl config from String
34+
try (ConfigEvaluator evaluator = ConfigEvaluator.preconfigured()) {
35+
String fileString = new String(inputStream.readAllBytes(), StandardCharsets.UTF_8);
36+
pklConfig = evaluator.evaluate(ModuleSource.text(fileString));
37+
} catch (IOException e) {
38+
throw new SQLException(e);
39+
}
40+
41+
// If key is present, we parse that pkl class
42+
String key = options.get("key");
43+
if (key != null) {
44+
try {
45+
pklConfig = pklConfig.get(key);
46+
} catch (NoSuchChildException e) {
47+
throw new IllegalArgumentException(
48+
key + " key appears in URL but is missing in module.");
49+
}
50+
}
51+
52+
// User common connect_descriptor as the URL
53+
OjdbcConfig ojdbcConfig = pklConfig.as(OjdbcConfig.class);
54+
55+
if (ojdbcConfig.connect_descriptor != null)
56+
properties.put("URL",
57+
"jdbc:oracle:thin:@" + ojdbcConfig.connect_descriptor);
58+
59+
if (ojdbcConfig.user != null)
60+
properties.put("user", ojdbcConfig.user);
61+
62+
if (ojdbcConfig.password != null) {
63+
// Get password from the provider
64+
String passwordProviderType = ojdbcConfig.password.type;
65+
OracleConfigurationSecretProvider passwordSecretProvider =
66+
OracleConfigurationSecretProvider.find(passwordProviderType);
67+
68+
byte[] decodedPassword = Base64
69+
.getDecoder()
70+
.decode(new String(passwordSecretProvider.getSecret(
71+
toSecretMap(ojdbcConfig.password))));
72+
properties.setProperty(CONNECTION_PROPERTY_PASSWORD,
73+
new String(decodedPassword));
74+
}
75+
76+
if (ojdbcConfig.wallet_location != null) {
77+
// Get wallet from the provider
78+
String walletProviderType = ojdbcConfig.wallet_location.type;
79+
OracleConfigurationSecretProvider walletSecretProvider =
80+
OracleConfigurationSecretProvider.find(walletProviderType);
81+
82+
char[] walletCharArray =
83+
walletSecretProvider.getSecret(
84+
toSecretMap(ojdbcConfig.wallet_location));
85+
86+
// The value returned from the provider is a base64 encoded char array of
87+
// a wallet in base64 format. So after the fist decoding, the value is
88+
// still base64 encoded.
89+
String wallet = new String(
90+
Base64.getDecoder()
91+
.decode(new String(walletCharArray)));
92+
properties.setProperty(CONNECTION_PROPERTY_WALLET_LOCATION,
93+
"data:;base64," + wallet);
94+
}
95+
96+
// Retrieve config time to live
97+
if (ojdbcConfig.config_time_to_live != null) {
98+
properties.setProperty("config_time_to_live",
99+
String.valueOf(
100+
durationToInt(ojdbcConfig.config_time_to_live)));
101+
}
102+
103+
// Retrieve Jdbc connection properties
104+
try {
105+
properties.putAll(toJdbcProperties(ojdbcConfig.jdbc));
106+
} catch (IllegalAccessException e) {
107+
throw new RuntimeException(e);
108+
}
109+
110+
return properties;
111+
}
112+
113+
@Override
114+
public String getType() {
115+
return "pkl";
116+
}
117+
118+
/**
119+
* @return value of the element under node, if presents. Otherwise, return null.
120+
*/
121+
private Config getOptional(Config node, String s) {
122+
try {
123+
Config child = node.get(s);
124+
if (!(child.getRawValue() instanceof PNull)) // not a leaf node
125+
return child;
126+
} catch (NoSuchChildException e) {
127+
// no-op
128+
}
129+
130+
return null;
131+
}
132+
133+
private Map<String, String> toSecretMap(OjdbcConfig.Secret secretConfig) {
134+
// Convert Pkl config to map
135+
Map<String, String> options = new HashMap<>();
136+
options.put("value", secretConfig.value);
137+
138+
if (secretConfig.authentication != null) {
139+
// Rename the key from "method" to "authentication" and put into the password options
140+
options.put("authentication", secretConfig.authentication.remove("method"));
141+
// Put the rest into authentication options
142+
options.putAll(secretConfig.authentication);
143+
}
144+
145+
return options;
146+
}
147+
148+
private Properties toJdbcProperties(OjdbcConfig.Jdbc ojdbcConfig)
149+
throws IllegalAccessException {
150+
151+
Properties properties = new Properties();
152+
153+
Field[] fields = ojdbcConfig.getClass().getDeclaredFields();
154+
for (Field field : fields) {
155+
Object value = field.get(ojdbcConfig);
156+
if (value == null) continue;
157+
158+
Class<?> type = field.getType();
159+
if (type == Duration.class) {
160+
value = durationToInt((Duration)value);
161+
}
162+
163+
// Replace $$ with .
164+
String name = field.getName().replace("$$", ".");
165+
properties.setProperty(name, value.toString());
166+
}
167+
168+
return properties;
169+
}
170+
171+
private int durationToInt(Duration duration) {
172+
return Double.valueOf(duration.getValue()).intValue();
173+
}
174+
}

0 commit comments

Comments
 (0)