13 October 2009

Exploring EclipseLink @OptimisticLocking

Been a while since I've had some fun with JPA, so I decided to spend a little time with it today.

I created a very simple domain model (Employee --> LeaveRecord) to use.



Since I was just intent of doing some quick testing, instead of following the usual route of creating an EJB session facade to expose the @Entity objects, and then exercising that from a client to test things out, I simply created some JUnit4 @Test cases to act as the test clients. These @Test cases exercised the @Entity objects from outside the container, so it was actually a very easy way to go.





One thing I'd never looked at much was the EclipseLink specific annotations, so I decided to take a quick peek around there for something interesting to test. A quick peruse of the EclipseLink documentation drew me to the @OptimisticLocking annotation.  How could you not be optimistic with that!

The goal of the @OptimisticLocking annotation is to direct EclipseLink to use an optimistic locking strategy for the @Entity, directing it to the current property values from the object it is persisting against the data currently in the database to ensure it hasn't changed since it was last read. 

There are several different options available, so I took a look at the differences between the OptimisticLockingType.ALL_COLUMNS and the OptimisticLockingType.CHANGED_COLUMNS options.

The @OptimisticLocking annotation is specified on the POJO.

  @Table(name = "EMPLOYEES")
  @OptimisticLocking(type=OptimisticLockingType.ALL_COLUMNS)
  public class Employee implements Serializable {
      ...
  }
 
Doing simple reads and updates of the Employee @Entity with the eclipselink.logging.level set to FINEST shows the SQL that is created when the different types are applied.

@OptimisticLocking(type=OptimisticLockingType.ALL_COLUMNS)
Connection(26174809)--UPDATE EMPLOYEES SET VACATION_HOURS = ? 
  WHERE ((EMPLOYEE_ID = ?) AND 
  (((((EMAIL_ADDRESS = ?) AND 
      (FIRST_NAME = ?)) AND 
      (LAST_NAME = ?)) AND 
      (SALARY = ?)) AND 
      (VACATION_HOURS = ?)))
   bind => [999, 1, jack.rooster@anon.org1, Jack1, Rooster1, 1.0, 1]

In this configuration, all the fields of the @Entity are contained in the WHERE clause of the UPDATE statement.

@OptimisticLocking(type=OptimisticLockingType.CHANGED_COLUMNS)
Connection(2554341)--UPDATE EMPLOYEES SET VACATION_HOURS = ? 
  WHERE ((EMPLOYEE_ID = ?) AND (VACATION_HOURS = ?))
  bind => [999, 1, 1]

In this configuration, only the updated fields of the @Entity are contained in the WHERE clause of the UPDATE statement.

After testing the @OptimisticLocking annotation and observing that I worked as expected in my test environment, the next step was to test what happens when a change is made to an object after it has been read, but before it is updated.

The flow is essentially this:

  T1 --> read employee 1
  T1 --> create and start T2
    T2 --> read employee 1
    T2 --> update employee 1
    T2 --> persist employee 1
  T1 --> update employee 1
  T1 --> persist employee 1  *expect OptimisticLockingException*

The @Test case below represents this sequence.

@Test(expected = RollbackException.class, timeout = 20000)
public void checkOptimisticLocking() throws Exception {

    Employee pre = employeePM.find(Employee.class, Long.valueOf(1));

    // do the separate thread update of the specified employee with value
    EmployeeTestOptimisticLockingHelper t = 
        new EmployeeTestOptimisticLockingHelper(1L, -999L);

    t.start();
    t.join(10000);

    // Now do the local the update
    // should throw OptimisticLockException
    employeePM.getTransaction().begin();
    pre.setVacationHours(999L);
    employeePM.getTransaction().commit();
}

The EmployeeTestOptimisticLockingHelper is a separate class that is executed via another Thread.  This allows it to perform the change using a separate EntityManager.

public class EmployeeTestOptimisticLockingHelper extends Thread {

    private Long id;
    private Long newval;

    public EmployeeTestOptimisticLockingHelper(Long id, Long newval) {
        this.id = id;
        this.newval = newval;
    }

    @Override
    public void run() {
        EntityManager em = null;
        try {
            em = Persistence.createEntityManagerFactory("CompanyUnit")
                            .createEntityManager();
            Employee emp = em.find(Employee.class, id);
            em.getTransaction().begin();
            emp.setVacationHours(newval);
            em.getTransaction().commit();
        } catch (Exception e) {
            e.printStackTrace();
        } finally {
            em.close();
            interrupt();
        }
    }
}

When this @Test is executed, it results in the following exception being thrown, demonstrating that the specified @OptimisticLocking model is working as expected.

