Tuesday, October 15, 2019

5 JavaScript Features That I Miss in Java

Over the years, I have developed a lot of passion for Java programming. There is a lot of things in life that are more fun than Java (like Scandivania, pictured 😉), but out of those things I get paid for, Java is certainly near the top of my list.
I also used to do a lot of backend server programming where Java was predominant back then. Still I was amazed at how often I'd hear my fellow technologists say things like:
  • "JavaScript is a flawed language"
  • "it is a language for script-kiddies"
  • "there is much hype about JavaScript"
I used to wonder, was JavaScript really that bad? But I wasn't able to tell until I had an opportunity to work on a couple of JavaScript projects myself. Since then I have learned that JavaScript, despite it has a dark side, definitely does have a bright side too. Here I put together a list of JavaScript features that are so cool I wish they were available in Java too.

For every feature I give an example in JavaScript, and an equivalent code in Java, to my best effort. Please share in comments if you can do better. For some of the examples I used TypeScript because the JavaScript code with no types would have appeared to be shorter and more concise, and I wanted to keep the comparison as fair as possible.

I only added explanation where I felt it was necessary.

1. Template String Literals

JavaScript Java

2. Destructuring Assignment

JavaScript Java

3. Spread Operator

Suppose that you have two unrelated types with some overlapping properties, for instance Student and Customer. How can you copy all overlapping properties from the customer object to the student object?
TypeScript Java
Strictly speaking, the JavaScript object will receive all properties from the customer object, not just the overlapping ones. For most practical purposes this will not play any significant role though.

4. Default Parameters

Write a function that returns a logarithm of a given number to a given base, with the base defaulting to 10 if not provided.
TypeScript Java

5. JavaScript Object Initializer

JSON has been increasingly popular for data interchange, and for good reason. Initializing objects in JavaScript is even more concise than in JSON!
JavaScript Java

Conclusion

I am not arguing that JavaScript is superior to Java or vice versa. JavaScript and Java have quite different execution mode, runtime model, design philosophy and history. Yet more often than not, you will be able to make a choice between those two languages based on your personal or team preferences. In this post I just wanted to show that JavaScript can be pretty sexy, even to diehard Java developers.

What are your favorite JavaScript features? Do you have another opinion about Java or JavaScript? Let me know in the comments below!

Saturday, July 15, 2017

Learning Functional Style in Java by Example

In my last post, I shared my passion for functional programming. Luckily, with the new features in Java 8 you can embrace the functional style without using a pure functional language like Haskell or Lisp.

Learn Java Functional Style in Style

There's plenty of articles on the functional features in Java 8 around the net. In this blog post I offer you a different learning path: by example.
I'll show you a problem and solve it step by step using the Java 8 functional features naturally. I'll point out the interesting aspects of the solution so that you have some anchor points for your further research. That's learning Java functional style programming in style!

The Problem

So here's the problem to solve: calculate the number 𝜋 to a precision of 20 decimal digits. I'll do the coding work so that you can focus on another things: understanding how the solution works and figuring out for yourself if you embrace this style in your daily Java coding.

Nilakantha Sequence

First we need a method how to calculate 𝜋. For the sake of simplicity I've chosen to use the Nilakantha sequence, the Indian mathematician's discovery dating back to the 15th century:


First Bite: Infinite Alternating Sequence

You're probably familiar with the notorious advice:
"How do you eat an elephant? One bite at a time."
Our first bite when eating the elephant (umm I mean producing the Nilakantha sequence) will be creating a Stream of BigDecimal's containing elements of this alternating sequence:
2, -4, 6, -8, 10, -12, 14, -16, ...
This turns out to be a bit more difficult than it seems, since the sequence generation needs to address two aspects of the above sequence:
  • the iteration through all even numbers
  • the alternation of the sign of the elements
While it's possible to use a fine crafted expression to address both aspects of this sequence, I personally find it's better to address those two aspects also separately in the code. When I was giving a Java 8 hands-on course using this very exercise one student came up with this very elegant solution:

Note that the above code very neatly separates all concerns of the sequence generation:
  • on line 2 an infinite stream of positive members of the sequence is generated using Stream#iterate
  • on line 3 a negative counterpart for each positive member of the sequence is added using Stream#of and Stream#flatMap
  • on line 4 the stream of integers is converted to a stream of BigDecimal's using Stream#map (we need BigDecimal's because otherwise the double arithmetics would fail to provide the fractional elements of the sequence with the necessary precision)
Let me further explain the flatMap call. What would happen if I just used map instead? The result would be a stream with every element being a stream of two elements.
Let's visualize this scenario using the following alternative way to produce the root sequence:

The comments on the right hand side show what the stream looks like after each intermediate step. The flatMap invocation takes an identity function as parameter, which effectively means that the flatMap call only flattens the stream - the resulting stream contains the same numbers but in a flat structure.

Key Takeaways

  • Infinite streams can be created with iterate
  • map vs flatMap
    • Use map to replace each element with some other element
    • Use flatMap to replace each element with an arbitrary number of other elements
    • When using map the number of elements in the stream will never change. With flatMap the resulting stream can have different number of elements than the original stream.

Second Bite: Infinite Nilakantha Sequence

Our second bite will be creating all fractional elements of the Nilakantha sequence:

This can be solved by transforming the elements using the map method we already encountered in the previous bite:

This code replaces each of the root sequence elements (2, -4, 6, ...) with the corresponding fraction - which is specified in the lambda expression passed to the map method. The fraction expression also contains the specification of the rounding mode (without it a runtime exception occurs since the JVM cannot calculate the fraction precisely).

Third Bite: Calculating the Sum

The third bite is the calculation of the sum of the Nilakantha sequence elements. But hey, the sequence is infinite so how are we going to calculate the sum after all? Of course, the more elements we take for the calculation, the closer we get to the exact value of 𝜋. So the question actually is - how many elements do we need to take to get the number 𝜋 with the precision of 20 digits? The answer lies within the code:

Let's have a look at the new stuff here:
  • on line 3 the infinite stream is turned into a finite one by telling the stream to stop generating more elements after 6,578,000 elements have been generated
    •  in case you wonder how the limit call affects the sequence generation, which occurs as the first method in the code, the answer is laziness: Java 8 streams are lazy so no operations are actually triggered before a terminal operation is applied on the stream. Limit itself is not a terminal operation but the very next operation on the stream - reduce - is a terminal one, and when it runs, the stream is already marked to contain a limited number of elements.
  • on line 4 the sum of all elements in the sequence is calculated by starting with 3 and then adding each elements of the sequence
  • on line 5 the required precision is set
And voila, that's it! The above method computes 𝜋 to 20 digits!

Key Takeaways

  • Infinite streams can be truncated to contain a finite number of elements with Stream#limit.
  • Streams are lazy:
    • any intermediate operation is only performed when a terminal operation is initiated
    • stream elements are generated only when they are needed
  • Combine all elements in the stream with a specified binary operation to produce a single result using Stream#reduce.

The Dessert: Parallelizing the Calculation

We did manage to eat the elephant in three bites, but I've got a bonus - since there's no piece of elephant left I'll call it a dessert: let's make the calculation more efficient by employing parallelism. It is very straightforward to make a Java 8 stream process in parallel - you only need to invoke parallel on the stream.
I chose to make the stream parallel after the initialization, before the fractions and their sum are calculated - see line 3 in the following Gist:

