Saturday 24 February 2007

JDeveloper script mastery with Ant

In my earlier days as a C++ (cough) newbie programmer on a real-time database system (a long story - Oracle just wasn't fast enough apparently), I had the pleasure of working with a team of C++ UNIX gurus. When I mean gurus I mean gurus with a capital URU.

You'll know these sort of guys if you ever meet one. Most have the ability to debug the UNIX kernel using a tuning fork sitting on the disk platter. They also as a rule love Emacs and its serious macro scripting facilities. They wouldn't think twice of writing an Emacs script to turn on the coffee pot or change the weather.

As I was tone deaf I decided to leave these gurus and stick with Oracle instead, and never looked back .... until now where I've been hacking away with C++'s teenage monster Java for the last few years.

JDeveloper, my IDE of choice, is no Emacs (thank goodness). But in a nod to my C++ colleagues of past, what sort of scripting can we do in JDeveloper? Ant comes to the rescue.

Ant is an XML cross-platform based scripting language for building applications in an automated fashion. Imagine you want to write a script to compile your Java program and FTP it to a server in an automated manner, Ant is the tool to use.

Ant has become such a powerful little beastie that it goes beyond builds, and here's a little hack I like to use which hopefully will highlight its usefulness.

On my Windows XP laptop I don't let Windows services start my hack-and-slash (aka development) Oracle 10g Enterprise Edition database automatically as it takes up far too many resources. However once JDev has started it goes hand-in-hand that I'd like the database started too. Starting the RDBMS via the Windows admin tools is far too many mouse clicks, and writing a batch file on my filesystem that I loose every time I rebuild my lappy doesn't work either.

However as I'm always working in JDev, I can write an Ant script to do the same thing.

As you already know, the Windows services required to run the Enterprise Edition of the RDBMS are:

  • OracleServiceXX (where XX is the RDBMS service name)
  • OracleOraDb10g_home1TNSListener

To start these from DOS you can use the command:

net start (servicename)

To start the services in Ant and JDeveloper, we use JDeveloper to create the basic Ant script file called build.xml. This can be created via the New Gallery selecting All Technologies -> General -> Ant -> Empty Buildfile.

By default within JDeveloper's Application Navigator the build file is placed under the Resources node of your current project.

The XML Ant buildfile I use to start and stop the RDBMS looks as follows:

<?xml version="1.0" encoding="windows-1252" ?>
<project>
  <target name="startDB">
    <exec executable="net">
      <arg value="start"/>
      <arg value="oracleservicexx"/>
    </exec>
    <exec executable="net">
      <arg value="start"/>
      <arg value="oracleoradb10g_home1tnslistener"/>
    </exec>
  </target>
  <target name="stopDB">
    <exec executable="net">
      <arg value="stop"/>
      <arg value="oracleoradb10g_home1tnslistener"/>
    </exec>
    <exec executable="net">
      <arg value="stop"/>
      <arg value=" oracleservicexx"/>
    </exec>
  </target>
</project>

(Again were oracleservicexx is your actual db service name)

Note that the buildfile is comprised of a project, and two targets startDB and stopDB. A target is a named runnable part of your buildfile. JDeveloper has out of the box support to run the specific targets by right clicking on the build.xml file, selecting Run Ant Target, then selecting the particular target you wish to run in the submenu.

Within each target there is an exec tag to execute an external command. In this case you'll note I'm calling the Windows net command, passing in two arguments with the arg tag.

That's it. It is a very simple example but again a useful little hack. Once you execute the target, the Ant output is logged to JDeveloper's log window.

As you can imagine you can use Ant for all sorts of house keeping exercises. Rather than doing all the house work yourself, let Ant do the work for you. So no longer are DBAs the script masters, developers can be too.

Tuesday 20 February 2007

JDeveloper and the art of the rollback

It's tempting for beginner ADF programmers to map the Cancel button to the Rollback operation on an edit page within an ADF BC/Faces application, to lose the current changes the user has made within the edit page. However issuing a rollback in a JDeveloper application using ADF BC can have a gotcha for beginner programmers, or those coming from a traditional Forms background.

A side-effect of issuing a rollback is that any open iterators have their current row pointer reset to the first record in the record set. This presents a confusing situation to the user on navigating back to (for example) a page showing a read-only table with a record selector, as the table will be "magically" reset to the first record in the table, which could in fact be a different row set in the table.

The following describes the steps in implementing a method for overriding the side-effects of the rollback, and an alternative method from calling the Rollback at all. Which you use is your choice based around the functionality you require.

Restore current row after rollback

The first method is based on Steve Muench's undocumented example Restore Current Row After Rollback #68. This method changes the manner in which the ADF BC framework handles rollbacks for specified View Objects. It can be applied to all View Objects or a selective set as implemented by the programmer.

The changes for this solution lie in both your ADF BC Model project and your ADF Faces ViewController project. Follow these steps to implement:

ADF BC Model Project

1) Create a new class in your model layer called CustomViewObjectImpl similar to the recommendations in the Advanced Business Components Techniques section of the ADF Guide for Forms/4GL Programmers. Copy the same Java class code from Steve Muench's example into this new class, specifically the beforeRollback and afterRollback methods. Change the package declaration to where ever you've placed the new class.

