Main modifications between the UWS Library v2.0 and v3.0.
This page gives details useful for migration about the undergone API modifications between v2.0 and v3.0 of the UWS Library. A brief overview of main modifications is already provided in the News page.
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.
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.
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.
public class UWSTimers extends HttpServlet { protected void doDelete(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException { doPost(req, resp); } protected void doPut(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException { doPost(req, resp); } protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException { doPost(req, resp); } 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); } } }
public class UWSTimers extends HttpServlet { protected BasicUWS<JobChrono> uws = null; 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); } } 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()); } } }
In the previous version you were able to customize all the default UWS actions by overriding the corresponding functions in AbstractUWS: listJobs(JL, 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.
public class MyUWS extends BasicUWS<JobChrono> { ... 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); } ... }
myUws.replaceUWSAction(new MyListJob<JobList<JobChrono>, JobChrono>(myUws));
public class MyListJob<JL extends JobList<J>, J extends AbstractJob> extends ListJobs<JL, J> { ... 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); } ... }
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:
You have to customize the new version of UWSUrl.
Either you may change the concerned actions (or maybe add new ones to your UWS) or you may override executeRequest(HttpServletRequest, HttpServletResponse).
Even if UWSUrl still exists, it has been subject to many modifications:
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.
Once initialized, AbstractUWS will wait the first request to create a URL interpreter (instance of UWSUrl) which extracts automatically the base UWS URL.
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.
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.
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.
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.
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.
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().
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.
Thus it is now possible to give a relative URI rather than a full URL.