diff --git a/README.md b/README.md index 25c9163e00dbbd1e70719ddf10d25c821b53bd32..901ccd1ecc366f30c59fff78af116c82650ef840 100644 --- a/README.md +++ b/README.md @@ -33,14 +33,18 @@ Each library has its own package (`adql` for ADQL, `uws` for UWS and `tap` for T ### Dependencies Below are summed up the dependencies of each library: -* ADQL: `adql`, `cds.utils` -* UWS: `uws`, `org.json` -* TAP: `adql`, `uws`, `cds.*`, `org.json` +* ADQL: `adql`, `cds.utils`, `org.postgresql` *(for adql.translator.PgSphereTranslator only)* +* UWS: `uws`, `org.json`, HTTP Multipart lib. (`com.oreilly.servlet`) +* TAP: `adql`, `uws`, `cds.*`, `org.json`, `org.postgresql` *(for adql.translator.PgSphereTranslator only)*, HTTP Multipart lib. (`com.oreilly.servlet`), STIL (`nom.tap`, `org.apache.tools.bzip2`, `uk.ac.starlink`) + +In the `lib` directory, you will find 2 JAR files: +* `cos-1.5beta.jar` to deal with HTTP multipart requests +* `stil3.0-5.jar` for [STIL](http://www.star.bris.ac.uk/~mbt/stil/) (VOTable and other formats support) ### ANT scripts At the root of the repository, there are 3 ANT scripts. Each is dedicated to one library. They are able to generate JAR for sources, binaries and Javadoc. 3 properties must be set before using one of these scripts: -* `CATALINA`: a path toward a JAR or a binary directory containing org.apache.catalina.connector.ClientAbortException.class +* `POSTGRES`: a path toward a JAR or a binary directory containing all org.postgresql.* - [https://jdbc.postgresql.org/download.html](JDBC Postgres driver) - **(ONLY for ADQL and TAP if you want to keep adql.translator.PgSphereTranslator)** * `SERVLET-API`: a path toward a JAR or a binary directory containing all javax.servlet.* -* (`JUNIT-API` *not required before the version 2.0 of the tap library*: a path toward one or several JARs or binary directories containing all classes to use JUnit.) +* (`JUNIT-API` *not required before the version 2.0 of the tap library OR if you are not interested by the `test` directory (JUnit tests)*: a path toward one or several JARs or binary directories containing all classes to use JUnit.) diff --git a/buildADQL.xml b/buildADQL.xml index 111a44894366b91c42bbd57aad9c4b1ce4d4cdf0..d2ae0630c216a88be631b1701a69bd8ad061feef 100644 --- a/buildADQL.xml +++ b/buildADQL.xml @@ -11,7 +11,7 @@ <property name="adqlPath" value="adql/**" /> <property name="utilsPath" value="cds/utils/**" /> - <property name="licensePath" value="COPYING.LESSER.txt" /> + <property name="licensePath" value="COPYING.LESSER" /> <property name="includesList" value="${adqlPath},${utilsPath},${licensePath}" /> <property name="jarDest" value="." /> @@ -22,6 +22,14 @@ <property name="adqlParserLink" value="adqlParser.jar" /> + <fail message="The property POSTGRES must be set! It provides the path toward a directory or a JAR which contains all classes inside org.postgresql."> + <condition><not><isset property="POSTGRES"/></not></condition> + </fail> + + <path id="adql.classpath"> + <pathelement location="${POSTGRES}" /> + </path> + <echo>ADQL LIBRARY VERSION = ${version}</echo> <!-- BUILD ALL TASK --> @@ -43,7 +51,9 @@ <target name="compileLib" depends="clean" description="Build all the classes of the ADQL library. This target is particularly usefull because it lets highlighting missing dependencies."> <mkdir dir="${compileDir}" /> - <javac destdir="${compileDir}" srcdir="${srcDir}" includes="${includesList}" includeantruntime="false" /> + <javac destdir="${compileDir}" srcdir="${srcDir}" includes="${includesList}" includeantruntime="false"> + <classpath refid="adql.classpath" /> + </javac> </target> <target name="buildLib" depends="compileLib" description="After 'clean', build the library JAR (only classes) and the runnable ADQL parser."> @@ -63,7 +73,9 @@ </target> <target name="buildLibAndSrc" depends="buildLib" description="After 'clean' and 'buildLib', build the sources JAR (only .java)."> - <jar compress="false" baseDir="${srcDir}" destfile="${srcJarFile}" includes="${includesList}" /> + <jar compress="false" destfile="${srcJarFile}"> + <zipfileset dir="${srcDir}" includes="${includesList},${licensePath}" prefix="${srcDir}" /> + </jar> </target> <!-- JAVADOC --> diff --git a/buildTAP.xml b/buildTAP.xml index 68f2727f35e165fdc29db7bc55becb686524272a..795b0c2ae7c307c8d0d19ecc803e3abd42e815eb 100644 --- a/buildTAP.xml +++ b/buildTAP.xml @@ -2,31 +2,34 @@ <!DOCTYPE project> <project name="tap" basedir="." default="buildLib"> - <property name="version" value="1.1b" /> + <property name="version" value="2.0beta" /> <property name="srcDir" value="src" /> <property name="libDir" value="lib" /> <property name="compileDir" value="antBuild" /> <property name="classesDir" value="${compileDir}"/> <property name="javadocDir" value="javadoc/tap" /> - - <property name="cosJar" value="${libDir}/cos-1.5beta.jar" /> - <property name="stilJar" value="${libDir}/stil3.0-5.jar" /> + + <property name="cosJarName" value="cos-1.5beta.jar" /> + <property name="cosJar" value="${libDir}/${cosJarName}" /> + <property name="stilJarName" value="stil3.0-5.jar" /> + <property name="stilJar" value="${libDir}/${stilJarName}" /> <property name="tapPath" value="tap/**,adql/**,uws/**,cds/**" /> <property name="jsonPath" value="org/json/**" /> <property name="extLibsPath" value="com/oreilly/servlet/**,nom/tam/**,org/apache/tools/bzip2/**,uk/ac/starlink/**" /> - <property name="licensePath" value="COPYING.LESSER.txt" /> - <property name="includesList" value="${tapPath},${jsonPath},${extLibsPath},${licensePath}" /> + <property name="licensePath" value="COPYING.LESSER" /> + <property name="includesList" value="${tapPath},${jsonPath},${extLibsPath}" /> <property name="jarDest" value="." /> <property name="libJarFile" value="${jarDest}/tap_${version}.jar" /> <property name="srcJarFile" value="${jarDest}/tap_src_${version}.jar" /> <property name="javadocJarFile" value="${jarDest}/tap_javadoc_${version}.jar" /> - <fail message="Missing property: CATALINA ! It provides the path toward a directory or a JAR which contains the following class: org.apache.catalina.connector.ClientAbortException."> - <condition><not><isset property="CATALINA"/></not></condition> + <fail message="The property POSTGRES must be set! It provides the path toward a directory or a JAR which contains all classes inside org.postgresql."> + <condition><not><isset property="POSTGRES"/></not></condition> </fail> + <fail message="The property SERVLET-API must be set! It provides the path toward a directory or a JAR which contains all classes inside javax.servlet."> <condition><not><isset property="SERVLET-API"/></not></condition> </fail> @@ -34,7 +37,7 @@ <path id="tap.classpath"> <pathelement location="${cosJar}" /> <pathelement location="${stilJar}" /> - <pathelement location="${CATALINA}" /> + <pathelement location="${POSTGRES}" /> <pathelement location="${SERVLET-API}" /> </path> @@ -67,14 +70,16 @@ <jar basedir="${classesDir}" destfile="${libJarFile}" includes="${includesList}"> <zipfileset src="${cosJar}" excludes="META-INF/*" /> <zipfileset src="${stilJar}" excludes="META-INF/*" /> + <zipfileset dir="src" includes="${licensePath}" /> </jar> <delete dir="${compileDir}" failonerror="true" /> </target> <target name="buildLibAndSrc" depends="buildLib" description="After 'clean' and 'buildLib', build the sources JAR (only .java)."> - <jar compress="false" baseDir="${srcDir}" destfile="${srcJarFile}" includes="${includesList}"> - <fileset file="${cosJar}" /> - <fileset file="${stilJar}" /> + <jar compress="false" destfile="${srcJarFile}"> + <zipfileset dir="${srcDir}" includes="${includesList},${licensePath}" prefix="${srcDir}" /> + <zipfileset dir="${libDir}" includes="${cosJarName}" fullPath="${cosJar}" /> + <zipfileset dir="${libDir}" includes="${stilJarName}" fullPath="${stilJar}" /> </jar> </target> diff --git a/buildUWS.xml b/buildUWS.xml index 88a8dedd0e71e6edb10a2e9efe22efb3678c09f2..a4e0b350527de07924390ecb812dfe6ceef6752a 100644 --- a/buildUWS.xml +++ b/buildUWS.xml @@ -2,32 +2,34 @@ <!DOCTYPE project> <project name="uws" basedir="." default="buildLib"> - <property name="version" value="4.1b" /> + <property name="version" value="4.1" /> <property name="srcDir" value="src" /> + <property name="libDir" value="lib" /> <property name="compileDir" value="antBuild" /> <property name="classesDir" value="${compileDir}"/> <property name="javadocDir" value="javadoc/uws" /> + + <property name="cosJarName" value="cos-1.5beta.jar" /> + <property name="cosJar" value="${libDir}/${cosJarName}" /> <property name="uwsPath" value="uws/**" /> <property name="jsonPath" value="org/json/**" /> - <property name="licensePath" value="COPYING.LESSER.txt" /> - <property name="includesList" value="${uwsPath},${jsonPath},${licensePath}" /> + <property name="licensePath" value="COPYING.LESSER" /> + <property name="extLibsPath" value="com/oreilly/servlet/**" /> + <property name="includesList" value="${uwsPath},${jsonPath},${extLibsPath}" /> <property name="jarDest" value="." /> <property name="libJarFile" value="${jarDest}/uws_${version}.jar" /> <property name="srcJarFile" value="${jarDest}/uws_src_${version}.jar" /> <property name="javadocJarFile" value="${jarDest}/uws_javadoc_${version}.jar" /> - <fail message="Missing property: CATALINA ! It provides the path toward a directory or a JAR which contains the following class: org.apache.catalina.connector.ClientAbortException."> - <condition><not><isset property="CATALINA"/></not></condition> - </fail> <fail message="The property SERVLET-API must be set! It provides the path toward a directory or a JAR which contains all classes inside javax.servlet."> <condition><not><isset property="SERVLET-API"/></not></condition> </fail> <path id="uws.classpath"> - <pathelement location="${CATALINA}" /> + <pathelement location="${cosJar}" /> <pathelement location="${SERVLET-API}" /> </path> @@ -57,12 +59,18 @@ <target name="buildLib" depends="compileLib" description="After 'clean', build the library JAR (only classes)."> <echo>Generate the library:</echo> - <jar basedir="${classesDir}" destfile="${libJarFile}" includes="${includesList}" /> + <jar basedir="${classesDir}" destfile="${libJarFile}" includes="${includesList}"> + <zipfileset src="${cosJar}" excludes="META-INF/*" /> + <zipfileset dir="src" includes="${licensePath}" /> + </jar> <delete dir="${compileDir}" failonerror="true" /> </target> <target name="buildLibAndSrc" depends="buildLib" description="After 'clean' and 'buildLib', build the sources JAR (only .java)."> - <jar compress="false" baseDir="${srcDir}" destfile="${srcJarFile}" includes="${includesList}" /> + <jar compress="false" destfile="${srcJarFile}"> + <zipfileset dir="${srcDir}" includes="${includesList},${licensePath}" prefix="${srcDir}" /> + <zipfileset dir="${libDir}" includes="${cosJarName}" fullPath="${cosJar}" /> + </jar> </target> <!-- JAVADOC --> diff --git a/src/tap/resource/TAP.java b/src/tap/resource/TAP.java index 65ec8b0d06c3e52f8a3dc11f5cffc704e5affcbe..eaefb96553338e5853f50adef7258ed450abe94d 100644 --- a/src/tap/resource/TAP.java +++ b/src/tap/resource/TAP.java @@ -45,6 +45,7 @@ import tap.log.TAPLog; import tap.metadata.TAPMetadata; import uk.ac.starlink.votable.VOSerializer; import uws.UWSException; +import uws.job.ErrorType; import uws.job.user.JobOwner; import uws.service.UWS; import uws.service.UWSService; @@ -59,7 +60,7 @@ import adql.db.FunctionDef; * <p>At its creation it is creating and configuring the other resources in function of the given description of the TAP service.</p> * * @author Grégory Mantelet (CDS;ARI) - * @version 2.0 (12/2014) + * @version 2.0 (01/2015) */ public class TAP implements VOSIResource { @@ -727,10 +728,20 @@ public class TAP implements VOSIResource { getLogger().logHttp(LogLevel.INFO, response, reqID, owner, "HTTP " + UWSException.OK + " - Action \"" + resourceName + "\" successfully executed.", null); }catch(Throwable t){ - // Write the error in the response and return the appropriate HTTP status code: - errorWriter.writeError(t, response, request, reqID, owner, resourceName); - // Log the error: - getLogger().logHttp(LogLevel.ERROR, response, reqID, owner, "HTTP " + response.getStatus() + " - Can not complete the execution of the TAP resource \"" + resourceName + "\"!", t); + // CLIENT ABORTION: (note: should work with Apache/Tomcat and JBoss) + if (t.getClass().getName().endsWith("ClientAbortException")){ + // Log the client abortion: + getLogger().logHttp(LogLevel.INFO, response, reqID, owner, "HTTP " + response.getStatus() + " - HTTP request aborted by the client => the TAP resource \"" + resourceName + "\" has stopped!", t); + // Notify the client abortion in a TAP error: + errorWriter.writeError("The client aborts this HTTP request! It may happen due to a client timeout or to an interruption of the response waiting process.", ErrorType.TRANSIENT, UWSException.ACCEPTED_BUT_NOT_COMPLETE, response, request, reqID, owner, resourceName); + } + // ANY OTHER ERROR: + else{ + // Log the error: + getLogger().logHttp(LogLevel.ERROR, response, reqID, owner, "HTTP " + response.getStatus() + " - Can not complete the execution of the TAP resource \"" + resourceName + "\"!", t); + // Write the error in the response and return the appropriate HTTP status code: + errorWriter.writeError(t, response, request, reqID, owner, resourceName); + } }finally{ // Notify the queue of the asynchronous jobs that a new connection is available: if (resourceName.equalsIgnoreCase(Sync.RESOURCE_NAME) && service.getFactory().countFreeConnections() >= 1) diff --git a/src/uws/service/UWSService.java b/src/uws/service/UWSService.java index 9867ef694fc5ae1ec80ffcb7eb8ed9ecfcd09c1f..4b935751f5b7a63e4b121b7c57b8cb672891fa6e 100644 --- a/src/uws/service/UWSService.java +++ b/src/uws/service/UWSService.java @@ -35,6 +35,7 @@ import javax.servlet.http.HttpServletResponse; import uws.AcceptHeader; import uws.UWSException; import uws.UWSToolBox; +import uws.job.ErrorType; import uws.job.ExecutionPhase; import uws.job.JobList; import uws.job.JobThread; @@ -185,7 +186,7 @@ import uws.service.request.RequestParser; * * * @author Grégory Mantelet (CDS;ARI) - * @version 4.1 (12/2014) + * @version 4.1 (01/2015) */ public class UWSService implements UWS { @@ -1152,7 +1153,13 @@ public class UWSService implements UWS { actionApplied = true; sendError(ex, request, reqID, user, ((action != null) ? action.getName() : null), response); }catch(Exception ex){ - sendError(ex, request, reqID, user, ((action != null) ? action.getName() : null), response); + if (ex.getClass().getName().endsWith("ClientAbortException")){ + // Log the client abortion: + logger.logHttp(LogLevel.INFO, request, reqID, "HTTP " + UWSException.ACCEPTED_BUT_NOT_COMPLETE + " - Action \"" + action.getName() + "\" aborted by the client! [Client abort => " + ex.getClass().getName() + "]", ex); + // Notify the client abortion in a TAP error: + errorWriter.writeError("The client aborts this HTTP request! It may happen due to a client timeout or to an interruption of the response waiting process.", ErrorType.TRANSIENT, UWSException.ACCEPTED_BUT_NOT_COMPLETE, response, request, reqID, user, action.getName()); + }else + sendError(ex, request, reqID, user, ((action != null) ? action.getName() : null), response); }finally{ executedAction = action; // Free resources about uploaded files ; only unused files will be deleted: diff --git a/src/uws/service/UWSServlet.java b/src/uws/service/UWSServlet.java index e755f4e2633db2ba1482fce40e57caefa350f246..b85ebc5aae92079df293e47ebb7b3ded071b97d0 100644 --- a/src/uws/service/UWSServlet.java +++ b/src/uws/service/UWSServlet.java @@ -39,13 +39,12 @@ import javax.servlet.http.HttpServlet; import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse; -import org.apache.catalina.connector.ClientAbortException; - import uws.AcceptHeader; import uws.UWSException; import uws.UWSExceptionFactory; import uws.UWSToolBox; import uws.job.ErrorSummary; +import uws.job.ErrorType; import uws.job.JobList; import uws.job.JobThread; import uws.job.Result; @@ -133,7 +132,7 @@ import uws.service.request.UploadFile; * </p> * * @author Grégory Mantelet (CDS;ARI) - * @version 4.1 (12/2014) + * @version 4.1 (01/2015) */ public abstract class UWSServlet extends HttpServlet implements UWS, UWSFactory { private static final long serialVersionUID = 1L; @@ -437,10 +436,14 @@ public abstract class UWSServlet extends HttpServlet implements UWS, UWSFactory }catch(UWSException ue){ sendError(ue, req, reqID, user, uwsAction, resp); - }catch(ClientAbortException cae){ - logger.logHttp(LogLevel.INFO, req, reqID, "HTTP " + UWSException.OK + " - Action \"" + uwsAction + "\" aborted by the client! [Client abort => ClientAbortException]", cae); }catch(Throwable t){ - sendError(t, req, reqID, user, uwsAction, resp); + if (t.getClass().getName().endsWith("ClientAbortException")){ + // Log the client abortion: + logger.logHttp(LogLevel.INFO, req, reqID, "HTTP " + UWSException.ACCEPTED_BUT_NOT_COMPLETE + " - Action \"" + uwsAction + "\" aborted by the client! [Client abort => " + t.getClass().getName() + "]", t); + // Notify the client abortion in a TAP error: + errorWriter.writeError("The client aborts this HTTP request! It may happen due to a client timeout or to an interruption of the response waiting process.", ErrorType.TRANSIENT, UWSException.ACCEPTED_BUT_NOT_COMPLETE, resp, req, reqID, user, uwsAction); + }else + sendError(t, req, reqID, user, uwsAction, resp); }finally{ // Free resources about uploaded files ; only unused files will be deleted: UWSToolBox.deleteUploads(req);