package uws.service; /* * This file is part of UWSLibrary. * * UWSLibrary is free software: you can redistribute it and/or modify * it under the terms of the GNU Lesser General Public License as published by * the Free Software Foundation, either version 3 of the License, or * (at your option) any later version. * * UWSLibrary is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public License * along with UWSLibrary. If not, see <http://www.gnu.org/licenses/>. * * Copyright 2012,2014 - UDS/Centre de DonnĂ©es astronomiques de Strasbourg (CDS), * Astronomisches Rechen Institut (ARI) */ import java.io.Serializable; import java.net.MalformedURLException; import java.net.URL; import java.util.Map; import javax.servlet.http.HttpServletRequest; import uws.UWSToolBox; import uws.job.UWSJob; /** * This class helps managing with UWS URLs and URIs. * * @author Grégory Mantelet (CDS;ARI) * @version 4.1 (09/2014) */ public class UWSUrl implements Serializable { private static final long serialVersionUID = 1L; /** The whole request URL (i.e. http://foo.org/mySite/uws/jobList/job1/results/report). */ protected String requestURL = null; // http://cds-dev-gm:8080/uwstuto/basic/timers/job1/results/report /** The URL prefix (i.e. http://foo.org/mySite). */ protected String urlHeader = null; // http://cds-dev-gm:8080/uwstuto /** The request URI (i.e. /uws/jobList/job1/results/report) */ protected String requestURI = null; // /basic/timers/job1/results/report /** Base UWS URI (i.e. /uws). */ protected final String baseURI; // /basic /** The URI from the base UWS URI (i.e. /jobList/job1/results/report). */ protected String uwsURI = null; // /timers/job1/results/report /** Name of a jobs list found in uwsURI (i.e. jobList). */ protected String jobListName = null; // timers /** The JobID found in uwsURI (i.e. job1). */ protected String jobId = null; // job1 /** Name of the job attribute found in uwsURI (i.e. {results, report}). */ protected String[] attributes = new String[0]; // {results, report} /* ************ */ /* CONSTRUCTORS */ /* ************ */ /** * Builds a copy of the given UWSUrl. * * @param toCopy The UWSUrl to copy. */ public UWSUrl(UWSUrl toCopy){ requestURL = toCopy.requestURL; urlHeader = toCopy.urlHeader; requestURI = toCopy.requestURI; baseURI = toCopy.baseURI; uwsURI = toCopy.uwsURI; jobListName = toCopy.jobListName; jobId = toCopy.jobId; attributes = new String[toCopy.attributes.length]; System.arraycopy(toCopy.attributes, 0, attributes, 0, attributes.length); } /** * Builds a UWSUrl with a fixed baseURI. * * @param baseURI The baseURI to consider in all URL or request parsing. * * @throws NullPointerException If the given baseURI is <i>null</i> or is an empty string. */ public UWSUrl(String baseURI) throws NullPointerException{ if (baseURI == null) throw new NullPointerException("The given base UWS URI is NULL!"); this.baseURI = normalizeURI(baseURI); if (baseURI.length() == 0) throw new NullPointerException("The given base UWS URI is empty!"); } /** * Builds a UWSUrl considering the given request to set the baseURI. * * @param request The request to parse to get the baseURI. * * @throws NullPointerException If the given request is <i>null</i> or if the extracted baseURI is <i>null</i> or is an empty string. * * @see #extractBaseURI(HttpServletRequest) */ public UWSUrl(HttpServletRequest request) throws NullPointerException{ // Extract the base URI: String uri = extractBaseURI(request); if (uri == null) throw new NullPointerException("The extracted base UWS URI is NULL!"); else baseURI = normalizeURI(uri); // Load the rest of the request: load(request); } /** * Extracts the base UWS URI from the given request. * * @param request The request from which the base UWS URI must be extracted. * * @return The extracted URI (may be <i>null</i>). */ protected String extractBaseURI(HttpServletRequest request){ if (request == null) return null; return request.getServletPath(); } /** * <p>Normalizes the given URI.</p> * * <p><i><u>Note:</u> A normalized URI always starts with a / and ends with no /.</i></p> * * @param uri The URI to normalize. * * @return The normalized URI. */ protected static final String normalizeURI(String uri){ uri = uri.trim(); if (uri.length() > 0 && uri.charAt(0) != '/') uri = "/" + uri; while(uri.length() >= 1 && uri.charAt(uri.length() - 1) == '/') uri = uri.substring(0, uri.length() - 1).trim(); return uri.trim(); } /* ************ */ /* LOAD METHODS */ /* ************ */ /** * <p>Parses and loads the given request.</p> * * <p> * Before all, {@link #extractBaseURI(HttpServletRequest)} is called so that extracting the base URI from the request. * If this URI is different from the URI stored in this UWSUrl, {@link #load(URL)} is called so that parsing only the request URL * and then this method ends immediately. * </p> * * <p> * Otherwise this method sets its fields as following: * <ul> * <li>requestURL = {@link HttpServletRequest#getRequestURL()}</li> * <li>urlHeader = {@link HttpServletRequest#getScheme()}+"://"+{@link HttpServletRequest#getServerName()}+":"+{@link HttpServletRequest#getServerPort()}+{@link HttpServletRequest#getContextPath()}</li> * <li>requestURI = {@link HttpServletRequest#getRequestURI()}</li> * <li>uwsURI = {@link HttpServletRequest#getPathInfo()}</li> * <li>for jobListName, jobId and attributes, see {@link #loadUwsURI()}</li> * </ul> * </p> * * <p><i><u>Note:</u> If the given request is NULL, all fields are set to NULL.</i></p> * * @param request The request to parse and to load. * * @see #extractBaseURI(HttpServletRequest) * @see #load(URL) * @see #loadUwsURI() */ public void load(HttpServletRequest request){ if (request == null){ urlHeader = null; requestURL = null; requestURI = null; uwsURI = null; }else{ if (extractBaseURI(request).equalsIgnoreCase(baseURI)){ requestURL = request.getRequestURL().toString(); urlHeader = (new StringBuffer(request.getScheme())).append("://").append(request.getServerName()).append(":").append(request.getServerPort()).append(request.getContextPath()).toString(); requestURI = request.getRequestURI().substring(request.getRequestURI().indexOf(baseURI)); uwsURI = request.getPathInfo(); }else{ URL url = null; try{ url = new URL(request.getRequestURL().toString()); }catch(MalformedURLException ex){ ; } load(url); return; } } loadUwsURI(); } /** * <p>Parses and loads the given request URL.</p> * * <p> * All the fields are set as following: * <ul> * <li>requestURL = requestUrl.substring(0, requestUrl.indexOf("?")</li> * <li>urlHeader = requestURL.substring(0, requestURL.indexOf(baseURI))</li> * <li>requestURI = requestURL.substring(requestURL.indexOf(baseURI))</li> * <li>uwsURI = requestURI.substring(baseURI.length())</li> * <li>for jobListName, jobId and attributes, see {@link #loadUwsURI()}</li> * </ul> * </p> * * <p><i><u>Note:</u> If the given URL is NULL, all fields are set to NULL.</i></p> * * @param requestUrl The URL to parse and to load. * * @see #loadUwsURI() */ public void load(URL requestUrl){ if (requestUrl == null){ urlHeader = null; requestURL = null; requestURI = null; uwsURI = null; }else{ requestURL = requestUrl.toString(); if (requestURL.indexOf("?") > 0) requestURL = requestURL.substring(0, requestURL.indexOf("?")); int indBaseURI = requestURL.indexOf(baseURI); if (indBaseURI >= 0){ urlHeader = requestURL.substring(0, indBaseURI); requestURI = requestURL.substring(indBaseURI); uwsURI = requestURI.substring(baseURI.length()); }else{ urlHeader = null; requestURI = null; uwsURI = null; } } loadUwsURI(); } /** * <p>Loads and parses the URI stored in the member {@link #uwsURI}.</p> * * <p> * The URI is split by the / character. The items of the resulting array corresponds to: * <ul> * <li>item 0 = empty (the empty string before the first / of a URI)</li> * <li>item 1 = jobListName</li> * <li>item 2 = jobId</li> * <li>item 3 and more = attributes</li> * </ul> * </p> * * <p><i><u>Note:</u> If {@link #uwsURI} is NULL, jobListName and jobId are set to null while attributes is set to an empty array.</i></p> */ protected void loadUwsURI(){ jobListName = null; jobId = null; attributes = new String[0]; if (uwsURI != null){ // URI normalization: it must always begin with a / but never ends with a / ! uwsURI = normalizeURI(uwsURI); String[] uriParts = uwsURI.split("/"); // uwsURI begins always with a / so uriParts[0] is always null ! if (uriParts.length >= 2){ jobListName = uriParts[1].trim(); if (jobListName.length() == 0) jobListName = null; } if (uriParts.length >= 3){ jobId = uriParts[2].trim(); if (jobId.length() == 0) jobId = null; } if (uriParts.length >= 4){ attributes = new String[uriParts.length - 3]; for(int i = 3; i < uriParts.length; i++) attributes[i - 3] = uriParts[i].trim(); } } } /* ******* */ /* GETTERS */ /* ******* */ /** * Gets the base UWS URI given at the initialization of this instance of {@link UWSUrl}. * * @return The baseUri. */ public final String getBaseURI(){ return baseURI; } /** * Gets the <b>SUPPOSED</b> name of the UWS from its baseURI. * * @return The presumed UWS name. */ public final String getUWSName(){ return baseURI.substring(baseURI.lastIndexOf('/') + 1); } /** * Gets the request URL. * * @return The last loaded request URL. */ public final String getRequestURL(){ return requestURL; } /** * <p>Gets the URL header of the request URL.</p> * * <p> * <i><u>Example:</u> * If the base URI is "/uws" and the request URL is "http://foo.org/mySite/uws/jobList/job1/results/report", then the URL header will be: * "http://foo.org/mySite". * </i> * </p> * * @return The last loaded URL header. */ public final String getUrlHeader(){ return urlHeader; } /** * <p>Gets the request URI.</p> * * <p> * <i><u>Example:</u> * If the base URI is "/uws" and the request URL is "http://foo.org/mySite/uws/jobList/job1/results/report", then the request URI will be: * "/uws/jobList/jobId/results/report". * </i> * </p> * * @return The last loaded request URI. */ public final String getRequestURI(){ return requestURI; } /** * <p>Gets the UWS URI.</p> * * <p> * <i><u>Example:</u> * If the base URI is "/uws" and the request URL is "http://foo.org/mySite/uws/jobList/job1/results/report", then the request URI will be: * "/jobList/jobId/results/report". * </i> * </p> * * @return The extracted UWS URI. */ public final String getUwsURI(){ return uwsURI; } /** * Tells whether the last loaded request or request URL contains a jobs list name. * * @return <i>true</i> if a jobs list name has been extracted, <i>false</i> otherwise. */ public final boolean hasJobList(){ return jobListName != null; } /** * Gets the jobs list name extracted from the last parsed request or request URL. * * @return The extracted jobs list name. */ public final String getJobListName(){ return jobListName; } /** * Tells whether the last loaded request or request URL contains a job ID. * * @return <i>true</i> if a job ID has been extracted, <i>false</i> otherwise. */ public final boolean hasJob(){ return jobId != null; } /** * Gets the job ID extracted from the last parsed request or request URL. * * @return The extracted job ID. */ public final String getJobId(){ return jobId; } /** * Tells whether the last loaded request or request URL contains at least one job attribute. * * @return <i>true</i> if at least one job attribute has been extracted, <i>false</i> otherwise. */ public final boolean hasAttribute(){ return attributes != null && attributes.length > 0; } /** * Tells whether the last loaded request or request URL contains a job attribute with the given name. * * @param attributeName The name of the job attribute expected in the last request or request URL. * * @return <i>true</i> if the specified job attribute has been extracted, <i>false</i> otherwise. */ public final boolean hasAttribute(String attributeName){ for(String att : attributes){ if (att.equalsIgnoreCase(attributeName)) return true; } return false; } /** * Gets all the job attributes extracted from the last request or request URL. * * @return The extracted job attributes. */ public final String[] getAttributes(){ return attributes; } /* ******* */ /* SETTERS */ /* ******* */ /** * <p>Updates the field {@link #uwsURI} in function of {@link #jobListName}, {@link #jobId} and {@link #attributes} as following: * uwsURI = "/"+jobListName+"/"+jobId+"/"+attributes.</p> * * <p>Once {@link #uwsURI} updated the request URL and URI are also updated.</p> * * @see #updateRequestURL() */ protected void updateUwsURI(){ uwsURI = null; if (hasJobList()){ StringBuffer uri = new StringBuffer("/"); uri.append(jobListName); if (hasJob()){ uri.append("/").append(jobId); if (hasAttribute()){ for(String att : attributes) uri.append("/").append(att); } } uwsURI = uri.toString(); } updateRequestURL(); } /** * <p> * Updates the fields {@link #requestURI} and {@link #requestURL} as following: * <ul> * <li>requestURI = baseURI+uwsURI</li> * <li>requestURL = urlHeader+requestURI (or <i>null</i> if urlHeader is <i>null</i>)</li> * </ul> * </p> */ protected void updateRequestURL(){ requestURI = baseURI + ((uwsURI != null) ? uwsURI : ""); requestURL = (urlHeader == null) ? null : (urlHeader + requestURI); } /** * Sets the whole UWS URI (that is to say a URI starting with the jobs list name). * Once done all the other fields of this UWS URL are updated. * * @param uwsURI The UWS URI to set. * * @see #loadUwsURI() * @see #updateRequestURL() */ public final void setUwsURI(String uwsURI){ if (uwsURI == null || uwsURI.trim().length() == 0) this.uwsURI = null; else this.uwsURI = uwsURI.trim(); loadUwsURI(); updateRequestURL(); } /** * Sets the jobs list name. * Once done all the other fields of this UWS URL are updated. * * @param jobListName A jobs list name. * * @see #updateUwsURI() */ public final void setJobListName(String jobListName){ this.jobListName = jobListName; updateUwsURI(); } /** * Sets the job ID. * Once done all the other fields of this UWS URL are updated. * * @param jobId A job ID. * * @see #updateUwsURI() */ public final void setJobId(String jobId){ this.jobId = jobId; updateUwsURI(); } /** * <p>Sets all the job attributes. * Once done all the other fields of this UWS URL are updated.</p> * * <p><i><u>Note:</u> The given array is entirely copied.</i></p> * * @param newAttributes The new job attributes. * * @see #updateUwsURI() */ public final void setAttributes(String[] newAttributes){ if (newAttributes == null) attributes = new String[0]; attributes = new String[newAttributes.length]; System.arraycopy(newAttributes, 0, attributes, 0, attributes.length); updateUwsURI(); } /* ******************** */ /* URL BUILDING METHODS */ /* ******************** */ /** Gets the base UWS URI = UWS home page. */ public final UWSUrl homePage(){ UWSUrl url = new UWSUrl(this); url.setUwsURI(null); return url; } /** Gets the UWS URL to get the specified <b>jobs list</b>. */ public final UWSUrl listJobs(String jobListName){ UWSUrl url = homePage(); url.setJobListName(jobListName); return url; } /** Gets the UWS URL to get the <b>summary</b>. */ public final UWSUrl jobSummary(String jobListName, String jobId){ UWSUrl url = listJobs(jobListName); url.setJobId(jobId); return url; } /** Gets the UWS URL to get the <b>runID</b>. */ public final UWSUrl jobName(String jobListName, String jobId){ UWSUrl url = jobSummary(jobListName, jobId); url.setAttributes(new String[]{UWSJob.PARAM_RUN_ID}); return url; } /** Gets the UWS URL to get the <b>phase</b>. */ public final UWSUrl jobPhase(String jobListName, String jobId){ UWSUrl url = jobSummary(jobListName, jobId); url.setAttributes(new String[]{UWSJob.PARAM_PHASE}); return url; } /** Gets the UWS URL to get the <b>execution duration</b>. */ public final UWSUrl jobExecDuration(String jobListName, String jobId){ UWSUrl url = jobSummary(jobListName, jobId); url.setAttributes(new String[]{UWSJob.PARAM_EXECUTION_DURATION}); return url; } /** Gets the UWS URL to get the <b>destruction time</b>. */ public final UWSUrl jobDestruction(String jobListName, String jobId){ UWSUrl url = jobSummary(jobListName, jobId); url.setAttributes(new String[]{UWSJob.PARAM_DESTRUCTION_TIME}); return url; } /** Gets the UWS URL to get the <b>error summary</b>. */ public final UWSUrl jobError(String jobListName, String jobId){ UWSUrl url = jobSummary(jobListName, jobId); url.setAttributes(new String[]{UWSJob.PARAM_ERROR_SUMMARY}); return url; } /** Gets the UWS URL to get the <b>quote</b>. */ public final UWSUrl jobQuote(String jobListName, String jobId){ UWSUrl url = jobSummary(jobListName, jobId); url.setAttributes(new String[]{UWSJob.PARAM_QUOTE}); return url; } /** Gets the UWS URL to get the <b>results</b>. */ public final UWSUrl jobResults(String jobListName, String jobId){ UWSUrl url = jobSummary(jobListName, jobId); url.setAttributes(new String[]{UWSJob.PARAM_RESULTS}); return url; } /** Gets the UWS URL to get the <b>specified result</b>. */ public final UWSUrl jobResult(String jobListName, String jobId, String resultId){ UWSUrl url = jobSummary(jobListName, jobId); url.setAttributes(new String[]{UWSJob.PARAM_RESULTS,resultId}); return url; } /** Gets the UWS URL to get the <b>parameters</b>. */ public final UWSUrl jobParameters(String jobListName, String jobId){ UWSUrl url = jobSummary(jobListName, jobId); url.setAttributes(new String[]{UWSJob.PARAM_PARAMETERS}); return url; } /** Gets the UWS URL to get the <b>parameters/parameter</b>. */ public final UWSUrl jobParameter(String jobListName, String jobId, String paramName){ UWSUrl url = jobSummary(jobListName, jobId); url.setAttributes(new String[]{UWSJob.PARAM_PARAMETERS,paramName}); return url; } /** Gets the UWS URL to get the <b>owner ID</b>. */ public final UWSUrl jobOwner(String jobListName, String jobId){ UWSUrl url = jobSummary(jobListName, jobId); url.setAttributes(new String[]{UWSJob.PARAM_OWNER}); return url; } /* ******************************* */ /* URL BUILDING METHODS (HTTP GET) */ /* ******************************* */ /** Gets the UWS URL <b>(HTTP-GET ONLY)</b> to <b>create</b> a job with the given parameters. */ public final String createJob(String jobListName, Map<String,String> parameters){ return listJobs(jobListName) + "?" + UWSToolBox.getQueryPart(parameters); } /** Gets the UWS URL <b>(HTTP-GET ONLY)</b> to <b>delete</b> the specified job. */ public final String deleteJob(String jobListName, String jobId){ return jobSummary(jobListName, jobId) + "?" + UWSJob.PARAM_ACTION + "=" + UWSJob.ACTION_DELETE; } /** Gets the UWS URL <b>(HTTP-GET ONLY)</b> to <b>start</b> the specified job. */ public final String startJob(String jobListName, String jobId){ return jobPhase(jobListName, jobId) + "?" + UWSJob.PARAM_PHASE.toUpperCase() + "=" + UWSJob.PHASE_RUN; } /** Gets the UWS URL <b>(HTTP-GET ONLY)</b> to <b>abort</b> the specified job. */ public final String abortJob(String jobListName, String jobId){ return jobPhase(jobListName, jobId) + "?" + UWSJob.PARAM_PHASE.toUpperCase() + "=" + UWSJob.PHASE_ABORT; } /** Gets the UWS URL <b>(HTTP-GET ONLY)</b> to change the run ID. */ public final String changeJobName(String jobListName, String jobId, String newName){ return jobName(jobListName, jobId) + "?" + UWSJob.PARAM_RUN_ID.toUpperCase() + "=" + newName; } /** Gets the UWS URL <b>(HTTP-GET ONLY)</b> to change the destruction time. */ public final String changeDestructionTime(String jobListName, String jobId, String newDestructionTime){ return jobDestruction(jobListName, jobId) + "?" + UWSJob.PARAM_DESTRUCTION_TIME.toUpperCase() + "=" + newDestructionTime; } /** Gets the UWS URL <b>(HTTP-GET ONLY)</b> to change the execution duration. */ public final String changeExecDuration(String jobListName, String jobId, String newExecDuration){ return jobExecDuration(jobListName, jobId) + "?" + UWSJob.PARAM_EXECUTION_DURATION.toUpperCase() + "=" + newExecDuration; } /** Gets the UWS URL <b>(HTTP-GET ONLY)</b> to change the specified parameter. */ public final String changeJobParam(String jobListName, String jobId, String paramName, String paramValue){ return jobParameters(jobListName, jobId) + "?" + paramName.toUpperCase() + "=" + paramValue; } /** * Gets the full request URL corresponding to this UWSUrl. * * @return The corresponding request URL. * * @throws MalformedURLException If there is an error while building the URL object from the {@link #requestURL} field. * * @see #getRequestURL() */ public URL toURL() throws MalformedURLException{ String url = getRequestURL(); return (url != null) ? (new URL(url)) : null; } /** * Gets the full request URI corresponding to this UWSUrl. * * @return The corresponding request URI. * * @see #getRequestURI() */ public String toURI(){ return getRequestURI(); } /** * Gets the corresponding request URL. * * @see #getRequestURL() * @see java.lang.Object#toString() */ @Override public String toString(){ return getRequestURL(); } }