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

DriverManagerCleanUp can't really work for many scenarios #80

Open
wants to merge 18 commits into
base: master
Choose a base branch
from

Conversation

Geker
Copy link

@Geker Geker commented Apr 19, 2018

DriverManager.getDrivers() only return the drivers which be load by caller(DriverManagerCleanUp.class).
For many scenarios the Caller is not the same classloader which load the jdbc Drivers. So ,DriverManager.getDrivers() will return empty driver list,and DriverManagerCleanUp do nothing.
I think it need get registeredDrivers by reflection.

Geker added 2 commits April 19, 2018 10:40
Add getAllDrivers method. DriverManager.getDrivers() only return the
drivers which be load by caller(DriverManagerCleanUp.class).
For many scenarios the Caller is not the same classloader which load the
jdbc Drivers
@Geker Geker closed this Apr 19, 2018
@Geker Geker reopened this Apr 19, 2018
@mjiderhamn
Copy link
Owner

mjiderhamn commented Apr 19, 2018

Could you please adhere to the coding standards of the project, such as indentation with 2 spaces, camel humping etc?

* Deregister JDBC drivers loaded by classloader
*
*
Copy link
Owner

Choose a reason for hiding this comment

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

Why these empty JavaDoc lines?

Copy link
Author

Choose a reason for hiding this comment

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

sorry I use the diffenrent Java code style template ,i shoud follow your project coding standards

preventor.warn("get All registeredDrivers Exception ");
preventor.error(e);

Copy link
Owner

Choose a reason for hiding this comment

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

Can't we default to DriverManager.getDrivers() in case reflection fails?

catch (Exception e) {
preventor.warn("get All registeredDrivers Exception ");
preventor.error(e);
Copy link
Owner

Choose a reason for hiding this comment

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

We should decide whether this makes up a warning or an error - not both


}
return (result.elements());
Copy link
Owner

Choose a reason for hiding this comment

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

Remove the extra parethesis

@Override
public void cleanUp(ClassLoaderLeakPreventor preventor) {
final List<Driver> driversToDeregister = new ArrayList<Driver>();
Copy link
Owner

Choose a reason for hiding this comment

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

Is this list even needed now that we know we won't cause ConcurrentModificationException (depending on the reflectino fall below, by all means), or can't we deregister in the first loop?

Copy link
Author

@Geker Geker Apr 19, 2018

Choose a reason for hiding this comment

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

yes,driversToDeregister is no need any more.

while (allDrivers.hasMoreElements()) {
final Driver driver = allDrivers.nextElement();
if (preventor.isLoadedInClassLoader(driver)) // Should be true for all returned by DriverManager.getDrivers()
Copy link
Owner

Choose a reason for hiding this comment

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

Is the comment still relevant?

* @param preventor
* @return
*/
Copy link
Owner

Choose a reason for hiding this comment

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

Please clarify the JavaDoc

* @return
*/
public java.util.Enumeration<Driver> getAllDrivers(ClassLoaderLeakPreventor preventor) {
Copy link
Owner

Choose a reason for hiding this comment

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

Why Enumeration rather than Collection?

Copy link
Author

Choose a reason for hiding this comment

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

DriverManager.getDrivers() return type is Enumeration

*/
public java.util.Enumeration<Driver> getAllDrivers(ClassLoaderLeakPreventor preventor) {
java.util.Vector<Driver> result = new java.util.Vector<Driver>();
Copy link
Owner

Choose a reason for hiding this comment

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

Why Vector rather than ArrayList? Synchronization cannot possibly be needed.

Copy link
Author

Choose a reason for hiding this comment

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

because method DriverManager.getDrivers() use Vector,So i follow the usage

java.util.Vector<Driver> result = new java.util.Vector<Driver>();
try {
CopyOnWriteArrayList<?> driverinfos = preventor.getStaticFieldValue(DriverManager.class, "registeredDrivers");
Copy link
Owner

Choose a reason for hiding this comment

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

I suggest using List (or even Collection) as the variable type, and by all means keep CopyOnWriteArrayList as a comment. That way this class still works even if the internals of DriverManager is updated to use something other than CopyOnWriteArrayList

@mjiderhamn
Copy link
Owner

What is the scenario we're trying to solve here? The leak prevention library being part of a framework/application server, while the JDBC driver is dynamically loaded in an application instance (.war file)?

@Geker
Copy link
Author

Geker commented Apr 19, 2018

Yes I have a app server. which have two level classloader. the server classloader load classloader-leak-prevention.jar .The server main-thread execute: runPreClassLoaderInitiators -> start war classloader (war-classloader load jdbc drivers / .war etc)->runCleanUps

I modify the code, please see the code again.

modify code style;
return DriverManager.getDrivers() if Exception occurred
* @param preventor
* @return All drivers in DriverManager's registeredDrivers field,or
* DriverManager.getDrivers() if exception occurred
*/
Copy link
Owner

Choose a reason for hiding this comment

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

Please clean up the JavaDoc a bit. (For example, you don't need to document method X with "Add X method". Either add documentation or remove @param)

}
} catch (Exception e) {
preventor.warn("get All registeredDrivers Exception");
return DriverManager.getDrivers();
Copy link
Owner

Choose a reason for hiding this comment

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

The code now assumes the returned Enumeration does not cause ConcurrentModificationException if driver is removed while looping. Is that guaranteed by the API contract, or should we make of copy to ensure the library does not start failing in case the DriverManager internals happens to be changed?

Copy link
Author

Choose a reason for hiding this comment

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

I think it's no reason the jdk developer to changed the default manner of getDrivers. they are already considered avoid ConcurrentModificationException in current code.

}
return result.elements();
Copy link
Owner

@mjiderhamn mjiderhamn Apr 23, 2018

Choose a reason for hiding this comment

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

Move this inside try (unless used for copying, see below)

* DriverManager.getDrivers() if exception occurred
*/
public Enumeration<Driver> getAllDrivers(ClassLoaderLeakPreventor preventor) {
Vector<Driver> result = new java.util.Vector<Driver>();
Copy link
Owner

Choose a reason for hiding this comment

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

Move this inside try (unless used for copying, see below)

@OlegYch
Copy link

OlegYch commented Apr 24, 2018

DriverManager.deregisterDriver needs to be done via reflection too as it also checks caller classloader

@mjiderhamn
Copy link
Owner

Good catch @OlegYch !
Add some more work, though.

@Geker
Copy link
Author

Geker commented May 2, 2018

@OlegYch thanks your advices.
I'm already change the code.

Chiranjivee Thakur and others added 7 commits May 31, 2018 09:50
Summary:

In java 9, sun.misc.GC is moved to sun.rmi.transport.GC , trying again
if sun.misc.GC is not found else throwing ClassNotFoundException.
Conflicts:
	README.md
	classloader-leak-prevention/classloader-leak-prevention-core/README.md
Conflicts:
	classloader-leak-prevention/classloader-leak-prevention-core/pom.xml
	classloader-leak-prevention/classloader-leak-prevention-servlet/pom.xml
	classloader-leak-prevention/classloader-leak-prevention-servlet3/pom.xml
	classloader-leak-prevention/pom.xml
Conflicts:
	classloader-leak-prevention/classloader-leak-prevention-core/pom.xml
	classloader-leak-prevention/classloader-leak-prevention-servlet/pom.xml
	classloader-leak-prevention/classloader-leak-prevention-servlet3/pom.xml
	classloader-leak-prevention/pom.xml
@Geker
Copy link
Author

Geker commented Jan 4, 2019

I accept your suggestion,please review again.
The check failure was not caused by my commit.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

3 participants