Showing posts with label Process. Show all posts
Showing posts with label Process. Show all posts

Wednesday, June 6, 2012

ADF: How to use an af:popup during long running tasks?

For long-running tasks in your application, a pop-up message window can be raised to alert the users that the specific task may take a while.

This can be accomplished using a combination of ADF Faces components (af:popup and af:dialog) and some JavaScript code.

In this recipe, we will initiate a long-running task in a managed bean, and raise a pop-up for the duration of the task to alert us to the fact that this operation may take a while. We will hide the pop-up once the task completes.

Getting ready
----------------
You will need to create a skeleton Fusion Web Application (ADF) workspace before you proceed with this recipe.

How to do it
--------------

  1. Create a new JSF page called longRunningTask.jsf based on any of the quick start layouts.

  2. Drop a Button (af:commandButton) component from the Component Palette to the page.
    You may need to surround the button with an af:toolbar component. Using the Property Inspector, change the button's Text property to Long Running Task and set its PartialSubmit property to true.

  3. Create an action listener for the button by selecting Edit… from the Property Menu next to the ActionListener property in the Property Inspector. Create a new managed bean called LongRunningTaskBean and a new method called longRunningTask.

  4. Edit the LongRunningTaskBean Java class and add the following code to the longRunningTask() method:

  5. Return to the longRunningTask.jsf page editor. Right-click on the af:commandButton in the Structure window and select Insert Inside af:commandButton | ADF Faces….

    From the Insert ADF Faces Item dialog, select Client Listener. In the Insert Client Listener dialog, enter longRunningTask for the Method field and select action for the Type field.

  6. Add an af:resource to the af:document tag.
    Make sure that the af:resource type attribute is set to javascript and add the following JavaScript code inside it:

  7. Finally, add a Popup (af:popup) ADF Faces component to the page with an embedded Dialog (af:dialog) component in it.
    Ensure that the pop-up identifier is set to longRunningPopup and that its ContentDelivery attribute is set to immediate.
    Also add an af:outputText component to the dialog with some text indicating a long running process.
    Your pop-up should look similar to the following:

Here is the complete code for the backing bean:

And jsf page:

How it works
--------------
In steps 1 and 2, we created a JSF page called longRunningTask.jsf and added a button component to it. When pressed, the button will initiate a long-running task through an action listener. The action listener is added to the button in steps 3 and 4. It is defined to a method called longRunningTask() in a managed bean. The implementation of longRunningTask() simply waits for 5 seconds (step 4). We have also ensured (in step 2) that the button component's partialSubmit property is set to true. This will enable us to call the clientListener method that is added in steps 5 and 6.

In steps 5 and 6, we defined a clientListener for the button component. The client listener is implemented by the longRunningTask() JavaScript method, added to the page in step 6. The longRunningTask() JavaScript method adds a busy state listener for the pop-up component (the pop-up itself is added to the page in step 7) by calling addBusyStateListener() and prevents any user input by calling preventUserInput() on the JavaScript event. The busy state listener is implemented by the JavaScript method busyStateListener(). In it, we hide the pop-up and remove the busy state listener once the event completes.

Finally, in step 7, we added the longRunningPopup pop-up to the page. The pop-up is raised by the busyStateListener() as long as the event is busy (for 5 seconds). We made sure that the pop-up's contentDelivery attribute was set to immediate to deliver the pop-up content immediately once the page is loaded.

To test the recipe, right-click on the longRunningTask.jsf page in the Application Navigator and select Run or Debug from the context menu. When you click on the button, the pop-up is raised for the duration of the long-running task (the action listener in the managed bean). The pop-up is hidden once the long-running task completes.



Saturday, June 2, 2012

JDK7: ProcessBuilder and how redirecting input and output from operating system's processes.

The java.lang.ProcessBuilder class has several new methods added into JDK7 that are useful for redirecting the input and output of external processes executed from a Java application. The nested ProcessBuilder.Redirect class has been introduced to provide these additional redirect capabilities.

To demonstrate this process, we are going to send command-line arguments from a text file to a DOS prompt and record the output in another text file.

Getting ready
----------------
In order to control input and output from external processes, you must:
  1. Create a new ProcessBuilder object.
  2. Direct the input and output of the process to the appropriate locations.
  3. Execute the process via the start method.