Unfortunately this first try does not yield the expected result - the test is now broken!
~/ws/java-8-way $ mvn -Dtest=LifeOfPiTest test
...
Failed tests:
LifeOfPiTest.calculate:33 expected:<[3].1415926535897932384...> but was:<[249].1415926535897932384...>
WTF? (note: this is not bad language but a valid measurement of code quality) The fractional part is correct but the part before the decimal point is wrong. To solve this little mystery we have to reiterate how the elements of the sequence are added: with reduce(THREE, BigDecimal::add). So here is what happens: since the computation is now parallel, the reduce operation is also done on multiple threads and hence the initial value, THREE, is added way too many times. On your computer, you may get a different result before the decimal point, but it is guaranteed to be a multiple of three!
Once the problem is identified it is easy to fix:

The above code adds three as the final step - all reduce operations add the sequence elements starting with the initial sum of zero. Now the test is fixed but unfortunately the execution times don't seem to be much different between the sequential (first line) and the parallel (second line) version:
Time elapsed: 4.98 sec - in de.blogspot...LifeOfPiTest
Time elapsed: 5.064 sec - in de.blogspot...LifeOfPiTest
The reason why parallelism gave us no gain (yet) is that the stream is ordered - which defies any benefits that the parallel processing might yield. Since the sum of the sequence elements does not depend on their order, we can specify that the stream should be unordered declaratively:

With this modification, finally, we get some benefit from parallelism:
Time elapsed: 2.559 sec - in de.blogspot...LifeOfPiTest

Key Takeaways

  • Parallel streams can be tricky - so make sure you understand what you're doing. If you don't need to optimize then don't bother to introduce parallelism.
    • Using unordered streams may significantly improve parallel processing performance, but you can only use them if the semantics of your problem does not depend on the ordering.
  • Not every problem is embarrassingly parallel. The virtual machine I ran this example in has four CPU cores yet the parallel version runs barely twice as fast as the sequential version.

Conclusion

I hope you enjoyed learning Java 8 features on the example of 𝜋 calculation. If you did enjoy the math I can assure you that you are in a good company: also Isaac Newton used infinite series to compute 𝜋 to 15 digits, later writing "I am ashamed to tell you to how many figures I carried these computations".

Don't be ashamed yourself to carry some more computations! Feel free to further experiment with the code: LifeOfPi.java
Of course, you can download, clone or fork the entire project from GitHub. Have fun!

     

Wednesday, February 24, 2016

Funtastic Birthday with Haskell

Hey, it's my birthday today so I think it's good time for something less serious and just fun. Couple of folks asked me about my age today and since I anticipated the question I decided to answer with a small mathematical puzzle: my age is the smallest integer that is divisible by 11 and is a successor of a prime number. By successor of a number s I mean s+1.

I was curious though as to what is the next number that satisfies the above condition. So I decided to write a program in Haskell - my favorite functional language - to generate the sequence:

I won't dissect it too much - after all I promised this would be fun - so let me just point out one little fact about Haskell that I always find fascinating: it lets you define and use infinite sequences like the birthday numbers above. In fact, if you try to evaluate this sequence your machine will start producing the numbers but it would never stop - that is if it had unlimited amount of memory.

The beautiful trick is that once you have an infinite sequence, you can extract portions of it to get answers to finite questions, like my tiny age puzzle - which can be answered by taking the first element of the sequence:
So how optimistic would it be to hope to experience another birthday that satisfies the condition? According to wikipedia the highest verified age ever attained is 122 - so we can just check for "birthday" numbers up to this age:
*Fun> takeWhile (<=122) birthdayNumbers
[44,110]
As you can see, the answer is 'very optimistic' :-)
If you just simply want to see the first 10 numbers of the sequence you can do:
*Fun> take 10 birthdayNumbers
[44,110,132,198,242,264,308,374,440,462]
You may also be wondering, why not make the program even shorter by dropping the isqrt function and instead checking the divisors up to k-1? The reason is obvious: performance. I leave it to the inquiring reader to see the difference for themselves. This is how you can turn on the built-in profiling in the Haskell interpreter and calculate the gap between the consecutive birthday numbers:
*Fun> :set +s
*Fun> take 10 (zipWith (-) (tail birthdayNumbers) birthdayNumbers)
[66,22,66,44,22,44,66,66,22,110]
(0.02 secs, 3042172 bytes)
One final thought: there are actually two ways to solve the puzzle I've given to the curious inquirers:

  1. exact: verify the predecessor primality for all multiples of 11 until you find the solution
  2. heuristic: since I was giving the puzzle in a face-to-face talk it was much easier to estimate my age then compare it with the nearest multiples of 11 and rule out 33 and 55 as being too low / too high respectively.
