Upgrade details
Fixed bugs
- Redirections are now done by using the HTTP status code 303 rather than 302.
- HTTP methods - GET, POST, PUT and DELETE - can be distinguished directly by the library. This is particularly true for the creation of a job: before, a POST request with at least one parameter was required, but now, any POST request on a jobs list URL is enough.
- Simple job attributes (i.e. runID, phase, startTime, ...) are now returned in text/plain rather than application/xml.
New functionalities
-
Managing an execution queue:
A class dedicated to the management of the execution of all jobs has been added: ExecutionManager. Two additional extensions of AbstractUWS are able by default to manage an execution queue. See C.3.b. Execution WITH queue for more details.
-
Automatic destruction and abortion:
The job attributes destructionTime and executionDuration are now taken into account by the UWS to respectively destroy and abort the job automatically when the specified time is elapsed.
-
User identification:
For the moment no standard has been proposed about the user identification in a UWS. However it is now possible in this library to specify the way a user can be identified. See D.3. User identification for more details.
-
Adding/Removing UWS actions:
In the previous version all default UWS behaviors described in the IVOA Recommendation were implemented by default. But now you can also customize them or add new actions. For that they must extend the abstract class UWSAction. See D.6. Actions for more details.
-
Adding/Removing UWS serializers:
The default format of UWS resources is the XML. Even if it is possible to link a XML document with a XSLT style sheet it could be interesting to provide a way to return all UWS resources in another format. In the version 3 of this library you can define other UWS serializations than the XML one. Then by adding the HTTP header Accept to its request, a UWS user will be able to ask any UWS resource in any format. See D.7. Serializations for more details.
- Global management of the destruction time and the execution duration:
The value of the job attributes destructionTime and executionDuration of all managed jobs can be control globally by the UWS. In other words, the UWS administrator can set a default and a maximum value to these attributes. Obviously more controls are not excluded. See D.2. UWS Administration for more details.
- Job observer:
With the version 3 of this UWS library you have now the notion of JobObserver. It allows any object declared as JobObserver to be notified at each modification of the observed jobs phase. See C.6. Keeping an eye on jobs for more details.
API modifications
Unfortunately there is no backward compatibility from the version 2.0 to 3.0 !
Indeed several points of the API must have been partially or completely changed so that having the new functionalities listed above. In the most cases it only implies simplifications of the manner you are using this library. You may have some upgrade problems especially if you have customized your UWS while using the version 2.
That's why, the most important API modifications are listed and explained below. Besides I encourage you to take a look at the UML class diagrams of the two versions (v2.0 and v3.0), to have a better view of the main differences between these versions and to find the best way to do what you want more easily.
1. Servlet
a. User identification
With the version 2, to have the notion of user, the UWS was encapsulated in a session. The problem with this solution is that the servlet has to manage one UWS object per session and so per web-navigator interacting with the server. Thus we have not really one web service for several users, but one web-service per user. In addition this solution doesn't really identify a user, but one client (in the most cases, a web-navigator).
For those reasons, it would be better to replace this pseudo user identification by a true one. The interface UserIdentifier of the version 3 of this library is fully dedicated to this task. Once implemented, its only function is called by your UWS at each received request.
For more details see D.3. User identification.
b. HTTP methods
With the version 3 of this library, the servlet may be now very simple ! Indeed, the method init(ServletConfig) of HttpServlet is now used to create a UWS, whereas the method service(HttpServletRequest, HttpServletResponse) only forwards the request to the UWS. It is not required any more to forward request with doGet, doPost, doPut and doDelete as it was explained in the tutorial of the version 2. Actually it would rather be discouraged to forward request like that, because AbstractUWS is now designed to interpret request whatever is the used HTTP method.
For more information about the way a UWS servlet may be written, see the part A.2. Writing the servlet. In this part a servlate template can also be downloaded.
Version 2.0
public class UWSTimers extends HttpServlet { private static final long serialVersionUID = 1L; @Override protected void doDelete(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException { doPost(req, resp); } @Override protected void doPut(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException { doPost(req, resp); } @Override protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException { doPost(req, resp); } @SuppressWarnings("unchecked") @Override protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException { try{ // Get the current session (or create a new one): HttpSession session = req.getSession(true); /* If it is a new session, set its maximum inactive time interval ; * so that all managed jobs lists can be removed and so all jobs stopped (if running) and their resources freed * once the given time interval elapsed */ // if (session.isNew()) // session.setMaxInactiveInterval(3600); // Fetch the UWS from the current session: BasicUWS<JobChrono> uws = (BasicUWS<JobChrono>)session.getAttribute("BasicUWS"); // INITIALIZE OUR UWS: if (uws == null){ // Get the base UWS URL: URL baseUWSUrl = UWSUrl.extractBaseUWSUrl(req, true); // Create our UWS: uws = new BasicUWS<JobChrono>(baseUWSUrl, JobChrono.class); uws.setDescription("This UWS aims to manage one (or more) JobList(s) of JobChrono." + "JobChrono is a kind of Job whose the execution task consists to wait a given time."); // Create our job list: uws.addJobList(new JobList<JobChrono>("timers", uws.getBaseURL())); // Add this UWS to the current session: session.setAttribute("BasicUWS", uws); } // FORWARD THE REQUEST TO THE UWS: boolean done = uws.executeRequest(req, resp); System.out.println("### UWS INFO : REQUEST ? "+(done?"OK":"NOT DONE")+" ###"); }catch(UWSException uwsEx){ // Display properly the caught UWSException: resp.sendError(uwsEx.getHttpErrorCode(), uwsEx.getMessage()); }catch(MalformedURLException mue){ System.err.println("### UWS ERROR : wrong base UWS URL ! ###"); throw new ServletException(mue); } } }
Version 3.0
public class UWSTimers extends HttpServlet { private static final long serialVersionUID = 1L; protected BasicUWS<JobChrono> uws = null; @SuppressWarnings("unchecked") @Override public void init(ServletConfig config) throws ServletException { super.init(config); // INITIALIZE OUR UWS: try{ // Create the UWS: uws = new BasicUWS<JobChrono>(JobChrono.class); // Set the way the UWS must identify a user: uws.setUserIdentifier(new UserIdentifier() { private static final long serialVersionUID = 1L; @Override public String extractUserId(UWSUrl urlInterpreter, HttpServletRequest request) throws UWSException { return request.getRemoteAddr(); } }); // Set a description: uws.setDescription("This UWS aims to manage one (or more) JobList(s) of JobChrono." + "JobChrono is a kind of Job whose the execution task consists to wait a given time"); // Create the job list "timers": uws.addJobList(new JobList<JobChrono>("timers")); }catch(UWSException ex){ throw new ServletException(ex); } } @Override protected void service(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException { try{ // FORWARD THE REQUEST TO THE UWS: boolean done = uws.executeRequest(req, resp); System.out.println("### UWS INFO : REQUEST ? "+(done?"OK":"NOT DONE")+" ###"); }catch(UWSException uwsEx){ // Display properly the caught UWSException: resp.sendError(uwsEx.getHttpErrorCode(), uwsEx.getMessage()); } } }
2. UWS
a. UWS Actions
In the previous version you were able to customize all the default UWS actions by overriding the corresponding functions in AbstractUWS: listJobs(JL, javax.servlet.http.HttpServletResponse), addJob(JL, Map<String,String>, HttpServletResponse), jobSummary(J, HttpServletResponse), ..... So that allowing to add and to remove UWS actions, all these methods have been replaced by an instance of UWSAction in v3.0:
v2.0 | v3.0 |
---|---|
writeHomePage(HttpServletResponse) | ShowHomePage |
listJobs(JL, HttpServletResponse) | ListJobs |
addJob(JL, Map<String,String>, HttpServletResponse) | AddJob |
jobSummary(J, HttpServletResponse) | JobSummary |
destroyJob(JL, J, HttpServletRequest, HttpServletResponse) | DestroyJob |
getJobParam(J, String, HttpServletResponse) | GetJobParam |
setJobParam(JL, J, String, HttpServletResponse) | SetJobParam |
Consequently, the done customizations must be moved into extensions of the corresponding UWSAction implementations. Then you just have to substitute the default actions in your UWS.
Version 2.0
public class MyUWS extends BasicUWS<JobChrono> { ... @Override public void listJobs(JobList<JobChrono> jl, HttpServletResponse response) throws UWSException, java.io.IOException { System.out.println("Hello ! I am printing the jobs list "+jl.getName()+" !"); super.listJobs(jl, response); } ... }
Version 3.0
myUws.replaceUWSAction(new MyListJob<JobList<JobChrono>, JobChrono>(myUws)); public class MyListJob<JL extends JobList<J>, J extends AbstractJob> extends ListJobs<JL, J> { ... @Override public boolean apply(UWSUrl url, String userId, HttpServletRequest request, HttpServletResponse response) throws UWSException, IOException { System.out.println("Hello ! "+userId+" is printing the jobs list "+url.getJobListName()+" !"); super.apply(url, userId, request, response); } ... }
See D.6. Actions for more details about the UWS action customization.
b. Action identification
The class UWSParameters does not exist any more in the version 3.0. It was used to interpret the URL so that identifying the corresponding action. But now, each action is able to indicate whether it can be applied or not, considering a given HTTP request. Consequently, the interpretation of the URL has been moved directly into the method executeRequest(HttpServletRequest, HttpServletResponse). Then this method loops on the list of all available actions and executes the first one which matches with the given HTTP request.
If you had customized UWSParameters, you have two cases. If your modifications concern:
-
the URL interpretation:
You have to customize the new version of UWSUrl. See the part D.5. UWS URL interpretation to know how.
-
the action choice:
Either you may change the concerned actions (or maybe add new ones to your UWS) or you may override executeRequest(HttpServletRequest, HttpServletResponse). See respectively the parts D.6. Actions and D.4. Request interpretation for more details.
c. URL interpretation
Even if UWSUrl still exists, it has been subject to many modifications:
-
There is no more constructor with a URL.
Now either a base URI (a String) or a request (a HttpServletRequest) is expected. It is due to the fact that now the extraction of the base UWS URL is done automatically by this class thanks to the request given at the initialization.
-
The base URL is no more required to create a UWS.
Once initialized, AbstractUWS will wait the first request to create a URL interpreter (instance of UWSUrl) which extracts automatically the base UWS URL.
-
In consequence, the static function extractBaseUWSUrl(HttpServletRequest) does not exist any more.
Actually, it has been more or less replaced by another function which is neither static nor public: extractBaseURI(HttpServletRequest). It is only called by the constructor. It must be overrided, if the base URL extraction method has to be changed.
-
All the functions which let generating UWS URL have been slightly changed: now, they have parameters.
Before this modification, the concerned fields of the UWSUrl object had to be set to get the wanted URL. For instance: to have the URL of the job phase, you had to ensure the UWSUrl had the good job list name and the good job ID. Now, this kind of information has to be given in parameter. In that way, the object is not modified.
All these modifications and some others are explained in more details in the part D.5. UWS URL interpretation. Instructions about the way to customize UWSUrl are also given.
3. Job
- The class DefaultJob does not exist any more.
-
The class member otherParameters of AbstractJob has been renamed in
additionalParameters:
So that being less ambiguous, this attribute and all its getters and setters have been renamed in the same way. However the former getters and setters still exist but are declared deprecated.
-
The method checkPhaseParam() has been renamed in applyPhaseParam():
Again, this method has been renamed to be more precise about the goal of the method. The former method has been kept but it is now declared deprecated.
-
The type of the phase attribute has been changed from ExecutionPhase
to JobPhase.
JobPhase lets managing all the phase transitions whereas ExecutionPhase only enumerates the different phases. Thus, the current phase of a job is now stored into a JobPhase object. However, the getter and the setters of the job phase have not changed at all. See the part C.3.a. Execution WITHOUT queue for more details.
-
The default ID generation of a job has been improved.
Rather than a simple static counter, it is now a string divided in two parts: the current date-time in milli-seconds and one upper-case letter. The letter is firstly A, and is incremented while the resulting job ID is already used. Besides it is still possible to customize the job ID generation by overriding generateJobId(). See the part C.1. Job ID for more details.
-
The job serialization has totally changed.
Indeed the abstract class ExportableUWSObject has been replaced by the abstract class SerializableUWSObject which is more flexible because it lets serializing a job in several different formats. Consequently the function getXMLContent(boolean) does not exist any more. It has been replaced by the function serialize(UWSSerializer) which does not the serialization itself but uses the given instance of UWSSerializer. See D.7. Serializations for more details.
-
The type of the attribute href of the class
Result has been changed from URL to String.
Thus it is now possible to give a relative URI rather than a full URL.