Skip to content
Snippets Groups Projects
TAP.java 15.3 KiB
Newer Older
  • Learn to ignore specific revisions
  • 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 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;
    
    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;
    
    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;
    
    
    public class TAP implements VOSIResource {
    
    
    	private static final long serialVersionUID = 1L;
    
    
    	protected final ServiceConnection service;
    
    	protected final Map<String,TAPResource> resources;
    
    
    	protected String tapBaseURL = null;
    
    	protected String homePageURI = null;
    
    	protected ServiceErrorWriter errorWriter;
    
    
    	public TAP(ServiceConnection serviceConnection) throws UWSException, TAPException{
    
    		service = serviceConnection;
    
    		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()){
    
    				dbConn = service.getFactory().createDBConnection("TAP(ServiceConnection)");
    
    				// TODO CLEAN ACTION: DROP SCHEMA!
    				/*dbConn.dropSchema("TAP_UPLOAD");
    				dbConn.createSchema("TAP_UPLOAD");*/
    
    				throw new UWSException(UWSException.INTERNAL_SERVER_ERROR, e, "Error while creating the schema TAP_UPLOAD !");
    
    				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){
    
    		setTAPBaseURL(request.getScheme() + "://" + request.getServerName() + ":" + request.getServerPort() + request.getContextPath() + request.getServletPath());
    
    	}
    
    	public final Availability getAvailability(){
    
    		return (Availability)resources.get(Availability.RESOURCE_NAME);
    
    	}
    
    	public final Capabilities getCapabilities(){
    
    		return (Capabilities)resources.get(Capabilities.RESOURCE_NAME);
    
    		return (Sync)resources.get(Sync.RESOURCE_NAME);
    
    	}
    
    	public final ASync getASync(){
    
    		return (ASync)resources.get(ASync.RESOURCE_NAME);
    
    	}
    
    	public final TAPMetadata getTAPMetadata(){
    
    		return (TAPMetadata)resources.get(TAPMetadata.RESOURCE_NAME);
    
    	}
    
    	public final Iterator<TAPResource> getTAPResources(){
    		return resources.values().iterator();
    	}
    
    
    	public final ServiceErrorWriter getErrorWriter(){
    
    	public final void setErrorWriter(ServiceErrorWriter errorWriter){
    
    		if (errorWriter != null){
    			this.errorWriter = errorWriter;
    			getUWS().setErrorWriter(errorWriter);
    		}
    	}
    
    	@Override
    
    	public String getStandardID(){
    		return "ivo://ivoa.net/std/TAP";
    	}
    
    		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> itFormats = service.getOutputFormats();
    		OutputFormat 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.
    	 */
    
    		return homePageURI;
    	}
    
    	public final void setHomePageURI(String uri){
    
    		homePageURI = (uri != null) ? uri.trim() : uri;
    
    		if (homePageURI != null && homePageURI.length() == 0)
    			homePageURI = null;
    	}
    
    
    	public void init(ServletConfig config) throws ServletException{
    
    		for(TAPResource res : resources.values())
    			res.init(config);
    	}
    
    
    		for(TAPResource res : resources.values())
    			res.destroy();
    	}
    
    
    	public void executeRequest(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException{
    
    		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
    
    					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){
    
    			errorWriter.writeError(ioe, response, request, owner, (resourceName == null) ? "Writing the TAP home page" : ("Executing the TAP resource " + resourceName));
    
    		}catch(UWSException ue){
    
    			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){
    
    			errorWriter.writeError(t, response, request, owner, (resourceName == null) ? "Writing the TAP home page" : ("Executing the TAP resource " + resourceName));
    
    	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())
    
    				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;
    
    				writer.print(new String(buffer, 0, nbReads));
    		}
    	}
    
    
    	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());
    	}
    
    
    	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[ ");
    
    		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);
    
    		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){
    
    			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
    
    		}
    
    		// 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;
    
    		resources.put((resourceId == null) ? newResource.getName() : resourceId, newResource);
    
    		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;
    	}
    
    }