Skip to content

Commit

Permalink
Merge pull request #13752 from tadamski/WFLY-14114
Browse files Browse the repository at this point in the history
[WFLY-14114] JDBC: deregister all drivers on undeployment
  • Loading branch information
bstansberry committed Dec 8, 2020
2 parents 7239081 + 533c439 commit 1e3289b
Show file tree
Hide file tree
Showing 5 changed files with 187 additions and 0 deletions.
Original file line number Diff line number Diff line change
@@ -0,0 +1,46 @@
/*
* JBoss, Home of Professional Open Source.
* Copyright 2020, Red Hat, Inc., and individual contributors
* as indicated by the @author tags. See the copyright.txt file in the
* distribution for a full listing of individual contributors.
*
* This is free software; you can redistribute it and/or modify it
* under the terms of the GNU Lesser General Public License as
* published by the Free Software Foundation; either version 2.1 of
* the License, or (at your option) any later version.
*
* This software is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this software; if not, write to the Free
* Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
* 02110-1301 USA, or see the FSF site: http://www.fsf.org.
*/

package org.jboss.as.connector._drivermanager;

import java.util.Enumeration;
import java.sql.Driver;
import java.sql.DriverManager;
import java.sql.SQLException;

/**
* @author <a href="mailto:tadamski@redhat.com">Tomasz Adamski</a>
*/