Now which is the best way? It really depends - do you need to get the correct answer 100% of the time? Or do you need to be really fast while you can tolerate an occasional mistake? In computing, as in life, it's up to you to make your choices :-)

Sunday, February 8, 2015

Color Bash Prompt for Git on Linux/Mac

If you use a bash prompt often then it really helps to highlight the information that matters for you most. For my professional git usage I care about these pieces of information:
  • the current working directory
  • the name of the git branch (if the current directory is a git working copy)
  • whether or not there are uncommitted changes

The above prompt is produced with this one-liner:

Prompt Contents

Let's first dissect the parts of the prompt that define what it actually shows:
  • \w - this is the bash shortcut for current working directory. Simple.
  • $(git status -s 2>/dev/null | head -1 | sed 's/.*/ */') - this will print an asterisk if the current working directory is a git working copy and if it has uncommitted changes (this can be also achiewed with __git_ps1 and
    GIT_PS1_SHOWDIRTYSTATE but I prefer to highlight the asterisk with different color)
  • $(git rev-parse --abbrev-ref HEAD 2>/dev/null | sed 's/.*/ &/') - this will print the branch name with a space in front of it

Prompt Colors

The prompt uses ANSI escape sequences to change the colors. I decided to use tput to generate the sequence instead of putting it in directly. It is simply more readable with explicit capability names. Here setaf sets the foreground color and sgr0 resets all attributes. You can check the man page terminfo(5) if you need for more details.
Finally, it is necessary to mark the ANSI escape sequences as non-printable in order for bash to correctly figure out the actual length of the prompt. This is done by adding \[ and \] around the control characters.

Monday, September 22, 2014

Create a Flickr Application hosted on the Google App Engine

How I got here

At the start of the last NHL season I got myself an AppleTV to watch the games via my Gamecenter subscription. However, the AppleTV turned out to be much more versatile. Now I am using it also to stream videos from an iPad to the TV, listen to the iTunes Radio and also to watch a slideshow of our family photo library, a feature the whole family loves.

The photos are hosted on Flickr and due to the Flickr API restriction you can have at most 500 photos in the slideshow. This didn't make me happy as our photo library has several thousand pics. I did not find any satisfactory solution on the net so I decided to:
  • create an application to periodically generate a random Flickr photo set
  • host the application in the cloud to avoid dependency on the home IT infrastructure
In the following I'll describe how I got this done and share the project that contains the working code.

Connecting to Flickr

If you want to get an application work with Flickr (if you only came here because you are interested in the Google App Engine you may jump right to the next section) you have to follow these steps:
  1. Register your application in the Flickr App Garden. This will get you an API key and a shared secret that you will need later to make the REST API calls.
  2. If your application needs authentication then you also need to obtain authorization from a Flickr account owner. Whether you need authentication depends on what the application is doing. Some Flickr API calls require no authentication - for instance the method flickr.people.getPublicPhotos. The app described herein needs authentication since it creates a photo set in my Flickr account. See Authentication How-To for more information.
  3. Make REST API calls to the Flickr API. You will need to sign the requests as described in the above Authentication How-To. You can see the example implementation in the method FlickrService.addSignedParams.
That's it! The application will talk to Flickr and create the desired photo set when the main servlet (PhotosetServlet.java) is invoked.

Hosting the Application on the Google App Engine

