Friday, October 9, 2015

ADF Session Replication on a Cluster for High Availability

Running an ADF application on a weblogic cluster is fairly simple. Just deploy the application to the cluster and your done. This gives you scalability as the load is distributed over multiple managed servers. However, it does not give you protection against machine failure out of the box. For that to work, you need to make sure all state in your ADF application is replicated across multiple nodes in the cluster. This post will explain the things you have to think about when setting up this session replication.

Most of this information is based on Configuring High Availability for Fusion Web Applications chapter of the Fusion Web Applications Developer's Guide but we've added some undocumented features and best practices based on our experience.

View

  • First thing you need to do is tell weblogic to replicate a http session to other nodes in the cluster. This is done by setting persistent-store-type to replicated_if_clustered in your weblogic.xml file:
    <weblogic-web-app>
      <session-descriptor>
        <persistent-store-type>
          replicated_if_clustered
        </persistent-store-type>
      </session-descriptor>
    </weblogic-web-app>
    
  • During development on my local workstation I like to set the session-description slightly differently:
    <weblogic-web-app>
      <session-descriptor>
        <persistent-store-type>file</persistent-store-type>
        <persistent-store-dir>c:/temp/</persistent-store-type>
        <cache-size>0</cache-size>
      </session-descriptor>
    </weblogic-web-app>
    
    This tells weblogic to write the http session request to file after each request. Since the cache-size is set to 0 it will not keep any session in memory. This means each subsequent request from the same session has to restore the session from file first. Since this (de)serializes the http session on each request it behaves the same as a session failover on a cluster after each request. This is a great way to test if you application is really cluster-safe and if none of the managed beans or other objects will loose their state.
  • In your web.xml you have to set CHECK_FILE_MODIFICATION to false:
    <web-app>
      ...
      <context-param>
        <param-name>
          org.apache.myfaces.trinidad.CHECK_FILE_MODIFICATION
        </param-name>
        <param-value>false</param-value>
      </context-param>
    <web-app>
    
    Having this on could lead to errors when a failover occurs. It is best practice to disable this for a production system anyhow. If you want this on during local development you should look into deployment plans to override such a setting per environment.

Tuesday, February 17, 2015

ADF Faces 12c Components Demo and Test Automation

You might have noticed that I am working on a series of blog articles on using Selenium to automate testing of Oracle ADF applications. This includes work on a little framework to make this easier and a set of sample JUnit tests against the public Oracle ADF Faces 12c Components Demo.

