Win a copy of Five Lines of Code this week in the OO, Patterns, UML and Refactoring forum!

Basil Bourque

Greenhorn
+ Follow
since Dec 30, 2003
Basil likes ...
Mac Postgres Database Java
Pacific Northwest
Cows and Likes
Cows
Total received
1
In last 30 days
0
Total given
0
Likes
Total received
3
Received in last 30 days
0
Total given
1
Given in last 30 days
0
Forums and Threads
Scavenger Hunt
expand Ranch Hand Scavenger Hunt
expand Greenhorn Scavenger Hunt

Recent posts by Basil Bourque

Question

How do I tell Tomcat 9 to use a Postgres-specific object factory for producing DataSource object in response to JNDI query?

Details

I have been wrestling Tomcat 9.0.26 to get its JNDI implementation to generate a `DataSource` whose implementation is the class `org.postgresql.ds.PGSimpleDataSource`, rather than the  `org.apache.tomcat.dbcp.dbcp2.BasicDataSource` class obtained by default.

I am using the JNDI approach to externalize the database connection info (username, password, etc.) as a config file for Tomcat. That externalizing seems better for my needs than embedding those settings inside my web-app’s WAR file.

My steps:

(1) Get the `postgresql-42.2.8.jar` on the appropriate class loader.
(2) Write an XML file for `<Context>` with a `factory` attribute for an implementation of `javax.naming.spi.ObjectFactory`.
(3) Place that context definition file in correct location.
(4) Register the `PGSimpleDataSource` class with Java’s Service Provider Interface (SPI).
(5) In my Java code, use a JNDI context to access a `DataSource` object.

—--—|  Step 1  |———————

In my designated “base” folder for Tomcat, in a `lib` folder, place the `postgresql-42.2.8.jar` file.

Given Tomcat’s default `catalina.properties` file’s settings, that *base*/lib location leads to the JDBC driver being loaded in Tomcat’s “Common” class loader.

—--—|  Step 2  |———————

Write an XML file named the same as my context. In this case: `clepsydra.xml` for a context named `clepsydra`.

That file’s content:


Note how I included an attribute for `factory` in that `Resource` definition. I am only guessing that is the right thing to do, based on my reading of the “Resource Definitions” section of the Tomcat page “The Context Container” at:

https://tomcat.apache.org/tomcat-9.0-doc/config/context.html#Resource_Definitions

That page is confusing as it discusses only global resources, but I want this resource only for my own web-app, not globally.

My understanding is that `PGObjectFactory` implements `javax.naming.spi.ObjectFactory`. This means I should be able to tell Tomcat to use this object factory rather than Tomcat’s own object factory. The goal is to get at runtime a `org.postgresql.ds.PGSimpleDataSource` object rather than a `org.apache.tomcat.dbcp.dbcp2.BasicDataSource`.

—--—|  Step 3  |———————

To place this XML file, I go to the `conf` folder I copied from Tomcat into my designated Tomcat “base” folder. In that `conf` folder, I create a `Catalina` folder for the name of the engine. Within that I create a folder named `localhost` for the name of the host, as I am running my Vaadin 14 web app from IntelliJ Ultimate edition 2019.3 externally in Tomcat 9.0.26 in macOS Mojave with Java 13.

I place my `clepsydra.xml` file in that *base*/conf/Catalina/localhost folder.

I know this context file is being loaded successfully because at runtime I am able to access the Environment entry seen above in the XML file:

value: DEV

—--—|  Step 4  |———————

I am guessing that given the `.spi.` in `javax.naming.spi.ObjectFactory`, I need to register my desired `PGObjectFactory` via Java Service Provider Interface (SPI) facility.

So in my Vaadin app’s `resources` folder I create a `META-INF` folder. In there I create a `services` folder. In that `resources/META-INF/services` folder I create a file named exactly the name of the interface:
javax.naming.spi.ObjectFactory

Inside that file I write one line, the name of the implementing class:
org.postgresql.ds.common.PGObjectFactory

—--—|  Step 5  |———————

After cleaning and rebuilding my project, at runtime I execute this code:

value: null

After all that effort, I get a null `DataSource`, with no Exception thrown. Perhaps there are error messages, but I do not see any on the console within IntelliJ. Is there somewhere else to look for error messages?

Can anyone tell me what I have missed, or what I am doing wrong?

For another telling of this tale, see my Stack Overflow Question:
https://stackoverflow.com/q/58385528/642706

—Basil Bourque
9 months ago
This blog post, Clock ticking loudly for Swing and SWT users
https://vaadin.com/blog/clock-ticking-loudly-for-swing-and-swt-users

…claims that in the fine print of the Java 9 note is a statement saying the Java Deployment Technologies are deprecated, specifically mentioning "WebStart" and "JNLP" being deprecated along with the Applet API & Java plug-in. The source is this page listing deprecated parts of Java 9:

http://www.oracle.com/technetwork/java/javase/9-deprecated-features-3745636.html

Java Deployment Technologies are deprecated and will be removed in a future release Java Applet and WebStart functionality, including the Applet API, The Java plug-in, the Java Applet Viewer, JNLP and Java Web Start including the javaws tool are all deprecated in JDK 9 and will be removed in a future release.

JDK-8184998 (not public)



This is surprising news to me. While the Applet deprecation has been well publicized, Java Web Start & JNLP has always been offered as a well-supported alternative.

https://en.wikipedia.org/wiki/Java_Web_Start

--Basil Bourque
2 years ago

Rob Spoor wrote:You shouldn't use those classes since they are for JVM internal use only,



You are incorrect; those classes are not for JVM internal use only. Quite the opposite.

These sun.* classes are the official reference implementations of RowSet interfaces. They are meant to be used by developers, as explained in the http://download.oracle.com/javase/7/docs/api/index.html?javax/sql/RowSet.html";" target="_new" rel="nofollow">RowSet documentation:

The reference implementation of the CachedRowSet interface provided by Oracle Corporation is a standard implementation. Developers may use this implementation just as it is, they may extend it, or they may choose to write their own…



Rob Spoor wrote:… those classes … may be changed or removed from one Java version to another. That means that code that's working right now may not work anymore when you update your Java installation. This is true for all classes in packages that start with sun, sunw or com.sun.



You are correct about this. Every developer should understand that the sun.* classes are not part of the official Java platform. They are not included in every Java implementation. However, they have been bundled in Sun/Oracle's implementations released by themselves as well as their licensees such as Apple, Inc. for Mac OS X. This bundling continues in Java 5, 6, and 7. Read Oracle's http://www.oracle.com/technetwork/java/faq-sun-packages-142232.html";" target="_new" rel="nofollow">official statement.

While we developers should be aware that Oracle retains the legal right to withdraw the sun.* classes, to say that we should never use them is an overstatement. Especially so when discussing the official reference implementations.

--Basil Bourque

The RowSet interfaces, including CachedRowSet, are indeed bundled in Java 5, 6, and 7.

CachedRowSet doc:
http://download.oracle.com/javase/7/docs/api/index.html?javax/sql/rowset/package-summary.html

Sun did indeed release their promised standard implementation of CachedRowSet, called "com.sun.rowset.CachedRowSetImpl". Now made available by Oracle:
http://download.oracle.com/docs/cd/E17824_01/dsc_docs/docs/jscreator/apis/rowset/com/sun/rowset/CachedRowSetImpl.html

I find that Sun implementation bundled in Apple's Java 6 on Mac OS X 10.6.8 (Snow Leopard).

Oracle's JDK 6u23 source code has these implementations:
• com.sun.rowset.CachedRowSetImpl
• com.sun.rowset.FilteredRowSetImpl
• com.sun.rowset.JdbcRowSetImpl
• com.sun.rowset.JoinRowSetImpl
• com.sun.rowset.WebRowSetImpl

Furthermore, some vendors release their own implementations. I've seen references to implementations from Oracle specific to their database products.

--Basil Bourque

I have a Java Swing app that connects directly to a JDBC relational database (Postgres 9) over the Internets.

[User] <--> [Swing app] <--> [JDBC] <--> [Internets] <--> [Database]

--> How do I secure the JDBC password?

My question is along the same lines as this Store JDBC connection password topic, but there the discussion lost focus.

First, I realize there are other architectures that get around this challenge. But I really want the richness and flexibility of Swing with the simplicity and flexibility of directly talking to the database. I don't want to burden the users with hardware keys/dongles. So instead of debating alternatives, let's focus the question to this:

  • Can the architecture shown above be secured (within the reasonable needs and resources of a common small business, not Top Secret military) ?
  • If so, how?


  • From what I've learned one good approach is:

    1) Human user gives their own logon name and password to the Swing app.

    2) The Swing app makes a secure connection (TLS/SSL) to a little password app or servlet passing the credentials (user name, user password plus a salt (perhaps).

    3) The little password app or servlet (a) authenticates that user, and (b) returns the current JDBC password.

    3) The Swing app stores that JDBC password in memory.

    4) The Swing app uses that JDBC password plus a salt (perhaps) to make a JDBC connection to the database over TLS/SSL.

    Diagram of these steps:



    Assuming the TLS/SSL is reliable, to break this and gain direct access to the database, an outside hacker would have to know a user's name and password, attach a debugger or memory-scanner to the Swing app to locate the JDBC password held temporarily in memory, and decompile the Swing app to find any hard-coded salt values. And we have the advantage of being able to change the JDBC password at anytime. So, not impenetrable, but also not easy to break. Is this correct?

    Is there a better approach to accomplish the same goals?

    --Basil Bourque
    8 years ago
    I'm trying to build a Swing app where one window/JFrame has a listing of database records, and another window/JFrame has a detail form to edit one of those database records.

    I've got the listing window working with a JTable, backed by a database RowSet, with a TableModel in between based on George Reese's JDBC book's code. Beneath the JTable are buttons to add or edit a row in the JTable. These buttons open a separate JFrame to use as a detail form.

    My question is: How can I coordinate data changes?

    The RowSet could possibly be re-populated, leaving out our particular record in the detail form.

    So are listeners the way to go? Or should I look at something more loosely coupled? Such as creating my own event bus to have each widget subscribe to events related to a particular table. Then each widget would look at each notification to see if the record id mentioned in the notification is a record of interest.
    9 years ago
    Here's a bit of code I'm using to get a native-style "Help" in Mac OS X while maintaining compatibility with other Look-and-Feels. A round purple button with a "?" icon appears.

    Setting the Client Property "JButton.buttonType" to "help" causes the Mac-savvy button to appear, at least in later versions of Java and Mac OS X.

    The next step is to suppress the display of the usual caption if running on a Mac. We accomplish that by overriding the "setText" method.

    I'm new to overriding Swing components. So please critique.

    This subclass seems to be working well with JFormDesigner 5.



    --Basil Bourque
    9 years ago
    That book is the printed equivalent of the online tutorial at:
    http://java.sun.com/docs/books/tutorial/uiswing/index.html
    16 years ago
    Is there any robust implementation of a parser for extracting a date from arbitrary text?
    By arbitrary, I mean anything a user may type into a text field on an HTML form, for example.
    The DateFormat class included with Java parses dates from text, but you must specify the _exact_format of the text. If I knew the exact format, and the user used it perfectly, I wouldn't need a parser library!
    I'm looking for a more robust parser library that can make sense out of various input, expecially locale-aware (i18n) ones.
    --Basil Bourque
    16 years ago