Choosing the hosting provider was a no-brainer since the Google App Engine comes with a free plan which is fully sufficient for this Flickr application. It is worth noting that the Google App Engine is a PaaS offering which means it provides the platform that your application runs on. Besides Java, which I chose for this Flickr application, the platform also supports Python, PHP and Go. The platform also supports couple of options for storing data (a proprietary data store, a cloud MySQL database and a large object storage).

If you require a specific infrastructure, like for instance a specific database server, then you should be probably looking at an IaaS offering instead.

To create a Java application for the Google App Engine you simply follow the steps from the Getting Started Guide. Here's a quick overview with links into the corresponding guide sections:
  1. Sign up for a Google account (unless you already have one).
  2. Create a project from the maven archetype appengine-skeleton-archetype — see Creating the Project.
    Tip: you can also create a project ID later, just before the first deployment to the Google App Engine (see step 5 below).
  3. Add the code for your application — see Adding Application Code and UI.
  4. Test the application locally using mvn appengine:devserver — see Building and testing the app
  5. Deploy your application to the Google App Engine — see Uploading your Application
These are also the steps that I followed to create the photo set application. To enable scheduling I added the cron.xml file and I thought I was done.

Final Hurdle

Soon after the deployment to the Google App Engine I noticed I'm actually not done yet. The app was working fine locally but an attempt to create the same 500 picture photo set on the Google App Engine resulted in a Malformed URL exception. The problem is that the GET request receives the list of the photo IDs in the URL which gets truncated if the list is too long.

I wasn't able to find a solution until I went to Bucharest where I met my friend and former colleague Octavian. He hinted to use a different HTTP client which ultimately solved the issue. Ironically I've just found out while writing this post that according to the Flickr API documentation I should have used a POST request instead!

Conclusion

I hope this post was helpful for you if you are either developing a Flickr application or working with the Google App Engine. Both topics are actually quite big to be covered in a single post. Nonetheless, with the help of the code example and the provided documentation it should be relatively easy to get going - have fun!

Saturday, March 1, 2014

Unit Testing Java EE Application with CDI

Java Enterprise Edition has undergone the much needed weight loss treatment in 2006 when Java EE 5 was introduced and it has continued evolving ever since. Today, developing of Java enterprise applications is easier than ever before. However, the rising popularity of Test Driven Development creates new challenges even for the revamped Java EE platform.

Things have improved, of course. Prior to EJB 3.0, there was virtually no other way of testing enterprise beans than actually deploying them in the container and testing them there.

The EJB 3.0 returned back to the roots by turning the enterprise beans into Plain old Java objects (POJOs). This revolutionary idea brings many advantages, one of them is making EJBs readily available to unit testing. You only have to mock the dependencies to the container.

The question arises though, how do you unit tests those parts that directly depend on the container, like the Data Access Objects (DAOs) which use container provided persistence services?

In this post, I will show on an example of a RESTful Web Service project with database persistence how it can be tested end-to-end without ever hitting the application server.

The Project
The example project contains the following RESTful Web Service and DAO to put under (unit) test:
 @Path("/employees")  
 public class EmployeeResource {  
     @EJB  
     private EmployeeDao employeeDao;  
   
     @GET  
     @Path("/{param}")  
     @Produces(MediaType.APPLICATION_JSON)  
     public Employee get(@PathParam("param") long id) {  
         return employeeDao.find(id);  
     }  
     @GET  
     @Produces(MediaType.APPLICATION_JSON)  
     public List<Employee> findAll() {  
         return employeeDao.findAll();  
     }  
     @POST  
     @Consumes(MediaType.APPLICATION_JSON)  
     @Produces(MediaType.APPLICATION_JSON)  
     public Map<String, Long> add(Employee employee) {  
         Map<String, Long> response = new HashMap<>();  
         response.put("employeeId", employeeDao.create(employee));  
         return response;  
     }  
 }  
 @Stateless  
 public class EmployeeDao {  
     @PersistenceContext  
     private EntityManager em;  
   
     public Employee find(long id) {  
         return em.find(Employee.class, id);  
     }  
     public List<Employee> findAll() {  
         return em.createNamedQuery(Employee.FIND_ALL).getResultList();  
     }  
     public long create(Employee employee) {  
         em.persist(employee);  
         return employee.getEmployeeId();  
     }  
 }  
