Wednesday, November 13, 2013

Overriding Entity doDML or prepareForDml Causes Locking Issues

It is not uncommon for people to override the doDML or prepareForDml method in an ADF BC Entity to do some additional work just before posting changes to the database. The official documentation even describes this extension point as being an equivalent to the Oracle Forms Post Processing triggers.
Today I discovered this can lead to locking issues in the database when this additional work changes other view objects or entities. The investigation is based on JDeveloper version 11.1.1.7 and this behavior might differ for other versions.

Update Nov 14: The issue doesn't reproduce in ADF 12.1.2.0. Inspecting of the source code seems to indicate (unpublished) bug 11896369 is to blame. Currently working with Oracle support to further investigate and ask for fix backport to 11.1.1.7

Update Jan 2: Oracle development acknowledged this behavior is caused by bug 11896369 and a backport request has been filed to bring the fix to 11.1.1.7.

Update Jan 10: Patch 11896369 is now available for download.

Let's start with an simplified example of an entity mutation another one. Below is the doDML method of the Department entity. Whenever a change happens to a department it sets the commission of its first employee to 99%. Not a very likely business scenario, but enough to demonstrate the issue.

@Override
protected void doDML(int i, TransactionEvent transactionEvent) {
    RowIterator employees = getEmployees();
    EmployeeImpl firstEmployee = (EmployeeImpl)employees.first();
    try {
        firstEmployee.setCommissionPct(new Number(0.99));
    } catch (SQLException e) {
        throw new JboException(e);
    }
    super.doDML(i, transactionEvent);
}

What we also need is a entity level validation on Employee that will be violated by this change. For demonstration purposes I've setup a range validation for CommissionPct to be between 0.00 and 0.50:
Entity-level Validation Rule

Now let's build a very simple ADF page to change a department and try to save the changes to the database. Here is what happens:
Validation Error in ADF Application

Everything appears to be okay. The user is confronted with the validation error as expected. But now let's try to update the same record from a different database session:
Database record locked after validation exception

Friday, November 8, 2013

Vodafone Content Tampering Making Sites Very Slow On Wi-Fi

I've had issues with this blog sometimes being very slow on my iPhone when using Wi-Fi. I finally figured out what is going and it seems like Vodafone (Netherlands) are to blame.

I noticed my browser is trying to download http://1.2.3.50/jsi/flash.php?file=gordon.js&max-age=3600 which never succeeds on Wi-Fi. A whois search seems to indicate the entire 1.2.3.0/24 address block is invalid and shouldn't be used on the public internet. All traffic to this address block is dropped along the route and it takes the browser (or TCP/IP stack) a full minute to give up and continu loading my blog. Strangely enough downloading this script on a Vodafone NL 3G connection does succeed.

But why is my client requesting this bizarre URL? It is actually part of http://googleads.g.doubleclick.net/pagead/blank.html which is used on my blog pages. When requesting this page over a Vodafone NL 3G mobile connection the content of this blank page is:
<html><script src="http://1.2.3.50/jsi/flash.php?file=gordon.js&max-age=3600" language="javascript"></script>
<body style="background-color: transparent"></body></html>

There it is; this blank.html page contains a script tag to load the mysterious resource from 1.2.3.50. When requesting this same blank.html from my Wi-Fi connection I get a trully blank page:
<html><body style="background-color: transparent"></body></html>

You don't really notice the difference while your are on Vodafone NL 3G network. Your browser will download the file from 1.2.3.50 and the site seems to function okay. But what happens when your device (re)connects to Wi-Fi? Google sends response headers with blank.html telling your browser it is okay to cache the page for 24 hours. So your device will simply use the cached (tampered) version of blank.html it retrieved through Vodafone's network. But now you are on Wi-Fi and your device can't load the file from 1.2.3.50 and the site is dead slow.

Okay, this is bad, but let's hope the problem clears after 24 hours. After all your browser is only allowed to cache the tampered blank.html page for 24 hours. Unfortunately the problem doesn't disappear after 24 hours. This is caused by Google sending an ETag response header with blank.html as well. An ETag is an opaque identifier assigned by a web server to a specific version of a resource found at a URL. If the resource content at that URL ever changes, a new and different ETag should be assigned. Google sending an ETag is a good thing, but Vodafone is altering the content so they should also change the ETag. Unfortunately they don't so your browser is caching this altered version under Google's original ETag. So even when the cache expires after 24 hours and your browser is asking for a fresh copy of blank.html it will include the ETag with this request. Whether you are on Wi-Fi or 3G, Google will always respond that blank.html hasn't changed since your request includes their original ETag. This instructs your browser to keep using the (tampered) cached version. In the end, you are stuck with the altered version of blank.html until you clear your browser cache.