2) In your existing ApplicationModuleImpl, add this routine:

protected void prepareSession(Session session) {
super.prepareSession(session);
getDBTransaction().setClearCacheOnRollback(false);
}

3) For all View Objects where you want to avoid the rollback side effect, you need to extend their ViewObjectImpl custom classes as follows:

public class myViewObjectImpl extends CustomViewObjectImpl

....and import the CustomViewObjectImpl.

4) In addition in each custom ViewObjectImpl class, and the following routine:

protected void create() {
super.create();
setManageRowsByKey(true);
}

ADF Faces ViewController Project

5) In *each* web page where you have a rollback button, instead of calling the Rollback actionBinding defined within the pageDef, we want the button to call the following code:

public void executeRollbackActionAfterDisablingExecuteOnRollback() {
FacesContext fc = FacesContext.getCurrentInstance();
ValueBinding vb = fc.getApplication().createValueBinding("#{bindings}");
DCBindingContainer bindings = (DCBindingContainer)vb.getValue(fc);
if (bindings != null) {
bindings.setExecuteOnRollback(false);
OperationBinding ob = bindings.getOperationBinding("Rollback");
if (ob != null) {
ob.execute();
} else {
throw new RuntimeException("Binding container has no 'Rollback' action binding");
}
}
}

Note that this solution still requires the pageDef for each page with the rollback button includes the "Rollback" binding. If you deleted the rollback button from the JSF page, JDeveloper will have automatically deleted the pageDef Rollback binding, so you will need to recreate it if need be.

6) Rather than duplicating the above code in each backing bean, it would better be placed and defined once in a utility class. In Steve's example he creates a class RollbackHelperBase, wrapping the above code in the following method spec:

public void executeRollbackActionAfterDisablingExecuteOnRollback() { ... }

7) The button then makes a call to its associated backing bean method onRollback on as follows:

<af:commandButton text="Rollback" immediate="true" action="#{TestPage.onRollback}">

8) The backing bean should extend the RollbackHelperBase:

public class myBackingBean extends RollbackHelperBase { .... }

9) and the onRollback method makes a call to the parent's method executeRollbackActionAfterDisablingExecuteOnRollback as follows:

public String onRollback() {
executeRollbackActionAfterDisablingExecuteOnRollback();
return "navigateToWhereEver";
}

Now when you run your webpage and test the rollback button, for any web page iterator that has been extended with the custom View Object class, the iterator row currency will not be reset.

Steve's solution has the advantage that it a generic enough that it can be applied across all ViewObjects and their associated iterators. The disadvantage of this approach is it requires more code, and to be effective across your app you need to extend each ADF BC ViewObjectImpl to the custom CustomViewObjectImpl class, as well as each rollback button with ADF Faces calling the executeRollbackActionAfterDisablingExecuteOnRollback functionality. The code changes however can be minimised through the use of a customer ADF BC framework.

Drop the current row changes

An alternative approach to Steve's solution is to not change the rollback functionality, but instead just lose the changes to the current row the user is editing. This can be done on the JSF side by retrieving the current row from the iterator, and instructing the row to drop any changes since the beginning of the transaction, including dropping any new rows.

To implement this solution, follow these steps:

1) In your edit page, create a new commandButton whose action attribute makes a call to the following backing bean code:

public String dropChangesAndReturn() {
FacesContext fc = FacesContext.getCurrentInstance();
ValueBinding vb = fc.getApplication().createValueBinding("#{bindings}");
DCBindingContainer bc = (DCBindingContainer)vb.getValue(fc);

DCIteratorBinding iterator = bc.findIteratorBinding("EmployeesView1Iterator");
ViewObject vo = iterator.getViewObject();
Row row = vo.getCurrentRow();

if (row != null) {
row.refresh(row.REFRESH_UNDO_CHANGES | row.REFRESH_FORGET_NEW_ROWS);
iterator.getDataControl().commitTransaction();
}
return "SomeNavigationRule";
}

2) For the commandButton, set it's immediate attribute to true.

That's it. A smaller solution but dependent on you knowing the iterator name, and adding to all edit pages where you want to drop the row.

Thanks and final comments

Thanks to Steve Muench for giving permission to document his undocumented example # 68, and if I remember correctly to Frank Nimphius and Didier Laurent for their original assistance on the second solution on OTN and via Support way back in 2004 when I was a wee JDeveloper schnapper.

