J2EE Archives
Updated list of JDBC drivers supporting JDBC 4.0
Posted by lancea on September 18, 2007 at 01:44 PM | Permalink
| Comments (4)
The following is the current list of available JDBC 4.0 drivers:
Java DB upgraded in Glassfish V2
Posted by lancea on September 17, 2007 at 08:25 AM | Permalink
| Comments (1)
Java DB, Sun's supported distribution of Apache Derby, has been upgraded from Java DB 10.1.3.1 which was bundled with Glassfish V1, to Java DB 10.2.2.
The new release of Java DB includes many new features and improvements including:
You can find the complete list of new features in Java DB 10.2.2 here.
For more information on Java DB, check out the following resources:
Glassfish v2 is now available for download.
Using Java Web Start with the Java Persistence API
Posted by lancea on June 15, 2007 at 09:02 AM | Permalink
| Comments (2)
Untitled Document
I created a simple Java Persistence API application using Toplink Essentials which runs like a champ from NetBeans and from the
command line. So I figure, great, I will spice up the example a little more and use Java Web Start (yes I am a rookie to Java Web Start, so be gentle!) and I whip up a simple jnlp file JPAWebStart.bad.jnlp:
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE jnlp PUBLIC "-//Sun Microsystems, Inc.//DTD JNLP 1.5//EN" "http://www.netbeans.org/jnlp/DTD/jnlp.dtd">
<jnlp codebase="file:///C:/Netbeans/JPAWebStart" href="JPAWebStart.bad.jnlp">
<information>
<title>JPAWebStart fail</title>
<vendor>Company, Inc.</vendor>
<homepage href="homepage.html"/>
<description> </description>
<icon href="default"/>
<offline-allowed/>
<shortcut online="true"/>
</information>
<resources>
<j2se href="http://java.sun.com/products/autodl/j2se" version="1.6+"/>
</resources>
<resources>
<jar download="eager" href="dist/JPAWebStart.jar" main="false"/>
</resources>
<resources>
<jar download="eager" href="dist/lib/toplink-essentials.jar" main="false" version=""/>
</resources>
<resources>
<jar download="eager" href="dist/lib/derby.jar" main="false" version=""/>
</resources>
<application-desc main-class="demo.ui.JPAWebStartDemo"/>
</jnlp>
|
Ok, off I go to run my application:
javaws JPAWebStart.bad.jnlp
|
And low and behold, I get the following error:
Exception in thread "AWT-EventQueue-0"
javax.persistence.PersistenceException: No Persistence provider for EntityManager named JPAWebStartPU
at javax.persistence.Persistence.createEntityManagerFactory(Persistence.java:89)
at javax.persistence.Persistence.createEntityManagerFactory(Persistence.java:60)
at demo.ContactImpl$1.run(ContactImpl.java:37)
at java.security.AccessController.doPrivileged(Native Method)
at demo.ContactImpl.(ContactImpl.java:34)
at demo.ContactFactory.getInstance(ContactFactory.java:28)
at demo.ContactTableModel.(ContactTableModel.java:34)
at demo.ui.JPAWebStartDemo.initComponents(JPAWebStartDemo.java:134)
at demo.ui.JPAWebStartDemo.(JPAWebStartDemo.java:23)
at demo.ui.JPAWebStartDemo$7.run(JPAWebStartDemo.java:304)
at java.awt.event.InvocationEvent.dispatch(Unknown Source)
at java.awt.EventQueue.dispatchEvent(Unknown Source)
at java.awt.EventDispatchThread.pumpOneEventForFilters(Unknown Source)
at java.awt.EventDispatchThread.pumpEventsForFilter(Unknown Source)
at java.awt.EventDispatchThread.pumpEventsForHierarchy(Unknown Source)
at java.awt.EventDispatchThread.pumpEvents(Unknown Source)
at java.awt.EventDispatchThread.pumpEvents(Unknown Source)
at java.awt.EventDispatchThread.run(Unknown Source)
|
Why is my Persistence provider not found when I can run the application fine as a standalone application from the command line or from NetBeans?
The error message is misleading as the issue turns out to be due to the sandbox environment that Java Web Start uses to protect users from untrusted applications.
So where do we go from here? Well, we will create two jnlp files, one to start our application, the other which contains the classes which require more access then the sandbox allows. The jar files contained in the second jnlp, which is referenced from our first jnlp file, will enable access to the system and all jar files listed as resources will be signed.
Here is the new JNLP file, JPAWebStart.jnlp, used to launch my application:
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE jnlp PUBLIC "-//Sun Microsystems, Inc.//DTD JNLP 1.5//EN" "http://www.netbeans.org/jnlp/DTD/jnlp.dtd">
<jnlp codebase="file:///C:/Netbeans/JPAWebStart" href="JPAWebStart.jnlp">
<information>
<title>JPAWebStart Demo</title>
<vendor>Company, Inc.</vendor>
<homepage href="homepage.html"/>
<description> </description>
<icon href="default"/>
<offline-allowed/>
<shortcut online="true"/>
</information>
<resources>
<j2se href="http://java.sun.com/products/autodl/j2se" version="1.6+"/>
</resources>
<resources>
<jar download="eager" href="dist/JPAWebStartMain.jar" main="false"/>
</resources>
<resources>
<extension href="JPAPermissions.jnlp" name="jpa"/>
</resources>
<application-desc main-class="demo.main.JPADemo"/>
</jnlp>
|
I made the following changes to JPAWebStart.jnlp:
- Start the application via a new program which resides in the jar JPAWebStartMain.jar
- Use the extension element to reference the JPAPermissions.jnlp which contains the jars that needed to be signed as well as grant the access beyond what is allowed by the sandbox
Here is the JPAPermissions.jnlp which contains all of the signed jars and enables the extra security access:
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE jnlp PUBLIC "-//Sun Microsystems, Inc.//DTD JNLP 1.5//EN" "http://www.netbeans.org/jnlp/DTD/jnlp.dtd">
<jnlp codebase="file:///C:/Netbeans/JPAWebStart" href="JPAPermissions.jnlp">
<information>
<title>JPAPermissions</title>
<vendor>Company, Inc.</vendor>
<homepage href="homepage.html"/>
<description> </description>
<icon href="default"/>
<offline-allowed/>
<shortcut online="true"/>
</information>
<security>
<all-permissions/>
</security>
<resources>
<jar download="eager" href="dist/lib/toplink-essentials.jar" main="false" version=""/>
</resources>
<resources>
<jar download="eager" href="dist/lib/derby.jar" main="false" version=""/>
</resources>
<resources>
<jar download="eager" href="dist/JPAWebStart.jar" main="false"/>
</resources>
<component-desc/>
</jnlp>
|
Next, we need to sign the jars. To do this I added a -post-jar target to the default build.xml in my NetBeans project:
<target name="-post-jar">
<property name="key-alias" value="jpawebstart"\>
<property name="keystore.password" value="foobar"\>
<property name="keystore.location" value="dist/keystore"\>
<delete file="${keystore.location}"\>
<genkey alias="${key-alias}" keystore="${keystore.location}" storepass="${keystore.password}" validity="3650" dname="CN=jpawebstart, OU=jpawestart, O=net, C=US"\>
<signjar jar="dist/JPAWebStart.jar" alias="${key-alias}" keystore="${keystore.location}" storepass="${keystore.password}"\>
<signjar jar="dist/lib/derby.jar" alias="${key-alias}" keystore="${keystore.location}" storepass="${keystore.password}"\>
<signjar jar="dist/lib/toplink-essentials.jar" alias="${key-alias}" keystore="${keystore.location}" storepass="${keystore.password}"\>
<jar destfile="dist/JPAWebStartMain.jar"
basedir="build/classes"
includes="demo/main/**"
manifest="MANIFEST_MAIN.MF"
\>
</target>
|
One other addition to the -post-jar target is the creation of the jar file that is referenced in JPAWebStart.jnlp. Why am I doing it here you ask? Well, it was easier then overriding all of the default targets for building the application that NetBeans provides (if someone has an alternative suggestion, let me know).
About the JPAWebStart sample application
The sample application demonstrates the use of the Java Persistence API from Java SE, using Swing, Java DB and Java Web Start:
When the application is started the main screen is shown:
There are no contacts in the database when the application is started. To add contacts to the database, you would select the Contacts menu item, "Add Contact"