Vodafone is altering pages I request from the internet and to make things worse they are altering them in such a way that these pages won't work outside of their network while allowing my browser to cache this crippled content. This really sucks! I want the real internet and not some crippled version! Vodafone support is acknowledging they are injecting javascript through a transparent proxy. They state the only way to get rid of this is to use a different APN setting on your mobile device which first has to be activated for your account through technical support. This sucks big time! Sure I can get my account fixed, but who knows how many more people are running into this issue without ever figuring out what is going on.

Hopefully this rant can help others understand what is going on when they see this failed downloads from the 1.2.3.50 or 1.2.3.4 IP address.

Thursday, November 7, 2013

Decimal Comma with Numeric Keypad as ADF Client Behavior

According to wikipedia 24% of the world's population uses a comma as decimal separator, including The Netherlands where I live. This means entering numeric information with the numeric keypad on the keyboard can be challenging. You can only use it to type a decimal point (.) while we need a decimal comma (,). To make things ADF simply ignores the decimal point in our locale. When a user enters 1.23 it is converted to 123 and wrong information is entered into the system.
Numeric keypad decimal point

We came up with a solution based on a custom ADF Behavior tag. I've recently posted how to create your own ADF (client side) behavior. The first post was a simple version without properties, while the second post expanded this example with properties. Now it is time for the sequel showing how you can handle key presses in an input item and replace any decimal point keystroke with a decimal separator (possibly comma) keystroke. The user can simply use the decimal point on the numeric keypad and when using a European locale it will simply type a comma.

Monday, October 14, 2013

Check for postChanges without commit or rollback in ADF BC

It is not uncommon for an ADF application to invoke DBTransactionImpl::postChanges() to perform database DML without invoking commit (or rollback). This is typically done in environments where we also want to invoke PL/SQL logic in the database that already needs to see these pending changes.

The developer should make sure a commit or rollback is executed in the same JSF request. If this is not done, the database session has pending changes and as we know there is no guarantee a subsequent request by the same user will get the same Application Module and JDBC Connection. It is considered bad practice to have these pending changes survive a single request and today we had a situation where this accidentally happened with all sorts of nasty side-effects. One of the things that happens is that the pending changes also could mean long-lived database locks. We added some code to our ADF BC base classes to detect this and throw an exception so we at least know what is going on and to alert a developer he/she is implementing this bad practice.

First thing we need is to configure our application module to use a custom database transaction class. This is described in the ADF documentation. First we need to create our own DatabaseTransactionFactory so we can use our own subclass of DBTransactionImpl2:
import oracle.jbo.server.DBTransactionImpl2;
import oracle.jbo.server.DatabaseTransactionFactory;

public class MyDatabaseTransactionFactory
  extends DatabaseTransactionFactory
{
  @Override
  public DBTransactionImpl2 create()
  {
    return new MyDBTransactionImpl2();
  }
}

Then we need to make sure this factory class is used instead of the default by setting the TransactionFactory property of the ADF Application Module configuration to the full class name of our own transaction factory:
Set TransactionFactory property of AM Configuration

Next, we can create our own subclass of DBTransactionImpl2 that keeps track of pending postChanges. It sets a flag when postChanges is executed and clears this flag when performing a commit or rollback. We are going to check this flag later on when releasing an Application Module at the end of a request:
import oracle.jbo.server.DBTransactionImpl2;
import oracle.jbo.server.TransactionEvent;

public class MyDBTransactionImpl2
  extends DBTransactionImpl2
{
  private boolean postedChanges = false;

  @Override
  protected void postChanges(TransactionEvent te)
  {
    super.postChanges(te);
    setPostedChanges(true);
  }

  @Override
  protected void doCommit()
  {
    setPostedChanges(false);
    super.doCommit();
  }

  @Override
  protected void doRollback()
  {
    setPostedChanges(false);
    super.doRollback();
  }

  private void setPostedChanges(boolean postedChanges)
  {
    this.postedChanges = postedChanges;
  }

  public boolean isPostedChanges()
  {
    return postedChanges;
  }

}

Final step is to check for pending postChanges at the end of each request. We can do this from our Application Module. This would typically be code you add to your own ADF BC base classes:
import oracle.jbo.ApplicationPoolSvcMsgContext;
import oracle.jbo.JboException;
import oracle.jbo.server.ApplicationModuleImpl;
import oracle.jbo.server.DBTransaction;