How to do it
---------------
1. First, create a new console application. Create three new file instances to represent the three files involved in our process execution: input, output, and errors as follows:

2. Create the file Commands.txt using the path specified for the file and enter the following text:
C:
dir
mkdir "Test Directory"
dir
3. Make sure that there is a carriage return after the last line.

4. Next, create a new instance of a ProcessBuilder, passing the string "cmd" to the constructor to specify the external process that we want to launch, which is the operating system command window. Call the redirectInput, redirectOutput, and redirectError methods with no arguments and print out the default locations:

5. Then we want to call the overloaded form of the previous methods, passing the respective file to each one. Once again, call the no argument form of each method executed using the toString method to verify that the IO sources have been changed:

6. Finally, call the start method to execute the process as follows:

7. Run the application. You should see output similar to the following:

8. Examine each of the text files. Your output file should have text similar to this:

9. Execute the program again and examine the contents of your error log. Because your test directory had already been created with the first process execution, you should now see the following error message:

How it works
---------------
We created three files to handle the input and output of our process. When we created the instance of the ProcessBuilder object, we specified the application to launch to be the command window. The information required to perform actions within the application was stored in our input file.

When we first called the redirectInput, redirectOutput, and redirectError methods, we did not pass any arguments. These methods all return a ProcessBuilder. Redirect object, which we printed. This object represents the default IO source, which in all three cases was Redirect.PIPE, one of the ProcessBuilder.Redirect.Type enumerations. A pipe takes the output of one source and sends it to another.

The second form of the methods that we used involved passing a java.io.File instance to the redirectInput, redirectOutput, and redirectError methods. These methods return a ProcessBuilder object as well, but they also have the function of setting the IO source. In our example, we then called the no argument form of each method once more to verify that the IO had been redirected.

The first time the program was executed, your error log should have been empty, assuming you used valid file paths for each File object, and you have write permissions on your computer. The second execution was intended to display how the capture of errors can be directed to a separate file.

If the redirectError method is not invoked, the errors will inherit the standard location and will be displayed in your IDE's output window. See the There's More... section for information about inheriting standard IO locations.

It is important to note that the start method must be called after the redirect methods. Starting the process before redirecting input or output will cause the process to disregard your redirects and the application will execute using the standard IO locations.

There's more
---------------
In this section, we will examine the use of the ProcessBuilder.Redirect class and the inheritIO method.

Using the ProcessBuilder.Redirect class

The ProcessBuilder.Redirect class provides another way to specify how the IO data is redirected. Using the previous example, add a new line prior to calling the start method:
pb.redirectError(Redirect.appendTo(errors));
This form of the redirectError method allows you to specify that the errors should be appended to the error log text file rather than overwritten. If you execute the application with this change, you will see two instances of the error when the process tries to create the Test Directory directory again:
A subdirectory or file Test Directory already exists.
A subdirectory or file Test Directory already exists.
This is an example of using the overloaded form of the redirectError method, passing a ProcessBuilder.Redirect object instead of a file. All three methods, redirectError, redirectInput, and redirectOutput, have this overloaded form.

The ProcessBuilder.Redirect class has two special values, namely, Redirect. PIPE and Redirect.INHERIT. Redirect.PIPE is the default way external process IO is handled, and simply means that the Java process will be connected to the external process via a pipe. The Redirect.INHERIT value means that the external process will have the same input or output location as the current Java process. You can also redirect the input or output of data using the Redirect.to and Redirect.from methods.

Using the inheritIO method to inherit the default IO locations

If you execute an external process from a Java application, you can set the location of the source and destination data to be the same as that of the current Java process. The ProcessBuilder class' inheritIO method is a convenient way to accomplish this. If you have a ProcessBuilder object pb, executing the following code:
pb.inheritIO()
Then it has the same effect as executing the following three statements together:
pb.redirectInput(Redirect.INHERIT)
pb.redirectOutput(Redirect.INHERIT)
pb.redirectError(Redirect.INHERIT)
In both cases, the input, output, and error data will be located in the same places as the current Java process' input, output, and error data.

References:
---------------
1.Class ProcessBuilder.
2.Java 7 New Features (by Richard M. Reese, Jennifer L. Reese)