Showing posts with label Ant. Show all posts
Showing posts with label Ant. Show all posts

Thursday, July 15, 2010

Evil Ant Build Properties

In anticipation of the release of Java 6, which will include a standard for integration of scripting languages with Java called ”JSR-223“, there is a heightened interest in the subject of combining scripting languages with Java. While a quasi-standard API (BSF) has existed for a while, it's also possible to use a scripting engine through its native API. While this approach eschews some of the benefits of both JSR-223 and BSF (e.g., the possibility to use scripts in any language, not just one particular one), it makes it possible to use advanced features of a scripting language that cannot be accessed through a standardized API.

This article looks at the capabilities of the Rhino JavaScript engine, which has been around for quite a while. It's important to realize that Rhino implements the JavaScript language only; there are no window or document objects which in a web page could be used to manipulate the page content. That's because Rhino does not operate in a browser environment (even though its origins are in Netscape's abortive attempt to write a web browser in Java).

Applications use script engines generally in one of two ways: embedding, which means external (e.g. user-defined) scripts are called by the application, or scripting, which means that an external script calls a Java application (or library) for its own purposes. Loosely speaking, in embedding mode, the script does something for the application, while in scripting mode, the application does something for the script. Rhino can be used for both purposes.

Examples

The following examples illustrate how a Java application can interact with JavaScript scripts, and how data is passed back and forth between both languages. The source code, which also includes the Rhino library, can be downloaded here.

Examples 1 through 4 can be run from the command line by

java -classpath .:js-1.6R3.jar Example1

(replace Example1 by Example2 etc.), while Example5 is run by

java -classpath js-1.6R3.jar org.mozilla.javascript.tools.shell.Main -f scripts/example5.js

Example1 is just about the shortest possible host application that calls into Rhino to make it do something. It creates a Context for executing JavaScript and uses that to call the example1.js script. The script in turn defines a simple function and calls it with a particular parameter (42). The result of the function is passed back to the Java application where it is converted to a double and printed to standard out. String or boolean values could also be handled through the toString and toBoolean methods, respectively, instead of toNumber.

Example2 is a little bit more complicated. It reads the script example2.js -which defines a single JavaScript function that takes two parameters-, but instead of calling it directly, it causes the function to be compiled into a Function object. This allows the function to be called repeatedly with varying parameters. The application then calls the compiled function ten times with different parameters.

Note the difference between cx.evaluateReader used in Example1, which interprets a complete script in one go, andcx.compileFunction and func.call used in Example2, which deal with one particular function.

Example3 introduces the Scriptable object, which can be used to pass named variables back and forth between Java and JavaScript. In the example, an Integer (”javaNumber“), a String (”javaString“) and System.out (”systemOut“) are passed to the script, while the ”result“ variable is set in the script and then read by the host application.

In addition, the script uses the System.out object to invoke its println method, and thus cause output to be written to standard out. This works via the Java Reflection API, and can be used to invoke any method of any object accessible to a script.

Example4 demonstrates how to invoke methods in several other ways. It completes the construction of a GUI which the Java application has begun. Note that in order to access Java classes, they need to be prefixed by ”Packages.“, so e.g.java.awt.Button becomes Packages.java.awt.Button. This is necessary to distinguish Java objects from regular JavaScript identifiers (which ”Java“ would otherwise be).

Finally, Example5 does away with the Java host application completely. It consists of just a JavaScript script that constructs a Java GUI application.

It also introduces the ”importPackage(java.awt)“ notation, which is similar to the Java import statement, and allows us to write ”Button“ instead of ”Packages.java.awt.Button“.

In addition, it shows how event handlers (an ActionListener and a WindowListener) can be used.

Advanced topics

The previous examples introduced some of the basic features of the Rhino scripting engine, but it has plenty of advanced capabilities, which at least merit a brief mention.

  • It is possible to keep several JavaScript execution environments in a single application by creating more than one Scriptable object. Those environments will have separate namespaces, meaning the same variable name can have different values in the differentScriptable objects, and a different set of JavaScript functions can be defined in each.

  • Besides interpreting scripts, scripts can be compiled into Java bytecode and also optimized, thus improving performance. This is handled by the Context.setOptimizationLevel method.

  • It is possible to prevents scripts from accessing particular classes. That's useful if a script is not fully trusted, and can be controlled by using a ClassShutter object with the Context.setClassShutter method.

  • For even tighter security, a Context can be sealed, which means that a script can not alter it or any of its properties (Context.seal and Context.unseal methods).

  • Rhino also contains an interactive shell, through which JavaScript code can be executed directly. This can be useful for testing purposes. The shell is started by
    java -classpath js-1.6R3.jar org.mozilla.javascript.tools.shell.Main

  • Thanks to the Apache XMLBeans library, XML is kind of a data type in Rhino, and can be queried and manipulated through Javascript syntax. This technology is known as E4X.

Advanced Ant Techniques, Part II

Introduction

This January Ant celebrated its 6th year birthday. In January of 2000, the Ant tool, which was created by James Duncan Davidson to build his Apache project called Tomcat, was moved out of the Tomcat source and into a separate Apache project. Since then it has brought the words "build" and "manageability" closer than ever. Ant gained popularity because of its simplicity, extensibility and cross platform support and within a short span of time has become the build tool of choice for a large number of commercial and open source projects alike.

Although Ant has been extremely successful as an enterprise build management tool, most Ant implementations do not use some of the advanced features provided by the tool. In this article, we'll look at a few advanced techniques that can unleash the true powers of Ant, and turn this mere build tool into an indispensable enterprise asset. Examples are provided where applicable, but lack of detailed code is intentional. It is important to focus on the concepts, not so much on the implementation. Software is a writing. Ideas expressed in software, just like in art, music, plays and other media, can be done in many unique ways. Familiarity with the Ant tool and some experimental spirit is all that you need to turn these techniques into real working code.

Automating tests

One of the tenets of Agile development is "test early, test often". It is about implementing common sense testing strategies that make the overall quality of the software that you ship better. By incorporating frequent testing (preferably automated testing) and frequent build/test/deploy cycles, you will detect bugs earlier. To quote Martin Fowler - the key to successful testing is "test to show an application, or parts of it, doesn't work" as opposed to "test to show it works", which is not as rigorous, and hides the real problems till you deploy and start getting support calls.

Ant's support for standard testing suites such as JUnit, HTTPUnit, Cactus and a host of other testing software lets you integrate testing cycles with the build process and get into the groove of Test Driven Development. Although TDD has been around for a while, I have personally seen a large number of projects that don't leverage this integration. Running tests manually is a wasteful use of a talented developer, and it is error prone due to the human factor. A well written suite of tests should be a part of every build process. Running automated tests is especially useful for typical software development companies that have globally distributed development teams.

If you are in the Ant enthusiasts camp, or simply sitting on the testing fence for a while, here are some strategies worthy of consideration:

  • Extend the boundaries of enterprise build management to include unit testing, regression testing, smoke testing, and finally load testing.
  • Tests run on separate multiple dedicated boxes with simulated production configurations.
  • Use Ant to setup test data, and to capture test results. See Techniques beyond building later in this feature.
  • Tightly integrate build and unit test scripts with SCM hooks so that only the changes that pass the unit test gets checked in.

Continuous automation and continuous integration

Activities involved in a typical SDLC workflow offers several opportunities for automation, and Ant offers unlimited possibilities. Here we focus on integrating with Source Code Management(SCM) systems.

Ant tasks are available to talk to most popular SCM systems, including CVS, Subversion, ClearCase, Continuus/Synergy, Microsoft Visual SourceSafe, Perforce SCM, PVCS, SourceOffSite and StarTeam. With Ant's powerful SCM support, you can hook up parts of the build process to your source control system and perform continuous integration tasks such as check out, check in, baselining etc. Marry that with automated testing, and you can detect bugs as early as the day they got in to the source stream. Once you plumb the verification suite from your build file, you can test after every edit to make sure that nothing breaks. The benefits are substantial. Beyond process maturity and repeatability, a rigorous and portable build process the incorporates elements of continuous integration often results in fewer bugs, higher quality and dollars saved.

If you are not yet on the Agile bandwagon, here are some interesting possibilities to tease you into trying this out:

  • build, unit test, baseline in SCM and promote to integration environment.
  • build, unit test, build dependent projects, perform integration test, baseline in SCM and promote to production.
  • build common blocks, unit test, check in changes, baseline, build consumer apps, perform load test, base-line performance metrics, and promote ??? allows you to compare deltas in performance with every build.

You can even build automated edit analysis scripts that checks for modified source files and submits them for a verified check-in process. Ant project contributors use Ant's own source code analysis tool:

ant -f patch.xml 

to automatically generate a patch file to Ant. With some ingenuous hacking, you can actually make this work for your project too. For the sake of brevity, I am omitting the details, but the patch.xml file distributed with Ant source download should serve as a good starting point. If you still need help, drop me a line.

Technique: Stretching Ant

Ant isn't a silver bullet and there are times when you reach a dead end with its capabilities and you may need to take things into your own hands. For example, your build script may need some authentication information from an internal LDAP or Active Directory server in order to promote code from development to production; or you are required to retrieve a build number from an internal repository for baselining an integration stream in CVS. Such needs often call for functionality that is not available from an out-of-the-box Ant installation.

There are two main approaches to extending Ant: invoke an executable or OS command from within Ant, or write a custom task (i.e., ataskdef.) Let's talk more about the second option: writing custom tasks.

Custom

It helps to know that under the covers, Ant tasks are just Java classes. In theory, any Java class can be cooked into an Ant task simply by extending org.apache.tools.Ant.Task class and implementing an execute() method. Here's where you do the work.

package mytasks; import org.apache.tools.Ant.BuildException; import org.apache.tools.Ant.Task; public class CustomTask extends  Task {     public void execute() throws  BuildException {         // ...     } } 

And then, you simply include it in a build file using the tag to adds the new task definition to the current project.

                                          
Output of JavaRanch's book promotion pick a winner dependency structure and a contrived sample:
  • Grand - Grand is also a Java library that creates a .dot file. It takes a different approach and actually creates the Ant directory structure using Ant's Java libraries. It can support anything in your classpath including ant-contrib and Ant 1.6's import feature. The logic doesn't capture the subtleties of Ant-Contrib like the forEach loop though. The graph is a bit more detailed. The default target is a yellow hexagon. Targets with a description are marked in blue so you can show entry points. The remaining targets are shown as ovals. You can also drill down to show part of your build tree. You can use a Grand UI tool instead of the dot file, but I wasn't able to get the UI. Like Ant2Dot, dependencies are numbered. Grand was as easy to use as Vizant. They provide you with a jar for download. You call it through a simple Ant build file adding any other jars used to the classpath:
                  
    Output of JavaRanch's book promotion pick a winner dependency structure and a contrived sample:
  • Comparison of visualization tools
    ToolShows dependency orderingFlags default targetFlags main targets
    Ant2DotYesYesNo
    VizantNoNoNo
    GrandYesYesYes

    Discuss this article in The Big Moose Saloon!