[EL Finer]: 2009.10.13 14:54:43.796--ClientSession(14031599)--Connection(26174809)--rollback transaction
[EL Warning]: 2009.10.13 14:54:43.796--UnitOfWork(26953544)--javax.persistence.OptimisticLockException: Exception [EclipseLink-5006] (Eclipse Persistence Services - 1.0.2 (Build 20081024)): org.eclipse.persistence.exceptions.OptimisticLockException
Exception Description: The object [Employee 1 Jack1 Rooster1 jack.rooster@anon.org1 999 $1.0] cannot be updated because it has changed or been deleted since it was last read. 
Class> sab.demo.company.domain.Employee Primary Key> [1]
 at org.eclipse.persistence.internal.sessions.RepeatableWriteUnitOfWork.commitToDatabase(RepeatableWriteUnitOfWork.java:480)
 at org.eclipse.persistence.internal.sessions.UnitOfWorkImpl.commitToDatabaseWithChangeSet(UnitOfWorkImpl.java:1330)
 at org.eclipse.persistence.internal.sessions.RepeatableWriteUnitOfWork.commitRootUnitOfWork(RepeatableWriteUnitOfWork.java:159)
 at org.eclipse.persistence.internal.sessions.UnitOfWorkImpl.commitAndResume(UnitOfWorkImpl.java:1002)
 at org.eclipse.persistence.internal.jpa.transaction.EntityTransactionImpl.commitInternal(EntityTransactionImpl.java:84)
 at org.eclipse.persistence.internal.jpa.transaction.EntityTransactionImpl.commit(EntityTransactionImpl.java:63)
 at sab.demo.testdomains.EmployeeTest.checkOptimisticLocking(EmployeeTest.java:149)

And the JUnit runner shows the @Test passes as expected, since it is configred to expect the wrapper javax.persistence.RollbackException to occur.



12 October 2009

Managing WebLogic servers with JConsole

Another fine blog entry from Oracle's JMX guru, Philippe Le Mouel.

http://blogs.oracle.com/WebLogicServer/2009/10/managing_weblogic_servers_with.html

07 October 2009

Getting samples schema to run against an Oracle DB

The samples domain that is able to be optionally created with a WebLogic Server installation provides a wealth of useful examples, covering core JavaEE APIs through to an full sample application called MedRec.

By default, the samples domain installs and uses a PointBase database to host its application data, which allows it to work immediately after installation with no additional requirements to install, configure a database.

It probably goes without saying, but there is interest in making the samples also work with an Oracle database.

When the samples domain is created, it provides its own set of online documentation that describes how to configure, install and use the various samples.

One section in the doc notes how to install the sample schema against an Oracle database, which ultimately results in the execution of the demo.ddl file against the specified Oracle database instance.

>ant db.setup.oracle


I just tried it against an Oracle XE (10.2) database I have lying around and noticed some problems when it executed, based on inserting date format data into several of the tables used by the MedRec application.

[sql] Failed to execute:   INSERT INTO patient (id,first_name,middle_name,last_name,dob,gender,ssn,address_id,phone,email) VALUES (101,'Fred','I','Winner','1965-03-26','Male','123456789',101,'4151234564','fred@golf.com')
[sql] java.sql.SQLDataException: ORA-01861: literal does not match format string

[sql] Failed to execute:   INSERT INTO record (id,pat_id,phys_id,record_date,vital_id,symptoms,diagnosis,notes) VALUES (101,101,102,'1999-06-18',101,'Complains about chest pain.','Mild stroke.  Aspiran advised.','Patient needs to stop smoking.')
[sql] java.sql.SQLDataException: ORA-01861: literal does not match format [sql] 

[sql] Failed to execute:   INSERT INTO prescription (id,pat_id,date_prescribed,drug,record_id,dosage,frequency,refills_remaining,instructions) VALUES (101,101,'1999-06-18','Advil',101,'100 tbls','1/4hrs',0,'No instructions')
[sql] java.sql.SQLDataException: ORA-01861: literal does not match format string


To workaround this, I found that by editing the $WLS_HOME\wlserver_10.3\samples\server\examples\src\examples\common\demo.ddl and appending the DATE function to the respective insert statements, the demo.ddl script executed without error and the data was inserted correctly.

Here are examples of the row inserts that have been modified:

INSERT INTO patient (id,first_name,middle_name,last_name,dob,gender,ssn,address_id,phone,email) 
VALUES 
(101,'Fred','I','Winner',DATE'1965-03-26','Male','123456789',101,'4151234564','fred@golf.com');

