Newer
Older
package tap;
/*
* 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-2016 - UDS/Centre de Données astronomiques de Strasbourg (CDS),
* Astronomisches Rechen Institut (ARI)
import java.util.Collection;
import java.util.List;
import java.util.Map;
import javax.servlet.http.HttpServletRequest;
import tap.db.DBConnection;
import tap.error.DefaultTAPErrorWriter;
import tap.metadata.TAPMetadata;
import tap.metadata.TAPSchema;
import tap.metadata.TAPTable;
import tap.parameters.TAPParameters;
import tap.upload.Uploader;
import uws.UWSException;
import uws.job.ErrorSummary;
import uws.job.Result;
import uws.job.user.JobOwner;
import uws.service.UWS;
import uws.service.UWSService;
import uws.service.backup.UWSBackupManager;
import uws.service.error.ServiceErrorWriter;
import adql.db.DBChecker;
import adql.parser.ADQLParser;
import adql.parser.ADQLQueryFactory;
import adql.parser.ParseException;
import adql.parser.QueryChecker;
/**
* Default implementation of most of the {@link TAPFactory} function.
* Only the functions related with the database connection stay abstract.
*
* @author Grégory Mantelet (CDS;ARI)
* @version 2.1 (01/2016)
public abstract class AbstractTAPFactory extends TAPFactory {
gmantele
committed
/** The error writer to use when any error occurs while executing a resource or to format an error occurring while executing an asynchronous job. */
protected final ServiceErrorWriter errorWriter;
/**
* Build a basic TAPFactory.
* Nothing is done except setting the service connection.
*
* @param service Configuration of the TAP service. <i>MUST NOT be NULL</i>
*
* @throws NullPointerException If the given {@link ServiceConnection} is NULL.
*
* @see AbstractTAPFactory#AbstractTAPFactory(ServiceConnection, ServiceErrorWriter)
protected AbstractTAPFactory(ServiceConnection service) throws NullPointerException{
this(service, new DefaultTAPErrorWriter(service));
}
/**
* <p>Build a basic TAPFactory.
* Nothing is done except setting the service connection and the given error writer.</p>
*
* <p>Then the error writer will be used when creating a UWS service and a job thread.</p>
*
* @param service Configuration of the TAP service. <i>MUST NOT be NULL</i>
* @param errorWriter Object to use to format and write the errors for the user.
*
* @throws NullPointerException If the given {@link ServiceConnection} is NULL.
*
* @see TAPFactory#TAPFactory(ServiceConnection)
*/
protected AbstractTAPFactory(final ServiceConnection service, final ServiceErrorWriter errorWriter) throws NullPointerException{
super(service);
this.errorWriter = errorWriter;
}
@Override
public final ServiceErrorWriter getErrorWriter(){
return errorWriter;
/* *************** */
/* ADQL MANAGEMENT */
/* *************** */
/**
* <p><i>Note:
* Unless the standard implementation - {@link ADQLExecutor} - does not fit exactly your needs,
* it should not be necessary to extend this class and to extend this function (implemented here by default).
* </i></p>
*/
@Override
public ADQLExecutor createADQLExecutor() throws TAPException{
return new ADQLExecutor(service);
}
/**
* <p><i>Note:
* This function should be extended if you want to customize the ADQL grammar.
* </i></p>
*/
@Override
public ADQLParser createADQLParser() throws TAPException{
return new ADQLParser();
}
/**
* <p><i>Note:
* This function should be extended if you have customized the creation of any
* {@link ADQLQuery} part ; it could be the addition of one or several user defined function
* or the modification of any ADQL function or clause specific to your implementation.
* </i></p>
*/
@Override
public ADQLQueryFactory createQueryFactory() throws TAPException{
return new ADQLQueryFactory();
}
/**
* <p>This implementation gathers all tables published in this TAP service and those uploaded
* by the user. Then it calls {@link #createQueryChecker(Collection)} with this list in order
* to create a query checked.
* </p>
*
* <p><i>Note:
* This function can not be overridded, but {@link #createQueryChecker(Collection)} can be.
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
* </i></p>
*/
@Override
public final QueryChecker createQueryChecker(final TAPSchema uploadSchema) throws TAPException{
// Get all tables published in this TAP service:
TAPMetadata meta = service.getTAPMetadata();
// Build a list in order to gather all these with the uploaded ones:
ArrayList<TAPTable> tables = new ArrayList<TAPTable>(meta.getNbTables());
// Add all tables published in TAP:
Iterator<TAPTable> it = meta.getTables();
while(it.hasNext())
tables.add(it.next());
// Add all tables uploaded by the user:
if (uploadSchema != null){
for(TAPTable table : uploadSchema)
tables.add(table);
}
// Finally, create the query checker:
return createQueryChecker(tables);
}
/**
* <p>Create an object able to check the consistency between the ADQL query and the database.
* That's to say, it checks whether the tables and columns used in the query really exist
* in the database.</p>
*
* <p><i>Note:
* This implementation just create a {@link DBChecker} instance with the list given in parameter.
* </i></p>
*
* @param tables List of all available tables (and indirectly, columns).
*
* @return A new ADQL query checker.
*
* @throws TAPException If any error occurs while creating the query checker.
*/
protected QueryChecker createQueryChecker(final Collection<TAPTable> tables) throws TAPException{
try{
return new DBChecker(tables, service.getUDFs(), service.getGeometries(), service.getCoordinateSystems());
}catch(ParseException e){
throw new TAPException("Unable to build a DBChecker instance! " + e.getMessage(), e, UWSException.INTERNAL_SERVER_ERROR);
}
}
/* ****** */
/* UPLOAD */
/* ****** */
/**
* <p>This implementation just create an {@link Uploader} instance with the given database connection.</p>
*
* <p><i>Note:
gmantele
committed
* This function should be overrided if you need to change the DB name of the TAP_UPLOAD schema.
* Indeed, by overriding this function you can specify a given TAPSchema to use as TAP_UPLOAD schema
* in the constructor of {@link Uploader}. But do not forget that this {@link TAPSchema} instance MUST have
* an ADQL name equals to "TAP_UPLOAD", otherwise, a TAPException will be thrown.
* </i></p>
*/
@Override
public Uploader createUploader(final DBConnection dbConn) throws TAPException{
return new Uploader(service, dbConn);
}
/* ************** */
/* UWS MANAGEMENT */
/* ************** */
/**
* <p>This implementation just create a {@link UWSService} instance.</p>
*
* <p><i>Note:
* This implementation is largely enough for a TAP service. It is not recommended to override
* this function.
* </i></p>
*/
@Override
public UWSService createUWS() throws TAPException{
try{
UWSService uws = new UWSService(this, this.service.getFileManager(), this.service.getLogger());
uws.setName("TAP/async");
uws.setErrorWriter(errorWriter);
return uws;
}catch(UWSException ue){
throw new TAPException("Can not create a UWS service (asynchronous resource of TAP)!", ue, UWSException.INTERNAL_SERVER_ERROR);
}
}
/**
* <p>This implementation does not provided a backup manager.
* It means that no asynchronous job will be restored and backuped.</p>
*
* <p>You must override this function if you want enable the backup feature.</p>
*/
public UWSBackupManager createUWSBackupManager(final UWSService uws) throws TAPException{
return null;
}
/**
* <p>This implementation provides a basic {@link TAPJob} instance.</p>
*
* <p>
* If you need to add or modify the behavior of some functions of a {@link TAPJob},
* you must override this function and return your own extension of {@link TAPJob}.
* </p>
*/
protected TAPJob createTAPJob(final HttpServletRequest request, final JobOwner owner) throws UWSException{
// Extract the HTTP request ID (the job ID should be the same, if not already used by another job):
String requestID = null;
if (request.getAttribute(UWS.REQ_ATTRIBUTE_ID) != null && request.getAttribute(UWS.REQ_ATTRIBUTE_ID) instanceof String)
requestID = request.getAttribute(UWS.REQ_ATTRIBUTE_ID).toString();
// Extract the TAP parameters from the HTTP request:
TAPParameters tapParams = createTAPParameters(request);
// Create the job:
return new TAPJob(owner, tapParams, requestID);
}catch(TAPException te){
if (te.getCause() != null && te.getCause() instanceof UWSException)
throw (UWSException)te.getCause();
else
throw new UWSException(UWSException.INTERNAL_SERVER_ERROR, te, "Can not create a TAP asynchronous job!");
/**
* <p>This implementation provides a basic {@link TAPJob} instance.</p>
*
* <p>
* If you need to add or modify the behavior of some functions of a {@link TAPJob},
* you must override this function and return your own extension of {@link TAPJob}.
* </p>
*/
protected TAPJob createTAPJob(final String jobId, final JobOwner owner, final TAPParameters params, final long quote, final long startTime, final long endTime, final List<Result> results, final ErrorSummary error) throws UWSException{
return new TAPJob(jobId, owner, params, quote, startTime, endTime, results, error);
}catch(TAPException te){
if (te.getCause() != null && te.getCause() instanceof UWSException)
throw (UWSException)te.getCause();
else
throw new UWSException(UWSException.INTERNAL_SERVER_ERROR, te, "Can not create a TAP asynchronous job !");
/**
* <p>This implementation extracts standard TAP parameters from the given request.</p>
*
* <p>
* Non-standard TAP parameters are added in a map inside the returned {@link TAPParameters} object
* and are accessible with {@link TAPParameters#get(String)} and {@link TAPParameters#getAdditionalParameters()}.
* However, if you want to manage them in another way, you must extend {@link TAPParameters} and override
* this function in order to return an instance of your extension.
* </p>
*/
public TAPParameters createTAPParameters(final HttpServletRequest request) throws TAPException{
return new TAPParameters(request, service);
/**
* <p>This implementation extracts standard TAP parameters from the given request.</p>
*
* <p>
* Non-standard TAP parameters are added in a map inside the returned {@link TAPParameters} object
* and are accessible with {@link TAPParameters#get(String)} and {@link TAPParameters#getAdditionalParameters()}.
* However, if you want to manage them in another way, you must extend {@link TAPParameters} and override
* this function in order to return an instance of your extension.
* </p>
*/
public TAPParameters createTAPParameters(final Map<String,Object> params) throws TAPException{
return new TAPParameters(service, params);