Newer
Older
package tap.config;
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
/*
* 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 2013 - Astronomisches Rechen Institute (ARI)
*/
import static tap.config.TAPConfiguration.DEFAULT_DIRECTORY_PER_USER;
import static tap.config.TAPConfiguration.DEFAULT_EXECUTION_DURATION;
import static tap.config.TAPConfiguration.DEFAULT_GROUP_USER_DIRECTORIES;
import static tap.config.TAPConfiguration.DEFAULT_IS_AVAILABLE;
import static tap.config.TAPConfiguration.DEFAULT_RETENTION_PERIOD;
import static tap.config.TAPConfiguration.KEY_DEFAULT_EXECUTION_DURATION;
import static tap.config.TAPConfiguration.KEY_DEFAULT_OUTPUT_LIMIT;
import static tap.config.TAPConfiguration.KEY_DEFAULT_RETENTION_PERIOD;
import static tap.config.TAPConfiguration.KEY_DIRECTORY_PER_USER;
import static tap.config.TAPConfiguration.KEY_DISABILITY_REASON;
import static tap.config.TAPConfiguration.KEY_FILE_MANAGER;
import static tap.config.TAPConfiguration.KEY_FILE_ROOT_PATH;
import static tap.config.TAPConfiguration.KEY_GROUP_USER_DIRECTORIES;
import static tap.config.TAPConfiguration.KEY_IS_AVAILABLE;
import static tap.config.TAPConfiguration.KEY_MAX_EXECUTION_DURATION;
import static tap.config.TAPConfiguration.KEY_MAX_OUTPUT_LIMIT;
import static tap.config.TAPConfiguration.KEY_MAX_RETENTION_PERIOD;
import static tap.config.TAPConfiguration.KEY_OUTPUT_FORMATS;
import static tap.config.TAPConfiguration.KEY_PROVIDER_NAME;
import static tap.config.TAPConfiguration.KEY_SERVICE_DESCRIPTION;
import static tap.config.TAPConfiguration.VALUE_CSV;
import static tap.config.TAPConfiguration.VALUE_JSON;
import static tap.config.TAPConfiguration.VALUE_LOCAL;
import static tap.config.TAPConfiguration.VALUE_SV;
import static tap.config.TAPConfiguration.VALUE_TSV;
import static tap.config.TAPConfiguration.fetchClass;
import static tap.config.TAPConfiguration.getProperty;
import static tap.config.TAPConfiguration.isClassPath;
import static tap.config.TAPConfiguration.parseLimit;
import java.io.File;
import java.lang.reflect.InvocationTargetException;
import java.sql.ResultSet;
import java.util.ArrayList;
import java.util.Collection;
import java.util.Iterator;
import java.util.Properties;
import tap.ServiceConnection;
import tap.TAPException;
import tap.TAPFactory;
import tap.file.LocalTAPFileManager;
import tap.file.TAPFileManager;
import tap.formatter.OutputFormat;
import tap.formatter.ResultSet2JsonFormatter;
import tap.formatter.ResultSet2SVFormatter;
import tap.formatter.ResultSet2VotableFormatter;
import tap.log.DefaultTAPLog;
import tap.log.TAPLog;
import tap.metadata.TAPMetadata;
import uws.UWSException;
import uws.service.UserIdentifier;
/**
*
* @author Grégory Mantelet (ARI) - gmantele@ari.uni-heidelberg.de
* @version 1.1 (12/2013)
*/
public final class DefaultServiceConnection implements ServiceConnection<ResultSet> {
private TAPFileManager fileManager;
private TAPLog logger;
private DefaultTAPFactory tapFactory;
private final String providerName;
private final String serviceDescription;
private boolean isAvailable = false;
private String availability = null;
private int[] executionDuration = new int[2];
private int[] retentionPeriod = new int[2];
private final ArrayList<OutputFormat<ResultSet>> outputFormats;
private int[] outputLimits = new int[2];
private LimitUnit[] outputLimitTypes = new LimitUnit[2];
public DefaultServiceConnection(final Properties tapConfig) throws NullPointerException, TAPException, UWSException{
// 1. INITIALIZE THE FILE MANAGER:
initFileManager(tapConfig);
// 2. CREATE THE LOGGER:
logger = new DefaultTAPLog(fileManager);
// 3. BUILD THE TAP FACTORY:
tapFactory = new DefaultTAPFactory(this, tapConfig);
// 4. SET ALL GENERAL SERVICE CONNECTION INFORMATION:
providerName = getProperty(tapConfig, KEY_PROVIDER_NAME);
serviceDescription = getProperty(tapConfig, KEY_SERVICE_DESCRIPTION);
availability = getProperty(tapConfig, KEY_DISABILITY_REASON);
initRetentionPeriod(tapConfig);
initExecutionDuration(tapConfig);
// 5. CONFIGURE OUTPUT:
// default output format = VOTable:
outputFormats = new ArrayList<OutputFormat<ResultSet>>(1);
outputFormats.add(new ResultSet2VotableFormatter(this));
// set additional output formats:
addOutputFormats(tapConfig);
// set output limits:
initOutputLimits(tapConfig);
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
// 5. MAKE THE SERVICE AVAILABLE (or not, depending on the property value):
String propValue = getProperty(tapConfig, KEY_IS_AVAILABLE);
isAvailable = (propValue == null) ? DEFAULT_IS_AVAILABLE : Boolean.parseBoolean(propValue);
}
private void initFileManager(final Properties tapConfig) throws TAPException{
// Read the desired file manager:
String fileManagerType = getProperty(tapConfig, KEY_FILE_MANAGER);
if (fileManagerType == null)
throw new TAPException("The property \"" + KEY_FILE_MANAGER + "\" is missing! It is required to create a TAP Service. Two possible values: " + VALUE_LOCAL + " or a class path between {...}.");
else
fileManagerType = fileManagerType.trim();
// LOCAL file manager:
if (fileManagerType.equalsIgnoreCase(VALUE_LOCAL)){
// Read the desired root path:
String rootPath = getProperty(tapConfig, KEY_FILE_ROOT_PATH);
if (rootPath == null)
throw new TAPException("The property \"" + KEY_FILE_ROOT_PATH + "\" is missing! It is required to create a TAP Service. Please provide a path toward a directory which will contain all files related to the service.");
File rootFile = new File(rootPath);
// Determine whether there should be one directory for each user:
String propValue = getProperty(tapConfig, KEY_DIRECTORY_PER_USER);
boolean oneDirectoryPerUser = (propValue == null) ? DEFAULT_DIRECTORY_PER_USER : Boolean.parseBoolean(propValue);
// Determine whether there should be one directory for each user:
propValue = getProperty(tapConfig, KEY_GROUP_USER_DIRECTORIES);
boolean groupUserDirectories = (propValue == null) ? DEFAULT_GROUP_USER_DIRECTORIES : Boolean.parseBoolean(propValue);
// Build the Local TAP File Manager:
try{
fileManager = new LocalTAPFileManager(rootFile, oneDirectoryPerUser, groupUserDirectories);
}catch(UWSException e){
throw new TAPException("The property \"" + KEY_FILE_ROOT_PATH + "\" (" + rootPath + ") is incorrect: " + e.getMessage());
}
}
// CUSTOM file manager:
else{
Class<? extends TAPFileManager> classObj = fetchClass(fileManagerType, KEY_FILE_MANAGER, TAPFileManager.class);
if (classObj == null)
throw new TAPException("Unknown value for the property \"" + KEY_FILE_MANAGER + "\": \"" + fileManagerType + "\". Only two possible values: " + VALUE_LOCAL + " or a class path between {...}.");
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
try{
fileManager = classObj.getConstructor(Properties.class).newInstance(tapConfig);
}catch(InstantiationException | IllegalAccessException | IllegalArgumentException | InvocationTargetException | NoSuchMethodException | SecurityException e){
throw new TAPException("Impossible to create a TAPFileManager instance with the constructor (java.util.Properties tapConfig) of \"" + classObj.getName() + "\" for the following reason: " + e.getMessage());
}
}
}
private void initRetentionPeriod(final Properties tapConfig){
retentionPeriod = new int[2];
// Set the default period:
String propValue = getProperty(tapConfig, KEY_DEFAULT_RETENTION_PERIOD);
try{
retentionPeriod[0] = (propValue == null) ? DEFAULT_RETENTION_PERIOD : Integer.parseInt(propValue);
}catch(NumberFormatException nfe){
retentionPeriod[0] = DEFAULT_RETENTION_PERIOD;
}
// Set the maximum period:
propValue = getProperty(tapConfig, KEY_MAX_RETENTION_PERIOD);
try{
retentionPeriod[1] = (propValue == null) ? DEFAULT_RETENTION_PERIOD : Integer.parseInt(propValue);
}catch(NumberFormatException nfe){
retentionPeriod[1] = DEFAULT_RETENTION_PERIOD;
}
// The maximum period MUST be greater or equals than the default period.
// If not, the default period is set (so decreased) to the maximum period.
if (retentionPeriod[1] > 0 && retentionPeriod[1] < retentionPeriod[0])
retentionPeriod[0] = retentionPeriod[1];
}
private void initExecutionDuration(final Properties tapConfig){
executionDuration = new int[2];
// Set the default duration:
String propValue = getProperty(tapConfig, KEY_DEFAULT_EXECUTION_DURATION);
try{
executionDuration[0] = (propValue == null) ? DEFAULT_EXECUTION_DURATION : Integer.parseInt(propValue);
}catch(NumberFormatException nfe){
executionDuration[0] = DEFAULT_EXECUTION_DURATION;
}
// Set the maximum duration:
propValue = getProperty(tapConfig, KEY_MAX_EXECUTION_DURATION);
try{
executionDuration[1] = (propValue == null) ? DEFAULT_EXECUTION_DURATION : Integer.parseInt(propValue);
}catch(NumberFormatException nfe){
executionDuration[1] = DEFAULT_EXECUTION_DURATION;
}
// The maximum duration MUST be greater or equals than the default duration.
// If not, the default duration is set (so decreased) to the maximum duration.
if (executionDuration[1] > 0 && executionDuration[1] < executionDuration[0])
executionDuration[0] = executionDuration[1];
}
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
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
@SuppressWarnings({"unchecked","rawtypes"})
private void addOutputFormats(final Properties tapConfig) throws TAPException{
// Fetch the value of the property for additional output formats:
String formats = TAPConfiguration.getProperty(tapConfig, KEY_OUTPUT_FORMATS);
// Since it is a comma separated list of output formats, a loop will parse this list comma by comma:
String f;
int indexSep;
while(formats != null && formats.length() > 0){
// Get a format item from the list:
indexSep = formats.indexOf(',');
// no comma => only one format
if (indexSep < 0){
f = formats;
formats = null;
}
// comma at the first position => empty list item => go to the next item
else if (indexSep == 0){
formats = formats.substring(1).trim();
continue;
}
// else => get the first format item, and then remove it from the list for the next iteration
else{
f = formats.substring(0, indexSep).trim();
formats = formats.substring(indexSep + 1).trim();
}
// Identify the format and append it to the output format list of the service:
// JSON
if (f.equalsIgnoreCase(VALUE_JSON))
outputFormats.add(new ResultSet2JsonFormatter(this));
// CSV
else if (f.equalsIgnoreCase(VALUE_CSV))
outputFormats.add(new ResultSet2SVFormatter(this, ",", true));
// TSV
else if (f.equalsIgnoreCase(VALUE_TSV))
outputFormats.add(new ResultSet2SVFormatter(this, "\t", true));
// any SV (separated value) format
else if (f.toLowerCase().startsWith(VALUE_SV)){
// get the separator:
int endSep = f.indexOf(')');
if (VALUE_SV.length() < f.length() && f.charAt(VALUE_SV.length()) == '(' && endSep > VALUE_SV.length() + 1){
String separator = f.substring(VALUE_SV.length() + 1, f.length() - 1);
// get the MIME type and its alias, if any of them is provided:
String mimeType = null, shortMimeType = null;
if (endSep + 1 < f.length() && f.charAt(endSep + 1) == ':'){
int endMime = f.indexOf(':', endSep + 2);
if (endMime < 0)
mimeType = f.substring(endSep + 2, f.length());
else if (endMime > 0){
mimeType = f.substring(endSep + 2, endMime);
shortMimeType = f.substring(endMime + 1);
}
}
// add the defined SV(...) format:
outputFormats.add(new ResultSet2SVFormatter(this, separator, true, mimeType, shortMimeType));
}else
throw new TAPException("Missing separator char/string for the SV output format: \"" + f + "\"!");
}
// custom OutputFormat
else if (isClassPath(f)){
Class<? extends OutputFormat> userOutputFormatClass = fetchClass(f, KEY_OUTPUT_FORMATS, OutputFormat.class);
try{
OutputFormat<ResultSet> userOutputFormat = userOutputFormatClass.getConstructor(ServiceConnection.class).newInstance(this);
outputFormats.add(userOutputFormat);
}catch(InstantiationException | IllegalAccessException | IllegalArgumentException | InvocationTargetException | NoSuchMethodException | SecurityException e){
throw new TAPException("Impossible to create an OutputFormat<ResultSet> instance with the constructor (ServiceConnection<ResultSet>) of \"" + userOutputFormatClass.getName() + "\" (see the property output_add_format) for the following reason: " + e.getMessage());
}
}
// unknown format
else
throw new TAPException("Unknown output format: " + f);
}
}
private void initOutputLimits(final Properties tapConfig) throws TAPException{
Object[] limit = parseLimit(getProperty(tapConfig, KEY_DEFAULT_OUTPUT_LIMIT), KEY_DEFAULT_OUTPUT_LIMIT, false);
outputLimitTypes[0] = (LimitUnit)limit[1];
setDefaultOutputLimit((int)limit[0]);
limit = parseLimit(getProperty(tapConfig, KEY_MAX_OUTPUT_LIMIT), KEY_DEFAULT_OUTPUT_LIMIT, false);
outputLimitTypes[1] = (LimitUnit)limit[1];
if (!setMaxOutputLimit((int)limit[0]))
throw new TAPException("The default output limit (here: " + outputLimits[0] + ") MUST be less or equal to the maximum output limit (here: " + limit[0] + ")!");
}
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
@Override
public String getProviderName(){
return providerName;
}
@Override
public String getProviderDescription(){
return serviceDescription;
}
@Override
public boolean isAvailable(){
return isAvailable;
}
public void setAvailability(final boolean isAvailable){
this.isAvailable = isAvailable;
}
@Override
public String getAvailability(){
return availability;
}
public void setDisabilityReason(final String disabilityReason){
availability = disabilityReason;
}
@Override
public int[] getRetentionPeriod(){
return retentionPeriod;
}
public boolean setDefaultRetentionPeriod(final int period){
if ((retentionPeriod[1] <= 0) || (period > 0 && period <= retentionPeriod[1])){
retentionPeriod[0] = period;
return true;
}else
return false;
}
public boolean setMaxRetentionPeriod(final int period){
if (period <= 0 || (retentionPeriod[0] > 0 && period >= retentionPeriod[0])){
retentionPeriod[1] = period;
return true;
}else
return false;
}
@Override
public int[] getExecutionDuration(){
return executionDuration;
}
public boolean setDefaultExecutionDuration(final int period){
if ((executionDuration[1] <= 0) || (period > 0 && period <= executionDuration[1])){
executionDuration[0] = period;
return true;
}else
return false;
}
public boolean setMaxExecutionDuration(final int period){
if (period <= 0 || (executionDuration[0] > 0 && period >= executionDuration[0])){
executionDuration[1] = period;
return true;
}else
return false;
}
@Override
public Iterator<OutputFormat<ResultSet>> getOutputFormats(){
return outputFormats.iterator();
}
@Override
public OutputFormat<ResultSet> getOutputFormat(final String mimeOrAlias){
if (mimeOrAlias == null || mimeOrAlias.trim().isEmpty())
return null;
for(OutputFormat<ResultSet> f : outputFormats){
if ((f.getMimeType() != null && f.getMimeType().equalsIgnoreCase(mimeOrAlias)) || (f.getShortMimeType() != null && f.getShortMimeType().equalsIgnoreCase(mimeOrAlias)))
return f;
}
return null;
}
public void addOutputFormat(final OutputFormat<ResultSet> newOutputFormat){
outputFormats.add(newOutputFormat);
}
public boolean removeOutputFormat(final String mimeOrAlias){
OutputFormat<ResultSet> of = getOutputFormat(mimeOrAlias);
if (of != null)
return outputFormats.remove(of);
else
return false;
}
@Override
public int[] getOutputLimit(){
return outputLimits;
}
public boolean setDefaultOutputLimit(final int limit){
if ((outputLimits[1] <= 0) || (limit > 0 && limit <= outputLimits[1])){
outputLimits[0] = limit;
return true;
}else
return false;
}
public boolean setMaxOutputLimit(final int limit){
if (limit > 0 && outputLimits[0] > 0 && limit < outputLimits[0])
return false;
else{
outputLimits[1] = limit;
return true;
}
}
@Override
public final LimitUnit[] getOutputLimitType(){
return new LimitUnit[]{LimitUnit.rows,LimitUnit.rows};
}
@Override
public Collection<String> getCoordinateSystems(){
return null;
}
@Override
public TAPLog getLogger(){
return logger;
}
@Override
public TAPFactory<ResultSet> getFactory(){
return tapFactory;
}
@Override
public TAPFileManager getFileManager(){
return fileManager;
}
@Override
public UserIdentifier getUserIdentifier(){
// TODO Auto-generated method stub
return null;
}
@Override
public boolean uploadEnabled(){
// TODO Auto-generated method stub
return false;
}
@Override
public int[] getUploadLimit(){
// TODO Auto-generated method stub
return null;
}
@Override
public LimitUnit[] getUploadLimitType(){
// TODO Auto-generated method stub
return null;
}
@Override
public int getMaxUploadSize(){
// TODO Auto-generated method stub
return 0;
}
@Override
public TAPMetadata getTAPMetadata(){