INSERT INTO record (id,pat_id,phys_id,record_date,vital_id,symptoms,diagnosis,notes) 
VALUES 
(101,101,102,DATE'1999-06-18',101,'Complains about chest pain.','Mild stroke.  Aspiran advised.','Patient needs to stop smoking.');

INSERT INTO prescription
(id,pat_id,date_prescribed,drug,record_id,dosage,frequency,refills_remaining,instructions) VALUES
(101,101,DATE'1999-06-18','Advil',101,'100 tbls','1/4hrs',0,'No instructions');

Once that was done, the demo.ddl executed successfully and the schema was created in the specified Oracle database.

25 September 2009

Basic WebLogic Server JMX Client

Good article by Philippe covering the creation of a simple JMX client for WLS.

http://blogs.oracle.com/WebLogicServer/2009/09/sample_weblogic_jmx_client.html

14 September 2009

Using Identity Based Connection Pooling with WebLogic Server

From an OTN how-to I recently created:

Using Identity Based Connection Pooling with WebLogic Server

The typical model of interaction an application server has with a database is through the use of datasources.

A datasource is an entity that is configured with appropriate information to allow it to create and manage connections with a database, and to hand these out to applications when they request them. A datasource typically creates pools of connections for effiency purposes and shares these amongst applications that make use of it.

In the typical datasource use case, all the connections the datasource creates use the same username and password. This results in all access to the database being performed using the same database credentials. In most cases this is perfectly acceptable and handled as part of the overall application architecture when needing to dealing with shared, partioned data.

For some rare cases, requirements can exist where it’s necessary to preserve the application user identity in some form all the way down to the database. This could be for the purposes of restricting information access, establishing audit trails, resource scheduling based on user context, etc.

To support these two different usage requirements, WebLogic Server supports two different types of connection pools through its datasource implementation:
  • Homogeneous: Regardless of the current user of the application, all connections in the pool use the same security credentials to access the DBMS.
  • Heterogeneous: Allows applications to use a JDBC connection with a specific DBMS credential by pooling physical connections with different DBMS credentials.
