UWS 1.1 introduction with UWS-Lib

Let's discover what are the new features introduced by the new UWS standard version - 1.1 - and their implementation and usage with this library!

Since version 1.1 of the UWS standard, a new attribute is added to the root nodes of the XML representation of only the job list and the job.

<jobs version="1.1" ...>
	<jobref id="123456A" xlink:type="simple" xlink:href=".../123456A">
		<phase>...</phase>
	</jobref>
	...
</jobs>
<job version="1.1" ...>
	<jobId>123456A<jobId>
	<phase>...</phase>
	<owner> xsi:nil="true" />
	...
</job>
And...

...also for the UWS node. This one exists only in this library and is not part of the UWS standard. It defines an XML document listing all available job lists. It is the default output of the root object of a UWS service created by this library if no home page is defined.

<uws version="1.1 ...>
	<description>...</description>
	<jobLists>
		<jobListRef name="..." href="..." />
		...
	</jobLists>
</job>

What is it?

A great feature introduced by UWS 1.1 is the ability to block an HTTP-GET request on /{jobs}/{job-id}. Thus in the version 1.0, a client had to poll several times per second during a more or less long time a UWS service in order to know the evolution of a given job execution. Instead, in the version 1.1, a same client has the possibility to specify that it wants a response only when either the phase of a specified job changes or a given waiting time is elapsed.

For that, nothing more than a single parameter must be provided in the URL: WAIT. This parameter must have a value. This value must be an integer representing a waiting time in seconds. There are two special values to know:

And for negative value?

Nothing being mentionned explicitely in the UWS 1.1 standard, this library will consider any negative time the same way as for -1: unlimited waiting time.

Of course, in order to avoid useless blocking, a UWS service will block ONLY IF the job is in an active phase. A such phase is: PENDING, QUEUED or EXECUTING. If the job is in another phase, the "blocking request" will return immediately.

UWS 1.1 defines an additional and optional parameter: PHASE. It lets specify in which phase the job must be while performing the blocking. Thus, only one of the active phases is allowed. If the job is not in this phase, the server will respond immediately.

In brief, here will be the behavior of a UWS 1.1 service in function of the given WAIT and PHASE parameters: (in the table below NO means that no blocking is done.)

PENDING QUEUED EXECUTING COMPLETED, ABORTED, ERROR, ...
/{jobs}/ {job-id} NO
/{jobs}/ {job-id} ?WAIT=0 NO
/{jobs}/ {job-id} ?WAIT=2 Block 2 seconds MAX NO
/{jobs}/ {job-id} ?WAIT=2&PHASE=EXECUTING NO Block 2s. MAX NO
/{jobs}/ {job-id} ?WAIT=-1 UNLIMITED WAITING DURATION NO

How to use/customize it in the library?

In function of the server needs and limitations, the blocking strategy may not be always the same. For instance, a maximum waiting time may be set, even in case of unlimited blocking. Another example is to limit the number of blocking requests that a user can perform on a same job. Both of these strategies/policies are proposed by the UWSLibrary and corresponds to the following classes: LimitedBlockingPolicy and UserLimitedBlockingPolicy. But obviously, as in the rest of this library, customization is possible with an interface: BlockingPolicy. Thus, you can easily define your own blocking strategy.

To set the strategy you want to use with the library, you have to use the function: setWaitPolicy(BlockingPolicy). This function exists in UWSService and in UWSServlet.

// POLICY 1: Block WAIT request at most 1 minute (default)
setWaitPolicy(new uws.service.wait.LimitedBlockingPolicy(60));

// POLICY 2: Block WAIT request at most 1 hour (1st parameter)
//           AND limit blocking requests by user and job to 3 maximum (2nd parameter)
//           ; when there is a new incoming request, the oldest one is stopped (3rd parameter):
setWaitPolicy(new uws.service.wait.UserLimitedBlockingPolicy(360, 3, true));
Java limitation!

In Java, it is not possible to detect when the client stops waiting an answer, though it is notified at a TCP level. For that reason, it is really interesting to limit the blocking duration per job but also per user. Indeed, it is very often that a user sends a request from a browser tab, and stops it few seconds after when he realizes the response is slower than expected, or just because he does not want to wait any more. In such case, a Java servlet does not get the abortion notification and keeps blocking. That's why choosing a specific blocking policy can be very appreciated by your server, particularly if your UWS service is popular.

UML diagram of the
					BlockingPolicy class and its extensions.

FAQ

What is the default blocking strategy?

The default policy set by the UWSLibrary is a LimitedBlockingPolicy with 1 minute as maximum waiting time.

What happen if WAIT or/and PHASE is/are repeated?

When several occurrences of the parameter WAIT are provided, only the one with the smallest positive value is kept.

If more than one PHASE parameter value is found, only the last legal occurrence is taken into account.

Must the parameter be always given in upper case?