public class MyBaseAppModuleImpl
  extends ApplicationModuleImpl
{
  /**
   * This is invoked by the Application Module Pool whenever an 
   * application module is being used, released, removed or recycled
   * from the pool.
   */
  @Override
  public ApplicationPoolSvcMsgContext doPoolMessage(ApplicationPoolSvcMsgContext ctx)
  {
    if (ctx.getMessageType() == 
        ApplicationPoolSvcMsgContext.MESSAGE_TYPE_RELEASING)
    {
      DBTransaction txn = getDBTransaction();
      if (txn instanceof MyDBTransactionImpl2 && 
          ((MyDBTransactionImpl2) txn).isPostedChanges())
      {
        // throwing exception will mark AM as dead and close tainted
        // DBTransaction and JDBC connection
        throw new JboException("Application Module released to the pool with pending posted changes");
      }
    }
    return super.doPoolMessage(ctx);
  }

}

ApplicationModule::doPoolMessage is invoked whenever the pool uses, releases, removes or recycles an application module instance. This can be seen by inspecting ApplicationPoolSvcMsgContext::getMessageType() and comparing to any of the MESSAGE_* constants in ApplicationPoolSvcMsgContext. We check for uncommitted postChanges whenever the application module instance is released to the pool (aka at the end of each request). If these exist we simply throw a JboException. This will not be visible to the end-user as the JSF response has already been completed by then. It will show up in the log for administrators and developers. Because we are throwing an exception during pool management the AM instance will be destroyed together with its JDBC connection. This is actually good as we don't want the AM instance with pending changes, and potential database locks, to linger around.

Update 2 jan: We changed the code to no longer throw an exception thus destroying the applicationModuke, but only log a warning message. Due to an ADF bug we have quite a few AM instances with posted changes at the end of their request. When they get destroyed all ViewObjects loose their where clause and other (or all) records are fetched on the next page request. So until that bug is we fixed we reverted to only logging a warning.

Thursday, August 22, 2013

JDeveloper installer very small on Mac OS X

I have previously installed JDeveloper 11 on my MacBook Pro running Mac OS X Mountain Lion (10.8). Basically you download the generic installer from Oracle and run:
java -jar jdevstudio11124install.jar

Today I tried it again and the installer does start but with a very small screen only showing the exit button:
JDeveloper Installer with only Exit button

As it turns out this is caused by a recent install of JDeveloper 12c on the same machine. That had forced me to install JDK version 7 which is now the default java runtime environment on my machine. Apparently the JDeveloper version 11 installer doesn't like java version 7, at least on Mac OS X.

The solution is rather simple. Run the following commands in a terminal window to start the JDeveloper 11 installer:
wMac:~ wilfred$ /usr/libexec/java_home -v 1.6
/System/Library/Java/JavaVirtualMachines/1.6.0.jdk/Contents/Home
wMac:~ wilfred$ /System/Library/Java/JavaVirtualMachines/1.6.0.jdk/Contents/Home/bin/java -version
java version "1.6.0_51"
Java(TM) SE Runtime Environment (build 1.6.0_51-b11-457-11M4509)
Java HotSpot(TM) 64-Bit Server VM (build 20.51-b01-457, mixed mode)
wMac:~ wilfred$ /System/Library/Java/JavaVirtualMachines/1.6.0.jdk/Contents/Home/bin/java -jar jdevstudio11124install.jar 
Extracting scripts to /var/folders/vl/qsk0dkgn39b2_4sdngwvcf840000gn/T/
Executing MacOS-specific pre-installation scripts
You may be prompted to enter your Mac OS X password in order to create required directories and symbolic links
Extracting 0%....................................................................................................100%


Line 1 runs java_home to get you the full path to the java version 6 home directory. Line 3 uses this path and adds "/bin/java -version" to run java from that directory to check its exact version. Make sure it is in fact a 1.6.0_xx version. Then finally line 7 uses java from that directory to run the installer. This time it just starts fine:
JDeveloper 11 installer runs fine with JDK 6

Monday, June 17, 2013

Credential Store Framework

Sometimes you have the need for credentials (username/password) in your ADF, or other Fusion Middleware, application. I've seen numerous solutions with property files, web.xml context parameters, deployment plans, etc. Most of these run into problems with SysOps or anyone else worried with security. You don't want these credentials scattered around in plain text files and you don't want developers to know the passwords for each environment. This is better left to configuration by a sys-admin after deployment.