As there is a large amount of text above I've surely made an error at some point. If you find an error please include a comment and any fix and I'll append the above post to the benefit of other readers - thanks!

Saturday 10 February 2007

Another JDeveloper blogger

In my role as a committee member of the Australian Oracle User Group (AUSOUG), I like to promote local Oracle talent in the user community beyond Oracle's own employees, be it by presentations or online efforts. Australia surprisingly has little Oracle blogging activity (Dizwell being the exception), though we are a big adopters of new technology and heavily use Oracle.

I'd like to point you to Brenden Anstey's blog. Brenden is a regular poster on Oracle's JDeveloper OTN forums and has many interesting insights and questions into the world of JDeveloper. In fact Brenden and I bumped into each other on OTN a year or so ago, realised we are both from the same home town, and have kept in touch since. Brenden was kind enough to present on my request on JDeveloper at the AUSOUG conference in both Melbourne and Perth on his experiences with JDeveloper too. That shows a level of professionalism beyond the norm by that act alone, along with his generous support on OTN.

Brenden isn't currently blogging regularly, but hopefully this will encourage him to start listing his favourite hints and tips. In particular check out his post regards JDeveloper vs CVS. A number of sites I've been at have huge headaches of using the two, so his post is valuable to have a look at.

If anybody else is aware of any other Australian Oracle bloggers I'd be keen to hear of them.

Thursday 8 February 2007

Get your dirty little hands on

I recently had the privilege of getting my grubby little hands on Peter Koletzke's and Duncan Mill's latest book Oracle JDeveloper 10g for Forms & PL/SQL Developers. I thought I'd write an impromptu mini-review, because overall I'm a fan of this book for JDeveloper beginners from my own experience of flogging JDeveloper on the black market.

