Showing posts with label Java. Show all posts
Showing posts with label Java. Show all posts
Tuesday, February 3, 2009
FoxPro Java ODBC Query Bug
The result set for a query to a FoxPro database may have incorrect data in the row's fields if the ORDER BY clause is not used. This occurred using ODBC from Java and Groovy code. I'm thinking this might have been caused by the old database driver I was using. I can't remember the publication date, but it was sometime in the late 90's, I'm thinking 98 or 99.
Monday, January 19, 2009
Upgrade Java to 1.5 (at least), Please
I can't believe software is still being created using Java 1.3 (or older) and deployed on systems running Java
1.3. If at all possible, it's time to move forward people. At least upgrade to Java 1.5 (marketing: Java 5)
as this is a huge leap forward over 1.3 and is supported by most tools and environments I come across. I wish
everyone was using Java 1.6, but that might be asking too much.
Following are some reasons to upgrade to Java 1.5:
Following are some reasons to upgrade to Java 1.5:
- The latest JVMs perform much more efficiently.
- Assert facility -- allows programmers to make statements about what they believe their program is doing and quickly uncovers misconceptions.
- Generics -- allows much enhanced type safety (at compile time, as opposed to runtime), and eliminates casting.
- Enhanced for loops -- eliminates error prone indexing of for loops and loops that are easier to understand.
- Auto boxing and unboxing -- eliminates manual conversion between primitives and class types and results in cleaner and easier to read code.
- Type safe enumerations -- much cleaner, easier to use, and safer than current techniques of using a combination of constant ints, strings, and arrays.
- Regular expressions -- very, very useful for parsing and validating strings.
- Static import -- less typing and cleaner code
- Chained exceptions -- better error reporting and reduced chances of losing exception information.
- Logging API -- very useful for server applications.
-
Larger API to work with including:
- JDBC (database connectivity) updates.
- New classes for threading (concurrency).
- New IO classes.
- New classes for converting between strings and various types.
- New XML processing classes, including XPath (very useful).
- New security classes.
- New Java 2D drawing and image IO framework.
- New printing API.
- Lots of changes to Swing/AWT.
- New collection classes and interfaces.
Thursday, January 1, 2009
The Danger of Static Variables in Multithreaded Environments: An Example
I fixed a very subtle bug the other day that illustrates the dangers of using static variables in multithreaded environments, such as multi-user web applications. I had implemented a Singleton class in a non-multithreaded desktop application many months ago that contained a static map (actually Java's HashMap) of database (DB) connections. The map was used to cache opened connections to different DBs so they could be reused by different parts of the application. When some part of the application needed a connection, my singleton was used to get one such that if an opened connection already existed it was returned; otherwise a new connection was opened, added to the map, and returned (a trivial connection pool if you will).
A little while ago I needed to update this class for use in a multithreaded server for a web application. So, I replaced the singleton with a class that could be instantiated by each user (i.e. thread) using the default constructor. When doing the changes, I missed removing the static storage class from the declaration of the map instance and ended up with a class something like this (only shows what is necessary):
class MyConnectionManager
{
private static final Map<String,Connection> _map =
new HashMap<String,Connection>();
public Connection getConnection(String db)
{
if (!_map.containsKey(db))
_map.put(db, makeNewConnection(db));
return _map.get(db);
}
....
}
Even though I did have unique instances of the manager class for each user/thread, all instances used the same Map. There are at least two threading issues here. The first is that two or more different users could use the same connection. Even if the Connection class is thread safe, we still have a problem if thread A closes the connection while thread B is using it. The second issue is that HashMap is not thread safe.
One fix to all thread safety issues in this case is simply to remove the static storage class from the declaration of the Map instance.
Labels:
Concurrency,
Java
Wednesday, November 19, 2008
Flying Saucer, XHTML Rendering, and Local XML Entities
I have been using Flying Saucer's (FS) XHTML Renderer [1] for at least 5 months now.
It's an excellent library for rendering XHTML for display in Java Swing (using FS's XHTMLPanel) and for converting XHTML content to PDF files (see
Generating PDFs for Fun and Profit with Flying Saucer and iText [2]). In my latest project, I create a report in XHTML and use FS to create a PDF version as follows:
One benefit of using this method to create a PDF is that it is much easier to layout the report in XHTML than using a PDF library like iText directly. A second benefit is that I can render the report in two different formats (PDF, XHTML) and render it in a GUI with very little extra work.
Everything worked fine until yesterday.
The problem I ran into today was FS (more correctly the libraries it depends on) would randomly fail with errors such as
After help from the very responsive FS users group [3], the problem was that my XML document builder would sometimes fail when accessing the web to resolve XML entities, even though I was connected to the Internet. I was able to fix the problem by adding one line of code to configure the entity resolver to use XML entities on the class path (and conveniently packaged in FS's core-renderer.jar).
The moral of the story is that some thought should always be given to how you configure your XML parsers to resolve entities. In many cases it makes more sense to use a local store, not a default remote site such as www.w3.org. This is especially important if the application doing the parsing may run on computers not connected to the Internet. This applies to FS and other libraries that depend on parsing XML.
References
[1] The Flying Saucer Project, 2008
[2] Joshua Marinacci, Generating PDFs for Fun and Profit with Flying Saucer and iText, 2007
[3] Flying Saucer User Mailing List, 2008
String baseUrl ... // root URL for resources
InputStream xhtml = ... // XHTML content
DocumentBuilder builder =
DocumentBuilderFactory.newInstance().newDocumentBuilder();
Document doc = builder.parse(xhtml);
ITextRenderer renderer = new ITextRenderer();
renderer.setDocument(doc, baseUrl);
OutputStream os = new FileOutputStream("Out.pdf");
renderer.layout();
renderer.createPDF(os);
One benefit of using this method to create a PDF is that it is much easier to layout the report in XHTML than using a PDF library like iText directly. A second benefit is that I can render the report in two different formats (PDF, XHTML) and render it in a GUI with very little extra work.
Everything worked fine until yesterday.
The problem I ran into today was FS (more correctly the libraries it depends on) would randomly fail with errors such as
java.net.SocketException: Connection reset
andjava.io.IOException: Server returned HTTP response code: 503 for URL:http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd
After help from the very responsive FS users group [3], the problem was that my XML document builder would sometimes fail when accessing the web to resolve XML entities, even though I was connected to the Internet. I was able to fix the problem by adding one line of code to configure the entity resolver to use XML entities on the class path (and conveniently packaged in FS's core-renderer.jar).
String baseUrl ...
InputStream xhtml = ...
DocumentBuilder builder =
DocumentBuilderFactory.newInstance().newDocumentBuilder();
// Use FS's local cached XML entities so we don't
// have to hit the web.
builder.setEntityResolver(FSEntityResolver.instance());
Document doc = builder.parse(xhtml);
ITextRenderer renderer = new ITextRenderer();
renderer.setDocument(doc, baseUrl);
OutputStream os = new FileOutputStream("Out.pdf");
renderer.layout();
renderer.createPDF(os);
The moral of the story is that some thought should always be given to how you configure your XML parsers to resolve entities. In many cases it makes more sense to use a local store, not a default remote site such as www.w3.org. This is especially important if the application doing the parsing may run on computers not connected to the Internet. This applies to FS and other libraries that depend on parsing XML.
References
[1] The Flying Saucer Project, 2008
[2] Joshua Marinacci, Generating PDFs for Fun and Profit with Flying Saucer and iText, 2007
[3] Flying Saucer User Mailing List, 2008
Subscribe to:
Posts (Atom)