Not everybody seems to know Oracle Fusion Middleware, more specifically Oracle Platform Security Services (OPSS), provides a great solution with the Credentials Store Framework. This is a set of APIs that applications can use to create, read, update, and manage credentials securely.

A credential store is a repository of security data (credentials) that can hold user name and password combinations, tickets, or public key certificates. A credential store can be file-, LDAP- (Oracle Internet Directory), or DB-(Oracle RDBMS)based. A file-based credential store, also referred to as wallet-based and represented by the file cwallet.sso, is the out-of-the-box credential store.

The Credentials Store Framework also limits which application (or components thereof) are allowed to retrieve or modify credentials. This allows for a very secure setup where only trusted libraries that go through extensive auditing are allowed to retrieve credentials.

This post describes the basic steps to get started with the Credentials Store Framework, but more information can be found in the official documentation (Fusion Middleware Application Security Guide):

Wednesday, May 8, 2013

Customizing JDeveloper Preferences

I like to tweak some of the preferences in the Tools menu of JDeveloper. I thought I would document them here for my own reference and in case anyone else is interested. I'll try to list all the settings I typically change from their default. These are ordered and grouped by their panels in the preferences dialog so you should be able to locate them easily.

  • Environment
    • Line Terminator to "Line Feed (Unix/Mac)" especially if you are in a mixed environment with windows and linux/mac developers as it prevents a lot of problems if everyone creates the files in the same way.
    • Encoding to "UTF-8". I have no idea why the default is platform dependent (MacRoman or some obscure windows code page). I like all developers in the team to use the same encoding. This is also used as encoding in XML files you create. Changing it afterwards can be a lot more work as existing files might need recoding
  • Environment > Log
    • Maximum Log Lines to something like 50000. The default of 3000 can be too small if you crank up the logging levels in a development session.
  • ADF Business Components
    • Look at all these settings carefully (and read below). Lots of these settings are used when creating new ADF BC objects so be careful to set these up before you start developing as it can safe a lot of rework later
  • ADF Business Components > Base Classes
    • You can set the default base classes for any ADF BC object you will create in JDeveloper. It is wise to create company wide extension classes for these and configure JDeveloper to use your company extended classes instead of the JDeveloper base ones. You could even  create a layer of extension classes for your project (extending from company classes) and setup the per-project settings to use these application level extension classes
  • ADF Business Components > Packages
    • A lot of developers like to group their ADF BC objects per type in separate sub packages. For instance put all view objects in a subpackage .views or .queries. In stead of remembering to set these sub packages each time you are creating ADF BC objects simply set the defaults here.
  • ADF Business Components > View Objects
    • You could set the default fetching tuning parameters for new view objects here. But in reality they need consideration for each view object you create. One trick we used in the past is to set a ridiculous default value here and then check for that ridiculous value in your extended ADF ViewObject classes. If the developer left the ridiculous initial value simply throw an exception telling the developer to set reasonable values.
  • Audit
    • The JDeveloper Audit framework is under-appreciated. I would advise to tweak the Code Assist Rules that you see while developing. Go over the rules that are disabled by default and see if you want to enable them. My guess is you can enable most of them, especially to warn developers about missing or incorrect javadoc. Also be sure to check the "Audit During Compile" with perhaps a slightly less restrictive set to prevent your developers from violating certain rules. The next step would be to monitor these quality issues from your continuous build server
  • Code Editor
    • I like to enable "Reformat Code Block When Pasting". That is mainly since I tend to keep most of my code auto-formatted so reformatting when pasting someone else's code seems like a good idea.
    • One other thing I like to enable is "Show Total Number of Lines in the Status Bar" just to remind to keep the files small and simple.
  • Code Editor > Code Templates
    • You can add your own code templates here. We've added a bunch to easily use ADFLogger in your Java source code. More on that in a future post.
  • Code Editor > Display
    • Enable Text Anti-Aliasing because it just looks better :-)
  • Code Editor > Line Gutter
    • Enable "Show Line Numbers"
  • Code Editor > Save Actions
    • These are actions that JDeveloper should perform on each file you save. I typically add "Organize Imports", "Trim Trailing Whitespace" and "Clear All Highlighting". I've tried using Reformat as well which is great for Java sources which should always be formatted by a tool for consistency. But JDeveloper will then also reformat all XML files including JSF pages. In those files it is much more common to perform manual formatting and I don't like the always-auto-format of these save actions.
  • Compiler
    • Enable "Clean Project Before Project Rebuild". If you are rebuilding your entire project I see no reason why you don't want to start with a clean project first. Otherwise you might run the risk of keeping compiled artifacts for source objects you have already removed.
  • CSS Editor
    • If you do anything with ADF skinning be sure to set the CSS level to Level 3 (and on JDev 11gR1) enable the ADF Faces Extensions checkbox
  • Debugger
    • Check "Show Action Buttons" to get the debugger buttons (step, continue, etc) also in the log window of JDeveloper.
  • Debugger > Beakpoints
    • Set the scope for new breakpoints to Global. Especially if you are building on a large system with multiple workspaces. With the default setting your debugger will not stop if you set a breakpoint in one workspace and run the application from another workspace. My workflow is to keep the number of breakpoints limited and I frequently clean them. I would like the confidence that a breakpoint is always used.
  • Debugger > Data
    • I personally don't like the new Tree View in the 11gR2/12c debugger where you drill down into objects and have to traverse back up. I prefer the old-style Table View so I change the default view here.
  • Debugger > Smart Data
    • I like to increase the "Number of Lines to Analyze" to something like 5 to show a bit more information in this debugger panel.
    • I personally don't like the new Tree View in the 11gR2/12c debugger where you drill down into objects and have to traverse back up. I prefer the old-style Table View so I change the default view here.
  • Debugger > Watches
    • I personally don't like the new Tree View in the 11gR2/12c debugger where you drill down into objects and have to traverse back up. I prefer the old-style Table View so I change the default view here.
  • File Types
    • I like to change the default editor panel used for certain files. I don't like JSF files to open in design WYSIWYG mode as initializing that editor can be slow. I prefer these to start in source view and I can always switch to the design tab if needed. You can set this in the Default Editors tab of these preferences. I like to set this to "Source" for "ADF Fragment File", "HTML Source", "HTML Template", "JSFF Label", "JSP Segment", "JSP Source", "XHTML/Facelets Source" and "XHTML Source" (not all of these exist in every version of JDeveloper)
  • News (JDev 12c only)
    • Add http://feeds.feedburner.com/RedHeap to the list of News Feeds to get Red Heap posts in JDeveloper :-)
  • Run > WebLogic
    • On 11gR2 only enable FastSwap deployment to you can make more changes to a deployed application without doing a full redeploy. Unfortunately this feature is not available on 11gR1.
  • Web Browser and Proxy
    • If your organisation uses a web proxy be sure to fill in these details so JDeveloper can access the internet for things like checking for updates. You can also set you default web browser here in case that is different from the default browser of your operating system. I like to use Google Chrome as my development browser and sometimes you cannot change the default web browser of your operating system due to administrator restrictions.
    • When using Chrome as your browser be sure to start it in incognito mode. This ensures you start with a clean browser each time you start your application. In JDeveloper 11g you can simply add --incognito to the command line of chrome while JDeveloper 12c allows you to specify --incognito ${URL} as command line parameters.
