Skip to content
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

Added configuration option to destroy UCP pool #1551

Open
wants to merge 2 commits into
base: 6.1.x
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -178,6 +178,11 @@ public String getValidationQuery() {
return calculatedSettings.getValidationQuery();
}

/**
* Sets the validation query.
*
* @param validationQuery The validation query
*/
public void setValidationQuery(String validationQuery) {
try {
delegate.setSQLForValidateConnection(validationQuery);
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,35 @@
/*
* Copyright 2017-2025 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.configuration.jdbc.ucp;

import io.micronaut.context.annotation.ConfigurationProperties;
import io.micronaut.context.annotation.Requires;
import io.micronaut.core.annotation.Nullable;

import static io.micronaut.configuration.jdbc.ucp.OracleUcpConfiguration.PREFIX;

/**
* Configuration properties for Oracle Universal Connection Pooling (UCP).
*
* @param destroyOnReload Flag indicating whether to destroy connections on reload
*/
@ConfigurationProperties(PREFIX)
@Requires(property = PREFIX)
public record OracleUcpConfiguration(@Nullable Boolean destroyOnReload) {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I thought there might be other oracle.ucp.* properties to set and we can use this for that purpose and looks to me it's better to keep separated from the ucp-manager.


/** Prefix used for configuration properties. */
static final String PREFIX = "oracle.ucp";
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,66 @@
/*
* Copyright 2017-2025 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.configuration.jdbc.ucp;

import io.micronaut.context.annotation.Context;
import io.micronaut.context.annotation.Requires;
import io.micronaut.core.annotation.Internal;
import io.micronaut.core.annotation.Nullable;
import jakarta.annotation.PostConstruct;
import oracle.ucp.jdbc.PoolDataSource;

/** Oracle UCP configuration setting some {@code oracle.ucp} system properties. */
@Context
@Internal
@Requires(classes = PoolDataSource.class)
@Requires(beans = OracleUcpConfiguration.class)
public class OracleUcpConfigurator {

private static final String UCP_DESTROY_ON_RELOAD = "oracle.ucp.destroyOnReload";

/**
* Initializes the Oracle UCP (Universal Connection Pooling) configuration.
*
* <p>If the {@code oracle.ucp.destroyOnReload} system property is not set or is empty, this method
* sets it based on the value of the {@link OracleUcpConfiguration#destroyOnReload()} field.
* This property determines whether the connection pool should be destroyed when the application
* is reloaded.
*
* <p>This initialization helps prevent duplicate connection pool errors that may occur during
* application reloading.
*
* @param oracleUcpConfiguration The Oracle UCP configuration
*/
@PostConstruct
public void initUcp(@Nullable OracleUcpConfiguration oracleUcpConfiguration) {
if (oracleUcpConfiguration != null && oracleUcpConfiguration.destroyOnReload() != null) {
final String ucpDestroyOnReloadProperty = System.getProperty(UCP_DESTROY_ON_RELOAD);
if (ucpDestroyOnReloadProperty == null || ucpDestroyOnReloadProperty.isBlank()) {
// This is to deal with a duplicate connection pool error of:
// "oracle.ucp.UniversalConnectionPoolException: Universal Connection Pool already
// exists in the Universal Connection Pool Manager. Universal Connection Pool cannot
// be added to the Universal Connection Pool Manager"
// This magic flag is used by oracle.ucp.util.Util.isDestroyOnReloadEnabled, which
// defaults it to false.
// When true the oracle.ucp.jdbc.PoolDataSourceImpl.createUniversalConnectionPool()
// will destroy the connection pool if it is still around.
System.setProperty(
UCP_DESTROY_ON_RELOAD,
String.valueOf(oracleUcpConfiguration.destroyOnReload()));
}
}
}
}
4 changes: 3 additions & 1 deletion src/main/docs/guide/jdbc/jdbc-connection-pools.adoc
Original file line number Diff line number Diff line change
Expand Up @@ -48,7 +48,9 @@ datasources:
maxPoolSize: 10
----

The Oracle UCP is managed by the link:https://docs.oracle.com/en/database/oracle/oracle-database/21/jjuar/oracle/ucp/admin/UniversalConnectionPoolManager.html[UniversalConnectionPoolManager]. The manager can be disabled byt setting `ucp-manager.enabled` to `false`. Additionally you can enable the link:https://docs.oracle.com/en/database/oracle/oracle-database/21/jjucp/jmx-based-management.html[JMX-Based Management] by setting the `ucp-manager.jmx.enabled` to `true` and providing the `ojdbc8dms.jar` and `dms.jar` dependencies.
The Oracle UCP is managed by the link:https://docs.oracle.com/en/database/oracle/oracle-database/21/jjuar/oracle/ucp/admin/UniversalConnectionPoolManager.html[UniversalConnectionPoolManager]. The manager can be disabled byt setting `ucp-manager.enabled` to `false`. Additionally, you can enable the link:https://docs.oracle.com/en/database/oracle/oracle-database/21/jjucp/jmx-based-management.html[JMX-Based Management] by setting the `ucp-manager.jmx.enabled` to `true` and providing the `ojdbc8dms.jar` and `dms.jar` dependencies.

In case when exception `Universal Connection Pool already exists in the Universal Connection Pool Manager` is thrown, there is `oracle.ucp.destroyOnReload` configuration that can be set to `true` to avoid this error. In that case, when creating new connection pool, if there is the one with the same name the old one will be destroyed first.

For a list of other properties able to be configured, simply refer to the implementation that is being used. All setter methods are candidates for configuration.

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,7 @@
@Property(name = "datasources.default.db-type", value = "oracle")
@Property(name = "datasources.default.connection-factory-class-name", value = "oracle.jdbc.pool.OracleDataSource")
@Property(name = "test-resources.containers.oracle.startup-timeout", value = "600s")
@Property(name = "oracle.ucp.destroyOnReload", value = "true")
public class OracleApp extends AbstractApp {
}

Loading