Getting the Faces 12c Component Demo running with test automation had some challenges. I wanted to write them down here in case somebody wants to try the same. It starts by downloading the Oracle ADF Faces Components Demo from OTN. This also includes instructions on how to run this application in your integrated weblogic server, but those instructions have some caveats and are for JDeveloper 11g, not version 12c. Please follow the instructions below as an alternative (I've marked the differences with the normal Oracle instructions and included screenshots at the end).

In the end this needed more work than I expected, so I also offer the fixed versions for download. If anyone from Oracle feels that this is a problem please contact me and I'll remove the download and you can follow the instructions below to create your own fixed version.

If you want to start from the downloads from Oracle and not use my fixed versions you would have to follow these steps:
  1. Download the ADF Faces 12c Components Demo WAR file, but don't unpack it.
  2. Start JDeveloper 12.1.3
  3. Instructions updated from 11g: Choose File > New > From Gallery from the menu to create a new application. Select General > Applications in the tree and select Custom Application as application type and press Ok.
  4. In the Create Application dialog type adffacesdemo as the application name, select a directory, leave the rest of the options alone and press Finish. This creates new application workspace and project.
  5. Instructions updated from 11g: The default created project is not needed and you may delete the project. Right click it and select Delete Project. In the subsequent dialog choose to not only delete the project form the application but also delete it from disk.
  6. Instructions updated from 11g: In the now empty workspace choose File > New > From Gallery from the JDeveloper menu. In the list of items select Projects and on the right hand side Project from WAR and press Ok. In the next dialog provide a name for the project, e.g. adffacesdemo, and keep the directory information. On the second panel, use the file browser to select the downloaded ADF Faces demo WAR file and finish the wizard.
  7. Double click onto the project node to open the project properties and select the Run > Debug > Profile option. Press the Edit button and select the Tool Settings. In the Before Running section, uncheck the Make Project and Dependencies option and close the dialog pressing Ok.
  8. Extra step added by me: Unfortunately some files are missing from the exploded WAR which will result in javascript errors and missing images.
    • Manually copy the META-INF directory from the src directory to the classes directory so you end up with classes/META-INF
    • Copy the src/oracle/adfdemo/view/js directory (and all of its subdirectories) to classes/oracle/adfdemo/view/js
    • Copy the two .properties files from src/oracle/adfdemo/view/resource to classes/oracle/adfdemo/view/resource
    • Copy the src/oracle/adfdemo/view/resource/fileExplorer directory and the .properties file it contains to classes/oracle/adfdemo/view/resource/fileExplorer
    • Copy all xml file from src/oracle/adfdemo/view/components/rich/tageditor to classes/oracle/adfdemo/view/components/rich/tageditor
    • Copy the xml and csv file from src/oracle/adfdemo/view/feature/rich/diagram/data to classes/oracle/adfdemo/view/feature/rich/diagram/data
    • Copy the src/oracle/adfdemo/view/feature/rich/dvt/data/election directory to classes/oracle/adfdemo/view/feature/rich/dvt/data/election
    • Copy all xml files from src/oracle/adfdemo/view/feature/rich/hv to classes/oracle/adfdemo/view/feature/rich/hv
  9. Extra step added by me: To be able to use test automation on this ADF sample application, enable automation by opening public_html/WEB-INF/web.xml in JDeveloper and remove the comment markers around the existing oracle.adf.view.rich.automation.ENABLED context parameter.
    For test automation to work you also have to copy JDEV_HOME/oracle_common/modules/oracle.adf.view_12.1.3/adf-richclient-automation-11.jar to the  public_html/WEB-INF/lib directory of the project.
  10. Extra step added by me: As a final step I prefer a simple URL when running the application. Double click the project to open the project properties. In the Java EE Application section change both the application name and context root to adf-richclient-demo
  11. Finally, expand the project and select index.jspx under the Web Content node. Choose Run from the right mouse context menu.

Sunday, February 15, 2015

ADFLogger 12.1.3 ignoring message parameters and resource keys

In JDeveloper 12.1.3 Oracle made a switch to a new log formatter that has its shortcomings. It no longer knows how to replace resource bundle keys with their actual message and also fails to replace the {0}, {1}, ... placeholders with their actual values. You can end up with logging looking like this:
<oracle.adf.view> <RichRenderKit> <isAutomationEnabled> <AUTOMATION_ENABLED_WITHOUT_AUTOMATION_JAR> 
<oracle.adf.common> <ADFConfigFactory> <findOrCreateADFConfig> <Resource {0} not found on the classpath.> 

Notice the AUTOMATION_ENABLED_WITHOUT_AUTOMATION_JAR that is not replaced with its actual message as well as the Resource {0}... message which should clearly mention the missing resource.

I don't know how this made it past basic QA, but this is now the default configuration for your Integrated WebLogic server in JDeveloper 12.1.3. Luckily there is an easy fix to revert to the 12.1.2 behaviour which is working fine.

Either start your integrated weblogic server in JDeveloper and click the actions button the log window and select Configure Oracle Diagnostics Logging or directly edit the JDEV_USER_HOME/system12.1.3.0.41.140521.1008/DefaultDomain/config/fmwconfig/servers/DefaultServer/logging.xml file.

Find the log_handler declaration at the beginning of the file for the console-handler. Change its formatter attribute from oracle.adf.share.logging.internal.diagnostic.ConsoleFormatter to oracle.core.ojdl.weblogic.ConsoleFormatter.

Restart your integrated weblogic server for the changes to take effect. You can now notice the resource keys and message parameters are correctly replaced:
<Feb 15, 2015 3:59:01 PM CET> <Warning> <oracle.adfinternal.view.faces.renderkit.rich.RichRenderKit> <ADF_FACES-60118> <Your application is running with the automation enabled in your web.xml file but the automation jar is unavailable. Please ensure that the jar is in the classpath.> 
<Feb 15, 2015 3:59:01 PM CET> <Warning> <oracle.adf.share.config.ADFConfigFactory> <BEA-000000> <Resource META-INF/adf-config.xml not found on the classpath.> 

Sunday, February 8, 2015

Waiting for Oracle ADF Partial Page Rendering in Selenium tests

One of the main reasons people fail to use Selenium (or any other tool) for automated web testing with Oracle ADF is timing issues. The test automation tool typically wants to execute its actions as quickly as possible. This can be a challenge in dynamic applications that load parts of the pages on demand or in response to user interactions. This is what ADF typically does with partial page rendering requests.

For example, the test could "click" on a tab in a af:pannelTabbed component. The content of the new tab will be retrieved with a partial page rendering request. If the test automation tool would continue immediately after "clicking" the tab and try to interact with elements on the new tab it would be too early and fail. Most automated testing tools have features to wait for new page DOM elements to appear before interacting with them. But even this can be too soon. When the response to the partial page rendering request is processed by the web browser client it adds the new elements to the page and then binds all sorts of javascript events and other goodies to them. Most automated testing tools will not wait for this to complete and will still fail to interact with the new elements.

One quick and dirty solution is to introduce sleep statements in your test and just wait a second or two for the request to complete. This will unnecessarily slow down your tests if the partial request is completed in less than your sleep time and will still break your test whenever the page load will take longer then normal and thus longer than your sleep time.

A much better way is to actually tell Selenium (or your other testing tool of choice) when the partial page rendering request is fully completed and the browser is ready for its next command. ADF includes a javascript method that does just that; AdfPage.isSynchronizedWithServer.

This has been available in older ADF versions as well. In version 12c Oracle even introduced AdfDhtmlPage.whyIsNotSynchronizedWithServer which tells you why the client is not ready yet. Please not this is part of the Oracle internal AdfDhtmlPage class and therefor not part of the public javascript API which means it might change or disappear in future versions.

Selenium WebDriver has the notion of explicit waits where you can instruct Selenium to wait for a certain condition. I figured it would be nice if we could just hook into that mechanism. As part of my effort to automate ADF testing I've created a subclass of org.openqa.selenium.support.ui.ExpectedCondition called ClientSynchedWithServer:
public class ClientSynchedWithServer implements ExpectedCondition<Boolean> {
    // return false if AdfPage object and functions do not exist
    // if they do exist return true if page is fully loaded and ready or reason why this is not completed yet
    String js =
        "return typeof AdfPage !== 'undefined' && " + 
        "typeof AdfPage.PAGE !== 'undefined' && " +
        "typeof AdfPage.PAGE.isSynchronizedWithServer === 'function' && " +
        "(AdfPage.PAGE.isSynchronizedWithServer() || " +
        "(typeof AdfPage.PAGE.whyIsNotSynchronizedWithServer === 'function' && " +
        "AdfPage.PAGE.whyIsNotSynchronizedWithServer()))";

    @Override
    public Boolean apply(WebDriver driver) {
        JavascriptExecutor jsDriver = (JavascriptExecutor) driver;
        Object result = jsDriver.executeScript(js);
        System.out.println("client ready: " + result);
        return Boolean.TRUE.equals(result);
    }
}

The javascript tries to be as careful as possible not to throw an exception when not on an ADF page by first checking if AdfPage, AdfPage.PAGE and AdfPage.PAGE.isSynchronizedWithServer are available. If so, it will execute AdfPage.PAGE.isSynchronizedWithServer() to see if the client is completely finished processing all events. If this is not the case it will check if the whyIsNotSynchronizedWithServer function is available and will invoke it if it is. This would return the reason why the client is not finished yet. If the whyIsNotSynchronizedWithServer function is not available it would just return the false result from isSynchronizedWithServer.
In the end the javascript function will only return true if isSynchronizedWithServer returned true, otherwise it might return the reason why the page is not finished or any other non-true value.

The apply method from this ExpectedCondition will invoke the javascript and would print the reason why the page is not finished yet. If you don't want any System.out.println in your tests you could just remove this. The important part is that it checks if the javascript returned true. If it did, the apply method will also return true and Selenium would know the condition has been met and it no longer needs to wait.

Using this class to wait for PPR after interacting with the page is similar to any explicit wait in Selenium WebDriver:
public void test() throws Exception {
    FirefoxProfile profile = new FirefoxProfile();
    profile.setEnableNativeEvents(true);
    profile.setPreference("app.update.enabled", false);
    WebDriver driver = new FirefoxDriver(profile);
    System.out.println("load demo page...");
    driver.get("http://jdevadf.oracle.com/adf-richclient-demo");
    System.out.println("wait for completion...");
    new WebDriverWait(driver, 10).until(new ClientSynchedWithServer());
    System.out.println("click search button...");
    driver.findElement(By.id("tmplt:gTools:glryFind:doFind")).click();
    System.out.println("wait for completion...");
    new WebDriverWait(driver, 10).until(new ClientSynchedWithServer());
    driver.quit();
}

This will setup a new Selenium session in lines 2 through 5. It will then navigate to the Oracle Rich Client Demo site. This already includes quite some client side javascript processing, so we need to wait for this to complete in line 9. We then click on the search button and again wait for that to complete in line 13. Both waits use a timeout of 10 seconds. If the condition is not met within that timeout Selenium will throw an exception.
Without the new waits this script would fail as it would try to click the search button before the page has completely rendered and attached all of its javascript listeners. With the new waits you can see the results in the console and why the page wasn't ready yet in lines 3-5 and 9-10:
.load demo page...
wait for completion...
client ready: WAITING_FOR_USER_INPUT_PHASE
client ready: WAITING_FOR_USER_INPUT_PHASE
client ready: Event queue is not empty
client ready: true
click search button...
wait for completion...
client ready: DTS is not ready
client ready: WAITING_FOR_USER_INPUT_PHASE
client ready: true

Time: 9.756

OK (1 test)

This post is part of a series on how to get Selenium to work with Oracle ADF.

Configuring an Oracle ADF Project for Selenium testing

Running Selenium testing against an ADF application requires direct interaction with the HTML DOM, JavaScript and CSS. An ADF application is normally optimised for performance and scalability which means CSS classes and javascript are minified and obfuscated. This makes testing with Selenium very difficult and brittle.

Fortunately you can configure quite a few settings in your project's web.xml file to make it more development friendly. I've written about these before but some are even more important for automated testing. The ADF Faces documentation also states a number of configuration changes have to be made for automated testing.

These are the settings to change when using automated testing:
  • oracle.adf.view.rich.automation.ENABLED should be set to true in web.xml. This ensures a javascript client component is created for each ADF component regardless the value of the clientComponent attribute on the JSF component. This makes interacting with the page from Selenium much easier. It also seems to enable some other client and server side features. Search for isAutomationEnabled in the ADF source code to get a feeling for things that will change when enabling this. One of the things it enables is to find objects using scope IDs (also known as Sub IDs). This is explained in the Oracle Application Testing Suite Open Script User Guide.
    For this to work you also need to put adf-richclient-automation-11.jar in your project classpath. The simplest way is to just put this JAR in the WEB-INF/lib folder of your project. The file itself can be found in JDEV_HOME/oracle_common/modules/oracle.adf.view_12.1.3/
  • org.apache.myfaces.trinidad.DISABLE_CONTENT_COMPRESSION to true in web.xml which will disable the compression of CSS classes like af_button to something like x7k. Having readable and deterministic CSS class names makes it possible to use CSS selectors in your Selenium scripts.
  • org.apache.myfaces.trinidad.DEBUG_JAVASCRIPT to true in web.xml o disable the minification of ADF's javascript files. This gives you human readable javascript which makes it easier to figure out how to interact with those scripts from Selenium. You should also get a copy of the ADF Source code from Oracle Support so you even have the versions with all the inline comments in place. But don't let this scare you. For simple testing scenarios you won't be needing javascript interactions. It's just when you want to go all the way and have very detailed interactions or tests with ADF components.
  • javax.faces.PROJECT_STAGE to Development in web.xml as your application will otherwise fail to start since you have enabled a number of development-only features. You can revert this to Production with deployment plans for other environments.
  • The aforementioned Oracle Application Testing Suite documentation also advises to set animation-enabled to false in trinidad-config.xml. This is not only to speed up the running of the testing script as it won't have to wait for the animations but will also make sure tests don't fail as they want to interact with things like tree nodes before the expanding animation of a tree node is finished. In my own testscripts I also make sure to execute the javascript AdfPage.PAGE.setAnimationEnabled(false) on each page for situations where we forgot to set this parameter. Unfortunately values in trinidad-config.xml cannot be overridden with deployment plans, but there is a neat trick where you can refer to web.xml context param values from trinidad-config.xml.

You can revert these settings to the optimised values with deployment plans. No need to change this in the source code or build artefact each time. Just set the development optimised versions in your source files so local runs in JDeveloper use the correct values. Then use deployment plans to override these for production and other environments.

This post is part of a series on how to use Selenium automated tests with Oracle ADF.

Testing Oracle ADF with Selenium WebDriver Page Objects

Selenium is an awesome (and free) tool to automate browser-based user interface testing. Selenium offers two ways of working; Selenium IDE; a firefox add-on for simple record-and-playback of interactions with your browser and Selenium WebDriver; a collection of language specific bindings to drive a browser -- the way it is meant to be driven.

For testing ADF applications you'll need to use Selenium WebDriver as that sends native events to the browser it is controlling. This means it will fire actual mouse, keyboard, and other events, which is something the javascript-heavy ADF framework needs.

I've built an example on how to test the public Oracle ADF Faces 12c Components Demo for a real life demo using JUnit and Selenium WebDriver. The example project is at github and I'll explain the important parts in a number of blog posts. This first post will show how the JUnit test classes interact with the page objects. The nitty gritty details on how to work with ADF and Selenium will be covered in separate posts.

My advice is to follow the Page Objects Pattern proposed by the Selenium team. It creates a clear separation between Page Objects and Test Objects. Page Objects know about the HTML, the page components and how to interact with them while the Test Objects drive these page objects and contain the real test logic and assertions. An alternative approach would be the Bot Style tests which combines page logic and Selenium interactions in a single class.

In an ideal world making changes to the ADF page itself only involves updating the Page Objects while the Test Objects can remain the same. Unless you're actually changing functionality on the page that requires changes to the tests itself. But even then it helps you to separate these two objects. The Page Object is more "developer oriented", while the Test Object is more "tester oriented".

Let's look at an example that drives the public Oracle ADF Faces Components Demo:

@Test
public void testNavigationToFileExplorer() throws Exception {
    FileExplorer page = getPage().clickFileExplorerLink().clickTreeTableTab();
    page.getScreenshotAs(new ScreenshotFile(new File("explorer-tree-table.png")));
}

This is a JUnit test method in the RichClientDemoTest test class. It starts in line 3 by navigation to the component demo homepage by invoking getPage(). This method returns a RichClientDemo page object. This is one of the aforementioned page objects that allow interaction with the web page.
ADF 12c Rich Client demo page with File Explorer link highlighted
Invoking the clickFileExplorerLink() method on the RichClientDemo page object will find the link on the page to navigate to the File Explorer demo and click that link to navigate to that page. Navigation methods on page objects will return other page objects. In this example we invoked a navigation method on RichClientDemo which returns a FileExplorer page object.
File Explorer page with Tree Table tab highlighted
Finally we invoke the clickTreeTableTab() method to click on the Tree Table tab in the right hand side af:pannelTabbed. Methods on Page Objects return the same page object instance or another when navigation occurs. In either case this means you can chain numerous of these methods on a single line when needed.

The last line of the test method shows how you can take a screenshot of what the browser is showing at the time. This can be very helpful especially with failing test cases where it could be useful to have a screenshot of the failed state.
Screenshot taken by Firefox ran by Selenium WebDriver

This example showed how to interact with page objects and it will fail if any of the required links or other elements are not available on the page. But it doesn't have any real test assertions yet. One final example shows how to assert that the number of expanded nodes in an af:tree should have increased when clicking one of the (collapsed) nodes in the tree:

@Test
public void testExpandTagGuideNodeA() {
    RichClientDemo page = getPage();
    int expandedNodesBefore = page.getTagGuideTreeExpandedNodeCount();
    page.clickLayoutTreeNode();
    Assert.assertEquals("number of expanded node should increase", 
                        expandedNodesBefore + 1,
                        page.getTagGuideTreeExpandedNodeCount());
}

Line 3 shows how we again first navigate to the rich client demo homepage as that is the starting point for all of our tests. Line 4 uses the RichClientDemo page object to retrieve the number of expanded nodes in the af:tree component. Notice how the knowledge on how to interact with the page to get this information is contained in the page objects and not exposed to the tester. Line 5 clicks the node in the tree labeled Layout. Again notice the knowledge on how to locate and click this node is hidden from the tester class. Finally in line 6 we have a JUnit assertion that the number of expanded nodes in the tree should have been increased by 1. If that is not the case this JUnit test will fail.

By the way; a Page Object doesn't have to represent a full page. Especially with ADF regions it is conceivable that each region would have its own Page Object (or rather Page Fragment Object). For complex page fragments this could be split up even further to keep the code manageable. More on that in other blog posts. I'll explain the other bits and pieces of this demo in separate blog posts. If you want to look at the full demo just hop over to github.

This post is part of a series on how to get Selenium to work with Oracle ADF.

Friday, January 23, 2015

showPopupBehavior align property examples

I always struggle to understand the official descriptions for the align attribute of the af:showPopupBehavior tag. A picture is worth a thousands words so I just created screenshots of all the possible values:

afterStart: The popup appears underneath the element with the popup's upper-left corner aligned with the lower-left corner of the element. The left edges of the element and the popup are aligned


afterEnd: The popup appears underneath the element with the popup's upper-right corner aligned with the lower-right corner of the element. The right edges of the element and the popup are aligned.

beforeStart: The popup appears above the element with the popup's lower-left corner aligned with the upper-left corner of the element. The left edges of the element and the popup are aligned.
 

beforeEnd: The popup appears above the element with the popup's lower-right corner aligned with the upper-right corner of the element. The right edges of the element and the popup are aligned.
 

endAfter: The popup appears to the right of the element with the popup's lower-left corner aligned with the lower-right corner of the element. The bottom edges of the element and the popup are aligned.

endBefore: The popup appears to the right of the element with the popup's upper-left corner aligned with the upper-right corner of the element. The top edges of the element and the popup are aligned.

startAfter: The popup appears to the left of the element with the popup's lower-right corner aligned with the lower-left corner of the element. The bottom edges of the element and the popup are aligned.

startBefore: The popup appears to the left of the element with the popup's upper-right corner aligned with the upper-left corner of the element. The top edges of the element and the popup are aligned.

Thursday, April 10, 2014

Host a Soap Web Service on Google App Engine with JAX-WS

We are about to release a great addon for JDeveloper that can access a SOAP web service. For demonstration purposes we want to have a publicly available web service that anyone can use. Having this web service hosted on Google App Engine has two major benefits: it is free and is accessible for anyone on the internet 24x7.

We wanted to implement a simple Java (JAX-WS) webservice on Google App Engine, but unfortunately this is not fully supported. All the javax.xml.* classes are available on Google App Engine, but not the com.sun.xml.ws.* classes that are normally used to implement a JAX-WS service. But with a little bit of custom code we can get a JAX-WS service to run on Google App Engine as can be seen in the SoapUI screenshot. You can download the public WSDL at https://redheap-jaxws.appspot.com/HelloWorldService.wsdl
SoapUI test invoking HelloWorld service on Google App Engine

You can use the normal JAX-WS annotations in your service class and use JAXB to marshal and unmarshal the request and responses. This is all very similar to a JAX-WS service on a JEE container. The thing you need extra is a custom HttpServlet that handles the HTTP POST, unmarshals the request payload to a java object using JAXB, invoke the actual web service class, marshal the web service class response back to XML and send it to the client.

This post describes all the steps to create a project using maven and complete it in JDeveloper 12c as well as deploying it to a local and remote server. If you prefer other build tools, like Apache ANT, or other Java IDE's you can still use similar steps but you might need to adjust them for your environment. The key part is the custom servlet which is the same for each setup.

Monday, March 31, 2014

Managed Bean changes should mark their ADF Scope dirty in a HA cluster

We're starting development on a new ADF application and the plan is to run this in a high-available weblogic cluster. The documentation clearly states it is the responsibility of the developer to make ADF aware of any changes to managed beans in an ADF scope with a lifespan longer than one request. This means it is up to you to notify ADF of each change in a viewScope or pageFlowScope bean with the following code:
Map viewScope = ADFContext.getCurrent().getViewScope();
ControllerContext.getInstance().markScopeDirty(viewScope);

That's not too difficult but it's a matter of time before a developer forgets about this. That would mean the ADF scope is not marked dirty and the changed managed bean is not replicated to the other nodes in the cluster. We wanted to implement a check (at least during development) that developers do not forget about this. JSF PhaseListener to the rescue!

Full source code is at the end of this posting, but I'll explain the vital parts first. We've create a JSF PhaseListener that listens to each JSF phase transition:
public PhaseId getPhaseId() {
    return PhaseId.ANY_PHASE;
}

In the beforePhase method for the RESTORE_VIEW phase we retrieve the viewScope and pageFlowScope maps. Next, we serialize these and calculate a MD5 hash. These hashes are store in the requestScope

In the afterPhase method for the RENDER_RESPONSE phase we calculate the same MD5 digests and compare these with the ones stored at the beginning of the request. We know we're in trouble when the digests changed and the developer has not invoked ControllerContext.markScopeDirty. When this happens we simple log an exception to the console without actually throwing it. This is more of a development/debugging tool and shouldn't actually abort JSF processing as that would also cancel any other PhaseListeners. We don't want to make things worse.

You probably want this enabled during development all the time. However, there is a performance overhead in serializing the viewScope and pageFlowScope twice per request and calculating a MD5 digest. It might be a good idea to disable this in production. That's why we opted to use the ADF logging framework for this. First, you can set the log levels that will be used for the output through web.xml context-parameters. By default, these are set to WARNING to ensure all logging is enabled in a default development environment. In production you want to use deployment plans to override this to something like FINE or FINEST. Once you know the logging level that is being used, you can even enable/disable these checks in a deployed application by tweaking the log levels of your weblogic container. The JSF PhaseListener is smart enough to not even perform the serialization and digest calculation of logging levels are setup so that logging doesn't occur. This means you could even leave the loggers in there for production so you could still enable them when cluster replication issues occur.

The demo workspace includes a singe page application to demonstrate the DirtyScopePhaseListener. Simply run that page and press the button marked "change viewState without marking dirty". This will log an error in the console that neatly explains the internal state of myViewScopeBean in the ADF viewScope was changed:

Hopefully this JSF PhaseListener can be a valuable tool for anyone building a ADF application intended to run on a session-replicating cluster.

As always you can download the full sample application or browse the subversion repository to look at the source code. If you want to have a quick look at the solution start with the com.redheap.dirtyscope.DirtyScopePhaseListener phase listener and the com.redheap.dirtyscope.ADFScopeChecker class that does all the digest calculating and checking.

Update: The sample code is broken. It only looks at the pageFlowScope and viewScope of the unbounded taskflow and does not consider any state in bounded taskflows and viewScopes running in regions. I am working on an improved version and will post a new blog entry once that is finished.

Monday, February 24, 2014

ADFLogger JAX-WS SoapHandler to log request, reponse and faults

Lately I see a lot of ADF projects consuming SOAP web services. This is typically done by creating a JAX-WS Proxy in JDeveloper and invoking this proxy from java beans exposed through the Bean Data Control or through programmatic ADF Business Components. This post will show how to instrument your JAX-WS proxy so it can log the SOAP request, payload and potential fault to an ADFLogger. This can be a very valuable tool during development and when diagnosing production issues.

Let's start with the final result, the weblogic console when invoking a web service that returns a soap fault. The nice thing is that it not only logs the fault but also the request that caused it:
SOAP request and response logged when receiving SOAP fault
When you crank up the log level you can even see all requests and responses that complete successful. As I described earlier this also allows for performance analysis with the Log Analyzer. This breaks down your entire request and our LoggingSoapHandler times the milliseconds it took to invoke the web service.
Log Analyzer showing this web service call took 5 msecs
This magic is performed by a JAX-WS SoapHandler. It can be registered with a JAX-WS proxy and has access to the web service request and response messages. Handlers can even change these, but in this example all we do is logging to the ADFLogger. You can setup handlers when creating the web service proxy or by right clicking an existing one and changing its properties.
Add LoggingSoapHandler as a Handler on the JAX-WS Proxy
You can get the full source code for the com.redheap.soaplog.LoggingSoapHandler class so you can add it to your own project or library. The embedded documentation is rather elaborate but I'll also explain the most important bits here.

Friday, January 3, 2014

Configuring ADF Faces for development

This post will describe how to configure your ADF Faces project for development through web.xml context parameters as well as enabling debug mode in trinidad-config.xml. It will also show how to override these settings for production deployment with a deployment plan even though the setting in trinidad-config.xml cannot be altered directly with a deployment plan.

More background information on all ADF Faces configuration parameters can be found in the appendix of the Web User Interface Developer's Guide. The ones we want to change during development are:
  • org.apache.myfaces.trinidad.CHECK_FILE_MODIFICATION to true to check for source files being modified on disk while the application is running and reloading them. Be sure to clear your browser cache after changing this value to clear out any old cached versions.
  • org.apache.myfaces.trinidad.resource.DEBUG to true to enable resource debugging and prevent the client from caching resources (eg javascript libraries, images, CSS, etc)
  • org.apache.myfaces.trinidad.DISABLE_CONTENT_COMPRESSION to true to disable CSS content compression and use human-readable CSS class names for skinning
  • org.apache.myfaces.trinidad.DEBUG_JAVASCRIPT to true to non-obfuscated javascript
  • oracle.adf.view.rich.LOGGER_LEVEL to FINE to enable client side javascript logging. Other allowed values are SEVERE, WARNING, INFO, CONFIG, FINE, FINER, FINEST, and ALL
  • oracle.adf.view.rich.ASSERT_ENABLED to true to enable client-side javascript assertions

Tuesday, November 19, 2013

JDeveloper Extension To Suppress Warnings

The JDeveloper auditing framework can be a very valuable tool in delivering high quality code. It not only gives you warnings and errors during development, but can also be run from the command-line on a build server. One thing that always annoyed me is the limited possibilities for suppressing individual warnings. Sure, there is the @SuppressWarnings annotation for Java code. JDeveloper 12c can even use this annotation to suppress any warning, not only the ones supported by the java compiler.

However, much of an ADF (or SOA) application is XML files, not java. JDeveloper 12c doesn't offer a way to suppress warnings in these files. Luckily the auditing framework is highly pluggable and after some inspection how the @SuppressWarning annotation is implemented in the auditing framework, I could create something similar for XML files.

Suppressing a warning in a JSF file

The screenshot above shows how the extension works. See the warning for the value property of the af:outputText component and how it marks this entire document as warning. Simply click the balloon in the gutter of the editor and select to suppress this warning. This adds a comment to the XML file to suppress the warning, very similar to a @SuppressWarnings annotation in java.

Suppressed warning in a JSF file
Notice how the document is now marked green an no more warnings appear. With this extension you can keep the number of warnings down so the real warnings get the attention they need.

I have plans on building a SonarQube extension to run ojaudit (the command line JDeveloper auditing tool) to keep track of your quality. Suppressing warnings can be especially valuable in that situation where you can use SonarQube to keep metrics and track unexpected warnings and errors.

The extension is already live, so simply start JDeveloper 12c and use the Help > Check for Updates feature. Be sure to check "Open Source and Partner Extensions". You should be able to find the "Suppress Audit Warnings" extension. Please leave a comment below if you have any questions or suggestions for a future version.

If you want to see how a custom suppression scheme is built you can download the full workspace or simply browse the subversion repository to look at the source code.

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.

Friday, March 15, 2013

ADF Faces Client Behavior with Attributes

Last month I posted about the basics of creating custom ClientBehavior in ADF Faces. Now it is time to take the next step and enhance that example with ways to set attributes on the JSP client-behavior tag, pass these on to the client-side javascript implementation and use them in the actual functionality.

We'll take the (simplified) example of the previous post that could show a javascript alert and adopt it to get the message from an attribute which we specify in the JSF page using the component. We'll also make sure we can use an EL expression to specify this values (this is the tricky part). We will be able to do something like:
<af:forEach begin="1" end="5" varStatus="vs">
  <af:commandButton text="click to see message #{vs.index}" id="cb">
    <redheap:showAlertBehavior message="This is message #{vs.index}"/>
  </af:commandButton>
</af:forEach>