I have a problem with cursor leakage in my Java project.
Typical example:
private void doSomething() throws Exception {
String sql1= "some sql statement";
String sql2= "some other sql statement";
PreparedStatement ps = null;
ResultSet rs = null;
try {
Connection con = getConnection();
ps = con.prepareStatement(sql1);
rs = ps.executeQuery();
//do something with the ResultSet rs
//[Need to call ps.close here. Otherwise I risk getting ORA-01000.]
ps = con.prepareStatement(sql2);
ps.executeQuery();
} catch (Exception e) {
} finally {
ps.close();
rs.close();
}
}
Since I have a rather large code base I would like to be able to find all methods
having two or more variables named sql.
Alternativly finding methods with two (or more) calls for prepareStatement without
calling ps.close; between the two.
I am using Eclipse and the file search has a regex option. Maybe thet is the way to go?
If so, what would it look like?
Recent versions of Eclipse (I used Juno [4.2]) will show a warning on those lines:
You can enable this warning in the Eclipse preferences:
Even for larger size code bases, you can filter the problems view for this warning in order to find these places in the code.
You can avoid having to close resources manually (if you are using at least JDK 7) by using a try with resources
try(con=getConnection()){
try(ps = con.prepareStatement()){
try(rs=ps.executeQuery()){
...
}
}
}
Anything that implements Autoclosable can be used in a try with resources and the resource gets automatically closed for you. No need to implement complicated resource closing operations anymore.
See the Try-with-Resources Tutorial
What you want to do is kind of static program analysis. As there are specialized tools for that, you may also write your own tool for this specific task.
In that way, you could count lines containing rs=ps.executeQuery and rs.close():
for(File file:sourceFiles) {
int openedResultSets = count("rs=ps.executeQuery");
int closedResultSets = count("rs.close()");
if (openedResultSets > closedResultSets) {
log.error(file.getName());
}
}
But it should be more complex because probably not only this snippet is used in your projects. Therefore I suppose you should write some code, not only one regexp.
Although specialized tools are expensive in most cases, probably some trial version will be enough for you.
There are FindBugs rules to find this, such as
ODR_OPEN_DATABASE_RESOURCE
ODR_OPEN_DATABASE_RESOURCE_EXCEPTION_PATH
OBL_UNSATISFIED_OBLIGATION
more if you look for the keyword 'resource' in the bug description
If you are not specifically looking for resource leaks, but rather for two or more variables named sql*, you can write a Checkstyle check to find them, possibly as a subclass of LocalVariableNameCheck. This is not a difficult kind of check, but requires coding and deployment work.
Related
I am working on a codebase that has recently migrated from Java 6 to Java 7. I would like to replace constructions like this:
Connection conn = null;
try{
conn = new Connection();
...
} catch(Exception ex){
...
} finally{
if (conn != null){
conn.close();
}
}
with try-with-resources (available from Java 1.7 onward):
try(Connection conn = new Connection()){
...
} catch(Exception ex){
...
}
Is there an automated way to automatically refactor the old to the new (perhaps with the Checkstyle-plugin, or within Eclipse itself)?
It would be difficult to change it all quickly. Please note that sometimes there's another try-catch block in finally which catches exceptions thrown while closing resource.
try-with-resources statement does allow you to handle resource closing exceptions (exceptions thrown at close method will be surpressed).
I haven't heard of such Eclipse feature, but if you may want to use IntelliJ IDEA Community Edition IDE just for this sole purpose.
#1
You can use code inspection features called:
'try finally' replaceable with 'try' with resources.
AutoCloseable used without 'try' with resources
You should just press Ctrl+Alt+Shift, write inspection name and hit Enter. After that you will see places where IDEA can apply this pattern, but be aware that it doesn't cover 100% cases.
#2
Another way, more difficult, but greatly customizable is Structural Search and Replace functionality. You can define there structure which is to be changed:
try {
$type$ $objectName$ = new $concreteType$($args$)
$tryStatements$;
} catch($exceptionType$ $exceptionName$) {
$catchStatements$;
} finally {
$finallyStatements$;
}
And the final structure:
try ($type$ $objectName$ = new $concreteType$($args$)) {
$tryStatements$;
} catch($exceptionType$ $exceptionName$) {
$catchStatements$;
}
In variable settings you can require that $concreteType$ implements AutoCloseable interface.
But please note, that:
I get rid of finally block here and support single catch block.
There's also assumption that there would be single resource opened per one try-with-resources block.
As mentioned before - there's no exception handling in finally block.
This template certainly needs more work and it just may not be worthwhile to do it.
I am using Google App Engine (Endpoints) to generate a simple API service.
I'm currently trying to make my queries to the database faster and more efficient, so I decided to double check where I was calling ResultSet and Connections and closing them.
However I want to use CachedRowSet and it almost seems impossible given that when I try to access CachedRowSetImpl() the logger returns:
java.lang.NoClassDefFoundError: com.sun.rowset.CachedRowSetImpl is a
restricted class. Please see the Google App Engine developer's guide
for more details
So I did some investigation and Google App Engine's JRE whitelist includes:
javax.sql.rowset.CachedRowSet
but not
com.sun.rowset.CachedRowSetImpl
Does that make any sense? How can I initialize/use CachedRowSet otherwise?
My code:
public ResultSet getRecordsWhereInt(String table, String where, int condition) throws SQLException {
c = DatabaseConnect();
preStatement = c.prepareStatement("SELECT * FROM " + table + " WHERE " + where + " = ?");
preStatement.setInt(1, condition);
CachedRowSet rowset = new CachedRowSetImpl();
rowset.populate(preStatement.executeQuery());
c.close();
return rowset;
}
Any help would/guidance would be appreciated.
Update 1 (09/06/2015):
Investigating further, I found that you can implement CachedRowSetImpl's functionality using RowSetProvider.newFactory().createCachedRowSet();
However, Google has also restricted use to RowSetProvider().
That left me with the only other whitelisted library RowSetFactory. So I made my own, implementing RowSetFactory according to Oracle's implementation:
public class CachedRowSetFactory implements RowSetFactory {
public CachedRowSet createCachedRowSet() throws SQLException {
return new CachedRowSetImpl();
}
public FilteredRowSet createFilteredRowSet() throws SQLException {
return null;
}
public JdbcRowSet createJdbcRowSet() throws SQLException {
return null;
}
public JoinRowSet createJoinRowSet() throws SQLException {
return null;
}
public WebRowSet createWebRowSet() throws SQLException {
return null;
}
}
And then used it like this:
CachedRowSet crs = new CachedRowSetFactory().createCachedRowSet();
However, even this fails. The above example returns a Null Pointer Exception when I try to populate it with a working result set. I'm guessing the factory implementation isn't 100% correct or that I'm skipping over something obvious.
Update 2 (11/06/2015):
I tried rolling my own implementation of CachedRowSetImpl, and of the RowSetProvider by duplicating some of the libraries by hand and eliminating the libraries not covered in App Engines Whitelist. Was not successful. I know I need to give up on this but I'm determined to make this work.
CahecRowSet is an interface so obviously this is whitelisted.
Interface CachedRowSet
I am guessing you are connecting a Google CloudSQL instance.
from the javadoc :
A CachedRowSet object is a container for rows of data that caches its
rows in memory, which makes it possible to operate without always
being connected to its data source.
What you are trying to do does not make sense IMO. AppEngine does not keep state between different requests and certainly not when your application auto-scales and new instances spin up.
Why don't you cache your results in Memcache, this will persist over subsequent requests and different instances.
I have used EMC Documentum Foundation Classes to perform some actions in documentum repository. The code was working fine. I exported the project as a runnable JAR and then tried to run it. However I got following error and I am not able to understand it.
And here is the code for DocMovementHandler.getSession()
Actually this is no new code but regular code for obtaining documentum session
public IDfSession getSession(String userName, String password)
{
DfClientX clientx = null;
IDfClient client = null;
IDfSession session = null;
try {
// create a client object using a factory method in DfClientX
clientx = new DfClientX();
client = clientx.getLocalClient(); //takes time
// call a factory method to create the session manager
IDfSessionManager sessionMgr = client.newSessionManager();
// create an IDfLoginInfo object and set its fields
IDfLoginInfo loginInfo = clientx.getLoginInfo();
loginInfo.setUser(userName);
loginInfo.setPassword(password);
// set single identity for all docbases
sessionMgr.setIdentity("xyz_repo", loginInfo);
session = sessionMgr.getSession("xyz_repo"); //takes time
//sessionMgr.beginTransaction();
System.out.println("Session obtaied.");
}
catch (DfServiceException dse)
{
DfLogger.debug(this, "Error while beginning transaction. ", null, dse);
dse.printStackTrace();
}
catch (Exception e)
{
DfLogger.debug(this, "Error while creating a new session. ", null, e);
e.printStackTrace();
}
return session;
}
And that line 38 is client = clientx.getLocalClient();
InvocationTargetException is a wrapper. It says, "an exception occurred behind this reflection call", and you use getCause() to get at the inner exception.
The stack trace contains the inner exception. It's an ExceptionInInitializerError. That's another wrapper. It says, "whatever you did caused a new class to be loaded, and that class's static initializer threw an exception".
The final exception in this chain is the NullPointerException. That's the one you need to solve. Which means you need to debug this com.documentum thing. As the comments pointed out, that's not going to be easy.
Here is the most likely problem:
The static initializer in one of the classes whose names you have struck is adding an entry with either a null key or a null value to a Hashtable, which does not allow null keys or values.
It is using the Hashtable as a place to store a bunch of persistent properties and all that, and my guess is that the value for one of the entries was the null (which is a perfectly reasonable way to indicate that some feature is unavailable or something like that).
The now deprecated Hashtable needs to be replaced with the more modern HashMap.
If it is a library, that you can't just modify, you should replace the whole library with an updated version.
Here are some clues may be helpful.
The NullPointerException is thrown by Hashtable#put, and this is normally because either the key or the value is null.
Hashtable#put is called by PreferenceManager.readPersistenceProperties, so most likely it's because something is missing in a properties file so the value is null.
This NPE caused the DfClient class could not be loaded.
DfPreferences is the class loading the DFC configuration file dfc.properties. There must be something wrong with it.
Ohkay I did not pin pointed the root cause, but found the solution that will definitely work everytime.
EMC provides a flavor of Eclipse called Documentum Composer to work with Documentum Projects. Since Eclipse variation we can create other types of projects like normal Java project, dynamic web project, web services in this. So I recreated my project in Documetnum Composer and exported it as JAR and whoaaaa it worked.
I tried this many times and this worked all time.
Some points to note:
You have to replace dfc.properties file in Composer installation folder with one in Content Server
The Export to JAR wizard in Composer is a bit different than one in Eclipse
This is usually caused by dfc.properties being incorrect.
Preferences are stored on the global registry repository and the connection details should be specified in dfc.properties. If not, this (or a similar error can occur).
Also, always try to clear cache and use the correct version of the dfc jar's (v6.7 content server requires 6.7 jars, etc...).
I'm a junior java programmer and I've finally made my first program, all by myself, apart from school :).
The basics are: you can store data on it and retrieve it anytime. The main thing is, I want to be able to run this program on another computer (as a runable .jar file).
Therefore I had to install JRE and microsoft access 2010 drivers (they both are 32 bit), and the program works perfect, but there is 1 small problem.
It takes ages (literaly, 17 seconds) to store or delete something from the database.
What is the cause of this? Can I change it?
Edit:
Here's the code to insert an object of the class Woord into the database.
public static void ToevoegenWoord(Woord woord) {
try (Connection conn = DriverManager.getConnection("jdbc:odbc:DatabaseSenne")) {
PreparedStatement addWoord =
conn.prepareStatement("INSERT INTO Woorden VALUES (?)");
addWoord.setString(1, woord.getWoord());
addWoord.executeUpdate();
} catch (SQLException ex) {
for (Throwable t : ex) {
System.out.println("Het woord kond niet worden toegevoegd aan de databank.");
t.printStackTrace();
}
}
}
Most likely creating Connection every time is slow operation in your case (especially using JDBC-ODBC bridge). To confirm this try to put print statements with timestamp before and after the line that get Connection from DriverManager. If that's the case consider not to open connection on every request but open it once and reuse, better yet use some sort of Connection Pooling, there are plenty of options available.
If that's mot the case then actual insert could be slow as well. Again simple profiling with print statements should help you to discover where your code is spending most of the time.
First of all, congrats on your first independent foray. To answer your question / elaborate on maximdim's answer, the concern is that calling:
try (Connection conn = DriverManager.getConnection("jdbc:odbc:DatabaseSenne")) {
every time you're using this function may be a major bottleneck (or perhaps another section of your code is.) Most importantly, you will want to understand the concept of using logging or even standard print statements to help diagnose where you are seeing an issue. Wrapping individual lines of code like so:
System.out.println("Before Connection retrieval: " + new Date().getTime());
try (Connection conn = DriverManager.getConnection("jdbc:odbc:DatabaseSenne")) {
System.out.println("AFTER Connection retrieval: " + new Date().getTime());
...to see how many milliseconds pass for each call can help you determine exactly where your bottleneck lies.
Advise: use another database, like Derby, hsqldb. They are not so different from MSAccess, (= can use a file based DB), but perform better (than JDBC/ODBC). And can even be embedded in the application (without extra installation of the DB).
I'm debugging a Java App, which connects to Oracle DB via a thin client.
The code looks as follows: (i'm trying to simplify the use case here so pardon me if t does not actually comile)
Connection conn = myEnv.getDbConnection();
CallableStatement call = conn.prepareCall(
"{ ? = call SomePackage.SomeFunction (?)}");
call.registerOutParameter(1, OracleTypes.CURSOR);
for (int runCount = 0; runCount <= 1; runCount++) {
currency = getCurrency(runCount); // NOTE: [0]=CAD, [1]=USD
call.setString(2, currency);
try { call.execute(); } catch { // BREAKS HERE! }
ResultSet rset = (ResultSet)call.getObject(1);
... more code that I think is irrelevant as it does not use/affect "call"
}
When I run this code, the following happens:
First iteration of the loop, currency is set to "CAN".
Entire code of the loop runs perfectly fine.
Second iteration of the loop,currency is set to "USD".
The "execute()" call throws SQLException, as follows:
ORA-01008: not all variables bound
Why?
My initial suspicion was that it somehow related to registerOutParameter call before the loop that doesn't get called on 2d iteration. But moving that call inside the loop does not fix the problem. It seems that execute() call un-binds something but having both bindings inside the loop does not help.
What am I missing?
If it's something obvious, please be gendle - I know very little about Oracle and thin client, and Googling witrh miriad of fancy queries returned no love.
One additional clue: this design seemed to have worked before when the app was on Oracle 9 with OCI drivers. The reason I'm debuggin it is someone "upgraded" it to Oracle 10.2 thi client and it broke.
My next step should probably be bringing in entire CallableStatement into the loop, but that kind of defeats the whole idea of why I though prepared statements are used in the first place, no?
Have you tried adding call.clearParameters() into the loop? Perhaps it would reset some internal state on the object that it needs to execute again.
The explanation obtained via Oracle Support call was that this version of Java (1.3) was not compatible with new Oracle. Java 1.4 fixed the issue.