-
Notifications
You must be signed in to change notification settings - Fork 198
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Support including Module and Action in each JDBC session with Oracle JDBC #3183
Open
radovanradic
wants to merge
40
commits into
4.10.x
Choose a base branch
from
jdbc-clientinfo
base: 4.10.x
Could not load branches
Branch not found: {{ refName }}
Loading
Could not load tags
Nothing to show
Loading
Are you sure you want to change the base?
Some commits from the old base branch may be removed from the timeline,
and old review comments may become outdated.
Open
Changes from 25 commits
Commits
Show all changes
40 commits
Select commit
Hold shift + click to select a range
b45b532
Investigation for setting connection client info
radovanradic e0b6f4a
Merge branch '4.10.x' into jdbc-clientinfo
radovanradic 19e58f0
Use Connectable interface to pass connection client tracing info
radovanradic b8ed459
Merge branch '4.10.x' into jdbc-clientinfo
radovanradic 92902bd
Remove unneeded changes
radovanradic afb396d
Use connectable for Oracle Book repo
radovanradic a481771
Merge branch '4.10.x' into jdbc-clientinfo
radovanradic 27bdc07
Documentation, comments and code cleanup.
radovanradic 8bb94e8
Merge branch '4.10.x' into jdbc-clientinfo
radovanradic 7874bdf
Rename ConnectionClientTracingInfo to ConnectionTracingInfo
radovanradic 41fd257
Changes per CR comments, still not there.
radovanradic 8e70480
Merge branch '4.10.x' into jdbc-clientinfo
radovanradic 71e66de
Change as suggested in PR comment
radovanradic 7a16299
Properly clear connection client info
radovanradic 2785d8d
Introduce new OracleConnectionClientInfo annotation for connection cl…
radovanradic 304d577
Fixed javadoc
radovanradic 7e90fa5
Merge branch '4.10.x' into jdbc-clientinfo
radovanradic b3b0468
Merge branch '4.10.x' into jdbc-clientinfo
radovanradic b8060d3
Resolve module/class name using InvocationContext.getTarget()
radovanradic 3320b38
Introduce ConnectionCustomizer for more flexibility
radovanradic d84dad1
More changes as suggested in pull request comments.
radovanradic 1bb490a
Merge branch '4.10.x' into jdbc-clientinfo
radovanradic 4e98412
Add @Experimental to ConnectionClientInfoDetails
radovanradic 91b3cd6
Applied more suggestions from pull request comments.
radovanradic fdff622
Updated comments
radovanradic d56a78b
Update src/main/docs/guide/dbc/jdbc/jdbcConfiguration.adoc
radovanradic c25d742
Update src/main/docs/guide/dbc/jdbc/jdbcConfiguration.adoc
radovanradic f6b7f80
Update src/main/docs/guide/dbc/jdbc/jdbcConfiguration.adoc
radovanradic 1f9e9e9
Update src/main/docs/guide/dbc/jdbc/jdbcConfiguration.adoc
radovanradic c68b657
Renamed classes as suggested and also property to enable Oracle clien…
radovanradic 06901f3
Refactoring according to suggestions in PR comments.
radovanradic 5adc61e
Cleanup
radovanradic f66881f
Cache module name by the class name
radovanradic 5c97b15
Remove enabled attribute and create repeatable annotation
radovanradic da4e8a3
Fixes for Sonar
radovanradic 913d9a8
Merge branch '4.10.x' into jdbc-clientinfo
radovanradic 886b103
Update @since attributes
radovanradic 60458ad
Rename classes to shorter names
radovanradic e0099b8
Rename connection client info annotations
radovanradic e5e0c1b
Connection interceptor
dstepanov File filter
Filter by extension
Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
70 changes: 70 additions & 0 deletions
70
...in/java/io/micronaut/data/connection/jdbc/oracle/OracleClientInfoCustomizerCondition.java
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,70 @@ | ||
/* | ||
* Copyright 2017-2024 original authors | ||
* | ||
* Licensed under the Apache License, Version 2.0 (the "License"); | ||
* you may not use this file except in compliance with the License. | ||
* You may obtain a copy of the License at | ||
* | ||
* https://www.apache.org/licenses/LICENSE-2.0 | ||
* | ||
* Unless required by applicable law or agreed to in writing, software | ||
* distributed under the License is distributed on an "AS IS" BASIS, | ||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | ||
* See the License for the specific language governing permissions and | ||
* limitations under the License. | ||
*/ | ||
package io.micronaut.data.connection.jdbc.oracle; | ||
|
||
import io.micronaut.context.BeanResolutionContext; | ||
import io.micronaut.context.Qualifier; | ||
import io.micronaut.context.condition.Condition; | ||
import io.micronaut.context.condition.ConditionContext; | ||
import io.micronaut.core.annotation.Internal; | ||
import io.micronaut.core.naming.Named; | ||
import io.micronaut.inject.BeanDefinition; | ||
|
||
/** | ||
* A condition that determines whether to customize Oracle client information based on configuration properties. | ||
* | ||
* This condition checks if the data source dialect is set to Oracle and if the 'customize-oracle-client-info' property is enabled. | ||
* | ||
* @author radovanradic | ||
* @since 4.10 | ||
*/ | ||
@Internal | ||
final class OracleClientInfoCustomizerCondition implements Condition { | ||
radovanradic marked this conversation as resolved.
Show resolved
Hide resolved
|
||
|
||
static final String DATASOURCES = "datasources"; | ||
private static final Character DOT = '.'; | ||
private static final String DIALECT = "dialect"; | ||
private static final String ORACLE_CLIENT_INFO_ENABLED = "customize-oracle-client-info"; | ||
radovanradic marked this conversation as resolved.
Show resolved
Hide resolved
|
||
private static final String ORACLE_DIALECT = "ORACLE"; | ||
|
||
@Override | ||
public boolean matches(ConditionContext context) { | ||
BeanResolutionContext beanResolutionContext = context.getBeanResolutionContext(); | ||
String dataSourceName; | ||
if (beanResolutionContext == null) { | ||
return true; | ||
} else { | ||
Qualifier<?> currentQualifier = beanResolutionContext.getCurrentQualifier(); | ||
if (currentQualifier == null && context.getComponent() instanceof BeanDefinition<?> definition) { | ||
currentQualifier = definition.getDeclaredQualifier(); | ||
} | ||
if (currentQualifier instanceof Named named) { | ||
dataSourceName = named.getName(); | ||
} else { | ||
dataSourceName = "default"; | ||
} | ||
} | ||
|
||
String dialectProperty = DATASOURCES + DOT + dataSourceName + DOT + DIALECT; | ||
String dialect = context.getProperty(dialectProperty, String.class).orElse(null); | ||
if (!ORACLE_DIALECT.equalsIgnoreCase(dialect)) { | ||
return false; | ||
} | ||
|
||
String property = DATASOURCES + DOT + dataSourceName + DOT + ORACLE_CLIENT_INFO_ENABLED; | ||
return context.getProperty(property, Boolean.class, false); | ||
} | ||
} |
151 changes: 151 additions & 0 deletions
151
...o/micronaut/data/connection/jdbc/oracle/OracleClientInfoCustomizerConnectionListener.java
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,151 @@ | ||
/* | ||
* Copyright 2017-2024 original authors | ||
* | ||
* Licensed under the Apache License, Version 2.0 (the "License"); | ||
* you may not use this file except in compliance with the License. | ||
* You may obtain a copy of the License at | ||
* | ||
* https://www.apache.org/licenses/LICENSE-2.0 | ||
* | ||
* Unless required by applicable law or agreed to in writing, software | ||
* distributed under the License is distributed on an "AS IS" BASIS, | ||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | ||
* See the License for the specific language governing permissions and | ||
* limitations under the License. | ||
*/ | ||
package io.micronaut.data.connection.jdbc.oracle; | ||
|
||
import io.micronaut.context.annotation.EachBean; | ||
import io.micronaut.context.annotation.Requires; | ||
import io.micronaut.core.annotation.Internal; | ||
import io.micronaut.core.annotation.NonNull; | ||
import io.micronaut.core.util.StringUtils; | ||
import io.micronaut.data.connection.ConnectionDefinition; | ||
import io.micronaut.data.connection.ConnectionStatus; | ||
import io.micronaut.data.connection.support.ConnectionClientInfoDetails; | ||
import io.micronaut.data.connection.support.ConnectionListener; | ||
import org.slf4j.Logger; | ||
import org.slf4j.LoggerFactory; | ||
|
||
import javax.sql.DataSource; | ||
import java.sql.Connection; | ||
import java.sql.SQLClientInfoException; | ||
import java.sql.SQLException; | ||
import java.util.List; | ||
import java.util.Map; | ||
import java.util.concurrent.ConcurrentHashMap; | ||
|
||
/** | ||
* A customizer for Oracle database connections that sets client information after opening and clears before closing. | ||
* | ||
* This customizer checks if the connection is an Oracle database connection and then sets the client information | ||
* (client ID, module, and action) after opening the connection. It also clears these properties before closing the connection. | ||
* | ||
* @author radovanradic | ||
* @since 4.10 | ||
*/ | ||
@EachBean(DataSource.class) | ||
@Requires(condition = OracleClientInfoCustomizerCondition.class) | ||
@Internal | ||
final class OracleClientInfoCustomizerConnectionListener implements ConnectionListener<Connection> { | ||
radovanradic marked this conversation as resolved.
Show resolved
Hide resolved
|
||
|
||
/** | ||
* Constant for the Oracle connection client info client ID property name. | ||
*/ | ||
private static final String ORACLE_CLIENT_ID = "OCSID.CLIENTID"; | ||
/** | ||
* Constant for the Oracle connection client info module property name. | ||
*/ | ||
private static final String ORACLE_MODULE = "OCSID.MODULE"; | ||
/** | ||
* Constant for the Oracle connection client info action property name. | ||
*/ | ||
private static final String ORACLE_ACTION = "OCSID.ACTION"; | ||
/** | ||
* Constant for the Oracle connection database product name. | ||
*/ | ||
private static final String ORACLE_CONNECTION_DATABASE_PRODUCT_NAME = "Oracle"; | ||
private static final List<String> RESERVED_CLIENT_INFO_NAMES = List.of(ORACLE_CLIENT_ID, ORACLE_MODULE, ORACLE_ACTION); | ||
|
||
private static final Logger LOG = LoggerFactory.getLogger(OracleClientInfoCustomizerConnectionListener.class); | ||
|
||
private final Map<Connection, Boolean> connectionSupportedMap = new ConcurrentHashMap<>(20); | ||
|
||
@Override | ||
public boolean supportsConnection(@NonNull ConnectionStatus<Connection> connectionStatus) { | ||
return connectionSupportedMap.computeIfAbsent(connectionStatus.getConnection(), this::isOracleConnection); | ||
} | ||
|
||
@Override | ||
public void afterOpen(@NonNull ConnectionStatus<Connection> connectionStatus) { | ||
ConnectionDefinition connectionDefinition = connectionStatus.getDefinition(); | ||
// Set client info for connection if Oracle connection after connection is opened | ||
ConnectionClientInfoDetails connectionClientInfo = connectionDefinition.connectionClientInfo(); | ||
if (connectionClientInfo != null) { | ||
Connection connection = connectionStatus.getConnection(); | ||
LOG.trace("Setting connection tracing info to the Oracle connection"); | ||
try { | ||
if (connectionClientInfo.appName() != null) { | ||
connection.setClientInfo(ORACLE_CLIENT_ID, connectionClientInfo.appName()); | ||
} | ||
connection.setClientInfo(ORACLE_MODULE, connectionClientInfo.module()); | ||
connection.setClientInfo(ORACLE_ACTION, connectionClientInfo.action()); | ||
for (Map.Entry<String, String> additionalInfo : connectionClientInfo.connectionClientInfoAttributes().entrySet()) { | ||
String name = additionalInfo.getKey(); | ||
if (RESERVED_CLIENT_INFO_NAMES.contains(name)) { | ||
LOG.debug("Connection client info attribute {} already set. Skip setting value from the arbitrary attributes.", name); | ||
} else { | ||
String value = additionalInfo.getValue(); | ||
connection.setClientInfo(name, value); | ||
} | ||
} | ||
} catch (SQLClientInfoException e) { | ||
LOG.debug("Failed to set connection tracing info", e); | ||
} | ||
} | ||
} | ||
|
||
@Override | ||
public void beforeClose(@NonNull ConnectionStatus<Connection> connectionStatus) { | ||
// Clear client info for connection if it was Oracle connection and client info was set previously | ||
ConnectionDefinition connectionDefinition = connectionStatus.getDefinition(); | ||
ConnectionClientInfoDetails connectionClientInfo = connectionDefinition.connectionClientInfo(); | ||
if (connectionClientInfo != null) { | ||
try { | ||
Connection connection = connectionStatus.getConnection(); | ||
connection.setClientInfo(ORACLE_CLIENT_ID, null); | ||
connection.setClientInfo(ORACLE_MODULE, null); | ||
connection.setClientInfo(ORACLE_ACTION, null); | ||
for (Map.Entry<String, String> additionalInfo : connectionClientInfo.connectionClientInfoAttributes().entrySet()) { | ||
String name = additionalInfo.getKey(); | ||
if (!RESERVED_CLIENT_INFO_NAMES.contains(name)) { | ||
connection.setClientInfo(name, null); | ||
} | ||
} | ||
} catch (SQLClientInfoException e) { | ||
LOG.debug("Failed to clear connection tracing info", e); | ||
} | ||
} | ||
} | ||
|
||
@Override | ||
public String getName() { | ||
return "Oracle Connection Client Info Customizer"; | ||
} | ||
|
||
/** | ||
* Checks whether current connection is Oracle database connection. | ||
* | ||
* @param connection The connection | ||
* @return true if current connection is Oracle database connection | ||
*/ | ||
private boolean isOracleConnection(Connection connection) { | ||
try { | ||
String databaseProductName = connection.getMetaData().getDatabaseProductName(); | ||
return StringUtils.isNotEmpty(databaseProductName) && databaseProductName.equalsIgnoreCase(ORACLE_CONNECTION_DATABASE_PRODUCT_NAME); | ||
} catch (SQLException e) { | ||
LOG.debug("Failed to get database product name from the connection", e); | ||
return false; | ||
} | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -18,6 +18,7 @@ | |
|
||
import io.micronaut.core.annotation.NonNull; | ||
import io.micronaut.core.annotation.Nullable; | ||
import io.micronaut.data.connection.support.ConnectionClientInfoDetails; | ||
|
||
import java.time.Duration; | ||
import java.util.Optional; | ||
|
@@ -101,6 +102,15 @@ enum Propagation { | |
@Nullable | ||
String getName(); | ||
|
||
/** | ||
* Returns the connection client information associated with this connection definition. | ||
* If no connection client information has been set, this method will return null. | ||
* | ||
* @return An instance of {@link ConnectionClientInfoDetails} representing the connection client information, or null if not set. | ||
* @since 4.10 | ||
*/ | ||
@Nullable ConnectionClientInfoDetails connectionClientInfo(); | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Please remove this; let it be fetched by the Oracle listener. Make |
||
|
||
/** | ||
* Connection definition with specific propagation. | ||
* @param propagation The new propagation | ||
|
Oops, something went wrong.
Oops, something went wrong.
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Why is this change?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Because you suggested interface methods accept
ConnectionStatus
and then creating it here and passing back toopenConnection
Will revert this
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I think it can be done without this change
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Yes, using existing internal method for open and introducing new for close.