diff --git a/src/uws/UWSToolBox.java b/src/uws/UWSToolBox.java index bb3df0ddda49348c067cc69870396aab212820e4..db370e88364a107f2845d2ce27482061b464311f 100644 --- a/src/uws/UWSToolBox.java +++ b/src/uws/UWSToolBox.java @@ -2,21 +2,21 @@ package uws; /* * 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-2017 - UDS/Centre de DonnĂ©es astronomiques de Strasbourg (CDS), + * + * Copyright 2012-2019 - UDS/Centre de DonnĂ©es astronomiques de Strasbourg (CDS), * Astronomisches Rechen Institut (ARI) */ @@ -53,9 +53,9 @@ import uws.service.request.UploadFile; /** * Some useful functions for the managing of a UWS service. - * + * * @author Grégory Mantelet (CDS;ARI) - * @version 4.2 (09/2017) + * @version 4.3 (01/2019) */ public class UWSToolBox { @@ -78,13 +78,13 @@ public class UWSToolBox { * <li><i>if you want the URL of the html page "basic.html" of the root directory:</i> servletPath=<b>"/basic.html"</b> => returned URL=<b>http://foo.org/uwstuto/basic.html</b></li> * <li><i>if you want the URL of the image "ivoa.png" contained into the directory "images":</i> servletPath=<b>"/images/ivoa.png"</b> => returned URL=<b>"http://foo.org/uwstuto/images/ivoa.png"</b></li> * </ul> - * + * * @param serverPath The relative path to access a server resource. * @param req A request of the servlet. - * + * * @return The absolute URL to access the desired server resource * or <i>null</i> if one of the parameter is <i>null</i> or if a well-formed URL can not be built. - * + * * @see HttpServletRequest#getRequestURL() * @see HttpServletRequest#getContextPath() * @see URL#URL(String) @@ -106,7 +106,7 @@ public class UWSToolBox { /** * Gets the default {@link UWSLog} instance. * Any log message will be print on the standard error output ({@link System#err}). - * + * * @return The default {@link UWSLog} instance. */ public static final UWSLog getDefaultLogger(){ @@ -120,35 +120,35 @@ public class UWSToolBox { /* ****************** */ /** * <p>Builds a map of strings with all parameters of the given HTTP request.</p> - * + * * <p><i>Note: * If the request attribute {@link UWS#REQ_ATTRIBUTE_PARAMETERS} has been already set by the UWS library, * this map (after conversion into a Map<String,String>) is returned. * Otherwise, the parameters identified automatically by the Servlet are returned (just the last occurrence of each parameter is kept). * </i></p> - * + * * <p><i><b>WARNING:</b> * This function does not extract directly the parameters from the request content. It is just returning those already extracted * either by the Servlet or by a {@link RequestParser}. * </i></p> - * + * * @param req The HTTP request which contains the parameters to extract. - * + * * @return The corresponding map of string. */ @SuppressWarnings("unchecked") - public static final Map<String,String> getParamsMap(final HttpServletRequest req){ - HashMap<String,String> map = new HashMap<String,String>(); + public static final Map<String, String> getParamsMap(final HttpServletRequest req){ + HashMap<String, String> map = new HashMap<String, String>(); /* If the attribute "PARAMETERS" has been already set by the UWS library, * return it by casting it from Map<String,Object> into Map<String,String>: */ if (req.getAttribute(UWS.REQ_ATTRIBUTE_PARAMETERS) != null){ try{ // Get the extracted parameters: - Map<String,Object> params = (Map<String,Object>)req.getAttribute(UWS.REQ_ATTRIBUTE_PARAMETERS); + Map<String, Object> params = (Map<String, Object>)req.getAttribute(UWS.REQ_ATTRIBUTE_PARAMETERS); // Transform the map of Objects into a map of Strings: - for(Map.Entry<String,Object> e : params.entrySet()){ + for(Map.Entry<String, Object> e : params.entrySet()){ if (e.getValue() != null){ if (e.getValue().getClass().isArray()){ StringBuffer str = new StringBuffer(); @@ -195,17 +195,17 @@ public class UWSToolBox { /** * Converts map of UWS parameters into a string corresponding to the query part of a HTTP-GET URL (i.e. ?EXECUTIONDURATION=60&DESTRUCTION=2010-09-01T13:58:00:000-0200). - * + * * @param parameters A Map of parameters. - * + * * @return The corresponding query part of an HTTP-GET URL (all keys have been set in upper case). */ - public final static String getQueryPart(final Map<String,String> parameters){ + public final static String getQueryPart(final Map<String, String> parameters){ if (parameters == null || parameters.isEmpty()) return ""; StringBuffer queryPart = new StringBuffer(); - for(Map.Entry<String,String> e : parameters.entrySet()){ + for(Map.Entry<String, String> e : parameters.entrySet()){ String key = e.getKey(); String val = e.getValue(); @@ -218,7 +218,8 @@ public class UWSToolBox { try{ queryPart.append(URLEncoder.encode(e.getKey(), "UTF-8") + "=" + URLEncoder.encode(val, "UTF-8")); queryPart.append("&"); - }catch(UnsupportedEncodingException uee){} + }catch(UnsupportedEncodingException uee){ + } } } @@ -227,13 +228,13 @@ public class UWSToolBox { /** * Converts the given query part of a HTTP-GET URL to a map of parameters. - * + * * @param queryPart A query part of a HTTP-GET URL. - * + * * @return The corresponding map of parameters (all keys have been set in lower case). */ - public final static Map<String,String> getParameters(String queryPart){ - HashMap<String,String> parameters = new HashMap<String,String>(); + public final static Map<String, String> getParameters(String queryPart){ + HashMap<String, String> parameters = new HashMap<String, String>(); if (queryPart != null){ queryPart = queryPart.substring(queryPart.indexOf("?") + 1).trim(); @@ -247,7 +248,8 @@ public class UWSToolBox { if (!keyValue[0].isEmpty() && !keyValue[1].isEmpty()){ try{ parameters.put(URLDecoder.decode(keyValue[0], "UTF-8"), URLDecoder.decode(keyValue[1], "UTF-8")); - }catch(UnsupportedEncodingException uee){} + }catch(UnsupportedEncodingException uee){ + } } } } @@ -259,19 +261,19 @@ public class UWSToolBox { /** * <p>Extract only the GET parameters from the given HTTP request and add them inside the given map.</p> - * + * * <p><b>Warning</b>: * If entries with the same key already exist in the map, they will overwritten. * </p> - * + * * @param req The HTTP request whose the GET parameters must be extracted. * @param parameters List of parameters to update. - * + * * @return The same given parameters map (but updated with all found GET parameters). - * + * * @since 4.1 */ - public static final Map<String,Object> addGETParameters(final HttpServletRequest req, final Map<String,Object> parameters){ + public static final Map<String, Object> addGETParameters(final HttpServletRequest req, final Map<String, Object> parameters){ String queryString = req.getQueryString(); if (queryString != null){ String[] params = queryString.split("&"); @@ -281,7 +283,8 @@ public class UWSToolBox { if (indSep >= 0){ try{ parameters.put(URLDecoder.decode(p.substring(0, indSep), "UTF-8"), URLDecoder.decode(p.substring(indSep + 1), "UTF-8")); - }catch(UnsupportedEncodingException uee){} + }catch(UnsupportedEncodingException uee){ + } } } } @@ -290,11 +293,11 @@ public class UWSToolBox { /** * Get the number of parameters submitted in the given HTTP request. - * + * * @param request An HTTP request; - * + * * @return The number of submitted parameters. - * + * * @since 4.1 */ @SuppressWarnings("unchecked") @@ -302,7 +305,7 @@ public class UWSToolBox { if (request == null) return 0; try{ - return ((Map<String,Object>)request.getAttribute(UWS.REQ_ATTRIBUTE_PARAMETERS)).size(); + return ((Map<String, Object>)request.getAttribute(UWS.REQ_ATTRIBUTE_PARAMETERS)).size(); }catch(Exception ex){ return request.getParameterMap().size(); } @@ -310,14 +313,14 @@ public class UWSToolBox { /** * Check whether a parameter has been submitted with the given name. - * + * * @param name Name of the parameter to search. <b>The case is important!</b> * @param request HTTP request in which the specified parameter must be searched. * @param caseSensitive <i>true</i> to perform the research case-sensitively, * <i>false</i> for a case INsensitive research. - * + * * @return <i>true</i> if the specified parameter has been found, <i>false</i> otherwise. - * + * * @since 4.1 */ public static final boolean hasParameter(final String name, final HttpServletRequest request, final boolean caseSensitive){ @@ -326,16 +329,16 @@ public class UWSToolBox { /** * Check whether the parameter specified with the given pair (name,value) exists in the given HTTP request. - * + * * @param name Name of the parameter to search. * @param value Expected value of the parameter. * @param request HTTP request in which the given pair must be searched. * @param caseSensitive <i>true</i> to perform the research (on name AND value) case-sensitively, * <i>false</i> for a case INsensitive research. - * + * * @return <i>true</i> if the specified parameter has been found with the given value in the given HTTP request, * <i>false</i> otherwise. - * + * * @since 4.1 */ public static final boolean hasParameter(final String name, final String value, final HttpServletRequest request, final boolean caseSensitive){ @@ -352,45 +355,46 @@ public class UWSToolBox { /** * Get the parameter specified by the given name from the given HTTP request. - * + * * @param name Name of the parameter to search. * @param request HTTP request in which the given pair must be searched. * @param caseSensitive <i>true</i> to perform the research case-sensitively, * <i>false</i> for a case INsensitive research. - * + * * @return Value of the parameter. - * + * * @since 4.1 */ @SuppressWarnings("unchecked") public static final Object getParameter(final String name, final HttpServletRequest request, final boolean caseSensitive){ try{ // Get the extracted parameters: - Map<String,Object> params = (Map<String,Object>)request.getAttribute(UWS.REQ_ATTRIBUTE_PARAMETERS); + Map<String, Object> params = (Map<String, Object>)request.getAttribute(UWS.REQ_ATTRIBUTE_PARAMETERS); // Search case IN-sensitively the given pair (name, value): - for(Map.Entry<String,Object> e : params.entrySet()){ + for(Map.Entry<String, Object> e : params.entrySet()){ if ((!caseSensitive && e.getKey().equalsIgnoreCase(name)) || (caseSensitive && e.getKey().equals(name))) return (e.getValue() != null) ? e.getValue() : null; } - }catch(Exception ex){} + }catch(Exception ex){ + } return null; } /** * <p>Delete all unused uploaded files of the given request.</p> - * + * * <p> * These files have been stored on the file system * if there is a request attribute named {@link UWS#REQ_ATTRIBUTE_PARAMETERS}. * </p> - * + * * @param req Request in which files have been uploaded. - * + * * @return The number of deleted files. - * + * * @see UploadFile#isUsed() - * + * * @since 4.1 */ @SuppressWarnings("unchecked") @@ -399,15 +403,16 @@ public class UWSToolBox { Object attribute = req.getAttribute(UWS.REQ_ATTRIBUTE_PARAMETERS); // If there is the request attribute "UWS_PARAMETERS": if (attribute != null && attribute instanceof Map){ - Map<String,Object> params = (Map<String,Object>)attribute; + Map<String, Object> params = (Map<String, Object>)attribute; // For each parameter... - for(Map.Entry<String,Object> e : params.entrySet()){ + for(Map.Entry<String, Object> e : params.entrySet()){ // ...delete physically the uploaded file ONLY IF not used AND IF it is an uploaded file: if (e.getValue() != null && e.getValue() instanceof UploadFile && !((UploadFile)e.getValue()).isUsed()){ try{ ((UploadFile)e.getValue()).deleteFile(); cnt++; - }catch(IOException ioe){} + }catch(IOException ioe){ + } } } } @@ -419,23 +424,23 @@ public class UWSToolBox { /* *************** */ /** * <p>Extract the user/job owner from the given HTTP request.</p> - * + * * Two cases are supported: * <ol> * <li><b>The user has already been identified and is stored in the HTTP attribute {@link UWS#REQ_ATTRIBUTE_USER}</b> => the stored value is returned.</li> * <li><b>No HTTP attribute and a {@link UserIdentifier} is provided</b> => the user is identified with the given {@link UserIdentifier} and stored in the HTTP attribute {@link UWS#REQ_ATTRIBUTE_USER} before being returned.</li> * </ol> - * + * * <p>In any other case, NULL is returned.</p> - * + * * @param request The HTTP request from which the user must be extracted. <i>note: if NULL, NULL will be returned.</i> * @param userIdentifier The method to use in order to extract a user from the given request. <i>note: if NULL, NULL is returned IF no HTTP attribute {@link UWS#REQ_ATTRIBUTE_USER} can be found.</i> - * + * * @return The identified user. <i>MAY be NULL</i> - * + * * @throws NullPointerException If an error occurs while extracting a {@link UWSUrl} from the given {@link HttpServletRequest}. * @throws UWSException If any error occurs while extracting a user from the given {@link HttpServletRequest}. - * + * * @since 4.1 */ public static final JobOwner getUser(final HttpServletRequest request, final UserIdentifier userIdentifier) throws NullPointerException, UWSException{ @@ -456,7 +461,7 @@ public class UWSToolBox { /* **************************** */ /** * Empties the specified directory. - * + * * @param directoryPath The path of the directory to empty. */ public static final void clearDirectory(String directoryPath){ @@ -465,9 +470,9 @@ public class UWSToolBox { /** * <p>Empties the specified directory.</p> - * + * * <p><i><u>Note:</u> The directory is NOT deleted. Just its content is destroyed.</i></p> - * + * * @param directory The directory which has to be emptied. */ public static final void clearDirectory(File directory){ @@ -484,19 +489,19 @@ public class UWSToolBox { /** * <p>Flush the buffer of the given {@link PrintWriter}.</p> - * + * * <p> * This function aims to be used if the given {@link PrintWriter} has been provided by an {@link HttpServletResponse}. * In such case, a call to its flush() function may generate a silent error which could only mean that * the connection with the HTTP client has been closed. * </p> - * + * * @param writer The writer to flush. - * + * * @throws ClientAbortException If the connection with the HTTP client is closed. - * + * * @see PrintWriter#flush() - * + * * @since 4.1 */ public static final void flush(final PrintWriter writer) throws ClientAbortException{ @@ -507,12 +512,12 @@ public class UWSToolBox { /** * Copies the content of the given input stream in the given HTTP response. - * + * * @param input Data to copy. * @param mimeType Type of data to copy (may be null). * @param contentSize Size of the file to write. * @param response Response in which the data must be copied. - * + * * @throws IOException If there is an error while opening the output stream or while copying. */ public static final void write(final InputStream input, final String mimeType, final long contentSize, final HttpServletResponse response) throws IOException{ @@ -545,14 +550,14 @@ public class UWSToolBox { * Writes the stack trace of the given exception in the file whose the name and the parent directory are given in parameters. * If the specified file already exists, it will be overwritten if the parameter <i>overwrite</i> is equal to <i>true</i>, otherwise * no file will not be changed <i>(default behavior of {@link UWSToolBox#writeErrorFile(Exception, ErrorSummary, UWSJob, OutputStream)})</i>. - * + * * @param ex The exception which has to be used to generate the error file. * @param error The error description. * @param job The job which ended with the given error. * @param output The stream in which the error description and trace must be written. - * + * * @return <i>true</i> if the file has been successfully created, <i>false</i> otherwise. - * + * * @throws IOException If there is an error while writing the description and the stack trace of the given error. */ public static final boolean writeErrorFile(final Exception ex, final ErrorSummary error, final UWSJob job, final OutputStream output) throws IOException{ @@ -573,10 +578,10 @@ public class UWSToolBox { /** * Prints the full stack trace of the given exception in the given writer. - * + * * @param ex The exception whose the stack trace must be printed. * @param pw The stream in which the stack trace must be written. - * + * * @throws IOException If there is an error while printing the stack trace. */ public static final void printStackTrace(final Throwable ex, final PrintWriter pw) throws IOException{ @@ -600,9 +605,9 @@ public class UWSToolBox { /* *********************** */ /** * Displays all the fields of the given UWSUrl. - * + * * @param url The UWSUrl which has to be displayed. - * + * * @see #printURL(UWSUrl, java.io.OutputStream) */ public static final void printURL(UWSUrl url){ @@ -615,10 +620,10 @@ public class UWSToolBox { /** * Displays all the fields of the given UWSUrl in the given output stream. - * + * * @param url The UWSUrl which has to be displayed. * @param output The stream in which the fields of the given UWSUrl has to be displayed. - * + * * @throws IOException If there is an error while writing in the given stream. */ public static final void printURL(UWSUrl url, java.io.OutputStream output) throws IOException{ @@ -643,16 +648,16 @@ public class UWSToolBox { /* MIME TYPE */ /* ********* */ /** List of file extensions whose the MIME type is known (see {@link #mimeTypes}). */ - protected static final String[] fileExts = new String[]{"","vot","json","json","csv","tsv","txt","xml","xml","pdf","ai","eps","ps","html","zip","gzip","gz","tar","gif","jpeg","jpg","png","bmp"}; + protected static final String[] fileExts = new String[]{ "", "vot", "json", "json", "csv", "tsv", "txt", "xml", "xml", "pdf", "ai", "eps", "ps", "html", "zip", "gzip", "gz", "tar", "gif", "jpeg", "jpg", "png", "bmp" }; /** List of known MIME types (see {@link #fileExts}). */ - protected static final String[] mimeTypes = new String[]{"application/octet-stream","application/x-votable+xml","application/json","text/json","text/csv","text/tab-separated-values","text/plain","application/xml","text/xml","application/pdf","application/postscript","application/postscript","application/postscript","text/html","application/zip","application/x-gzip","application/x-tar","image/gif","image/jpeg","image/jpeg","image/png","image/x-portable-bitmap"}; + protected static final String[] mimeTypes = new String[]{ "application/octet-stream", "application/x-votable+xml", "application/json", "text/json", "text/csv", "text/tab-separated-values", "text/plain", "application/xml", "text/xml", "application/pdf", "application/postscript", "application/postscript", "application/postscript", "text/html", "application/zip", "application/x-gzip", "application/x-gzip", "application/x-tar", "image/gif", "image/jpeg", "image/jpeg", "image/png", "image/x-portable-bitmap" }; /** * Gets the MIME type corresponding to the given file extension. - * + * * @param fileExtension File extension (i.e. .txt, json, .xml, xml, ....) - * + * * @return The corresponding MIME type or <i>null</i> if not known. */ public static final String getMimeType(String fileExtension){ @@ -672,9 +677,9 @@ public class UWSToolBox { /** * Gets the file extension corresponding to the given MIME type. - * + * * @param mimeType A MIME type (i.e. text/plain, application/json, application/xml, text/xml, application/x-votable+xml, ....) - * + * * @return The corresponding file extension or <i>null</i> if not known. */ public static final String getFileExtension(String mimeType){ diff --git a/test/uws/TestUWSToolBox.java b/test/uws/TestUWSToolBox.java new file mode 100644 index 0000000000000000000000000000000000000000..26c37ac3eda0e9bc085bb235bfa22ef9f1fbb02c --- /dev/null +++ b/test/uws/TestUWSToolBox.java @@ -0,0 +1,95 @@ +package uws; + +import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertNull; + +import org.junit.Test; + +public class TestUWSToolBox { + + @Test + public void testGetMimeType(){ + // TEST: NULL => NULL + assertNull(UWSToolBox.getMimeType(null)); + + // TEST: empty string => binary + assertEquals("application/octet-stream", UWSToolBox.getMimeType("")); + assertEquals("application/octet-stream", UWSToolBox.getMimeType(" ")); + + /* + * Note: each test is also performed with the file name and file + * extension separator(.). + */ + + // TEST: unknown file extension => NULL + assertNull(UWSToolBox.getMimeType("foo")); + assertNull(UWSToolBox.getMimeType(".foo")); + + /* Ensure length of known MIME types and file extensions have the same + * number of items: */ + assertEquals(UWSToolBox.fileExts.length, UWSToolBox.mimeTypes.length); + + // Roughly check the MIME types and file extensions mapping: + String ext, mime; + /* ...1st item (i.e. binary) */ + ext = UWSToolBox.fileExts[0]; + mime = UWSToolBox.mimeTypes[0]; + assertEquals("", ext); + assertEquals("application/octet-stream", mime); + assertEquals(mime, UWSToolBox.getMimeType(ext)); + assertEquals(mime, UWSToolBox.getMimeType("." + ext)); + /* ...last item (i.e. bmp) */ + ext = UWSToolBox.fileExts[UWSToolBox.fileExts.length - 1]; + mime = UWSToolBox.mimeTypes[UWSToolBox.mimeTypes.length - 1]; + assertEquals("bmp", ext); + assertEquals("image/x-portable-bitmap", mime); + assertEquals(mime, UWSToolBox.getMimeType(ext)); + assertEquals(mime, UWSToolBox.getMimeType("." + ext)); + + // TEST: VOTable mapping => ok + assertEquals("application/x-votable+xml", UWSToolBox.getMimeType("vot")); + assertEquals("application/x-votable+xml", UWSToolBox.getMimeType(".vot")); + + // Ensure it is not not case sensitive: + assertEquals("application/x-votable+xml", UWSToolBox.getMimeType(".VOt")); + } + + @Test + public void testGetFileExtension(){ + // TEST: NULL => NULL + assertNull(UWSToolBox.getFileExtension(null)); + + // TEST: empty string => NULL + assertNull(UWSToolBox.getFileExtension("")); + assertNull(UWSToolBox.getFileExtension(" ")); + + // TEST: unknown MIME type => NULL + assertNull(UWSToolBox.getMimeType("foo")); + + /* Ensure length of known MIME types and file extensions have the same + * number of items: */ + assertEquals(UWSToolBox.mimeTypes.length, UWSToolBox.fileExts.length); + + // Roughly check the MIME types and file extensions mapping: + String ext, mime; + /* ...1st item (i.e. binary) */ + mime = UWSToolBox.mimeTypes[0]; + ext = UWSToolBox.fileExts[0]; + assertEquals("application/octet-stream", mime); + assertEquals("", ext); + assertEquals(ext, UWSToolBox.getFileExtension(mime)); + /* ...last item (i.e. bmp) */ + mime = UWSToolBox.mimeTypes[UWSToolBox.mimeTypes.length - 1]; + ext = UWSToolBox.fileExts[UWSToolBox.fileExts.length - 1]; + assertEquals("image/x-portable-bitmap", mime); + assertEquals("bmp", ext); + assertEquals(ext, UWSToolBox.getFileExtension(mime)); + + // TEST: VOTable mapping => ok + assertEquals("vot", UWSToolBox.getFileExtension("application/x-votable+xml")); + + // Ensure it is not not case sensitive: + assertEquals("vot", UWSToolBox.getFileExtension("application/x-VOTable+XML")); + } + +}