D. How to customize a UWS ?

5. UWS URL Interpretation

In this library there is one very usefull and important class: UWSUrl. Indeed it is used each time a URL of a UWS must be interpreted and/or generated. So you should be very carefull if you want to customize it ! So that helping you in the customization, you will find below some explanations about the way a UWS URL is represented by this kind of object.

URL splitting

As said in the IVOA Recommendation all UWS URIs must be built in a hierarchical manner, according to REST. UWSUrl splits and generates URLs in the same way. Below are two schemas: the left schema describes the way UWS URLs are split by UWSUrl ; the right schema shows the splitting of a UWS URL example:

The base URI (in bold and red in the example) is used as separator between the URL header and the UWS URI. It is the key of the URL splitting in this class. It is required for any URL interpretation or generation !

Thus you can create a UWSUrl directly with the base URI (or a URL) or by copying another UWSUrl. Besides it can also be extracted automatically from a HttpServletRequest object thanks to the function getServletPath(). This path is set in the web.xml file of your servlet:

By default, the UWS URL interpreter of an AbstractUWS is initialized with the first received request. No interpreter exists before that ! However you can set one at any moment with the method setUrlInterpreter(UWSUrl).

URL interpretation

Once the base URI is known, you can use load(URL) or load(HttpServletRequest) to load and to interpret respectively a URL or a request. The two functions return always the same result except for the URL header which may be more complete with a request.

Note:

In load(HttpServletRequest), the base URI is always extracted from the given request and is then compared to the one stored in this class. If they are different nothing is done except calling load(URL).

Each part of the URL can be retrieved individually thanks to its corresponding getter function (i.e. getUwsURI(), getJobListName(), getJobId(), ...). Besides you can also know if some parts are valued or not: hasJobList() tells whether the UWS URL indicates at least a job list name, hasJob() tells the same thing but about a job ID, ...

getUWSName() returns the presumed name of the UWS. This "name" is the last item of the base URI. However it may not be the real name of the UWS which can be set at any moment with AbstractUWS.setName(String). Actually getUWSName() is only used by AbstractUWS.getName() to returns a default value.

URL generation

UWS URLs can be generated in two ways: by modifying the current instance of a UWSUrl or by using it as a base for a new UWSUrl.

a. With modification

A UWSUrl object can be updated thanks to its setter methods. But contrary to the getters, setters exist only for the UWS URI part (part of the request URL which starts just after the base URI).

Lets take an example ! Supposing we have created a UWSUrl object named uwsUrl with /basic as base URI. It has been initialized with a UWS URL which lets getting the additional parameter time of the job 1298904240779A. Then only the job ID of the UWS URL is modified thanks to setJobId(String). Here is the corresponding code:

UWSUrl uwsUrl = new UWSUrl("/basic");
uwsUrl.load(new URL("http://saada.u-strasbg.fr/uwstuto/basic/timers/1298904240779A/parameters/time"));

System.out.println("BEFORE MODIFICATION:");
UWSToolBox.printURL(uwsUrl);

uwsUrl.setJobId("1298971587132A");

System.out.println("AFTER MODIFICATION:");
UWSToolBox.printURL(uwsUrl);

And the result is:

BEFORE MODIFICATION:
***** UWS_URL (/basic) *****
Request URL: http://saada.u-strasbg.fr/uwstuto/basic/timers/1298904240779A/parameters/time
Request URI: /basic/timers/1298904240779A/parameters/time
UWS URI: /timers/1298904240779A/parameters/time
Job List: timers
Job ID: 1298904240779A
Attributes (2): parameters time

AFTER MODIFICATION:
***** UWS_URL (/basic) *****
Request URL: http://saada.u-strasbg.fr/uwstuto/basic/timers/1298971587132A/parameters/time
Request URI: /basic/timers/1298971587132A/parameters/time
UWS URI: /timers/1298971587132A/parameters/time
Job List: timers
Job ID: 1298971587132A
Attributes (2): parameters time

As you can notice only the job ID has been changed. Indeed when using a such function all the other parts of the main request URL are automatically updated.

Notes:

b. Without modification

To avoid modifying a UWSUrl object you have three solutions:

  1. To create a new UWSUrl() and to initialize it with a base URI and any request URL you want. (warning: the base URI must be contained in the URL !)
  2. To make a copy of an existing UWSUrl() object (thanks to the constructor UWSUrl(UWSUrl)) and to use the methods described above, directly on the copy.
  3. To use one of the following methods which return a modified copy of the current UWSUrl() instance:

Warning:

The following methods lets generating a URL corresponding to an action on a JobList or a Job:

Since these actions needs to add some HTTP parameters, all these methods return a String which corresponds to the final request URL.

Besides they are designed for a HTTP-GET request rather than HTTP-POST. But you can use these functions and then call UWSToolBox.getParameters(String queryPart) to extract the HTTP-GET parameters into a Map. Then you can use the URL and the parameters map to send a HTTP-POST request through a servlet.

How to customize ?

By default the base URI is extracted from a HttpServletRequest by extractBaseURI(HttpServletRequest). This function only calls HttpServletRequest.getServletPath(). Consequently if you want to change the extraction of this URI, you just have to override extractBaseURI(HttpServletRequest).

However if you intend to change the URL splitting or the whole UWS URL structure, you will have to override all the other functions:

One more time, this class is very important and you should take care of any of your modifications ! By the way I hope the UML class diagram opposite will help you to better understand this class and to extend it if needed.