Some other things I would like to chance with a default JDeveloper installation:

  • Select Tools > External Tools and let JDeveloper create the default external tools when running on Microsoft Windows. This gives you a convenient right-click on all your objects to start a windows explorer in that specific source directory. Something I frequently use, for example to get access to TortoiseSVN on that file. On Mac I like to setup this to run a terminal from the selected directory.
  • Change the memory options in JDEV_HOME/ide/bin/ide.conf. On a 32-bit JVM I like to set both -Xmx and -Xms to 1200M. On a 64-bit JVM you could even go a bit higher, like 1500M or 2000M.
  • When running with non-English regional settings on your operating system, edit JDEV_USER_HOME/system11.x.x.x.x.x.x/DefaultDomain/bin/setDomainEnv.cmd, search for the lines where EXTRA_JAVA_PROPERTIES are set and add a line
    set EXTRA_JAVA_PROPERTIES=-Duser.language=en -Duser.country=US %EXTRA_JAVA_PROPERTIES%
    This enforces WebLogic to use en_US as locale so error messages in the JDeveloper Log window are English and not the language from your operating system. This makes googling for these error messages much easier ;-)
  • While you're already editing JDEV_USER_HOME/system11.x.x.x.x.x.x/DefaultDomain/bin/setDomainEnv.cmd you might just as well increase the memory for WebLogic. Search for the lines where XMS_SUN_64BIT, XMS_SUN_32BIT, XMX_SUN_64BIT and XMX_SUN_32BIT are set. My advice is to change all four to 1024 but you might want to tweak this for your situation.
    When using JDeveloper 12.1.2 you can set memory arguments in JDEV_USER_HOME/system12.1.2.x.x.x.x/DefaultDomain/bin/setStartupEnv.cmd in the section for AdminServerStartupGroup.