Year: 2014

Google Chrome developer tip: extended reload button

When the “Developer Tools” console is open in Google Chrome, the reload button gets a drop down menu with some options which are quite useful when developing web applications:

  • Normal Reload: just reload the page, same as F5
  • Hard reload: reload the page, but do not use anything from the cache for this request
  • Empty Cache and Hard Reload: Empty the cache and reload (which is implicitly a hard reload then, since the cache is empty)
To actually open the menu, it is necessary to press and hold the reload button a short time, similar to the “back” button where chrome displays a page history then. Also, the functionality is only available when at the same time the developer console is open for the specific page – the developer console can be opened by pressing F12. See also What’s the difference between “Normal Reload”, “Hard Reload”, and “Empty Cache and Hard Reload” in chrome? for some additional information.

About the scope of definition objects

In Oracle ADF, each definition object (those objects which are used as the templates for actual objects) has a scope which can be either session based or application based (shared between sessions). The following diagram shows a rough (and probably somewhat incomplete) overview of the runtime structure of some of the most common objects (Entity object, View object, Application Module) and their corresponding definition objects:

Creating definition objects

Essentially, there are two possible ways how to create a definition object:

  • From an .xml file, as shown on the left side of the diagram. This is what the framework does automatically in the background. Each of the definition objects has a protected static loadFromXML() method which is used by the framework to load the corresponding .xml file.
  • Programmatically by calling the default (or single parameter name) constructor of a definition object, as shown on the right side of the diagram.
The important thing is: When the framework creates a definition object, it has application scope, and thus is shared between sessions. If the application modifies such a definition object, it has an impact on all objects which are derived from it afterwards! For example, if an application changes the query string of a ViewDefImpl object which has application scope, all ViewObjectImpl objects which will be created afterwards will inherit this changed query string. When creating a definition object programmatically, the scope can usually be defined by one of the constructor parameters. However, the general guideline in ADF is to use either the default constructor or the constructor which takes a single name parameter – these constructors ensure that the definition object has session scope.

The meta object manager

When a new definition object has been created, it should be registered with the meta object manager so that it can be looked up by its name later. This is done by calling the registerDefObject() method on the definition object:

ViewDefImpl mydef = new ViewDefImpl("view.DataVO");
...
mydef.registerDefObject();

The meta object manager is an application wide singleton, and it has a method dumpMOM() which can be used to dump the definition objects which are currently registered:

MetaObjectManager mom = MetaObjectManager.getSingleton(); 
mom.dumpMOM(new PrintWriter(System.err), true);

<< Shared DefinitionContext >>
-- oracle.jbo.mom.DefinitionContextAgeable.dumpMOM --
...
<< Session DefinitionContext >>
-- oracle.jbo.mom.DefinitionContextAgeable.dumpMOM --
...

Note that the parameter-less dumpMOM() overload prints to System.out, which might overlap with other ad-hoc debug output on System.err you might be using in your test application (you would never use System.out or System.err in production code anyway). Internally, the meta object manager uses entries in the ADFContext‘s applicationScope and sessionScope maps – so it is capable of managing session specific objects even though itself it is an application singleton.

Conclusion

When modifying definition objects at runtime, make sure that you are not modifying application scoped definition objects (unless your intention is that all objects in all sessions derived afterwards will inherit this modification). Instead, programmatically create a session scoped definition object, or use the instance specific methods for the modifications. For example, instead of modifying or creating a new ViewDefImpl object with a specific query string and then create a ViewObjectImpl based on it, it is also possible to set the query string directly on the ViewObjectImpl itself – it then only affects this particular view object instance.

Executables contained in the Java JDK and JRE

New article: Executables within the JDK and JRE. We certainly know common executables like javac.exe and java.exe – but when looking into the bin directories of a JRE or JDK installation, there are a lot more executables. What is their purpose? This article lists and briefly describes the various executables which can be found in an Java JRE’s or JDK’s bin directory. For some of the more interesting tools, screenshots and simple usage examples are also shown. In addition, each tool is linked to its official documentation, as long as it is available.