Injecting Dependencies
The above classes are richly annotated. A naive attempt to test the classes with JUnit will succeed to compile but it will fail at runtime with a NullPointerException due to unresolved dependencies to EmployeeDao and EntityManager. So is there a way to resolve these dependencies outside of the application server?
Enter CDI — context and dependency injection. CDI was added in Java EE 6 as a general dependency injection mechanism. With CDI it is possible to annotate references to EJBs with @Inject instead of @EJB:
 public class EmployeeResource {  
     @Inject  
     private EmployeeDao employeeDao;  
 ...  
This solves the DAO dependency nicely. However, the reference to the DAO will still be null because JUnit tests run with Java SE which does not support CDI. By now you can probably guess the central idea of the approach described in this post — to run the tests inside a CDI container instead of an application server. In the example project I use the JBoss Weld CDI container with Apache DeltaSpike which provides an abstraction layer to bootstrapping the container. You can inspect the project's Maven pom.xml file to see the actual library dependencies.
How about the dependency to the EntityManager though? It is defined as a private field in the DAO class and it has to be set outside of the application server. Is there some way to do it, short of breaking the encapsulation?
Actually, the solution is simple if you think of the famous aphorism by David Wheeler:

All problems in computer science can be solved by another level of indirection.

The indirection is implemented, of course, with CDI. The DAO uses an @Inject annotation instead of @PersistenceContext:
 public class EmployeeDao {  
     @Inject  
     private EntityManager em;  
 ...  
The definition of the entity manager in production/application server environment moves to a resource class which defines a CDI producer:
 public class Resources {  
     @PersistenceContext  
     @Produces  
     private EntityManager em;  
 }  
In the test environment an alternative resource class is used:
 @Alternative  
 public class TestResources {  
     @Produces  
     @Singleton  
     private EntityManager createEntityManager() {  
         EntityManagerFactory emf = Persistence.createEntityManagerFactory("hr_test");  
         return emf.createEntityManager();  
     }  
 }  
There are two things to notice about the above class:
  1. It is annotated with @Alternative. The alternative needs to be activated by specifying an <alternatives> tag in the beans.xml file. There are two beans.xml files in the example project — one in the production source code base (without <alternatives> tag so the persistence context is resolved using the Resources class) and another one in the test source code base.
  2. The above class creates an entity manager factory for the persistence unit hr_test. Alike beans.xml, there are also two persistence.xml files, for production and test respectively, in the example project.
Writing Test Classes
The test classes also use CDI to resolve the references to the classes being tested:
 @RunWith(CdiTestRunner.class)  
 public class EmployeeResourceTest {  
     @Inject  
     private EmployeeResource employeeResource;  
   
     @Test  
     public void testFindAll() {  
         List<Employee> employees = employeeResource.findAll();  
         assertThat(employees.size()).isGreaterThan(25);  
     }  
 }  
Bootstrapping the Container
Since the test classes are managed by CDI they need a custom JUnit test runner (specified with @RunWith) that has two responsibilities:
  1. Bootstrap the CDI container.
  2. Create instances of test classes using the CDI container.
 public class CdiTestRunner extends BlockJUnit4ClassRunner {  
     static {  
         CdiContainer cdiContainer = CdiContainerLoader.getCdiContainer();  
         cdiContainer.boot();  
     }  
     public CdiTestRunner(Class<?> clazz) throws InitializationError {  
         super(clazz);  
     }  
     @Override  
     protected Object createTest() throws Exception {  
         return BeanProvider.getContextualReference(getTestClass().getJavaClass());  
     }  
 }  
Adding Transaction Support
Transaction service is another service typically provided by the application server. In the standalone CDI test environment it is easy to add transaction support using an interceptor. The test methods are annotated with @Transactional and they can also specify whether the transaction should commit or rollback when the test finishes:
 @Test  
 @Transactional  
 public void testCreate() {  
     final long employeeId = 401L;  
     Employee employee = new Employee(employeeId, "PKANE", "PR_REP", "Kane", new Date());  
     assertThat(employeeDao.create(employee)).isEqualTo(employeeId);  
 }  
   
 @Test  
 @Transactional(defaultRollback = false)  
 public void testCreateCommit() {  
     final long employeeId = 402L;  
     Employee employee = new Employee(employeeId, "JTOEWS", "PR_REP", "Toews", new Date());  
     assertThat(employeeDao.create(employee)).isEqualTo(employeeId);  
 }  
 @InterceptorBinding  
 @Target({ElementType.METHOD, ElementType.TYPE})  
 @Retention(RetentionPolicy.RUNTIME)  
 public @interface Transactional {  
     boolean defaultRollback() default true;  
 }  
 @Interceptor  
 @Transactional  
 public class TransactionalRollbackInterceptor {  
     @Inject  
     private EntityManager em;  
   
     @AroundInvoke  
     public Object manageTransaction(InvocationContext ctx) throws Exception {  
         try {  
             em.getTransaction().begin();  
             return ctx.proceed();  
         } finally {  
             em.getTransaction().rollback();  
         }  
     }  
 }  
 @Interceptor  
 @Transactional(defaultRollback = false)  
 public class TransactionalCommitInterceptor {  
     @Inject  
     private EntityManager em;  
   
     @AroundInvoke  
     public Object manageTransaction(InvocationContext ctx) throws Exception {  
         em.getTransaction().begin();  
         Object result = ctx.proceed();  
         em.getTransaction().commit();  
         return result;  
     }  
 }  
Conclusion
That's it. If you want to check the entire example project's source code, you can find it in Subversion or download it as a zip archive.

Bonus Picture
As I was taking a break while writing the example project, our cat leapt on the table and took a sharp look on the source code, as if she was reviewing it. I was lucky enough to have my camera at my fingertips and I captured the moment:
Links

Thursday, February 20, 2014

Display Busy Mouse Cursor with PrimeFaces during Ajax Requests

Today, I want to share a solution for displaying a busy cursor while an Ajax request is active in a PrimeFaces application. The solution is strikingly simple once all the pieces click in, but it took me some good amount of research and try and error, so I decided it is worthwhile to post it here.

The journey starts with a simple CSS which defines the busy cursor:

 // <web-app-root>/resources/css/progress.css
 html.progress, html.progress * {  
  cursor: progress !important;  
 }  

The above is based on this forum post - you may want to check it out for more details or if you wish to use the original solution. The solution I went for is slightly different - it uses JavaScript with the following self-explanatory functions:

 // <web-app-root>/resources/js/progress.js
 var handle = {}  
   
 function on_start() {  
     handle = setTimeout(function() {  
         $('html').addClass('progress')  
     }, 250)  
 }  
   
 function on_complete() {  
     clearTimeout(handle)  
     $('html').removeClass('progress')  
 }  

Note that the progress class is not set immediately when the request starts. I found it very distracting when the cursor "flashes" on short Ajax requests and I decided to change the cursor after a delay of 250 ms only. Of course, you may modify the delay as you see fit (or maybe make it an argument of the on_start function). The clearTimeout call is needed to cancel the delayed cursor change when the Ajax request is completed before the delay expires.

Now to activate the solution you only need to include the following in your JSF page:

 <h:outputStylesheet library="css" name="progress.css" />  
 <h:outputScript name="js/progress.js" target="head"/>  
 <p:ajaxStatus onstart="on_start()" oncomplete="on_complete()"/>  

Final note: for the above inclusion to work you must also have an <h:head/> tag on your JSF page.