No. The character case is not important for the parameter names as well as for their values.

How does it work?

UWS 1.1 defines the three following HTTP-GET parameters to get the jobs list in order to filter the output:

Parameter What does it do? Examples
PHASE Only the job which are in the specified execution phase must be returned. If this parameter is repeated, the returned jobs must be in one of the specified phases.
Allowed values: any legal execution phase.
/{jobs} ?PHASE=EXECUTING
Only jobs in-progress are returned.
/{jobs} ?PHASE=EXECUTING&phase=queued
Only jobs in-progress or queued are returned.
AFTER This filter selects only jobs created (strictly) after the given date.
Allowed values: ISO-8601 dates.
/{jobs} ?AFTER=2015-10-30T09:00:00
Only jobs created after the 30th of October 2015 9am (GMT) are returned.
LAST This filter is kind of special. It actually sorts the jobs by descending creation time (i.e. from the most recently created job to the oldest one) and returns only the N most recently created jobs.
Allowed values: a positive value.
/{jobs} ?LAST=0
Since getting an empty list does not make any sense, this value is merely ignored by the library. So, all jobs are returned as if no LAST parameter has been specified.
/{jobs} ?LAST=10
Only the 10 most recently created jobs are returned sorted from the newest to the oldest one.

FAQ

Is it possible to use different kinds of filter together?
Yes. The effets of all specified different filters are cumulative.
What happen if I give more than one LAST or AFTER parameter?
Only one of each type of these parameters can be taken into account. However, considering several AFTER values is the same as having just one AFTER parameter with the most recent date. That is actually what the UWSLibrary is doing: only the most recent date is kept for the AFTER parameter.
The same mechanism is applied for the LAST parameter. Considering several LAST values is the same as having just LAST parameter with the smallest positive and not null value. So the library keeps only the smallest positive and not null value.

What is this phase for?

Since UWS 1.1, the destruction of a job is not any more the only solution to save disk memory. When archiving a job (i.e. changing the execution phase into ARCHIVED), all its results are definitely deleted. However, all its metadata are still there. So it is still possible to know how an archived job has been initialized and executed (how long?, did it succeed?, ...).

No archived job in the job listing!

Indeed, in order to keep a backward compatibility with UWS 1.0, archived jobs must never be listed when requesting /{jobs}.

EXCEPT IF...

...a PHASE filter is provided with the value ARCHIVED. This is actually the only way to get a list of all archived jobs.

How is it implemented in the library?

Since the UWS 1.1 document does not define a standard way to put a job into the ARCHIVED phase, the UWSLibrary has established 3 policies linked to the destruction of a job. All of them are identified with the Enum class JobDestructionPolicy:

This policy can be easily changed for a specified job list using the function JobList.setDestructionPolicy(JobDestructionPolicy).

FAQ

What is the default behaviour?
As said above, by default, the UWSLibrary use the ALWAYS_DELETE policy since it is the only one possible in UWS 1.0.
Is it still possible to destroy an archived job?
Yes. The only way to destroy an archived job is actually the normal way to destroy a job: an HTTP-DELETE request to the job or an HTTP-POST with the parameter ACTION=DELETE on the job.
Even if the policy is ALWAYS_ARCHIVE??
Yes. If the policy is ALWAYS_ARCHIVE, the first attempt of destruction of a non-archived job will indeed archive it. So a second destruction request is needed to definitely get rid of it.
Is it possible to archive a job with job.setPhase(ARCHIVED)?
Yes, but the results of the job won't be destroyed. This function only change the phase. That's why it is strongly recommended to use instead the function UWSJob.abort().

In UWS 1.0 a result node in the XML representation did not give any information on the type and the size of the result. This is now something made possible in UWS 1.1 with the two following optional attributes:

Implementation note

The library does not set automatically neither the size nor the MIME type of the result. You have to do it by yourself when implementing a JobThread. If the result is a file, the size can easily be got thanks to the function UWSFileManager.getResultSize(Result, UWSJob).

If you interested in testing a UWS 1.1 compatible service, you can download the WAR example for UWS 1.1. It is already ready for deployment ; nothing to configure. When deployed, you can access it through the URL: http://localhost:8080/uws1.1/uws. A very minimalist form will let you create a job. Jobs of this example accept only one parameter named "time" which corresponds to the execution duration in seconds you want ; it will be just a thread sleeping every second until reaching the specified time.

Everything, including the job work and parameters, can be configured in the only Java class available in this WAR archive: WEB-INF/classes/TestServlet.java. It can be easily compiled using the ANT script located directly into WEB-INF under the name build.xml:

.../uws1.1/WEB-INF$ ant

Some instructions are written as comments in the Java class so that helping you to locate interesting parts of the code, though it is not at all long and complicated.

Enjoy!
And if you encounter any bug or difficulty, or if a UWS 1.1 is missing or baldy implemented, do not hesitate to send be an email.