diff --git a/src/tap/resource/ForwardResource.java b/src/tap/resource/ForwardResource.java index 3e3f9a6e5c71166cdd49b29da43829c7a31d14fa..673924995495c002c06a917a0d09f6dec9c98423 100644 --- a/src/tap/resource/ForwardResource.java +++ b/src/tap/resource/ForwardResource.java @@ -2,21 +2,22 @@ package tap.resource; /* * This file is part of TAPLibrary. - * + * * TAPLibrary 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. - * + * * TAPLibrary 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 TAPLibrary. If not, see <http://www.gnu.org/licenses/>. - * - * Copyright 2015-2017 - Astronomisches Rechen Institut (ARI) + * + * Copyright 2015-2019 - Astronomisches Rechen Institut (ARI), + * UDS/Centre de Données astronomiques de Strasbourg (CDS) */ import java.io.BufferedReader; @@ -39,7 +40,7 @@ import uws.service.log.UWSLog.LogLevel; /** * <p>A {@link TAPResource} which is able to "forward" an HTTP request toward a specified URI.</p> - * + * * <p> * In function of the URI shape (i.e. what is the scheme? none/file:/other) and the servlet path, * the HTTP request will be internally forwarded to the Web Application file (using @@ -47,11 +48,11 @@ import uws.service.log.UWSLog.LogLevel; * the content of the specified file will be copied in the HTTP response or a redirection toward * the given URL will be performed. * </p> - * + * * <p><i>See {@link #forward(String, String, HttpServletRequest, HttpServletResponse)} for more details</i></p> - * - * @author Grégory Mantelet (ARI) - * @version 2.1 (03/2017) + * + * @author Grégory Mantelet (ARI;CDS) + * @version 2.2 (03/2019) * @since 2.1 */ public abstract class ForwardResource implements TAPResource { @@ -62,7 +63,7 @@ public abstract class ForwardResource implements TAPResource { /** * Builds a {@link ForwardResource} with a logger to use in case of "small" errors. - * + * * @param logger A TAP logger. */ protected ForwardResource(final TAPLog logger){ @@ -71,7 +72,7 @@ public abstract class ForwardResource implements TAPResource { /** * <p>Write the content of the specified file in the given HTTP response.</p> - * + * * <p>Three cases are taken into account in this function, in function of the given URI:</p> * <ol> * <li><b>a file inside WebContent</b> if the given URI has no scheme (e.g. "tapIndex.jsp" or "/myFiles/tapIndex.html"). @@ -83,7 +84,7 @@ public abstract class ForwardResource implements TAPResource { * <li><b>a distance document</b> in all other cases. Indeed, if there is a scheme different from "file:" the given URI will be considered as a URL. * In this case, any request to the TAP home page is redirected to this URL.</li> * </ol> - * + * * <p><b>Important note:</b> * The 1st option is applied ONLY IF the path of the TAP servlet is NOT the root path of the web application: * that's to say <code>/*</code>. In the case where a URI without scheme is provided though the servlet path @@ -92,14 +93,14 @@ public abstract class ForwardResource implements TAPResource { * specified file is not a JSP or does not need any kind of interpretation by the function * {@link RequestDispatcher#forward(javax.servlet.ServletRequest, javax.servlet.ServletResponse)}. * </p> - * + * * @param file URI/URL/path of the file to write/forward/redirect in the given HTTP response. * @param mimeType MIME type of the specified file. * @param request HTTP request which require the specified file. * @param response HTTP response in which the specified file must be written/forwarded/redirected. - * + * * @return <code>true</code> if the forward/redirection was successful, <code>false</code> otherwise. - * + * * @throws IOException When an error occur while forwarding toward the specified Web application resource, * or while writing the specified local file * or while redirection toward the specified URL @@ -154,7 +155,7 @@ public abstract class ForwardResource implements TAPResource { File f = new File(uri.getPath()); if (f.exists() && !f.isDirectory() && f.canRead()){ // set the content length: - response.setContentLength((int)f.length()); + UWSToolBox.setContentLength(response, f.length()); // get the input stream: input = new BufferedReader(new FileReader(f)); @@ -231,12 +232,12 @@ public abstract class ForwardResource implements TAPResource { /** * <p>Log the given error as a TAP log message with the {@link LogLevel} ERROR, and the event corresponding to the resource name.</p> - * + * * <p> * The logged message starts with: <code>Can not write the specified content ({file})</code>. * After the specified error message, the following is appended: <code>! => A default content may be displayed.</code>. * </p> - * + * * <p> * If the message parameter is missing, the {@link Throwable} message will be taken instead. * And if this latter is also missing, none will be written. diff --git a/src/uws/UWSToolBox.java b/src/uws/UWSToolBox.java index 9a1fc3ce7317ea9713671b09c73341e513d8010d..201728c19c2b5eda338e444d9ffd759dc246fd54 100644 --- a/src/uws/UWSToolBox.java +++ b/src/uws/UWSToolBox.java @@ -1,5 +1,25 @@ package uws; +import java.io.File; +import java.io.IOException; +import java.io.InputStream; +import java.io.OutputStream; +import java.io.PrintWriter; +import java.io.UnsupportedEncodingException; +import java.lang.reflect.Array; +import java.net.MalformedURLException; +import java.net.URL; +import java.net.URLDecoder; +import java.net.URLEncoder; +import java.util.Date; +import java.util.Enumeration; +import java.util.HashMap; +import java.util.Map; + +import javax.servlet.ServletOutputStream; +import javax.servlet.http.HttpServletRequest; +import javax.servlet.http.HttpServletResponse; + /* * This file is part of UWSLibrary. * @@ -31,25 +51,11 @@ import uws.service.log.UWSLog; import uws.service.request.RequestParser; import uws.service.request.UploadFile; -import javax.servlet.ServletOutputStream; -import javax.servlet.http.HttpServletRequest; -import javax.servlet.http.HttpServletResponse; -import java.io.*; -import java.lang.reflect.Array; -import java.net.MalformedURLException; -import java.net.URL; -import java.net.URLDecoder; -import java.net.URLEncoder; -import java.util.Date; -import java.util.Enumeration; -import java.util.HashMap; -import java.util.Map; - /** * Some useful functions for the managing of a UWS service. * * @author Grégory Mantelet (CDS;ARI) - * @version 4.3 (01/2019) + * @version 4.4 (03/2019) */ public class UWSToolBox { @@ -525,9 +531,8 @@ public class UWSToolBox { response.setCharacterEncoding(UWSToolBox.DEFAULT_CHAR_ENCODING); // Set the HTTP content length: - if (contentSize > 0) - response.setHeader("Content-Length", String.valueOf(contentSize)); - + setContentLength(response, contentSize); + // Write the file into the HTTP response: output = response.getOutputStream(); byte[] buffer = new byte[1024]; @@ -688,4 +693,31 @@ public class UWSToolBox { return null; } + + /** + * Set the content length in the given {@link HttpServletResponse}. + * + * <p><i><b>Implementation note:</b> + * This could perfectly be done using + * {@link HttpServletResponse#setContentLength(int)}, <b>but only if the + * content size is encoded or fit in an integer value</b>. Otherwise, that + * function will set no content length. + * On the contrary, this current function takes a long value and set + * manually the content type header. + * </i></p> + * + * <p><i><b>Note:</b> + * This function has no effect if the given {@link HttpServletResponse} is + * NULL or if the given content size is ≤ 0. + * </i></p> + * + * @param response HTTP response. + * @param contentSize The content size to set. + * + * @since 4.4 + */ + public static final void setContentLength(final HttpServletResponse response, final long contentSize){ + if (response != null && contentSize > 0) + response.setHeader("Content-Length", String.valueOf(contentSize)); + } } diff --git a/src/uws/job/jobInfo/SingleValueJobInfo.java b/src/uws/job/jobInfo/SingleValueJobInfo.java index f08be0b75eb25f4e121d62cb1a50835a985721d6..5228a7146875dbce95ec30018b7b7e371f112af8 100644 --- a/src/uws/job/jobInfo/SingleValueJobInfo.java +++ b/src/uws/job/jobInfo/SingleValueJobInfo.java @@ -2,21 +2,22 @@ package uws.job.jobInfo; /* * 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 2017 - Astronomisches Rechen Institut (ARI) + * + * Copyright 2017-2019 - Astronomisches Rechen Institut (ARI), + * UDS/Centre de Données astronomiques de Strasbourg (CDS) */ import java.io.IOException; @@ -25,20 +26,21 @@ import java.io.PrintWriter; import javax.servlet.http.HttpServletResponse; import uws.UWSException; +import uws.UWSToolBox; import uws.job.UWSJob; import uws.job.serializer.XMLSerializer; /** * Very simple implementation of {@link JobInfo}. It aims to represent a * key-value pair. - * + * * <p> * Both functions {@link #getXML(String)} and * {@link #write(HttpServletResponse)} will return the following XML document: * </p> - * + * * <pre><KEY>VALUE</KEY></pre> - * + * * <p>, where:</p> * <ul> * <li><i><code>KEY</code></i> can be get with {@link #getName()} and can be @@ -46,16 +48,16 @@ import uws.job.serializer.XMLSerializer; * <li><i><code>VALUE</code></i> can be get with {@link #getValue()} and set * with {@link #setValue(String)}.</li> * </ul> - * - * @author Grégory Mantelet (ARI) - * @version 4.2 (06/2017) + * + * @author Grégory Mantelet (ARI;CDS) + * @version 4.4 (03/2019) * @since 4.2 */ public class SingleValueJobInfo implements JobInfo { private static final long serialVersionUID = 1L; /** Name of the value stored inside this {@link JobInfo}. - * + * * <p><i><b>Warning:</b> By default, this name is not supposed to be * changed after initialization of this class. That's why only a public * getter function is provided.</i></p> */ @@ -66,7 +68,7 @@ public class SingleValueJobInfo implements JobInfo { /** XML representation of this {@link JobInfo}, returned by * {@link #getXML(String)} and {@link #write(HttpServletResponse)}. - * + * * <p><i>Note: * It has to be updated each time the {@link #value} is changed. So by * default, it is rebuilt by {@link #setValue(String)}. @@ -76,11 +78,11 @@ public class SingleValueJobInfo implements JobInfo { /** * Build a {@link JobInfo} representing a single value having the given * name. - * + * * <p><i>Note 1: * The name can not be changed after creation. * </i></p> - * + * * <p><i>Note 2: * With this constructor, the represented value is NULL. To set a value, * you have to use the function {@link #setValue(String)}. An alternative @@ -88,9 +90,9 @@ public class SingleValueJobInfo implements JobInfo { * {@link #SingleValueJobInfo(String, String)} so that setting immediately * the name and value. * </i></p> - * + * * @param name Name of the value to represent. - * + * * @throws NullPointerException If the given name is NULL or an empty * string. * @throws IllegalArgumentException If the given name is not a valid XML @@ -105,20 +107,20 @@ public class SingleValueJobInfo implements JobInfo { /** * Build a {@link JobInfo} representing a single value having the given * name and initial value. - * + * * <p><i>Note 1: * The name can not be changed after creation. * </i></p> - * + * * <p><i>Note 2: * The value can change after object creation with the function * {@link #setValue(String)}. * </i></p> - * + * * @param name Name of the value to represent. <i>Can not be NULL or an * empty string, and must be a valid XML node name.</i> * @param value Value to represent. <i>May be NULL.</i> - * + * * @throws NullPointerException If the given name is NULL or an empty * string. * @throws IllegalArgumentException If the given name is not a valid XML @@ -138,7 +140,7 @@ public class SingleValueJobInfo implements JobInfo { /** * Get the name of the represented value. - * + * * @return Value name. <i>Can NEVER be NULL.</i> */ public String getName(){ @@ -147,7 +149,7 @@ public class SingleValueJobInfo implements JobInfo { /** * Get the represented value. - * + * * @return The represented value. <i>Can be NULL.</i> */ public String getValue(){ @@ -156,7 +158,7 @@ public class SingleValueJobInfo implements JobInfo { /** * Set the value represented by this {@link JobInfo}. - * + * * @param value The new value to represent. <i>Can be NULL.</i> */ public void setValue(final String value){ @@ -174,7 +176,7 @@ public class SingleValueJobInfo implements JobInfo { public void write(HttpServletResponse response) throws IOException, UWSException{ response.setCharacterEncoding("UTF-8"); response.setContentType("text/xml"); - response.setContentLength(xmlRepresentation.getBytes("UTF-8").length); + UWSToolBox.setContentLength(response, xmlRepresentation.getBytes("UTF-8").length); PrintWriter writer = response.getWriter(); writer.println("<?xml version=\"1.0\" encoding=\"UTF-8\"?>"); diff --git a/src/uws/job/jobInfo/XMLJobInfo.java b/src/uws/job/jobInfo/XMLJobInfo.java index 39ce547e60f154d8297990e386facec14f426744..9493ad899cc330dba8e71b1a64600639945f63c2 100644 --- a/src/uws/job/jobInfo/XMLJobInfo.java +++ b/src/uws/job/jobInfo/XMLJobInfo.java @@ -2,21 +2,22 @@ package uws.job.jobInfo; /* * 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 2017 - Astronomisches Rechen Institut (ARI) + * + * Copyright 2017-2019 - Astronomisches Rechen Institut (ARI), + * UDS/Centre de Données astronomiques de Strasbourg (CDS) */ import java.io.BufferedReader; @@ -38,20 +39,20 @@ import uws.service.request.UploadFile; /** * A full XML document attached to a {@link UWSJob job}. - * + * * <p><b>XML representation</b></p> - * + * * <p> * The document stored inside this {@link JobInfo} is considered formatted * in XML. So the functions {@link #getXML(String)} and * {@link #write(HttpServletResponse)} will return them as such. * </p> - * + * * <p><i>Note 1: * The represented document is supposed to be XML, but absolutely no * verification is performed by {@link XMLJobInfo}. * </i></p> - * + * * <p><i>Note 2: * {@link #getXML(String)} will skip the XML declaration * (e.g. <code><?xml version="1.0" encoding="utf-8"?></code>) @@ -59,7 +60,7 @@ import uws.service.request.UploadFile; * will write an exact copy of the stored XML document. * Both functions can be overwritten if a different behavior is needed. * </i></p> - * + * * <p><i>Note 3: * The stored XML document can refer to the following * XML schemas: @@ -77,9 +78,9 @@ import uws.service.request.UploadFile; * {@link XMLSerializer} in order to append the needed namespaces to the root * XML node of any formatted XML documents. * </i></p> - * + * * <p><b>Internal representation and Creation</b></p> - * + * * <p> * This class proposes the two following constructors, each for a different * internal representation: @@ -94,17 +95,17 @@ import uws.service.request.UploadFile; * XML document.This constructor should be used <b>for large XML * document.</b></li> * </ul> - * + * * <p><b>Modification</b></p> - * + * * <p> * By default, this implementation of {@link JobInfo} does not allow the * modification of its XML document. If needed, this class should be * extended with the adequate functions. * </p> - * + * * <p><b>Backup/Restoration</b></p> - * + * * <p> * An {@link UploadFile} can not be serialized using the Java Class * Serialization mechanism because it does not implement the @@ -112,43 +113,43 @@ import uws.service.request.UploadFile; * will be marked as <i>transient</i> and will have to be rebuilt when needed * after a restoration process. * </p> - * + * * <p>However, it can be rebuilt only if:</p> * <ol> * <li>an access to a {@link UWSFileManager} is * possible.</li> * <li>the location of the file is known.</li> * </ol> - * + * * <p> * The first point (1) is fortunately possible through a {@link UWSJob} object. * This object is known after attachment to a job thanks to the function * {@link #setJob(UWSJob)}. So, a link toward the parent job should be kept ; * also marked as <i>transient</i>: see the attribute {@link #job}. * </p> - * + * * <p>For the second point (2), the location of the file must be kept as a * non-transient attribute (see {@link #location}) so that being backuped with the * other non-transient attributes of this class. In order to backup this * location up-to-date, the function * {@link #writeObject(java.io.ObjectOutputStream)} updates {@link #location} * before the normal Java Class Serialization. - * + * * <p> * So finally, the restoration of the {@link UploadFile} will be done by * {@link #getXML(String)} and {@link #write(HttpServletResponse)} with the * function {@link #restoreFile()}. * </p> - * - * @author Grégory Mantelet (ARI) - * @version 4.2 (06/2017) + * + * @author Grégory Mantelet (ARI;CDS) + * @version 4.4 (03/2019) * @since 4.2 */ public class XMLJobInfo implements JobInfo { private static final long serialVersionUID = 1L; /** XML file location. - * + * * <p><b>Warning:</b> * This field <b>ONLY</b> aims to contain the updated result of * {@link UploadFile#getLocation() file.getLocation()}. @@ -156,12 +157,12 @@ public class XMLJobInfo implements JobInfo { protected String location = null; /** Link toward the XML file represented by this {@link JobInfo}. - * + * * <p><b>Important:</b> * This field must be used when a large XML document has to be represented * by this {@link JobInfo}. * </p> - * + * * <p><i>Note: * It can be set only by {@link #XMLJobInfo(UploadFile)}. * If set, {@link #content} must be NULL. @@ -169,12 +170,12 @@ public class XMLJobInfo implements JobInfo { protected transient UploadFile file = null; /** XML document represented by this {@link JobInfo}. - * + * * <p><b>Important:</b> * This field MUST be used <b>ONLY</b> for small XML document in order to * keep enough memory free for the normal UWS service operations. * </p> - * + * * <p><i>Note: * It can be set only by {@link #XMLJobInfo(String)}. * If set, {@link #file} must be NULL. @@ -185,7 +186,7 @@ public class XMLJobInfo implements JobInfo { protected int length = -1; /** The job owning this {@link JobInfo}. - * + * * <p><i>Note: * This field is set only by {@link #setJob(UWSJob)} and is used * only by {@link #restoreFile()} in order to rebuild {@link #file} @@ -195,7 +196,7 @@ public class XMLJobInfo implements JobInfo { /** * Build a {@link JobInfo} representing a <b>small</b> XML document. - * + * * <p><b>Important:</b> * This constructor should be used only for <b>small</b> XML document * because the given string will be kept as such in memory. If the given @@ -205,9 +206,9 @@ public class XMLJobInfo implements JobInfo { * should save it in a file and use the constructor * {@link #XMLJobInfo(UploadFile)}.</i> * </p> - * + * * @param smallXML The small XML document to represent. - * + * * @throws NullPointerException If the given string is NULL or empty. */ public XMLJobInfo(final String smallXML) throws NullPointerException{ @@ -223,9 +224,9 @@ public class XMLJobInfo implements JobInfo { /** * Build a {@link JobInfo} representing a <b>large</b> XML document stored * inside a file. - * + * * @param xmlFile Link toward the large XML document to represent. - * + * * @throws NullPointerException If the given file is NULL or empty. */ public XMLJobInfo(final UploadFile xmlFile) throws NullPointerException{ @@ -277,7 +278,8 @@ public class XMLJobInfo implements JobInfo { if (input != null){ try{ input.close(); - }catch(IOException ioe){} + }catch(IOException ioe){ + } } } return xml.toString(); @@ -290,7 +292,7 @@ public class XMLJobInfo implements JobInfo { if (content != null){ response.setCharacterEncoding("UTF-8"); response.setContentType("text/xml"); - response.setContentLength(content.getBytes("UTF-8").length); + UWSToolBox.setContentLength(response, content.getBytes("UTF-8").length); PrintWriter writer = response.getWriter(); writer.println(content); @@ -330,17 +332,17 @@ public class XMLJobInfo implements JobInfo { /** * Serialize this {@link XMLJobInfo}. - * + * * <p><i>Note:</i> * This function will be called by the Java Class Serialization mechanism. * See the Javadoc of {@link Serializable} for more details. * </i></p> - * + * * <p> * This function just updates the XML file (if any) location before the * normal Java Class Serialization of this object. * </p> - * + * * @param out The stream used to contained the serialization of this * {@link XMLJobInfo}. * @@ -358,20 +360,20 @@ public class XMLJobInfo implements JobInfo { /** * Restore the link toward the XML file represented by this {@link JobInfo}. - * + * * <p> * This function has an effect only if {@link #file} is NULL but not * {@link #location} ; indeed, such configuration can be encountered only * if this {@link XMLJobInfo} has been de-serialized. * </p> - * + * * <p> * Nothing can be done if the parent job is unknown. In other words, * this {@link JobInfo} has to be attached to a job first * (i.e. {@link #setJob(UWSJob)} has to be called first with a non-NULL * parameter). If not, an exception will be thrown. * </p> - * + * * @throws UWSException If this {@link JobInfo} is not attached to a job. */ protected void restoreFile() throws UWSException{