Glen Mazza's Weblog

Main | Next page » Saturday June 27, 2015

Git & GitHub Notes

  1. For ease, fork the repo on GitHub and clone your fork rather than the main repo, then

    git remote add upstream
    to link to main repo.

  2. git push origin branchName -- "origin" refers to the fork (here, one's own, else can be upstream or any other created via git remote)

  3. To switch between branches locally, git checkout <branch name> (use git branch to see a list); to check out a new branch based on the one you're currently in, git checkout -b <new branch name>

  4. git fetch upstream [branch or remote branch:local branch] - update pointers to latest code, git merge afterwards (or git pull to do both) to update local code. If any automated merge failures, right-click Git->Resolve Conflicts from IntelliJ to resolve manually.

  5. To place your changes on one branch above those from another: (from your branch): git fetch as above, then

    git rebase [branch name to retrieve from]
    , then
    git push origin brname -f
    to update GitHub fork.
  6. Recovering from an accidental pull: SO #1, SO #2. Another possibility: git rebase -i HEAD~xxx to supposedly squash the commits, but I instead removed all unwanted commits from the pull. Then git rebase to bring in actual wanted branch.

  7. To pull a different branch to your local machine:

    git remote add upstream
    git fetch upstream
    git co upstream/release/branchname
    git co -b [newBranchNameHere]
  8. To checkout a tag.

  9. To check out a coworker's branch:

    git remote add coworkerFork
    git fetch coworkerFork hisBranch:newNameForYourLocalBranch
  10. In GitHub pull requests, use ``` or ```json to format code (JSON)

  11. In PR reviews, use : to bring up icons.

  12. Deleting a branch:

    git branch -D branchnames...

  13. List of repos presently watching:

  14. Squashing commits:

    git log
    to find number of commits to squash,
    git rebase -i HEAD~X
    (X is number of commits). 1st page: mark all but first commit "s" for squash, 2nd page, edit common commit message. Standard editor: Ctrl-K to remove lines, Ctrl-X to save. Then
    git push origin brName -f
    to update remote.

  15. git cherry-pick to copy commits from one place to another. (How to merge a PR against one fork into your own)
  16. Wanting to create a new branch without committing changes first:
    git stash, git checkout -b newBranch, git stash pop
  17. Undoing changes:
    git checkout <branch_copying_from> -- <file_to_reset>
  18. branch rewinding - another method for combining commits when the work was not done on a separate branch.
  19. JQuery Commits and Pull Requests Guide
  20. Checking out an older git version (snapshot)
  21. Adding Git Aliases -- simplify terminal window commands
  22. Efficient way to do commits:
    git log --oneline --decorate
  23. Which release contains a commit? git fetch --all followed by git tag --contains (hash)
  24. Amending commit messages Monday November 24, 2014

Using UsernameToken security with Apache CXF

This tutorial modifies the CXF version of the WSDL-first DoubleIt web service to include WS-Security with UsernameTokens. This profile should be used with transport-layer encryption (i.e., SSL) as a minimum to ensure the username and password are encrypted at least between the client and the first recipient node. Note the X.509 or SAML token approach would be more appropriate instead if any of cases below apply:

  • Clients need to sign the request to guard against it being altered in transit
  • There are intermediary nodes between client and service that would be unencrypting the message (and hence able to read its contents) before forwarding it on to the next node
  • The web service provider has incomplete nonce and timestamp support necessary to guard against replay attacks. CXF has implemented such caching since version 2.6, and it also appears supported with Metro.

CXF provides two main options for adding UsernameToken security headers, both of which will be covered below: WS-SecurityPolicy and manual CXF interceptors. The former relies on the WSDL already having WS-SecurityPolicy elements defined within it to obtain the security requirements. Use the manual CXF interceptor approach when security is not defined in the WSDL or more customized control of the security header construction is desired.

Note one difference between CXF's UsernameToken implementation and Metro's is that the former requires explicit service-side callback handlers to validate passwords while the latter, for the Tomcat and the GlassFish server, will validate against container usernames and passwords if no service-side callback handler is declared. However, CXF provides a JAASLoginInterceptor for container-based authentication.

The finished tutorial source code can be obtained from GitHub by using either the download ZIP button or git clone -v git:// command. The download is configured to use WS-SecurityPolicy, if desired make the adjustments specified below to switch to the CXF interceptor approach.

  1. Implement SSL without basic authentication for the web service. This is the same as Step #1 of the Metro/UsernameToken guide.

  2. Include additional Maven dependencies to handle security processing. The following dependency will need to be added to the project-level pom.xml to activate security processing.


    Also, since we'll be adding a Spring cxf.xml configuration file to the client to declare the security parameters, we'll need to add a Spring dependency to the client/pom.xml. (See notes at the bottom for a non-Spring way of doing client configuration.) While CXF is relatively flexible with the version of Spring that you use, to determine the optimal (tested) version of Spring for your version of CXF, go to the tags folder of the CXF source repository, select your version of CXF, and under that folder select the folder named "parent" and open its pom.xml. Search for the cxf.spring.version variable to determine the version to use.

  3. Configure the client to provide the user and password. We'll be introducing a Spring-based cxf.xml configuration file, presently configured for the WS-SecurityPolicy approach but can be switched over to the CXF interceptor approach by following the comments given below in this source file.

    Next supply the password CallbackHandler that was listed in the SOAP client above. Place this class in the same package as the SOAP client:

    package client;
    import org.apache.wss4j.common.ext.WSPasswordCallback;
    public class ClientPasswordCallback implements CallbackHandler {
        public void handle(Callback[] callbacks) throws IOException, 
                UnsupportedCallbackException {
            WSPasswordCallback pc = (WSPasswordCallback) callbacks[0];
            if ("joe".equals(pc.getIdentifier())) {
            } // else {...} - can add more users, access DB, etc.
  4. Add the WS-SecurityPolicy statements to the WSDL. This has already been done in the Service WSDL in the source code download, which uses the WS-Policy statements created in the Metro UsernameToken tutorial. CXF interceptor method only: We'll need to use a Policy-free WSDL, so remove this DoubleIt.wsdl and rename the Policy-free DoubleItInterceptorMethod.txt found in the service submodule resources folder to DoubleIt.wsdl (it's the same WSDL from the standard DoubleIt tutorial.)

  5. Configure the service provider to authenticate the username and password tokens. Here we'll need to modify the cxf-servlet.xml configuration file from Step #6 of the WSDL-first tutorial to add either the CXF inbound interceptor or WS-SecurityPolicy configuration information (not both.) Replace the previous cxf-servlet.xml file with the following, after modifying it based on your security implementation preference:

    Once done we'll need to add the new server-side password callback class referenced above, which provides the correct password for a user, which the CXF framework uses to compare with what is supplied in the client request. Place the following ServerPasswordCallback class to the same package as the service's DoubleItPortTypeImpl SEI implementation class:

    package service;
    import org.apache.wss4j.common.ext.WSPasswordCallback;
    public class ServerPasswordCallback implements CallbackHandler {
        public void handle(Callback[] callbacks) throws IOException,
                UnsupportedCallbackException {
            WSPasswordCallback pc = (WSPasswordCallback) callbacks[0];
            if ("joe".equals(pc.getIdentifier())) {

    You can now compile and redeploy the web service from the DoubleIt base folder.

  6. Test the client. Run the client as shown in the DoubleIt tutorial. Best to test also with incorrect usernames and passwords to ensure the web service provider is catching these errors.

    You can view the headers being added to the SOAP request if you temporarily switch your web service back to non-SSL usage. This can be done by updating the web.xml and URL within the WSDL, and additionally if you're using WS-SecurityPolicy, removing any WSDL element declaring a requirement for SSL. Once done you can either use Wireshark or activate logging within your WSClient class to see the unencrypted SOAP messages. Running the client from a terminal window will show results similar to the following:

    Oct 1, 2011 7:47:34 PM
    org.apache.cxf.interceptor.AbstractLoggingInterceptor log
    INFO: Outbound
    ID: 1
    Encoding: UTF-8
    Content-Type: text/xml
    Headers: {Accept=[*/*], SOAPAction=[""]}
    <soap:Envelope xmlns:soap="">
                <wsse:UsernameToken wsu:Id="UsernameToken-1">
            <ns2:DoubleIt xmlns:ns2="">
    Oct 1, 2011 7:47:34 PM
    org.apache.cxf.interceptor.AbstractLoggingInterceptor log
    INFO: Inbound
    ID: 1
    Response-Code: 200
    Content-Type: text/xml;charset=UTF-8
    Headers: {Content-Length=[238],
    content-type=[text/xml;charset=UTF-8], Date=[Sat, 01 Oct 2011 23:47:34
    GMT], Server=[Apache-Coyote/1.1]}
    <soap:Envelope xmlns:soap="">
            <ns2:DoubleItResponse xmlns:ns2="">
    The number 10 doubled is 20

    If you do this, remember to switch back to SSL for production usage.


If desired, you can avoid introducing a Spring dependency in the client by not using a cxf.xml configuration file and instead declaring security using the Java API in the client's WSClient class. A sample alteration demonstrating both the WS-SecurityPolicy and CXF interceptor approaches is as follows:

import org.apache.cxf.endpoint.Client;
import org.apache.cxf.endpoint.Endpoint;

public class WSClient {
    public static void main(String[] args) {
        DoubleItService service = new DoubleItService();
        DoubleItPortType port = service.getDoubleItPort();

        // WS-SecurityPolicy configuration method
        Map ctx = ((BindingProvider)port).getRequestContext();
        ctx.put("ws-security.username", "joe");
        ctx.put("ws-security.callback-handler", ClientPasswordCallback.class.getName());
        // instead of above line can also do:
        // ctx.put("ws-security.password", "joespassword");
        // Alternative CXF interceptor config method
        Client client = org.apache.cxf.frontend.ClientProxy.getClient(port);
        Endpoint cxfEndpoint = client.getEndpoint();
        Map outProps = new HashMap();
        outProps.put(WSHandlerConstants.ACTION, WSHandlerConstants.USERNAME_TOKEN);
        outProps.put(WSHandlerConstants.USER, "joe");
        outProps.put(WSHandlerConstants.PASSWORD_TYPE, WSConstants.PW_TEXT);
        WSS4JOutInterceptor wssOut = new WSS4JOutInterceptor(outProps);
        ... Monday October 06, 2014

Returning PDFs from Web Services using MTOM and Apache FOP

Summary: Use MTOM and Apache FOP within your Apache CXF- or Metro-based web services to send PDFs to and from SOAP clients.

[Read More] Monday September 29, 2014

Activating Transport Layer Security (SSL) for web services

See how to implement SOAP web services over SSL.

[Read More] Monday September 22, 2014

Creating a Java-first web service using CXF or Metro

Summary: This article shows the changes needed to the WSDL-first DoubleIt tutorial to convert it to a start-from-Java (no WSDL) process.

[Read More] Monday September 15, 2014

Creating a SOAP client with either Apache CXF or GlassFish Metro

Summary: This tutorial shows how SOAP clients can be created using either Apache CXF or GlassFish Metro. We'll be creating a Maven-based client for the eBay Shopping Web Service, which provides a full range of search and retrieval capabilities for items being auctioned on the eBay site.

[Read More] Monday September 08, 2014

Creating a WSDL-first web service with Apache CXF or GlassFish Metro

Summary: This tutorial shows how to create a WSDL-first web service using either Apache CXF or GlassFish Metro. We'll be using Maven as our build tool, with web service deployment on either Tomcat (for CXF or Metro) or OSGi deployment with Apache Karaf (CXF only).

[Read More] Saturday June 14, 2014

Creating a Java Swing alternative to JConsole for calling MBeans

In this article I show how to create a Java Swing application to interact with MBeans in a manner specific for your needs, reducing need to use JConsole.

[Read More] Sunday April 27, 2014

Working with Apache Roller source code

Note: I forked Apache Roller in May 2015, and am now working separately on a new blogging product named TightBlog (not yet ready for release).

This entry explains the development environment and process I use for working on the Java-based Apache Roller blog server. I'm blogging this article to make it easier for those wishing to help with Roller development, also to assist Roller users wishing to modify Roller trunk code to better suit their needs (perhaps to bring in additional themes beyond those pre-packaged by Roller.) I use IntelliJ IDEA community edition on Ubuntu, but other IDEs and OSs are also used by other Roller team members. Some prerequisites for programming Roller:

ToolBefore proceeding, make sure you can...
JDK 1.7 or 1.8Activate "java" and "javac" from any folder in a command-prompt window
Apache MavenActivate "mvn" from any folder in a terminal window
Command-line Subversion clientRun "svn" from any folder in a terminal window
Standalone Tomcat 7 or 8Can start and view Tomcat from http://localhost:8080
MySQL or Apache Derby databaseCan activate mysql or ij (for Derby) from any folder in a command-prompt window.
Firefox Web BrowserOptional; used for running Selenium tests without needing to activate Tomcat
SQL Query tool such as SquirrelSQLOptional but recommended; used for querying the Roller database instance.

Trying to keep this blog of reasonable size, if you're new to any of the above tools their usage and setup are all well documented elsewhere on the 'Net. If you're already a Java developer and have GUI alternatives for the above command-line tools they should work fine as well (but be mindful of Ben Franklin's admonition about deviating from the terminal window for your work. :)

The instructions here are for Roller trunk (upcoming 5.1 version), which is much simpler, faster to build, and more modernized compared to the Roller release (5.0.x) versions; most all development is now occurring on the trunk.

  1. Check out Roller source and add any desired additional themes - Do an SVN checkout of Roller trunk and build it via the standard Maven mvn clean install command. If you wish to add any additional blog themes, place them in the src/main/webapp/themes folder prior to building Roller. Make sure you have a successful Roller build (including JUnit tests) before proceeding further.

  2. Prepare database and (optional) mail configuration - Follow the short Chapter 5 and Chapter 6, Sections 1-4 of the Roller Install Guide (ODT). Chapter 5 provides the few commands needed to configure an empty MySQL, PostgreSQL, or Derby database and Chapter 6 the configuration of the file, optional Mail configuration, and the required Mail and JDBC JARs that will be needed in Tomcat's lib folder. The test file that I have in my Tomcat lib folder is as follows:

    # Any properties placed below overrides Roller default settings defined in
    # the file embedded within the Roller WAR, and should be 
    # stored in the CATALINA_HOME/lib folder for Tomcat.
    # Roller file and logging level
    # EclipseLink debugging
    # Mail config (See Roller Install Guide)

    Before moving on to the next step, best to deploy the app/target/roller.war to your Tomcat webapps directory, start Tomcat and confirm you can run the application at http://localhost:8080/roller. This is an important one-time check to ensure your database, file, Tomcat, and Roller WAR are all properly configured, and once confirmed you should be in good shape for all subsequent coding and debugging. If any deployment problems, make sure you've reviewed Chapters 5 and 6 of the Install Guide, and if necessary contact the Roller User's List for assistance.

  3. Create a script to start development with everything needed - For efficient start-up I've created a script that opens up all needed windows and applications at once instead of having me needing to do so manually each time I start development. A simplified version of my is as follows and explained below:

    gnome-terminal --geometry=132x24 \
       --tab-with-profile=HasTitle --title "ROL Trunk" --working-directory="/work/opensource/roller-trunk" -e "bash -c \"svn update; exec bash\"" \
       --tab-with-profile=HasTitle --title "ROL Trunk2" --working-directory="/work/opensource/roller-trunk" -e "bash -c \"echo -Dmaven.surefire.debug; exec bash\"" \
       --tab-with-profile=HasTitle --title "Servlet Container" \
       --tab-with-profile=HasTitle --title "IntellijIDEA" -e "bash -c \"sh; exec bash\"" \
       --tab-with-profile=HasTitle --title "GEdit" -e "gedit worklog.txt /home/gmazza/ $CATALINA_HOME/lib/ $CATALINA_HOME/logs/catalina.out $CATALINA_HOME/logs/roller-tomcat.log `find $CATALINA_HOME/logs/localhost*.log` $CATALINA_HOME/logs/eclipselink-tomcat.log /work/opensource/roller-trunk/app/target/roller.log /work/opensource/roller-trunk/app/target/eclipselink.log " \
       --tab -e "dolphin --geometry=600x500+1+1 /work/opensource/roller-trunk $CATALINA_HOME" \
       --tab -e "firefox http://localhost:8080/roller"
    #  --tab-with-profile=HasTitle --title "SquirrelSQL" --working-directory="/work/tools/squirrel-sql-3.5.2" -e "bash -c \"sh; exec bash\""

    The above script opens a multitab Console window which in turn opens a few separate application windows. In particular:

    • I open two terminal tabs pointing to the Roller trunk branch. This allows me to build Roller from one terminal while possibly reviewing my changes (using commands svn status and svn diff, for example) in the second window. I echo the -Dmaven.surefire.debug in the second tab just to quickly remind myself the Maven string to add during JUnit test debugging (covered below).
    • I have a separate "ServletContainer" tab open to my home folder for manual activation of servlet containers (Roller is tested on Tomcat, GlassFish, and JBoss) or other applications from the command line. I don't need this as often due to the script (discussed below) I now use.
    • I use a tab for starting IntelliJ IDEA.
    • I open the multi-tab GEdit text editor with several files that are handy for me during development:
      • worklog.txt - A scratchpad file of TODO notes, commands, etc. that I keep for personal use between coding sessions.
      • - The very script above, I keep handy in case I need to make adjustments or additions to it.
      • - The Roller configuration file discussed above and used by all Roller deployments to my standalone Tomcat. Changes I made here are activated on the next Tomcat restart.
      • catalina.out, roller-tomcat.log, localhost*.log, eclipselink-tomcat.log - These are logging files filled by Tomcat and/or Roller during running, usually very important for debugging as error logging usually gets written to one of these files. When you see terse "System" or similar errors reported by Roller in the web browser be sure to check these files for the error in detail.
      • roller.log, eclipselink.log - These files are under Roller's target directory and are populated during JUnit test running via the Maven test phase, as discussed below.
    • Dolphin - A multitab file browser that I have opened to the Roller trunk code and Tomcat folders for easy access to files.
    • Firefox - Here I pre-open tabs to the Roller website, JIRA task tracker and Sonar issues list, source code repository, and default location for Roller once it's deployed to Tomcat.
    • SquirrelSQL - Commented-out by default but used when I wish to query the Roller database to see the values that Roller is reading/writing. SquirrelSQL will need your database's JDBC JAR added to it as well as have the connection information you configured in

    For scripts such as the above make sure there's no whitespace after the ending "\" on each line (error messages will pop up otherwise), and use a leading # (as shown above for SquirrelSQL) for actions you wish to disable by default. The $CATALINA_HOME specified above, as usual, is the base folder for your standalone Tomcat installation. In addition to the above configuration, you may wish to keep handy the Roller trunk documentation, kept in OpenOffice format in the Roller/docs folder or online.

  4. How to build and deploy to local Tomcat - After a successful mvn clean install from the Roller trunk folder, I run this shell script that I keep in that folder:

    fuser -k 8080/tcp 8009/tcp 8005/tcp
    rm -r $CATALINA_HOME/webapps/roller
    cp ./app/target/roller.war $CATALINA_HOME/webapps
    rm $CATALINA_HOME/logs/*.log
    rm $CATALINA_HOME/logs/catalina.out

    For rapid iteration when I don't need to run the tests each time, I simplify my build and deploy process to a single line: mvn clean install -Dmaven.test.skip ; sh

    The above file first kills the Tomcat instance (via fuser -k), deletes the previous expanded Roller webapp directory on the Tomcat instance and copies the latest created Roller WAR over, and clears all the logs before finally restarting Tomcat with the new WAR. The new Roller will be accessible at http://localhost:8080/roller again using the same $CATALINA_HOME/lib/ and database (i.e., all database-stored information including test blog data created will be immediately picked up by the new Roller WAR.)

  5. How to debug on local Tomcat - Learning to debug from your IDE any webapp running locally on standalone Tomcat is frequently vital when troubleshooting and thankfully simple to do. First, add to your Tomcat CATALINA_OPTS environment variable:

    export CATALINA_OPTS=$CATALINA_OPTS" -Xdebug -Xrunjdwp:transport=dt_socket,address=5005,server=y,suspend=n"

    Then from IntelliJ IDEA (or Eclipse), go to menu item Run -> Edit Configurations, add a Remote Configuration with a name of your choice and accepting the given defaults, and select OK. If Roller is already running on Tomcat, debugging can be activated at any time by setting breakpoints in the code that the Roller app would be activating, selecting menu item Run --> Debug {debug config name}, and then proceed with any needed code tracing.

  6. How to debug unit tests - To activate a specific Roller JUnit test, navigate to the {Roller Trunk}/app folder and run mvn test -Dtest=TestClassName#OptionalTestMethodName, as explained in the Maven Surefire Plugin documentation. To debug (code trace) the JUnit test within your IDE, add the -Dmaven.surefire.debug setting, set breakpoints in your IDE within code called by the tests and have it listen to port 5005 as before.

    Files to read: When running the JUnit tests, besides the Surefire results in the target/surefire-reports folder the target/roller.log file provides logging of the temporary in-process Roller instance. Also, to determine any potential SQL/JPA problems, EclipseLink JPA logging can be activated, with the output file also in the target folder, by uncommenting the eclipselink.logging.* properties in the app/src/test/ file.

  7. How to run Selenium tests - Roller's Selenium tests test very basic functionality (setting up a blog and saving a blog entry) but can sometimes serve as a quick sanity check that minor, last-second source code changes did not cripple the application. Navigating to the trunk/it-selenium folder and running mvn clean install will cause a temporary instance of Roller to activate that is subsequently used by Selenium to run its tests in Firefox. For these tests, none of the database or Tomcat configuration created above will be used, instead Roller will be running an embedded Jetty and a temporary (in-memory) Derby database, and shut down once Selenium is finished.

Additional Notes: Monday February 03, 2014

Creating Selenium tests for Java Web Applications

To reduce the amount of manual testing needed for the Java-based Apache Roller blog server, I added a Maven submodule that uses Selenium for automated in-browser testing. Presently only basic Roller functionality is being checked (create a user, create a blog, blog an entry, confirm the entry was saved), but I expect it to be filled out more over time. Its structure may be useful for other Java projects wishing to incorporate Selenium testing. The submodule POM relies on the Jetty Maven plugin to activate Roller, Brian Matthew's inmemdb-maven-plugin to activate an in-memory (i.e., no files created) Derby database instance, and finally the Maven Failsafe plugin to activate the Selenium tests, necessary as the tests run under Maven's integration-test phase.

To see Selenium in action, testing Roller (requires Firefox and Maven 3.0.5):

  1. Check out the Roller source using SVN:

    svn co roller_trunk
  2. Run mvn clean install from the roller_trunk (base) folder to build Roller and have it installed in your local Maven repository (from where it will be read by the Selenium tests). Building itself is quick (about two minutes on an average machine), however the initial download of Roller's dependencies, if not already in your Maven repo, could take some additional time.

  3. Navigate to the roller-trunk/it-selenium folder and run mvn clean install or mvn integration-test. Selenium will activate Firefox at Roller's home URL (http://www.localhost:8080/roller) and run its tests.

Some notes on creating Selenium-driven tests for web applications:

Using Selenium IDE to generate browser actions. Reviewing the nicely succinct documentation for Selenium IDE and Selenium WebDriver is a great way to get started. Selenium IDE is a Firefox plugin that records manual interaction with the application under testing ("AUT", using the documentation's terminology) into a script, which can then be activated from Selenium IDE to automatically re-run the same actions against the AUT. After adding testing assertions and verifications and confirming the script is moving through the AUT successfully, Selenium IDE can then be used to export the script as Java to incorporate into your WebDriver-backed Maven submodule. After becoming acquainted with the WebDriver Java API by working with a few exported files, you'll most probably find yourself able to code additional tests in Java directly without need for Selenium IDE.

Making adjustments to Selenium IDE scripts. Due to the manner in which Selenium IDE populates HTML form fields (perhaps by direct manipulation of the underlying HTML DOM document), certain mouse, key, and focus DOM events are not activated as they would be with manual data entry, resulting in necessary JavaScript not getting activated. For example, a submit button which would become enabled via JavaScript as a result of the data entry fields all being filled manually may remain disabled when Selenium IDE populates the form, making it unable to click that button and proceed. This occurred on one of Roller's registration screens -- the solution was to look for the DOM event in the JSP or generated HTML source which is needed to trigger the necessary JavaScript:

    <td class="field"><s:password name="bean.passwordConfirm" size="20" maxlength="20" onkeyup="onChange()" /></td>

<script type="text/javascript">
function onChange() {
    var disabled = true;
    var openIdConfig    = '<s:property value="openIdConfiguration" />';
    var ssoEnabled      = <s:property value="fromSso" />;

...and then add a fireEvent command within Selenium IDE prior to the command for clicking the Submit button:

Command:  fireEvent
Target:   id=register_bean_passwordConfirm
Value:    keyup

Note the Value above is keyup and not onkeyup; also, the target ID can be determined by having the browser display the HTML source for the page.

Exporting test cases (or a suite of test cases) into Java. Note that the Java exported cannot be reimported back into Selenium IDE for subsequent modification, although you can always save another copy of the test cases as HTML, load it into Selenium IDE for tweaking, and then do another export into Java. Also, exporting into Java is not strictly required (the Selenium Maven plugin used by Apache JSPWiki as shown here can work with Selenium IDE's default HTML), although I would not recommend HTML as you'll lose significant object-oriented coding advantages including code reuse.

The Selenium IDE File-->Export Test Case menu item provides three JUnit 4-based options:

  • RC - Uses the older Selenium 1 RC API.
  • WebDriver Backed - Uses Selenium 2's WebDriver to implement the Selenium 1 RC API. Good for transitioning from Selenium 1 to 2.
  • "pure" WebDriver - Uses Selenium 2's WebDriver API. I exported using this option, as presumably all new work should be based on Selenium 2.

In looking at the exported Java class(es), you may see commented "errors" about fireEvents (and possibly other commands) being unsupported, for example:

// ERROR: Caught exception [ERROR: Unsupported command [fireEvent | id=xxxx | keyup]]

This is usually not cause for alarm--the Selenium team decided not to support fireEvents in Selenium 2, feeling that WebDriver should instead internally fire the events that would occur if the data was entered manually. Alternatively, in certain cases testers can add actions that will cause those events to naturally activate. In my particular instance with the Roller submit button, it turned out no replacement coding was necessary as WebDriver, unlike Selenium IDE, was able to automatically fire the needed events based on the fields it filled. Note, worst case, it remains possible to execute JavaScript to fire the DOM events manually if the Java tests will not work otherwise, but before doing so, best to Google and/or search the Selenium Users Group with the specific "Unsupported command" message to see if a more standard solution is available.

Examine better ways to design tests. When working with the Java test classes, ways to improve their design using standard object-oriented techniques will become apparent. Foremost is moving to the Page Object design pattern (links). Thomas Sundberg's article shows the natural process of getting to that pattern by way of factoring out common functionality from the tests and additionally suggests using Cucumber for behavior-driven development. Some other suggestions:

  • Create an abstract base class for your page objects to handle common functionality--populating fields, validating screen titles, taking screen snapshots or logging the page source for errors, etc.

  • Although using the method on form submits will normally halt processing until the next screen appears (and so far has always worked for me), the FluentWait object can also be used to explicitly halt Selenium until a specified HTML element on the new page appears (or a timeout you specify occurs).

  • For your page objects, create an additional multi-parameter constructor to allow for convenient creation of page objects in cases where the page is just being used to get to another page that is under testing. As such a page being activated with this constructor would not be under testing itself, just providing the minimum number of parameters in the constructor necessary to navigate to and test the desired page should be sufficient.

  • For time, accuracy, and efficiency, I would advise against turning your page objects into POJO's, with instance variables for each screen field and getters and setters for all fields. So far, I've added getters and setters for a field only when such a method is needed by a test case. Further, I'm not creating member variables in the page object for each widget, both to simplify the objects and out of fear that their values might deviate from what's actually on the browser screen. Instead, each accessor directly reads from or writes to the browser screen.

  • If you do wish to go the POJO route, take a look at the PageFactory object and @FindBy annotation, both described well on the ActivelyLazy blog.

  • In the Page Object model, when a submit button always moves the application from Screen A to Screen B, a typical Page Object method that your test classes will call will be as follows:

    public class LoginPage {
        public UserDashboardPage loginToApp() {
            // clickById() provided by AbstractRollerPage superclass
            return new UserDashboardPage(driver);

    What do you do, however, if the subsequent screen could vary depending on the state of the application--for example, a login page might take you to a password-has-expired screen, a message notification screen if messages present, or the usual application screen if neither of the other cases hold? According to this article, it's recommended to have the page object implement different methods based on each different output possible, and have the test case call the appropriate method it's expecting based on the application state that it has created:

    public class LoginPage {
        ...other method above...
        public ChangePasswordPage loginToAppPasswordExpired() {
            return new ChangePasswordPage(driver);
        public UserNotificationPage loginToAppUrgentNotification() {
            return new UserNotificationPage(driver);
  • Typically the constructor of a Page Object includes a sanity check verification that the page title is as expected (i.e., the WebDriver is actually on the page it is presumed to be on), throwing an exception if it is not. If you have multiple screens with the same title an alternative check based on an HTML element ID can be done. This will require that each page sharing the same title has a unique HTML ID attribute on an HTML element present only on that page, so you may need to have the page markup modified to include such an attribute.

Other Notes:

  1. To run multiple iterations of the same Selenium tests under different circumstances (e.g., using different security authentication methods), Juan Pablo of the Apache JSPWiki Team developed a WAR overlay method along with parameter filtering to configure each of the tests - check the JSPWiki IT Tests module to see the process.

  2. Functional Automated Testing Best Practices with Selenium WebDriver - presentation by Ben Burton

Valid HTML! Valid CSS!

This is a personal weblog, I do not speak for my employer.