Learning JDeveloper and the associated Application Development Framework (ADF) technologies such as ADF Business Components (ADF BC) and ADF Faces (Oracle's implementation of JavaServer Faces) is not an easy task. Full stop. Texts that make an effort to reduce the learning curve are essential for beginners.

At this time there are really only 2 texts for JDeveloper 10.1.3, specifically this guide, and Oracle's own ADF Developer's Guide for Forms/4GL Developers.

Earlier texts for the "10g" version of JDeveloper exist, but don't get caught out. 10g for JDeveloper, like other Oracle products, actually refer to a number of versions. For example the Oracle JDeveloper 10g Handbook which was co-authored by Avrom Roy-Faderman, Peter Koletzke and Paul Dorsey refers to the 10.1.2 release, not 10.1.3 release of JDeveloper. This older text is dated in parts as it doesn't consider ADF Faces. In turn though, this older text is still useful as it gives another explanation of the JDeveloper technologies such as ADF BC.

There are potentially three groups of people interested in learning JDeveloper; beginner Java programmers, traditional Oracle Forms and PL/SQL programmers, and other experienced Java programmers interested in both what the JDeveloper IDE and ADF frameworks to offer. As the title of this book suggests, it is aimed at the Forms and PL/SQL crew. However it is also applicable to the later group, experienced Java programmers, who want a guide for learning the IDE and framework.

Considering the new guide, it's useful to consider what it isn't: it isn't a book to learn Java, though it does have a "basics" Java chapter; it isn't a book to get your head around the entire JDeveloper IDE, it focuses on the IDE parts that support ADF BC and ADF Faces; it isn't a book to learn the entire set of Java frameworks that JDeveloper supports, including Oracle's own Toplink, nor EJBs; and finally it isn't a reference book, as it reads like one long tutorial.

As a tutorial then, what does this book do? Well this is where I'm impressed.

A few years back thanks to a lucky opportunity I made the jump from Forms to JDeveloper. The tutorials at the time focused on creating web-pages, then the ADF BC side, then other bits in time.

I've found over this time that my learning was backwards. As a Forms programmer I had little knowledge of Java which would have been useful (luckily I was a C++ coder in a former life, so this went okay for me), little knowledge of J2EE, no knowledge of JSPs, no knowledge of web applications, including HTTP request-responses and much more.

Since the beginning I've been back filling that knowledge and now finally know far too much. Now, JDeveloper touts itself as an "end-to-end" development tool meaning it supports database development, through creating a Java persistence layer, and creating web pages and deploying. This book is the missing part because it explains to the inexperienced Forms and PL/SQL programmers all the bits you need to know before you start putting those web pages together; it's not just about the flashy bits.

So the key to this book, is that yes, it is a long tutorial building an application from one end to the other, but it takes time out to talk about concepts the authors think you should know to supplement your knowledge.

Chapters that I thought out-of-the-box and beneficial to a beginner programmer included; Web Communications - how does HTTP request and response work - which is the underpinnings of the whole web gig; Required Web Languages - a discussion on languages besides Java that you'll need to pick up; and JavaServer Faces Basics, including what JSF components you really need to know.

Also I was a pleasantly surprised to find a chapter on Application Design Principles, including best practices, standards, and creating JSF templates, something I think missing and yet to be considered appropriately elsewhere in detail.

In any review you need to be critical somewhere, and besides some easily forgivable editorial mistakes, I think the one chapter included at the end on JHeadstart was inappropriate given this is an Oracle Consulting product that needs to be purchased separately. I would have preferred a discussion of OC4J under OEM on OAS as this is where your program goes and provides its own set of learning challenges. While OAS is not free, and JDeveloper doesn't haven't to be installed into OC4J (other J2EE servers are supported), it is the defacto choice for most existing Oracle sites with Forms and other similar development tools.

Readers need to understand that the book does have a large overlap with the ADF Developer's Guide for Forms/4GL Developers so you may not regards it is as good value. However to myself, this is not necessarily a bad thing as the explanation of comments from a 3rd party is often useful I find.

Readers must also note that once completing this book, you wont be an expert JDeveloper-er.... you'll be the over the first step of many on the way to productivity in the JDev environment. There is no golden chalice in IT, so don't have unrealistic expectations.

However you've got to start somewhere and I recommend this book as a great beginner guide. I've also found it useful for myself as it provides a good A.B.C of how to explain JDeveloper concepts to others in a logical fashion.

For the record both authors are well known in the Oracle arena. For myself I know of Peter Koletzke from his presentations at Oracle OpenWorld, among other sources including his website, and Duncan Mills from his blog and role as JDeveloper Principal Product Manager.

Sunday 4 February 2007

<af:page> bug or another tofu conspiracy?

Ever jump to the wrong conclusion just because it's easier? I'm that sort of guy. For instance if the milk is off, I leap right in and rant about the soy milk conspirators, how they've poisoned the dairy industry, and that they're the source of all the world's woes (including tofu).

And why should programming be any different? I've been having an on/off battle with the ADF Faces <af:page> and <af:panelPage> tags to render correctly in JDeveloper. So far I've blamed the whole GM crowd, Cobol programmers, and John Howard for good measure.

....but as usual it turns out the problem, might just, um, be me.

In JSF projects I regularly setup an <af:page> as detailed in section 19.2 Using Dynamic Menus of the JDev for 4GL/Forms guide to create dynamic menu structures. And I would expect to see this menu structure:

However, when quickly demonstrating the component rather than taking time to do it properly, I often receive the following look and feel at runtime when I drill down inside the menu structure?


For my first menu page it usually works as I expected, but for my other menu pages that I created on the fly, well..... where did that "Skip navigation elements to page contents" hyperlink come from? Why does it say SelectPage2 rather than showing the commandMenuItem? Why is the menu component only half rendered? Why doesn't it happen all the time? Why? Why? Why?

After some head scratching, a few serious but failed attempts to blame Larry, and a little spare time to actually sit down and look at the problem, I worked out it was my mistake (again).

When you create a JSF page within JDeveloper, the empty page often looks like this (I've trimmed the surrounding tags for simplicity):

<f:view>
  <html>
    <head>
      <meta http-equiv=\"Content-Type\" 
            content=\"text/html; charset=windows-1252\"/>
      <title>My Page Title</title>
    </head>
    <body><h:form></h:form></body>
  </html>
</f:view>

From here, on the first page I'd start dragging in data-bound components from the Data Control Palette, then add my <af:page> control, ending up with something like this:

<f:view>
  <afh:html>
    <afh:head title=\"Page 1\">
      <meta http-equiv=\"Content-Type\" 
            content=\"text/html; charset=windows-1252\"/>
    </afh:head>
    <afh:body>
      <h:form>
        <af:page title=\"Page 1\" var=\"node\" 
                 value=\"#{menuModel.model}\"> 
          <f:facet name=\"nodeStamp\">            
            <af:commandMenuItem text=\"#{node.label}\" 
                                action=\"#{node.getOutcome}\"/>
          </f:facet>          
          .... some data-bound components ....
        </af:page>
      </h:form>
    </afh:body>
  </afh:html>
</f:view>

Note that JDeveloper converts the original <html>, <head> and <body> tags to ADF Faces <afh:html>, <afh:head> and <afh:body> tags respectively when we've dragged in the data-bound components.

And that's where the issue lies, because later I wanted to add the <af:page> code that I'd written to other pages. So when I created a new page, I'd copy across the <af:page> code, but forgot to copy the <afh:html>, <afh:head> and <afh:body> tags. Those tags among other things take responsibility for loading in the ADF Faces Skin files (CSS style sheets), and a bunch of other smarts needed by such tags as the <af:page> tag, so I needed to copy these additional tags too.

So hopefully next time you're attempting to demonstrate the powers of ADF Faces and JDeveloper, you wont blame everybody but the coder at hand like I do.