Newer
Older
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/>.
*
gmantele
committed
* Copyright 2012,2014 - UDS/Centre de Données astronomiques de Strasbourg (CDS),
* Astronomisches Rechen Institute (ARI)
*/
import java.io.BufferedInputStream;
import java.io.File;
import java.io.FileInputStream;
import java.io.IOException;
import java.io.PrintWriter;
import java.net.MalformedURLException;
import java.net.URL;
import java.text.DateFormat;
import java.text.SimpleDateFormat;
import java.util.Date;
import java.util.HashMap;
import java.util.Iterator;
import java.util.Map;
gmantele
committed
import javax.servlet.ServletConfig;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import tap.ServiceConnection;
import tap.ServiceConnection.LimitUnit;
gmantele
committed
import tap.TAPException;
import tap.db.DBConnection;
import tap.error.DefaultTAPErrorWriter;
import tap.formatter.OutputFormat;
import tap.log.TAPLog;
import tap.metadata.TAPMetadata;
import uws.UWSException;
import uws.job.ErrorType;
import uws.job.UWSJob;
import uws.job.user.JobOwner;
import uws.service.UWSService;
import uws.service.UWSUrl;
import uws.service.error.ServiceErrorWriter;
gmantele
committed
public class TAP< R > implements VOSIResource {
private static final long serialVersionUID = 1L;
protected final ServiceConnection<R> service;
gmantele
committed
protected final Map<String,TAPResource> resources;
protected String tapBaseURL = null;
protected String homePageURI = null;
protected ServiceErrorWriter errorWriter;
gmantele
committed
public TAP(ServiceConnection<R> serviceConnection) throws UWSException, TAPException{
service = serviceConnection;
gmantele
committed
resources = new HashMap<String,TAPResource>();
errorWriter = new DefaultTAPErrorWriter(service);
TAPResource res = new Availability(service);
resources.put(res.getName(), res);
res = new Capabilities(this);
resources.put(res.getName(), res);
res = new Sync(service, (Capabilities)res);
resources.put(res.getName(), res);
res = new ASync(service);
resources.put(res.getName(), res);
getUWS().setErrorWriter(errorWriter);
if (service.uploadEnabled()){
DBConnection<?> dbConn = null;
gmantele
committed
try{
dbConn = service.getFactory().createDBConnection("TAP(ServiceConnection)");
dbConn.dropSchema("TAP_UPLOAD");
dbConn.createSchema("TAP_UPLOAD");
gmantele
committed
}catch(TAPException e){
throw new UWSException(UWSException.INTERNAL_SERVER_ERROR, e, "Error while creating the schema TAP_UPLOAD !");
gmantele
committed
}finally{
if (dbConn != null)
dbConn.close();
}
}
updateTAPMetadata();
}
public final TAPLog getLogger(){
return service.getLogger();
}
public void setTAPBaseURL(String baseURL){
tapBaseURL = baseURL;
for(TAPResource res : resources.values())
res.setTAPBaseURL(tapBaseURL);
}
public void setTAPBaseURL(HttpServletRequest request){
gmantele
committed
setTAPBaseURL(request.getScheme() + "://" + request.getServerName() + ":" + request.getServerPort() + request.getContextPath() + request.getServletPath());
}
public final Availability getAvailability(){
gmantele
committed
return (Availability)resources.get(Availability.RESOURCE_NAME);
}
public final Capabilities getCapabilities(){
gmantele
committed
return (Capabilities)resources.get(Capabilities.RESOURCE_NAME);
}
public final Sync getSync(){
gmantele
committed
return (Sync)resources.get(Sync.RESOURCE_NAME);
}
public final ASync getASync(){
gmantele
committed
return (ASync)resources.get(ASync.RESOURCE_NAME);
}
public final TAPMetadata getTAPMetadata(){
gmantele
committed
return (TAPMetadata)resources.get(TAPMetadata.RESOURCE_NAME);
}
public final Iterator<TAPResource> getTAPResources(){
return resources.values().iterator();
}
gmantele
committed
public final ServiceErrorWriter getErrorWriter(){
return errorWriter;
}
gmantele
committed
public final void setErrorWriter(ServiceErrorWriter errorWriter){
if (errorWriter != null){
this.errorWriter = errorWriter;
getUWS().setErrorWriter(errorWriter);
}
}
@Override
gmantele
committed
public String getStandardID(){
return "ivo://ivoa.net/std/TAP";
}
gmantele
committed
public String getAccessURL(){
return tapBaseURL;
}
gmantele
committed
public String getCapability(){
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
StringBuffer xml = new StringBuffer();
xml.append("<capability standardID=\"").append(getStandardID()).append("\" xsi:type=\"tr:TableAccess\">\n");
xml.append("\t<interface role=\"std\" xsi:type=\"vs:ParamHTTP\">\n");
xml.append("\t\t<accessURL use=\"base\">").append(getAccessURL()).append("</accessURL>\n");
xml.append("\t</interface>\n");
xml.append("\t<language>\n");
xml.append("\t\t<name>ADQL</name>\n");
xml.append("\t\t<version>2.0</version>\n");
xml.append("\t\t<description>ADQL 2.0</description>\n");
xml.append("\t</language>\n");
Iterator<OutputFormat<R>> itFormats = service.getOutputFormats();
OutputFormat<R> formatter;
while(itFormats.hasNext()){
formatter = itFormats.next();
xml.append("\t<outputFormat>\n");
xml.append("\t\t<mime>").append(formatter.getMimeType()).append("</mime>\n");
if (formatter.getShortMimeType() != null)
xml.append("\t\t<alias>").append(formatter.getShortMimeType()).append("</alias>\n");
if (formatter.getDescription() != null)
xml.append("\t\t<description>").append(formatter.getDescription()).append("</description>\n");
xml.append("\t</outputFormat>\n");
}
int[] retentionPeriod = service.getRetentionPeriod();
if (retentionPeriod != null && retentionPeriod.length >= 2){
if (retentionPeriod[0] > -1 || retentionPeriod[1] > -1){
xml.append("\t<retentionPeriod>\n");
if (retentionPeriod[0] > -1)
xml.append("\t\t<default>").append(retentionPeriod[0]).append("</default>\n");
if (retentionPeriod[1] > -1)
xml.append("\t\t<hard>").append(retentionPeriod[1]).append("</hard>\n");
xml.append("\t</retentionPeriod>\n");
}
}
int[] executionDuration = service.getExecutionDuration();
if (executionDuration != null && executionDuration.length >= 2){
if (executionDuration[0] > -1 || executionDuration[1] > -1){
xml.append("\t<executionDuration>\n");
if (executionDuration[0] > -1)
xml.append("\t\t<default>").append(executionDuration[0]).append("</default>\n");
if (executionDuration[1] > -1)
xml.append("\t\t<hard>").append(executionDuration[1]).append("</hard>\n");
xml.append("\t</executionDuration>\n");
}
}
int[] outputLimit = service.getOutputLimit();
LimitUnit[] outputLimitType = service.getOutputLimitType();
if (outputLimit != null && outputLimit.length >= 2 && outputLimitType != null && outputLimitType.length >= 2){
if (outputLimit[0] > -1 || outputLimit[1] > -1){
xml.append("\t<outputLimit>\n");
if (outputLimit[0] > -1)
xml.append("\t\t<default unit=\"").append(outputLimitType[0]).append("\">").append(outputLimit[0]).append("</default>\n");
if (outputLimit[1] > -1)
xml.append("\t\t<hard unit=\"").append(outputLimitType[1]).append("\">").append(outputLimit[1]).append("</hard>\n");
xml.append("\t</outputLimit>\n");
}
}
if (service.uploadEnabled()){
// Write upload methods: INLINE, HTTP, FTP:
xml.append("<uploadMethod ivo-id=\"ivo://ivoa.org/tap/uploadmethods#inline\" />");
xml.append("<uploadMethod ivo-id=\"ivo://ivoa.org/tap/uploadmethods#http\" />");
xml.append("<uploadMethod ivo-id=\"ivo://ivoa.org/tap/uploadmethods#ftp\" />");
xml.append("<uploadMethod ivo-id=\"ivo://ivoa.net/std/TAPRegExt#upload-inline\" />");
xml.append("<uploadMethod ivo-id=\"ivo://ivoa.net/std/TAPRegExt#upload-http\" />");
xml.append("<uploadMethod ivo-id=\"ivo://ivoa.net/std/TAPRegExt#upload-ftp\" />");
// Write upload limits:
int[] uploadLimit = service.getUploadLimit();
LimitUnit[] uploadLimitType = service.getUploadLimitType();
if (uploadLimit != null && uploadLimit.length >= 2 && uploadLimitType != null && uploadLimitType.length >= 2){
if (uploadLimit[0] > -1 || uploadLimit[1] > -1){
xml.append("\t<uploadLimit>\n");
if (uploadLimit[0] > -1)
xml.append("\t\t<default unit=\"").append(uploadLimitType[0]).append("\">").append(uploadLimit[0]).append("</default>\n");
if (uploadLimit[1] > -1)
xml.append("\t\t<hard unit=\"").append(uploadLimitType[1]).append("\">").append(uploadLimit[1]).append("</hard>\n");
xml.append("\t</uploadLimit>\n");
}
}
}
xml.append("\t</capability>");
return xml.toString();
}
public final UWSService getUWS(){
TAPResource res = resources.get("async");
if (res != null)
return ((ASync)res).getUWS();
else
return null;
}
/**
* @return The homePageURI.
*/
gmantele
committed
public final String getHomePageURI(){
return homePageURI;
}
public final void setHomePageURI(String uri){
gmantele
committed
homePageURI = (uri != null) ? uri.trim() : uri;
if (homePageURI != null && homePageURI.length() == 0)
homePageURI = null;
}
gmantele
committed
public void init(ServletConfig config) throws ServletException{
for(TAPResource res : resources.values())
res.init(config);
}
gmantele
committed
public void destroy(){
for(TAPResource res : resources.values())
res.destroy();
}
gmantele
committed
public void executeRequest(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException{
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
response.setContentType("text/plain");
if (tapBaseURL == null)
setTAPBaseURL(request);
JobOwner owner = null;
String resourceName = null;
try{
// Identify the user:
if (service.getUserIdentifier() != null)
owner = service.getUserIdentifier().extractUserId(new UWSUrl(request), request);
String[] resourcePath = (request.getPathInfo() == null) ? null : request.getPathInfo().split("/");
// Display the TAP Main Page:
if (resourcePath == null || resourcePath.length < 1){
resourceName = "homePage";
response.setContentType("text/html");
writeHomePage(response.getWriter(), owner);
}
// or Display/Execute the selected TAP Resource:
else{
resourceName = resourcePath[1].trim().toLowerCase();
TAPResource res = resources.get(resourceName);
if (res != null)
res.executeResource(request, response);
else
gmantele
committed
errorWriter.writeError("This TAP service does not have a resource named \"" + resourceName + "\" !", ErrorType.TRANSIENT, HttpServletResponse.SC_NOT_FOUND, response, request, null, "Get a TAP resource");
}
service.getLogger().httpRequest(request, owner, resourceName, HttpServletResponse.SC_OK, "[OK]", null);
response.flushBuffer();
}catch(IOException ioe){
gmantele
committed
errorWriter.writeError(ioe, response, request, owner, (resourceName == null) ? "Writing the TAP home page" : ("Executing the TAP resource " + resourceName));
}catch(UWSException ue){
gmantele
committed
errorWriter.writeError(ue, response, request, owner, (resourceName == null) ? "Writing the TAP home page" : ("Executing the TAP resource " + resourceName));
}catch(TAPException te){
writeError(te, response);
}catch(Throwable t){
gmantele
committed
errorWriter.writeError(t, response, request, owner, (resourceName == null) ? "Writing the TAP home page" : ("Executing the TAP resource " + resourceName));
gmantele
committed
public void writeHomePage(final PrintWriter writer, final JobOwner owner) throws IOException{
// By default, list all available resources:
if (homePageURI == null){
writer.println("<html><head><title>TAP HOME PAGE</title></head><body><h1 style=\"text-align: center\">TAP HOME PAGE</h1><h2>Available resources:</h2><ul>");
for(TAPResource res : resources.values())
gmantele
committed
writer.println("<li><a href=\"" + tapBaseURL + "/" + res.getName() + "\">" + res.getName() + "</a></li>");
writer.println("</ul></body></html>");
}
// or Display the specified home page:
else{
BufferedInputStream input = null;
try{
input = new BufferedInputStream((new URL(homePageURI)).openStream());
}catch(MalformedURLException mue){
input = new BufferedInputStream(new FileInputStream(new File(homePageURI)));
}
if (input == null)
throw new IOException("Incorrect TAP home page URI !");
byte[] buffer = new byte[255];
int nbReads = 0;
gmantele
committed
while((nbReads = input.read(buffer)) > 0)
writer.print(new String(buffer, 0, nbReads));
}
}
gmantele
committed
public void writeError(TAPException ex, HttpServletResponse response) throws ServletException, IOException{
service.getLogger().error(ex);
response.reset();
response.setStatus(ex.getHttpErrorCode());
response.setContentType("text/xml");
writeError(ex, response.getWriter());
}
gmantele
committed
protected void writeError(TAPException ex, PrintWriter output) throws ServletException, IOException{
output.println("<?xml version=\"1.0\" encoding=\"UTF-8\"?>");
output.println("<VOTABLE xmlns=\"http://www.ivoa.net/xml/VOTable/v1.2\" xmlns:xsi=\"http://www.w3.org/2001/XMLSchema-instance\" xsi:schemaLocation=\"http://www.ivoa.net/xml/VOTable/v1.2\" version=\"1.2\">");
output.println("\t<RESOURCE type=\"results\">");
// Print the error:
output.println("\t\t<INFO name=\"QUERY_STATUS\" value=\"ERROR\">");
output.print("\t\t\t<![CDATA[ ");
gmantele
committed
if (ex.getExecutionStatus() != null)
output.print("[WHILE " + ex.getExecutionStatus() + "] ");
output.print(ex.getMessage().replace('«', '\"').replace('»', '\"'));
output.println("]]>\t\t</INFO>");
// Print the current date:
DateFormat dateFormat = new SimpleDateFormat(UWSJob.DEFAULT_DATE_FORMAT);
gmantele
committed
output.print("\t\t<INFO name=\"DATE\" value=\"");
output.print(dateFormat.format(new Date()));
output.println("\" />");
// Print the provider (if any):
if (service.getProviderName() != null){
gmantele
committed
output.print("\t\t<INFO name=\"PROVIDER\" value=\"");
output.print(service.getProviderName());
if (service.getProviderDescription() != null){
output.print("\">\n\t\t\t<![CDATA[");
output.print(service.getProviderDescription());
output.println("]]>\n\t\t</INFO>");
}else
gmantele
committed
output.println("\" />");
}
// Print the query (if any):
if (ex.getQuery() != null){
output.print("\t\t<INFO name=\"QUERY\">\n\t\t\t<![CDATA[");
output.println(ex.getQuery());
output.println("]]>\t\t</INFO>");
}
output.println("\t</RESOURCE>");
output.println("</VOTABLE>");
output.flush();
}
public final boolean addResource(TAPResource newResource){
if (newResource == null)
return false;
resources.put(newResource.getName(), newResource);
return true;
}
public final boolean addResource(String resourceId, TAPResource newResource){
if (newResource == null)
return false;
gmantele
committed
resources.put((resourceId == null) ? newResource.getName() : resourceId, newResource);
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
return true;
}
public final int getNbResources(){
return resources.size();
}
public final TAPResource getResource(String resourceId){
return resources.get(resourceId);
}
public final boolean hasResource(String resourceId){
return resources.containsKey(resourceId);
}
public final TAPResource removeResource(String resourceId){
return resources.remove(resourceId);
}
public boolean updateTAPMetadata(){
TAPMetadata metadata = service.getTAPMetadata();
if (metadata != null){
resources.put(metadata.getName(), metadata);
return true;
}
return false;
}
}