and the following form will be opened:
The main entry point to the application is the JPADemo class. JPADemo is packaged in the jar JPAWebStartMain.jar and its sole purpose is to start the rest of the application which requires more permissions than the sandbox allows:
package demo.main;
import demo.ui.JPAWebStartDemo;
public class JPADemo {
/** Creates a new instance of JPADemo */
public JPADemo() {
}
/**
* @param args the command line arguments
*/
public static void main(String[] args) {
java.awt.EventQueue.invokeLater(new Runnable() {
public void run() {
new JPAWebStartDemo().setVisible(true);
}
});
}
}
|
As this is a simple demo, there is only one Entity used by the application, Contact:
package demo.entity;
import java.io.Serializable;
import javax.persistence.Entity;
import javax.persistence.GeneratedValue;
import javax.persistence.GenerationType;
import javax.persistence.Id;
import javax.persistence.Table;
/**
* Entity class Contact
*
*/
@Entity
@Table(name="Contacts")
public class Contact implements Serializable {
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
private Long id;
private String firstName;
private String lastName;
private String phone;
/**
* Creates a new instance of Contact
*/
public Contact() {
}
/**
* Creates a new instance of Contact
*/
public Contact(String firstName, String lastName, String phone) {
this.firstName = firstName;
this.lastName = lastName;
this.phone = phone;
}
/**
* Gets the id of this Contact.
*
* @return the id
*/
public Long getId() {
return this.id;
}
/**
* Sets the id of this Contact to the specified value.
*
* @param id the new id
*/
public void setId(Long id) {
this.id = id;
}
/**
* Returns a hash code value for the object. This implementation computes
* a hash code value based on the id fields in this object.
* @return a hash code value for this object.
*/
@Override
public int hashCode() {
int hash = 0;
hash += (this.id != null ? this.id.hashCode() : 0);
return hash;
}
/**
* Determines whether another object is equal to this TestPerson. The result is
* true if and only if the argument is not null and is a TestPerson object that
* has the same id field values as this object.
*
* @param object the reference object with which to compare
* @return true if this object is the same as the argument;
* false otherwise.
*/
@Override
public boolean equals(Object object) {
// TODO: Warning - this method won't work in the case the id fields are not set
if (!(object instanceof Contact)) {
return false;
}
Contact other = (Contact)object;
if (this.id != other.id && (this.id == null || !this.id.equals(other.id))) return false;
return true;
}
/**
* Returns a string representation of the object. This implementation constructs
* that representation based on the id fields.
* @return a string representation of the object.
*/
@Override
public String toString() {
return "entity.Contact[id=" + id + "], firstName= " + firstName + ", lastName= " + lastName + ", phone= " + phone;
}
public String getFirstName() {
return firstName;
}
public void setFirstName(String firstName) {
this.firstName = firstName;
}
public String getLastName() {
return lastName;
}
public void setLastName(String lastName) {
this.lastName = lastName;
}
public String getPhone() {
return phone;
}
public void setPhone(String phone) {
this.phone = phone;
}
}
|
To persist a new Contact, the addContact() method of ContactImpl is called:
public void addContact(Contact contact) {
try{
em = emf.createEntityManager();
em.getTransaction().begin();
em.persist(contact);
em.getTransaction().commit();
System.out.println("row created");
} finally {
em.close();
}
}
|
Because this application is strictly a Java SE application and not running inside of a container, the application must do the following:
- Explicitly create an EntityManagerFactory by calling Persistence.createEntityManagerFactory()
emf = Persistence.createEntityManagerFactory("JPAWebStartPU");
|
- Create an application managed EntityManager by calling the method createEntityManager() on an EntityManagerFactory instance in each method as an EntityManager is lightweight and not thread safe
- Explicitly control the transaction (this is a Resource-Local Transaction). The application must acquire an instance of EntityTransaction and then call the methods begin(), commit() and rollback() as needed.
- Close the EntityManger by calling the close() method. It is recommended that this is done in a finally block to guarantee that the EntityManager is closed.
One other thing to note is that in order to run TopLink Essentials with Java Web Start, you must enable privileges for the call to Peristence.createEntityManagerFactory which is done in the ContactImpl constructor:
public ContactImpl() {
emf = (EntityManagerFactory ) AccessController.doPrivileged(
new PrivilegedAction() {
public Object run() {
return Persistence.createEntityManagerFactory("JPAWebStartPU");
}
}
);
}
|
If you do not enable privileges for Peristence.createEntityManagerFactory, then you will encounter the following Exception:
---------------------------------------------------- Exception in thread "AWT-EventQueue-0" java.security.AccessControlException: access denied (java.util.PropertyPermission toplink.logging.level read) at java.security.AccessControlContext.checkPermission(Unknown Source) at java.security.AccessController.checkPermission(Unknown Source) at java.lang.SecurityManager.checkPermission(Unknown Source) at java.lang.SecurityManager.checkPropertyAccess(Unknown Source) at java.lang.System.getProperty(Unknown Source) at oracle.toplink.essentials.internal.ejb.cmp3.JavaSECMPInitializer.getTopLinkLoggingLevel(JavaSECMPInitializer.java:99) at oracle.toplink.essentials.internal.ejb.cmp3.JavaSECMPInitializer.initializeFromMain(JavaSECMPInitializer.java:272) at oracle.toplink.essentials.internal.ejb.cmp3.JavaSECMPInitializer.getJavaSECMPInitializer(JavaSECMPInitializer.java:80) at oracle.toplink.essentials.ejb.cmp3.EntityManagerFactoryProvider.createEntityManagerFactory(EntityManagerFactoryProvider.java:118) at javax.persistence.Persistence.createEntityManagerFactory(Persistence.java:83) at javax.persistence.Persistence.createEntityManagerFactory(Persistence.java:60) at demo.ContactImpl.<init>(ContactImpl.java:42) at demo.ContactFactory.getInstance(ContactFactory.java:28) at demo.ContactTableModel.<init>(ContactTableModel.java:34) at demo.ui.JPAWebStartDemo.initComponents(JPAWebStartDemo.java:134) at demo.ui.JPAWebStartDemo.<init>(JPAWebStartDemo.java:23) at demo.main.JPADemo$1.run(JPADemo.java:30) at java.awt.event.InvocationEvent.dispatch(Unknown Source) at java.awt.EventQueue.dispatchEvent(Unknown Source) at java.awt.EventDispatchThread.pumpOneEventForFilters(Unknown Source) at java.awt.EventDispatchThread.pumpEventsForFilter(Unknown Source) at java.awt.EventDispatchThread.pumpEventsForHierarchy(Unknown Source) at java.awt.EventDispatchThread.pumpEvents(Unknown Source) at java.awt.EventDispatchThread.pumpEvents(Unknown Source) at java.awt.EventDispatchThread.run(Unknown Source
|
When we configure the persistence.xml we will need to indicate that we are using a Resource-Local Transaction
<?xml version="1.0" encoding="UTF-8"?>
<persistence version="1.0" xmlns="http://java.sun.com/xml/ns/persistence" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://java.sun.com/xml/ns/persistence http://java.sun.com/xml/ns/persistence/persistence_1_0.xsd">
<persistence-unit name="JPAWebStartPU" transaction-type="RESOURCE_LOCAL">
<provider>oracle.toplink.essentials.ejb.cmp3.EntityManagerFactoryProvider</provider>
<class>demo.entity.Contact</class>
<properties>
<property name="toplink.jdbc.url" value="jdbc:derby:testDB;create=true"/>
<property name="toplink.jdbc.user" value="APP"/>
<property name="toplink.jdbc.driver" value="org.apache.derby.jdbc.EmbeddedDriver"/>
<property name="toplink.jdbc.password" value="APP"/>
<property name="toplink.ddl-generation" value="drop-and-create-tables"/>
<property name="toplink.logging.level" value="FINE"/>
</properties>
</persistence-unit>
</persistence>
|
After adding a few contacts, you can then query the database allowing for the rows to either be deleted or modified:
The application provides an implementation of the JTable TableModel interface, ContactTableModel, which is used to manage the display and modification of the rows within the JTable.
package demo;
import demo.entity.Contact;
import java.util.ArrayList;
import java.util.List;
import javax.swing.table.AbstractTableModel;
/*
* ContactTableModel.java
*
* Created on May 23, 2007, 4:59 PM
*
* To change this template, choose Tools | Template Manager
* and open the template in the editor.
*/
/**
*
* @author Owner
*/
public class ContactTableModel extends AbstractTableModel {
private List columnNames;
private List contacts;
private Contacts contactImpl;
private final int FIRSTNAME = 0;
private final int LASTNAME = 1;
private final int PHONE = 2;
/**
* Creates a new instance of ContactTableModel
*/
public ContactTableModel() {
contacts = new ArrayList();
contactImpl = ContactFactory.getInstance(ContactFactory.ConfigApi.USE_JPA);
columnNames = new ArrayList();
columnNames.add( "FIRST NAME");
columnNames.add( "LAST NAME");
columnNames.add( "PHONE NUMBER");
}
/*
* Return the Column name for the current column
*/
public String getColumnName(int column) {
return columnNames.get(column);
}
/*
* Return the number of Rows in our table
*/
public int getRowCount() {
return contacts.size();
}
/**
* Return the number of Columns in our table
*/
public int getColumnCount() {
return columnNames.size();
}
/**
* Allow all columns to be updatable
* @param row Row number in the JTable
* @param col Column number for the row in the JTable
*/
public boolean isCellEditable(int row, int col) {
// All columns are edititable
return true;
}
/**
* Return the column value for the specified columnIndex and rowIndex.
* @param rowIndex Row number in the JTable
* @param columnIndex Column number for the row in the JTable
*/
public Object getValueAt(int rowIndex, int columnIndex) {
String result = null;
if (contacts.size() != 0) {
Contact c = contacts.get(rowIndex);
switch( columnIndex) {
case FIRSTNAME:
result = c.getFirstName();
break;
case LASTNAME:
result = c.getLastName();
break;
case PHONE:
result = c.getPhone();
break;
}
}
return result;
}
/**
* Sets the column value specified at columnIndex and rowIndex to value.
* @param value New value for the column
* @param rowIndex Row number in the JTable
* @param columnIndex Column number for the row in the JTable
*/
public void setValueAt(Object value, int rowIndex, int columnIndex) {
System.out.println("Setting value at " + rowIndex + "," + columnIndex
+ " to " + value + " (an instance of " + value.getClass() + ")");
Contact c = contacts.get(rowIndex);
String result = null;
switch( columnIndex) {
case FIRSTNAME:
c.setFirstName((String) value);
break;
case LASTNAME:
c.setLastName((String) value);
break;
case PHONE:
c.setPhone((String) value);
break;
}
contacts.set(rowIndex, c);
fireTableCellUpdated(rowIndex, columnIndex);
}
/**
* Add a new contact
* @param p A new Contact(entity)
*
*/
public void addContact(Contact p) {
if (p != null) {
contactImpl.addContact(p);
} else {
System.out.println("No row to persist");
}
}
/**
* Query the database for Contacts using the criteria specified
* @param firstName First name of the contact
* @param lastName Last name of the contact
* @param phone Phone number of the contact
* @return The number of rows that matched the selection criteria
*/
public int executeQuery(String firstName, String lastName, String phone) {
System.out.println("first=" + firstName + "- last ="+ lastName + "- phone=" + phone +"-");
contacts= contactImpl.executeQuery( firstName, lastName, phone);
if (contacts.size() != 0 ) {
fireTableDataChanged();
}
return contacts.size();
}
/**
* Utility method which is just used for debugging
*/
public Contact getRow(int row ) {
return contacts.get(row);
}
/**
* Delete the selected row from the JTable and database
* @param selectedRow The row number displayed in the JTable to delete from the database
*/
public void deleteContact(int selectedRow) {
contactImpl.removeContact(contacts.get(selectedRow));
contacts.remove(selectedRow);
fireTableRowsDeleted(selectedRow, selectedRow);
}
/**
* Update the selected row in the JTable and database
* @param selectedRow The row number displayed in the JTable to update in the database
*/
public void updateContact(int selectedRow) {
contactImpl.updateContact(contacts.get(selectedRow));
}
}
|
The ContactTableModel invokes the static factory ContactFactory.getInstance() to obtain an instance of ContactImpl which in our example is implemented using the Java Persistence API. This factory allows for providing additional implementations for accessing the database such as JDBC.
contactImpl = ContactFactory.getInstance(ContactFactory.ConfigApi.USE_JPA);
|
When a query is submitted, it is built as a dynamic query. Normally you will find the use of Named queries more efficient. However, sometimes you will find you need to use a dynamic query based
on the number of parameters that might be optional.
public List executeQuery(String firstName, String lastName, String phone) {
Query q = null;
List result = null;
boolean paramSpecified = false;
StringBuffer buf = new StringBuffer("Select c from Contact c where ");
String query = null;
if (!firstName.equals(EMPTYSTRING)) {
paramSpecified = true;
buf.append("upper(c.firstName) like :firstName and ");
}
if (!lastName.equals(EMPTYSTRING)) {
paramSpecified = true;
buf.append("upper(c.lastName) like :lastName and ");
}
if (!phone.equals(EMPTYSTRING)) {
paramSpecified = true;
buf.append("upper(c.phone) like :phone and ");
}
// If there are parameters specified, then remove the last "and" otherwise
// remove "where" from the end of the query.
if (paramSpecified) {
query = buf.substring(0, buf.length() - " and".length());
} else {
query = buf.substring(0, buf.length() - " where ".length());
}
System.out.println("Query is \"" + query + "\"");
try {
em = emf.createEntityManager();
q = em.createQuery(query);
if (!firstName.equals(EMPTYSTRING)) {
q = q.setParameter("firstName", "%"+firstName.toUpperCase()+"%");
}
if (!lastName.equals(EMPTYSTRING)) {
q = q.setParameter("lastName", "%"+lastName.toUpperCase()+"%");
}
if (!phone.equals(EMPTYSTRING)) {
q = q.setParameter("phone", "%"+ phone.toUpperCase()+"%");
}
result = q.getResultList();
System.out.println("rows returned=" + result.size());
} finally {
em.close();
}
return result;
}
|
All of the rows that are displayed in the JTable are detached and must be managed by the persistence context prior to committing the transaction. This is accomplished by calling the EntityManager method merge() prior to committing the transaction:
/**
* Remove a contact to the database. The contact that is
* passed in, needs to be merged prior to removing.
* @param contact The Contact to remove
*/
public void removeContact(Contact contact) {
try {
if(contact != null) {
em = emf.createEntityManager();
em.getTransaction().begin();
Contact mergedContact = em.merge(contact);
em.remove(mergedContact);
em.getTransaction().commit();
System.out.println("row removed");
}
} finally {
em.close();
}
}
/**
* Update a contact in the database. The contact that is
* passed in, needs to be merged prior to the update.
* @param contact The Contact to update
*/
public void updateContact(Contact contact) {
try {
em = emf.createEntityManager();
em.getTransaction().begin();
em.merge(contact);
em.getTransaction().commit();
System.out.println("row :" + contact + " updated");
} finally {
em.close();
}
}
|
Configuring the JPAWebStart application
The following steps are needed to configure the JPAWebStart application:
- If you are going to run the JPAWebStart application using the javaws command, then you need to modify the jnlp elements in the files JPAWebStart.jnlp and JPAPermissions.jnlp files specifying the correct codebase:
<jnlp codebase="file:///C:/Netbeans/JPAWebStart" href="http://weblogs.java.net/blog/lancea/archive/JPAWebStart.jnlp">
|
For, example if you are on unix and installed JPAWebStart in /tmp, you would modify the jnlp element in JPAWebStart.jnlp and JPAPermissions.jnlp to be:
<jnlp codebase="file:///tmp/JPAWebStart" href="JPAWebStart.jnlp">
|
Running the JPAWebStart application
You can run the JPAWebStart application using Java Web Start in multiple ways:
- Running using the NetBeans Java Web Start plugin:
- Deploying and then running from a web browser using the NetBeans Java Web Start plugin:

- After the application deploys, a web browser will be launched allowing you to start the JPAWebStart application:
Summary
This blog provides an overview of how to successfully develop a Java SE application using Java Web Start, Java Persistence API, Swing and NetBeans 5.5. In order to use Java Web Start with the Java Persistence API, you must enable security and sign the jars for the classes which need more access than the Java Web Start sandbox allows.
The following are additional references which you might find useful when developing applications using the technologies demonstrated in this article:
Special thanks to Mitesh, Markus and Ryan for a quick review, testing and suggestions for the blog..
JDBC 4.0 and Java SE 6 have left the stable
Posted by lancea on December 11, 2006 at 09:11 AM | Permalink
| Comments (5)
Well, we have made it. Java SE 6 and JDBC 4.0 are now final and have been released. It has been an interesting and rewarding adventure!
Java SE 6 SDK bundles Java DB which provides a JDBC 4.0 driver. I suspect we will see quite a few JDBC 4.0 drivers soon and I will update this blog with the latest info.
JDBC 4.0 brings many new features such as improved LOB support, SQL XML data type support as well as many clarifications to the previous versions of the JDBC specification.
I once again, want to thank the members of the JDBC 4.0 expert group for their efforts in making the release of JSR 221 a success.
Once we catch our breadth, we will be looking at ways to continue to improve JDBC going forward and if you have suggestions, let me know.
Regards
Lance
JDBC 4.0 SQLXML Interface
Posted by lancea on May 02, 2006 at 11:09 AM | Permalink
| Comments (2)
Since the public draft of the JDBC spec, the JDBC EG has reworked the SQLXML interface completely providing for more flexibility. The new version of the interface will be available in the Java SE 6 upcoming beta and should also be available in the current nightly builds.
The SQLXML interface provides methods for accessing the XML data in a datasource as a String, a Reader or Writer, or as a Stream. The XML value may also be accessed through a Source or set as a Result, which are used with XML Parser APIs such as DOM, SAX, and StAX, as well as with XSLT transforms and XPath evaluations.
The revised interface includes the following methods:
- free - closes the object and releases the resources that it held
- getBinaryStream - Retrieves the XML value designated by this SQLXML instance as a stream
- getCharacterStream - Retrieves the XML value designated by this SQLXML instance as a java.io.Reader object
- getSource - Returns a Source for reading the XML value designated by this SQLXML instance
- getString - Returns a string representation of the XML value designated by this SQLXML instance
- setBinaryStream - Retrieves a stream that can be used to write the XML value that this SQLXML instance represents
- setCharacterStream - Retrieves a stream to be used to write the XML value that this SQLXML instance represents
- setResult - Returns a Result for setting the XML value designated by this SQLXML instance
- setString - Sets the XML value designated by this SQLXML instance to the given String representation
I have included some of the sample code we provided in the SQLXML javadoc:
The XML value of the SQLXML instance may be obtained as a BinaryStream using
SQLXML sqlxml = resultSet.getSQLXML(column);
InputStream binaryStream = sqlxml.getBinaryStream();
For example, to parse an XML value with a DOM parser:
DocumentBuilder parser = DocumentBuilderFactory.newInstance().newDocumentBuilder();
Document result = parser.parse(binaryStream);
or to parse an XML value with a SAX parser to your handler:
SAXParser parser = SAXParserFactory.newInstance().newSAXParser();
parser.parse(binaryStream, myHandler);
or to parse an XML value with a StAX parser:
XMLInputFactory factory = XMLInputFactory.newInstance();
XMLStreamReader streamReader = factory.createXMLStreamReader(binaryStream);
Because databases may use an optimized representation for the XML, accessing the value through getSource() and setResult() can lead to improved processing performance without serializing to a stream representation and parsing the XML.
For example, to obtain a DOM Document Node:
DOMSource domSource = sqlxml.getSource(DOMSource.class);
Document document = (Document) domSource.getNode();
To set the value to a DOM Document Node to myNode:
DOMResult domResult = sqlxml.setResult(DOMResult.class);
domResult.setNode(myNode);
To send SAX events to your handler:
SAXSource saxSource = sqlxml.getSource(SAXSource.class);
XMLReader xmlReader = saxSource.getXMLReader();
xmlReader.setContentHandler(myHandler);
xmlReader.parse(saxSource.getInputSource());
To set the result value from SAX events:
SAXResult saxResult = sqlxml.setResult(SAXResult.class);
ContentHandler contentHandler = saxResult.getXMLReader().getContentHandler();
contentHandler.startDocument();
// set the XML elements and attributes into the result
contentHandler.endDocument();
To obtain StAX events:
StAXSource staxSource = sqlxml.getSource(StAXSource.class);
XMLStreamReader streamReader = staxSource.getXMLStreamReader();
To set the result value from StAX events:
StAXResult staxResult = sqlxml.getResult(StAXResult.class);
XMLStreamWriter streamWriter = staxResult.getXMLStreamWriter();
To perform XSLT transformations on the XML value using the XSLT in xsltFile output to file resultFile:
File xsltFile = new File("a.xslt");
File myFile = new File("result.xml");
Transformer xslt = TransformerFactory.newInstance().newTransformer(new StreamSource(xsltFile));
Source source = sqlxml.getSource(null);
Result result = new StreamResult(myFile);
xslt.transform(source, result);
To evaluate an XPath expression on the XML value:
XPath xpath = XPathFactory.newInstance().newXPath();
DOMSource domSource = sqlxml.getSource(DOMSource.class);
Document document = (Document) domSource.getNode();
String expression = "/foo/@bar";
String barValue = xpath.evaluate(expression, document);
To set the XML value to be the result of an XSLT transform:
File sourceFile = new File("source.xml");
Transformer xslt = TransformerFactory.newInstance().newTransformer(new StreamSource(xsltFile));
Source streamSource = new StreamSource(sourceFile);
Result result = sqlxml.setResult(null);
xslt.transform(streamSource, result);
Any Source can be transformed to a Result using the identity transform specified by calling newTransformer():
Transformer identity = TransformerFactory.newInstance().newTransformer();
Source source = sqlxml.getSource(null);
File myFile = new File("result.xml");
Result result = new StreamResult(myFile);
identity.transform(source, result);
To write the contents of a Source to standard output:
Transformer identity = TransformerFactory.newInstance().newTransformer();
Source source = sqlxml.getSource(null);
Result result = new StreamResult(System.out);
identity.transform(source, result);
To create a DOMSource from a DOMResult:
DOMSource domSource = new DOMSource(domResult.getNode());
JDBC 4.0 RowId Interface
Posted by lancea on March 10, 2006 at 03:32 PM | Permalink
| Comments (0)
The RowID interface was added to JDBC 4.0 in order to support the ROWID datatype which is supported by databases such as Oracle and DB2. A ROWID may be thought of as the address for a given row within a table and maybe be considered either logical or physical depending on the underlying data source.
The lifetime of a RowId object may be valid as long as the row is not deleted and the lifetime of the RowId is within the bounds of the lifetime of the RowId's data source.
The DatabaseMetaDataMethod.getRowIdLifetime() can be used to
determine the lifetime validity of the RowId object. The return value from this method is a RowIdLifetime enumerated data-type. Possible values are:
- ROWID_UNSUPPORTED - backend does not support RowIds
- ROWID_VALID_OTHER - lifetime of the RowId is implementation dependant
- ROWID_VALID_TRANSACTION - lifetime of the RowId is within the transaction as long as the row is not deleted
- ROWID_VALID_SESSION - the lifetime of the RowId is as long as the session as long as the row is not deleted
- ROWID_VALID_FOREVER - the lifetime of the RowId is unlimited as long as the row is not deleted
You can obtain a ROWID using the ResultSet.getRowId() method and may use the PreparedStatement.setRowId() to use a RowId in query.
A RowId object value is typically not portable between data sources and should be considered as specific to the data source when using the set or update method in PreparedStatement and ResultSet objects respectively. It is therefore inadvisable to get a RowId from a ResultSet object with a connection ’Foo’ and then attempt to use the RowId in a unrelated ResultSet object with a connection ’Bar’.
JDBC 4.0 Wrapper Interface
Posted by lancea on February 23, 2006 at 02:46 PM | Permalink
| Comments (1)
The Wrapper interface provides a mechanism for JDBC users to be able to access an instance of a resource which has been wrapped for architectural reasons. This mechanism helps to eliminate the need to use non-standard means to access vendor specific resources.
The following JDBC interfaces are subinterfaces of the Wrapper interface:
- java.sql.Connection
- java.sql.DatabaseMetaData
- java.sql.ParameterMetaData
- java.sql.ResultSet
- java.sql.ResultSetMetaData
- java.sql.Statement
- javax.sql.Datasource
The Wrapper interface consists of two methods:
- isWrapperFor - Returns true if this either implements the interface argument or is directly or indirectly a wrapper for an object that does.
- unwrap - Returns an object that implements the given interface to allow access to non-standard methods, or standard methods not exposed by the proxy.
Here is a simple example of using these new methods:
Statement stmt = conn.createStatement();
Class clzz = Class.forName("oracle.jdbc.OracleStatement");
OracleStatement os;
if(stmt.isWrapperFor(clzz)) {
os = stmt.unwrap(clzz);
os.defineColumnType(1, Types.NUMBER);
}
JDBC 4.0 SQLException Enhancements
Posted by lancea on February 21, 2006 at 11:58 AM | Permalink
| Comments (0)
The following enhancements were made in JDBC 4.0 in order to provide a better developer's experience when dealing with SQLExceptions:
- Support for causal relationships
- For-each loop support
- New SQLException sub-classes
Causal Relationship Support
We have added support for the Java SE chained exception mechanism by adding additional constructors allowing for the cause to be specified. The cause could be a non-SQLException, it is just what resulted in the SQLException being thrown.
This feature does not reduce the need for the getSQLException() method as it is possible for multiple unique SQLExceptions to be generated (not all DBs do this currently but could going forward and is allowed by the SQL Standard) due to executing a statement on the backend.
Your code would look something like the following to process the causal relationships:
catch(SQLException ex) {
while(ex != null) {
System.out.println("SQLState:" + ex.getSQLState());
System.out.println("Error Code:" + ex.getErrorCode());
System.out.println("Message:" + ex.getMessage());
Throwable t = ex.getCause();
while(t != null) {
System.out.println("Cause:" + t);
t = t.getCause();
}
ex = ex.getNextException();
}
}
For Each Loop Support
The SQLException class now implements the Iterable interface providing support for the For each loop feature added in J2SE 5.0. The navigation of the loop will walk through the SQLException and its cause (if any):
catch(SQLException ex) {
for(Throwable e : ex ) {
System.out.println("Error encountered: " + e);
}
}
Categorization of SQLExceptions
JDBC 4.0 has introduced two categories of SQLException: SQLTransientException and SQLNonTransientException.
A SQLNonTransientException would be thrown in instances where a retry of the same operation would fail unless the cause of the
SQLException is corrected. The following Exceptions have been added, each extending SQLNonTransientException:
- SQLFeatureNotSupportedException
- SQLNonTransientConnectionException
- SQLDataException
- SQLIntegrityConstraintViolationException
- SQLInvalidAuthorizationException
- SQLSyntaxErrorException
A SQLTransientException will be thrown in situations where a previously failed operation might be able to succeed when the operation is retried without any intervention by application-level functionality. The following Exceptions have been added, each extending SQLTransientException:
- SQLTransientConnectionException
- SQLTransactionRollbackException
- SQLTimeoutException
Please refer to the JDBC specification to see the SQLState Class value code that is associated with the new SQLExceptions.
Correct SQLState for a DataTruncation on a write operation
We have also fixed a long outstanding JDBC bug so that the SQLState of 22001 is now returned for a DataTruncation Exception during a write operation to a data source.
JDBC 4.0 keeps moving forward
Posted by lancea on February 17, 2006 at 09:23 AM | Permalink
| Comments (19)
JDBC 4.0 has just completed public draft review and the EG is working on closing the last few issues. One of the interfaces that I expect to change signficantly is the SQLXML interface.
Here is a list of the major features being added to JDBC 4:
- ROWID Support
- National Character Set Support
- Additional SQLException sub classes
- Improved Blob/Clob support
- SQL XML support
- Ease of Development
- Ability to unwrap implementation classes to make use of vendor specific methods
- Auto loading of Driver class implementations
- Connection management enhancements
Some of the features have been enhanced in the current drops of Mustang (part of the specification evolution).
We have also spent a lot of time trying to clarify and improve the javadoc method and interface descriptions as well as various sections of the JDBC paper spec that have resulted in some confusion in the past for developers. We will continue to review and address as many issues that we can prior to the official release of Mustang.
As we wind down the spec work, we will also be focusing on addressing as many outstanding JDBC bugs as possible.
Exporting Tables from Pointbase to Derby
Posted by lancea on February 06, 2006 at 04:06 PM | Permalink
| Comments (0)
Brian Leonard has a nice article which shows you how to capture the ddl for a table in pointbase and create the same table in Derby using Netbeans 5.0.
Another option for doing this is by using the commander tool and the 'unload database' command:
./startcommander.sh
Do you wish to create a new Database. (Yes (Y) or No (N))? [default: N]:
Enter product to connect with: (Embedded (E) or Server (S))? [default: E]: e
Enter driver to use? [default: [com.pointbase.jdbc.jdbcUniversalDriver]:
Enter database URL? [default: [jdbc:pointbase:embedded:sample]:
Enter Username? [default: PBPUBLIC]:
Enter Password? [default: PBPUBLIC]:
PointBase Commander 5.2 ECF build 294 size restricted version EMBEDDED
Interactive SQL command language. SunOS/5.9
(C) Copyright 2004 DataMirror Mobile Solutions, Inc. All rights reserved.
Licensed to: Sun_customer_demo_use
For commercial version contact PointBase at:
pointbase.com
PHONE: 1-877-238-8798 (US & CANADA)
1-408-961-1100 (International)
WEBSITE: www.pointbase.com
SQL>unload database sampledb.sql;
SQL> unload database sampledb.sql;
SQL> 13 Row(s) Unloaded. (PBPUBLIC.CUSTOMER_TBL)
SQL> 4 Row(s) Unloaded. (PBPUBLIC.DISCOUNT_CODE_TBL)
SQL> 30 Row(s) Unloaded. (PBPUBLIC.MANUFACTURE_TBL)
SQL> 11 Row(s) Unloaded. (PBPUBLIC.MICRO_MARKETS_TBL)
SQL> 9 Row(s) Unloaded. (PBPUBLIC.OFFICE_TBL)
SQL> 4 Row(s) Unloaded. (PBPUBLIC.OFFICE_TYPE_CODE_TBL)
SQL> 15 Row(s) Unloaded. (PBPUBLIC.ORDER_TBL)
SQL> 6 Row(s) Unloaded. (PBPUBLIC.PRODUCT_CODE_TBL)
SQL> 30 Row(s) Unloaded. (PBPUBLIC.PRODUCT_TBL)
SQL> 10 Row(s) Unloaded. (PBPUBLIC.SALES_REP_DATA_TBL)
SQL> 10 Row(s) Unloaded. (PBPUBLIC.SALES_REP_TBL)
SQL> 52 Row(s) Unloaded. (PBPUBLIC.SALES_TAX_CODE_TBL)
SQL> 12 Table(s) Unloaded.
SQL> quit;
The results from executing the 'unload database' command is written in the above example to the file sampledb.sql.
The sampledb.sql file contains all of the DDL requried to create the necessary tables and indexes.
It also contains the DML to insert the data back into the database. The commander command RUN is intended to be used import the data into another pointbase database using the script that was generated.
Here is an example of what the INSERT statments and associated data look like in the generated file:
INSERT INTO "ADVENTURE"."CATEGORY" (
"CATID", "LOCALE", "NAME", "DESCRIPTION", "IMAGEURI" )
VALUES( ?, ?, ?, ?, ? );
{
'ISLAND ','en_US','Island Adventures','Experience an island paradise in a way fit for your needs.','Island_Adventures.gif'
'JUNGLE ','en_US','Jungle Adventures','Experience a jungle paradise in a way fit for your needs.','Jungle_Adventures.gif'
'MOUNTAIN ','en_US','Mountain Adventures','Experience an elevated paradise with a view.','Mountain_Adventures.gif'
'ORBITAL ','en_US','Orbital Adventures','Experience a vacuum paradise with a beautiful view and where no one can hear you scream.','Space_Adventures.gif'
'WESTERN ','en_US','Western Adventures','Enjoy the Wild West.','Western_Adventures.gif'
'SOUTH_POLE ','en_US','South Pole Adventures','Experience a frozen paradise in a way fit for your needs.','SouthPole_Adventures.gif'
};
You could easily edit the file generated from the commander 'unload database' command so that it only consisted of the DDL (it would not be hard to write a program which would process the insert statements and perhaps I will try and find time to do so).
As a simple test, I used the unload database command against the pointbase sample database. I edited the script that was generated making the following changes:
- Removed the phrase Organization Heap from the end of all CREATE Table Statements
- Removed the COMMIT command
- Changed the Boolean datatype to be smallint
- Removed all of the INSERT statements and the associated data
I then created a simple ant script to execute the DDL using the sql target.
I then repeated the same experiment for the sun-appserv-samples database requiring the following additional changes to the generated sql file:
- Made changes as described above for the sample database
- removed the create user commands
- removed the SET PATH commands
- Changed the Decimal precision from 38 to max of 31
- changed the float precision from 64 to max of 52
- The SPECIFIC keyword for CREATE PROCEDURE is not currently supported
- removed the GRANT commands
Converting Pointbase java procedures to work with Derby requires some changes to the java code as well as to the CREATE PROCEDURE statements. Info on creating Derby Java procedures can be found in the Derby Reference manual.
Support for the Boolean datatype should be in the next release of Derby.
JDBC 4.0 Early Draft Review 2 is available
Posted by lancea on October 12, 2005 at 10:31 AM | Permalink
| Comments (0)
The latest draft can be downloaded from here.
We look forward to your feedback.
JDBC 4.0 Early Draft Review is available
Posted by lancea on June 10, 2005 at 07:44 AM | Permalink
| Comments (1)
Features included in the JDBC 4.0 EDR are:
- Ease of Development features intended to assist in reducing the coding burden and maintenance responsibilities of the developer
- Automatic loading of java.sql.Driver implementations
- SQL2003 XML data type Support
- ROWID data type Support
- National Character Set Conversion Support
- Enhanced Blob and Clob support
- SQLException enhancements including J2SE chained Exception support
- Ability to unwrap implementation of JDBC classes to make use of
non-standard JDBC methods provided by vendor implementations
- Enhancements to Connection and Statement interfaces to permit
improved connection state tracking, and greater flexibility when managing Statement objects in pool environments
We look forward to your feedback.
Using Apache Derby with the J2EE SDK
Posted by lancea on November 09, 2004 at 09:40 AM | Permalink
| Comments (3)
Derby is an Open Source project based on the IBM contribution of the Cloudscape RDBMS to Apache. Cloudscape 10 and Derby are currently identical with the exception of what is packaged in the two products for extras.
If you download Cloudscape 10, it includes the DB2 JDBC Universal Driver which is needed for the Cloudscape/Derby Network Server. If you download Derby, you will need to download the DB2 JDBC Universal Driver seperately.
Installing the needed Derby/Cloudscape jar files
To use Derby/Cloudscape, copy the following jar files to $J2EE_HOME/domains/domain1/lib/ext and reboot the J2EE SDK:
For the DB2 Universal Driver:
derby.jar,derbynet.jar,db2jcc.jar,db2jcc_license_c.jar
For the Derby Embedded Driver:
derby.jar
Creating Derby Connection Pools
You can use either the DB2 JDBC Universal Driver or the Derby Embedded Driver when you create your Connection Pools. If you require XA support, currently you must use the Derby Embedded Driver. The work for the Derby Network Server to Support XA is underway, but not yet complete. If you must use the Application Client Container as well as other J2EE containers to access the same database, you need to use the DB2 JDBC Universal Driver and the Derby Network Server.
To create a connection Pool using the DB2 JDBC Universal Driver for Derby, you would specify the following values for your connection pool:
DataSource: com.ibm.db2.jcc.DB2DataSource
Properties:
- databaseName
- serverName
- user
- password
- driverType=4
- portNumber=1527 (default port for the Network Server)
To create a connection pool using the Derby Embedded driver, you would need to specify the following values for your connection pool:
DataSource:org.apache.derby.jdbc.EmbeddedDataSource
Properties:
- databaseName (path to your Derby Database)
- user
- password
Using Derby/Cloudscape with the J2EE SDK CMP container
Currently the J2EE SDK CMP container does not know about Derby/Cloudscape. However Most EJBQL queries work fine and by creating a file called .tpersistence.properties in $J2EE_HOME/domains/domain1/config you will have even
greater success.
The entries in the .tpersistence.properties file for Derby are:
database.apache_derby.QUOTE_CHAR_START=
database.apache_derby.QUOTE_CHAR_END=
database.apache_derby.QUOTE_CHAR_END=
database.apache_derby.SUBSTRING=SUBSTR
database.apache_derby.SUBSTRING_FROM=,
database.apache_derby.SUBSTRING_FOR=,
database.apache_derby.CHAR_LENGTH=LENGTH
database.apache_derby.POSITION=LOCATE
database.apache_derby.POSITION_SEP=,
database.apache_derby.POSITION_SEARCH_SOURCE=true
database.apache_derby.RTRIM=rtrim
database.apache_derby.STRING_CONCAT=||
database.apache_derby.SQRT=SQRT
database.apache_derby.ABS=ABS
database.apache_derby.MOD_FUNCTION_NAME=MOD
database.apache_derby.CONCAT_CAST=VARCHAR
Derby is a powerful Open Source Database which I think you will find works quite well with the J2EE SDK
Sun Java System Application Server Platform Edition 8 2004Q4 Beta is now available
Posted by lancea on September 21, 2004 at 09:04 AM | Permalink
| Comments (1)
A Beta release of Sun Java System Application Server Platform Edition 8 2004Q4 has been made available. You can download the software from the J2EE 1.4 download page .
If you have questions while using the product, you can post your issues to the J2EE SDK forum.
Also if you are interested in joining the Beta program, please refer to the following page for additional information.
EJB 3.0 Spec is available for Early Draft Review
Posted by lancea on July 27, 2004 at 12:37 AM | Permalink
| Comments (13)
The plans for the next release of J2EE 5.0 (formally 1.5) are in full swing. One of the key initiatives is to reduce the complexity for the developers and focus on Ease of Development (EoD).
EJB has always been an area where we have had requests to try and simplify things for the developer. I believe the early draft of the EJB 3.0 is off to a great start in accomplishing this requirement.
One area that has been greatly simplified, is the amount of code that is required to create an EJB. For example, consider the following EJB 2.1 Stateless Session Bean. You would need to code the following (plus create a Deployment Descriptor):
public interface Calculator extends EJBObject {
int add (int a, int b) throws RemoteException;
int subtract (int a, int b) throws RemoteException;
}
public interface CalculatorHome extends EJBHome {
Calculator create() throws CreateException, RemoteException;
}
public class CalculatorBean implements SessionBean {
private SessionContext ctx;
public void setSessionContext(SessionContext ctx) {
this.ctx = ctx;
}
public void ejbCreate () {}
public void ejbActivate () {}
public void ejbPassivate () {}
public void ejbRemove() {}
public int add (int a, int b) {
return a + b;
}
public int subtract ( int a, int b) {
return a - b;
}
}
With EJB 3.0, the above code could be written as:
@Stateless @Remote public class CalculatorBean {
public int add (int a, int b) {
return a + b;
}
public int subtract (int a, int b) {
return a - b;
}
}
That is it! You do not even have to create a Deployment Descriptor.
The Expert Group has been working very hard to address the needs of the EJB community. Please take the time to review the EJB 3.0 Early Draft and give us your feedback.
If you are writing J2EE applications then you should be using Java Application Verification Kit for the Enterprise
Posted by lancea on June 22, 2004 at 08:37 AM | Permalink
| Comments (3)
The Java Application Verification Kit for the Enterprise (J2EE AVK) is a valuable tool for any J2EE developer. The toolkit allows you to validate that your J2EE applications are correctly utilizing the APIs provided by J2EE and helps you to understand whether your application is using vendor specific features.
The newest release of the J2EE AVK provides support for J2EE 1.4 and incorporates some new features that I am sure you will find useful:
- Support for J2EE 1.4, J2EE 1.3 and J2EE 1.2 applications and standalone components
- Dynamic validation of WebServices which utilize Servlet or EJB based endpoints
- Support for component libraries
- A source code scanning mechanism to report the use of proprietary APIs
- Enhanced static verification of your applications and standalone modules
You are probably asking why should I starting using the J2EE AVK if my applications run just fine today? The use of the J2EE AVK will help you to find issues that might work with the current version of your application server, but could fail when you upgrade or migrate to another server.
One simple example of an error that the J2EE AVK will catch:
- You create a Session Bean and specify a transaction attribute for one of the methods on the home interface.
Now the above violates section 17.4.1 of the EJB 2.1 specification and on some application servers the deployment will fail and on some deployment will succeed but the attribute will be ignored.
Even if you have not had a chance to take the J2EE AVK for a test spin, we would be interested in your feedback to the following questions. We will be summarizing the responses as part of our J2EE AVK BOF:
- How often do you encounter portability issues during application development?
- What are your top three compliants when porting your applications from one application server to another?
- What tools if any besides the J2EE AVK do you use to help making porting your applications easier?
- In what areas, would you like to see additional tools to help ease the porting/migration of your applications from one application server to another?
I hope you will give the J2EE AVK a try. You can download a copy of the AVK from here.
To find out more about the J2EE AVK, consider attending one of the following JavaOne sessions:
- BOF-1530, Got Portable Apps? Using the JavaTM AVK to Help Write Portable JavaTM 2 Platform, Enterprise Edition (J2EETM) Applications
- TS-2945, Writing Portable Applications and the Java TM Technology AVK
If you cannot make any of the JavaOne sessions, please stop by the pavilion and visit POD #1225 Java Verified Program - Enterprise Application .
We look forward to seeing you at JavaOne!
Are You Ready for JavaOne?
Posted by lancea on June 04, 2004 at 02:11 PM | Permalink
| Comments (1)
It is hard to believe that JavaOne is fast approaching. It seems that I just got back from last year's. I am now preparing for this year's event (including finishing my presentation!) and there is a lot to think about:
- Where do I stay (and not blow my budget)?
- What sessions do i attend in person?
- Where should I go to eat?
- and of course which parties should i attend?
It looks like another strong year for J2EE related presentations.
If you have not tinkered with the J2EE 1.4 SDK, then you might want to check out:
- JavaTM 2 Platform, Enterprise Edition (J2EETM) Software Development Kit (J2EE 1.4 SDK) Overview, TS-1951
I am sure you are like me and want to see what the future holds. You can get a glimpse of it from the following J2EE sessions:
- J2EETM Platform Version 1.5 and Beyond, TS-3888
- Enterprise JavaBeansTM Architecture 3.0, TS-1861
- Enterprise JavaBeansTM (EJBTM) Technologies 3.0: Simplifying and Enhancing the EJB Persistence Model, TS-2836
- Next-Generation Web Services in the JavaTM Platform, TS-2394
- Web Tier State of the Union, TS-2702
A couple of Web Services sessions also caught my fancy:
- JavaTM 2 Platform, Enterprise Edition (J2EETM) Web Services, TS-1650
- Web Services Interoperability and Performance: JavaTM 2 Platform, Enterprise Edition (J2EETM) and .NET, TS-2797
Another hot J2EE area this year is Business Integration where there are several presentations to choose from:
- JavaTM Business Integration: JSR 208, TS-1056
- JavaTM Business Integration (JSR 208) , TS-2725
- JSR 208:JavaTM Business Integration, The Enterprise View ,TS-2455
This is just a small sampling of some of the really interesting presentations that I found on J2EE. I hope to see you there!
|