[See full article on OTN: http://www.oracle.com/technology/products/weblogic/howto/identity-pools/index.html]

03 September 2009

Switching Between JRockit and Sun JDK with WebLogic Server

Need to swap between JRockit and the Sun JDK when starting your WebLogic Server instance?

Looking at the start scripts $DOMAIN_HOME/bin/setDomainEnv.cmd, I just realized that this operational task is basically taken care of in the scripts we have.

To swap between the Sun JDK and JRockit to launch a WLS instance, all you need to do is set the JAVA_VENDOR environment variable to either "Sun" or "Oracle" and the scripts will take of launching WLS using the specified JDK.

Snippets from setDomainEnv.cmd:
set BEA_JAVA_HOME=d:\wls1031\jrockit_160_05_R27.6.2-20
set SUN_JAVA_HOME=d:\wls1031\jdk160_11

if "%JAVA_VENDOR%"=="Oracle" (
set JAVA_HOME=%BEA_JAVA_HOME%
) else (
if "%JAVA_VENDOR%"=="Sun" (
set JAVA_HOME=%SUN_JAVA_HOME%
) else (
set JAVA_VENDOR=Sun
set JAVA_HOME=d:\wls1031\jdk160_11
)
)

Where JAVA_HOME is then used by startWebLogic.cmd script when it launches the WLS instance to identify the JDK to use.

Snippets from startWebLogic.cmd
%JAVA_HOME%\bin\java %JAVA_VM% %MEM_ARGS% 
-Dweblogic.Name=%SERVER_NAME% 
-Djava.security.policy=%WL_HOME%\server\lib\weblogic.policy 
%JAVA_OPTIONS% 
%PROXY_SETTINGS% 
%SERVER_CLASS%

With this information at hand, then switching between the two different JDKs is as simple as setting an environment variable before launching WebLogic Server.

Using JRockit:
>set JAVA_VENDOR=Oracle
>startWebLogic.cmd
...
d:\wls1031\JROCKI~1.2-2\bin\java -jrockit -Xms512m -Xmx512m -Dweblogic.Name=AdminServer ...

And just as easy to switch back to Sun. Note here that you could just unset the JAVA_HOME environment variable, which will set the script to use whatever default was configured when the domain was created.

Using Sun JDK:
>set JAVA_VENDOR=Sun
>startWebLogic.cmd
...
d:\wls1031\JDK160~1\bin\java -client -Xms256m -Xmx512m -Dweblogic.Name=AdminServer ...

WebLogic Server Startup and Shutdown Classes

WebLogic Server supports the use of server level startup and shutdown (SU/SD) classes, which are invoked by the server when it is starting up, and conversely when it is shutting down.

The initial implementation of this functionality (not sure of the release but circa 6.x I believe) required the SU/SD classes to implement proprietary WebLogic Server interfaces:
  • weblogic.common.T3StartupDef
  • weblogic.common.T3ShutdownDef
As of WebLogic Server 9.0, these interfaces were marked as deprecated.

It appears that with the introduction of the new application lifecycle listeners feature at the same time, this has resulted in reduced visbility of the new POJO based SU/SD class approach in the documentation.

So here's a brief explanation.

With the deprecation of the earlier SU/SD interfaces, a new and simpler POJO based was introduced for SU/SD classes. This requires only that a SU/SD class only has to have a static main(String args[]) method, which the server will invoke after instantiating the class. No WLS specific interfaces are needed any longer. Any arguments that were configured for the SU/SD class configuration are passed to it via the String[] args parameter.

The POJO based SU/SD class still follows all the same deployment and configuration steps used by the previous model -- the class needs to be made available on the server classpath, the SU/SD class is configured via the console with the requisite parameters and settings, and ultimately stored as an entry in config.xml.

Startup Class:
package sab.demo.utils;

public class StartupMain {
/**
* @param args
*/
public static void main(String[] args) {

log(StartupMain.class.getName() + "::main");
log("Arguments::");
for(int i=0;args!=null && i<args.length;i++) {
log("  arg[" + i + "]: " + args[i]);
}
}

private static void log(String msg) {
System.out.printf("  --> [SAB]: %s\n", msg);
}
}


WLS Console:


config.xml:
<startup-class>
<name>StartupMain</name>
<target>AdminServer</target>
<deployment-order>1000</deployment-order>
<class-name>sab.demo.utils.StartupMain</class-name>
<arguments>arg1 arg2 arg3</arguments>
<failure-is-fatal>false</failure-is-fatal>
<load-before-app-deployments>false</load-before-app-deployments>
<load-before-app-activation>true</load-before-app-activation>
</startup-class>

28 August 2009

OC4J 10.1.3.5 Released


We published OC4J 10.1.3.5 to OTN this week.

This is a maintenance release, but it has a sprinkling of new features that had been in the works for a while and have now made it into an official OC4J release.

Download location:

http://www.oracle.com/technology/software/products/ias/htdocs/utilsoft.html

Updated Documentation:


http://download.oracle.com/docs/cd/E14101_01/index.htm


Release Notes:

http://download.oracle.com/docs/cd/E14101_01/doc.1013/e15342/oc4j.htm

New Feature List:

http://download.oracle.com/docs/cd/E14101_01/doc.1013/e15342/oc4j.htm#BDCCBAFD

I really like the small set of new features that have been added.

My pick of them, is probably the Peek utility. Peek provides a nice Web based front end for singing and dancing, all powerful, classloading functionality we've had in OC4J 10.1.3.x since its first dot zero release. Peek lets you drive easily around the classloading environment, visualizing the loader tree and letting you to drill down into it to see code-sources, packages, classes, etc. It also lets you execute the wide set of classloader queries we provide, directly from a Web browser. Really neat stuff.

There are also a set of new commands added to the admin_client utility, to support actions such as getting a listing of all deployed applications/web bindings, importing (and removing) shared libraries into applications, and a restart app command. Nice additions.

If you are still using OC4J and haven't yet moved over to the world of WebLogic Server, I reckon checking out OC4J 10.1.3.5 would be worth your time.

24 August 2009

WebLogic Server in the Amazon EC2 Cloud

I've long been wanting to try the WebLogic Server AMI image on the Amazon EC2 Cloud, but haven't yet had a chance to do it.

The description for how to get started is here:

http://www.oracle.com/technology/tech/cloud/pdf/wlsami_ref.pdf

The Amazon Machine Image (AMI) repository where WebLogic Server 10.3 is here:

http://developer.amazonwebservices.com/connect/kbcategory.jspa?categoryID=205

Has anyone out there given this a shot? What were your thoughts, how did it go?

20 August 2009

Hosted WebLogic Server Documentation Changes

Just received a note regarding changes that are occuring to the WebLogic Server online documentation.

As of Friday, August 7, 2009, all BEA product documentation currently available on the BEA online documentation site (edocs.bea.com) will be available on the Oracle Technology Network (OTN).

Please note: Effective Friday, August 31, 2009, at 5:00pm PDT, the BEA online documentation site will be decommissioned.

The OTN URL for legacy WLS release documentation is:

http://www.oracle.com/technology/documentation/weblogic_server.html

The OTN URL for legacy BEA release documentation is:

http://www.oracle.com/technology/documentation/bea_doc_index.html