public class DriverManagerAdapter {

private DriverManagerAdapter() {
}

public static Enumeration<Driver> getDrivers() {
return DriverManager.getDrivers();
}

public static void deregisterDriver(final Driver driver) throws SQLException {
DriverManager.deregisterDriver(driver);
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,112 @@
/*
* JBoss, Home of Professional Open Source.
* Copyright 2020, Red Hat, Inc., and individual contributors
* as indicated by the @author tags. See the copyright.txt file in the
* distribution for a full listing of individual contributors.
*
* This is free software; you can redistribute it and/or modify it
* under the terms of the GNU Lesser General Public License as
* published by the Free Software Foundation; either version 2.1 of
* the License, or (at your option) any later version.
*
* This software is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this software; if not, write to the Free
* Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
* 02110-1301 USA, or see the FSF site: http://www.fsf.org.
*/
package org.jboss.as.connector.deployers.ds.processors;

import org.jboss.as.connector._drivermanager.DriverManagerAdapter;
import org.jboss.as.server.deployment.Attachments;
import org.jboss.as.server.deployment.DeploymentPhaseContext;
import org.jboss.as.server.deployment.DeploymentUnit;
import org.jboss.as.server.deployment.DeploymentUnitProcessingException;
import org.jboss.as.server.deployment.DeploymentUnitProcessor;
import org.jboss.as.server.deployment.module.ModuleSpecification;
import org.jboss.modules.AbstractResourceLoader;
import org.jboss.modules.ClassSpec;
import org.jboss.modules.ResourceLoaderSpec;

import java.io.ByteArrayOutputStream;
import java.io.Closeable;
import java.io.IOException;
import java.io.InputStream;
import java.util.Collection;
import java.util.Collections;

/**
* @author <a href="mailto:tadamski@redhat.com">Tomasz Adamski</a>
* <p>
* https://issues.redhat.com/browse/WFLY-14114
* <p>
* This is a hack that allows us to get access to {@link java.sql.Driver} registered by the driver code. Those objects are created by the
* driver code and registered in {@link java.sql.DriverManager}. Driver objects are not guaranteed to be deregistered which leads to leaks.
* {@link java.sql.DriverManager} allows for obtaining the list of drivers, and deregistering a driver but only in a give classloading context.
* As a result, connector module can not neither list or deregister drivers from a deployed driver module.
* <p>
* To work this around, this hack modifies driver's module by injecting {@link DriverManagerAdapter} class to it. Because @{@link DriverManagerAdapter}
* is loaded by driver module it allows to obtain and deregister the drivers.
*/

public class DriverManagerAdapterProcessor implements DeploymentUnitProcessor {

@Override
public void deploy(final DeploymentPhaseContext phaseContext) throws DeploymentUnitProcessingException {
final DeploymentUnit deploymentUnit = phaseContext.getDeploymentUnit();
final ModuleSpecification moduleSpecification = deploymentUnit.getAttachment(Attachments.MODULE_SPECIFICATION);
final DriverAdapterResourceLoader resourceLoader = new DriverAdapterResourceLoader();
moduleSpecification.addResourceLoader(ResourceLoaderSpec.createResourceLoaderSpec(resourceLoader));
}

static class DriverAdapterResourceLoader extends AbstractResourceLoader {
@Override
public ClassSpec getClassSpec(final String fileName) throws IOException {
InputStream is = this.getClass().getClassLoader().getResourceAsStream(fileName);
if (is == null) {
return null;
}
final byte[] bytes = readAllBytesFromStream(is);
final ClassSpec spec = new ClassSpec();
spec.setBytes(bytes);
return spec;
}

@Override
public Collection<String> getPaths() {
return Collections.singletonList(DriverManagerAdapter.class.getPackage().getName().replace('.','/'));
}

private static byte[] readAllBytesFromStream(final InputStream is) throws IOException {
ByteArrayOutputStream bos = new ByteArrayOutputStream();
try {
final byte[] buffer = new byte[1024];
int read = 0;
while ((read = is.read(buffer)) != -1) {
bos.write(buffer, 0, read);
}
return bos.toByteArray();
} finally {
safeClose(is);
safeClose(bos);
}
}

private static void safeClose(final Closeable c) {
if (c != null) {
try {
c.close();
} catch (Throwable ignored) {}
}
}
}

@Override
public void undeploy(DeploymentUnit deploymentUnit) {

}
}
Original file line number Diff line number Diff line change
Expand Up @@ -25,9 +25,13 @@
import static org.jboss.as.connector.logging.ConnectorLogger.DEPLOYER_JDBC_LOGGER;

import java.lang.reflect.Constructor;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.sql.Driver;
import java.util.Enumeration;
import java.util.List;

import org.jboss.as.connector._drivermanager.DriverManagerAdapter;
import org.jboss.as.connector.services.driver.DriverService;
import org.jboss.as.connector.services.driver.InstalledDriver;
import org.jboss.as.connector.services.driver.registry.DriverRegistry;
Expand All @@ -42,6 +46,7 @@
import org.jboss.modules.ModuleClassLoader;
import org.jboss.msc.service.ServiceController.Mode;
import org.jboss.msc.service.ServiceName;
import org.wildfly.common.Assert;

/**
* Deploy any JDBC drivers in a deployment unit.
Expand Down Expand Up @@ -110,5 +115,25 @@ public void deploy(final DeploymentPhaseContext phaseContext) throws DeploymentU
/** {@inheritDoc} */
@Override
public void undeploy(final DeploymentUnit context) {
try {
/**
* https://issues.redhat.com/browse/WFLY-14114
*
* This hack allows to deregister all drivers registered by this module. See comments in {@link DriverManagerAdapterProcessor}
*/
final Module module = context.getAttachment(org.jboss.as.server.deployment.Attachments.MODULE);
Class<?> driverManagerAdapterClass = module.getClassLoader().loadClass(DriverManagerAdapter.class.getName());

Method getDriversMethod = driverManagerAdapterClass.getDeclaredMethod("getDrivers");
Enumeration<Driver> drivers = (Enumeration<Driver>) getDriversMethod.invoke(null, null);

Method deregisterDriverMethod = driverManagerAdapterClass.getDeclaredMethod("deregisterDriver", Driver.class);
while (drivers.hasMoreElements()) {
Driver driver = drivers.nextElement();
deregisterDriverMethod.invoke(null, driver);
}
} catch (ClassNotFoundException | IllegalAccessException | InvocationTargetException | NoSuchMethodException e) {
Assert.unreachableCode();
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,7 @@
import static org.jboss.as.connector.util.ConnectorServices.TRANSACTION_INTEGRATION_CAPABILITY_NAME;

import org.jboss.as.connector.deployers.ds.processors.DriverProcessor;
import org.jboss.as.connector.deployers.ds.processors.DriverManagerAdapterProcessor;
import org.jboss.as.connector.deployers.ds.processors.StructureDriverProcessor;
import org.jboss.as.connector.deployers.ra.processors.IronJacamarDeploymentParsingProcessor;
import org.jboss.as.connector.deployers.ra.processors.ParsedRaDeploymentProcessor;
Expand Down Expand Up @@ -55,6 +56,7 @@
* @author <a href="mailto:stefano.maestri@redhat.com">Stefano Maestri</a>
*/
public class RaDeploymentActivator {

private final boolean appclient;
private final MdrService mdrService = new MdrService();

Expand Down Expand Up @@ -104,6 +106,7 @@ public void activateProcessors(final DeploymentProcessorTarget updateContext) {
updateContext.addDeploymentProcessor(ResourceAdaptersExtension.SUBSYSTEM_NAME, Phase.PARSE, Phase.PARSE_RESOURCE_DEF_ANNOTATION_ADMINISTERED_OBJECT,
new AdministeredObjectDefinitionAnnotationProcessor());
updateContext.addDeploymentProcessor(ResourceAdaptersExtension.SUBSYSTEM_NAME, Phase.DEPENDENCIES, Phase.DEPENDENCIES_RAR_CONFIG, new RarDependencyProcessor(appclient));
updateContext.addDeploymentProcessor(ResourceAdaptersExtension.SUBSYSTEM_NAME, Phase.CONFIGURE_MODULE, Phase.CONFIGURE_JDBC_DRIVER_MANAGER_ADAPTER, new DriverManagerAdapterProcessor());
if (!appclient)
updateContext.addDeploymentProcessor(ResourceAdaptersExtension.SUBSYSTEM_NAME, Phase.POST_MODULE, Phase.POST_MODULE_RAR_SERVICES_DEPS, new RaXmlDependencyProcessor());
updateContext.addDeploymentProcessor(ResourceAdaptersExtension.SUBSYSTEM_NAME, Phase.POST_MODULE, Phase.POST_MODULE_RESOURCE_DEF_XML_CONNECTION_FACTORY,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,7 @@
</properties>

<exports>
<exclude path="org/jboss/as/connector/_drivermanager"/>
<exclude path="org/jboss/as/connector/logging"/>
</exports>

Expand Down

0 comments on commit 1e3289b

Please sign in to comment.