Programmatically iterating a RowSet

I have some tool method which I have been using to dump the contents of a RowSet, especially for debugging and testing purposes. At the core, the method looks like this:

void listRowSet(RowSet rowSet) {
    while(rowSet.hasNext()) {
        Row row = rowSet.next();

        // ... dump the contents of the current row
    }
}

and the result looks similar to this, dumping all the attributes in each row:

CId        | CCreated              | CLastupdated          
-----------------------------------------------------------
0          | 2014-07-04 13:16:46.0 | 2014-07-04 13:16:46.0 
1          | 2014-07-04 13:16:46.0 | 2014-07-04 13:16:46.0 
2          | 2014-07-04 13:16:46.0 | 2014-07-04 13:16:46.0 

Now, in a larger application, I was using the RowSet at several places, and I thought it would be a good idea to have the method always start at the first entry, and not rely on the fact that the iterator is already at the beginning when calling the method. This is what the RowIterator.reset() method is for. So, that seems to be easy:

void listRowSet(RowSet rowSet) {
    rowSet.reset();
    while(rowSet.hasNext()) {
        Row row = rowSet.next();

        // ... dump the contents of the current row
    }
}

Now, the result looks like this:

CId        | CCreated              | CLastupdated          
-----------------------------------------------------------
1          | 2014-07-04 13:16:46.0 | 2014-07-04 13:16:46.0 
2          | 2014-07-04 13:16:46.0 | 2014-07-04 13:16:46.0 

Ehmmm… Wait … Something’s wrong here … I have reset the iterator, but now the first row is missing? What is going on? Lets review the documentation of RowIterator.reset():

After this method, the current slot status will be SLOT_BEFORE_FIRST [...]

Alright, I know that concept from JDBC – there, the method is called beforeFirst(), and subsequent calls to next() move the cursor to the next row, which is the first one when next() is called for the first time. So, what is wrong here? Lets see – there is some additional information in the Javadoc:


...  except in cases where this iterator is associated to an iterator binding in an ADF
 application which sets the currency to the first row in the iterator if available.

Naturally, I skipped that part when I first looked up the documentation – but it looks like this is an important detail! On a side note, the next sentence in the Javadoc says

A subsequent invocation of next() will cause the first row to become the current row.

which is confusing, since this is exactly not the case when “this iterator is associated to an iterator binding in an ADF application which sets the currency to the first row in the iterator if available.”. Now that I know the problem, a quick search showed up a nice posting from Michael Koniotakis: Iterating through View Object RowIterator Bug.(NOT ADF BUG, Development Bug), and the suggestion is to use a secondary row iterator whenever iterating through a RowSet programmatically:

void listRowSet(ViewObject vo) {
    RowSetIterator iter = vo.createRowSetIterator(null); 
    while(iter.hasNext()) {
        Row row = iter.next();

        // ... dump the contents of the current row
    }
    iter.closeRowSetIterator();
}

With that, I now get all rows again, starting at the first row:

CId        | CCreated              | CLastupdated          
-----------------------------------------------------------
0          | 2014-07-04 13:16:46.0 | 2014-07-04 13:16:46.0 
1          | 2014-07-04 13:16:46.0 | 2014-07-04 13:16:46.0 
2          | 2014-07-04 13:16:46.0 | 2014-07-04 13:16:46.0 

Instead of the ViewObject, we can also use a RowSet to create the new iterator (remember that a ViewObject is a RowSet), so that the method signature can remain unchanged:

void listRowSet(RowSet rowSet) {
    RowSetIterator iter = rowSet.createRowSetIterator(null); 
    while(iter.hasNext()) {
        Row row = iter.next();

        // ... dump the contents of the current row
    }
    iter.closeRowSetIterator();
}