Project

General

Profile

Download (19.3 KB) Statistics
| Branch: | Revision:

git_sitools_idoc / sitools-idoc / hesiod / javaExt / src / fr / ias / sitools / vo / tap / TableAccessProtocolResponse.java @ 779bac69

1
/*
2
 * To change this license header, choose License Headers in Project Properties.
3
 * To change this template file, choose Tools | Templates
4
 * and open the template in the editor.
5
 */
6

    
7
package fr.ias.sitools.vo.tap;
8

    
9
import adql.parser.ADQLParser;
10
import adql.parser.ParseException;
11
import adql.query.ADQLQuery;
12
import adql.translator.ADQLTranslator;
13
import adql.translator.PostgreSQLTranslator;
14
import adql.translator.TranslationException;
15
import fr.cnes.sitools.common.exception.SitoolsException;
16
import fr.cnes.sitools.dataset.DataSetApplication;
17
import fr.cnes.sitools.dataset.converter.business.ConverterChained;
18
import fr.cnes.sitools.dataset.database.DatabaseRequest;
19
import fr.cnes.sitools.dataset.database.DatabaseRequestFactory;
20
import fr.cnes.sitools.dataset.database.DatabaseRequestParameters;
21
import fr.cnes.sitools.dataset.database.common.DataSetExplorerUtil;
22
import fr.cnes.sitools.dataset.dto.ColumnConceptMappingDTO;
23
import fr.cnes.sitools.dataset.dto.DictionaryMappingDTO;
24
import fr.cnes.sitools.dataset.model.Column;
25
import fr.cnes.sitools.dataset.model.Predicat;
26
import fr.cnes.sitools.dictionary.model.Concept;
27
import fr.cnes.sitools.plugins.resources.model.ResourceModel;
28
import fr.cnes.sitools.util.Util;
29
import fr.ias.sitools.vo.representation.DatabaseRequestIasModel;
30
import freemarker.template.TemplateSequenceModel;
31
import java.math.BigInteger;
32

    
33
import java.util.ArrayList;
34
import java.util.Collections;
35
import java.util.HashMap;
36
import java.util.List;
37
import java.util.Map;
38
import java.util.logging.Level;
39
import java.util.logging.Logger;
40
import net.ivoa.xml.votable.v1.AnyTEXT;
41
import net.ivoa.xml.votable.v1.DataType;
42
import net.ivoa.xml.votable.v1.Field;
43
import net.ivoa.xml.votable.v1.Info;
44
import net.ivoa.xml.votable.v1.Param;
45
import org.restlet.Context;
46

    
47
/**
48
 *
49
 * @author marc
50
 */
51
class TableAccessProtocolResponse implements TableAccessProtocolDataModelInterface { 
52
    
53
    /**
54
    * Data model.
55
    */
56
    private final transient Map dataModel = new HashMap();
57
    
58
    /**
59
    * Context 
60
    **/
61
    private final transient Context ctx;
62
    
63
    /**
64
    * The ADQL Query
65
    */
66
    private final String adqlQuery;
67
    
68
    /**
69
     * The Psql Query from the ADQL query
70
     */
71
    private transient String psqlQuery;
72
    /**
73
     * The col to query
74
     */
75
    private ArrayList<String> colsToQuery = new ArrayList<String>();
76
    
77
    private String clauseWhereToQuery;
78
    
79
    private String clauseLimit;
80
    private int clauseLimitInt;
81
    private String format;
82
    
83
    boolean isPrimaryKey;
84
    
85
    public TableAccessProtocolResponse(final TableAccessProtocolInputParameters inputParameters, final ResourceModel model) {        
86
        this.format = inputParameters.getFormat();
87
        this.adqlQuery = inputParameters.getQuery();
88
        this.ctx = inputParameters.getContext();
89

    
90
        if(this.adqlQuery == null || this.adqlQuery .equalsIgnoreCase("")){
91
            // TO DO
92
        }else{
93
            processQuery();
94
            createResponse(inputParameters, model); 
95
        }
96
    }
97

    
98
    private void createResponse(final TableAccessProtocolInputParameters inputParameters, final ResourceModel model){
99

    
100

    
101
        // On récupère le nom du dico
102
        final String dictionaryName = model.getParameterByName(TableAccessProtocolLibrary.DICTIONARY).getValue();
103

    
104
        //On set les params
105
        setVotableParametersFromConfiguration(this.dataModel, model);
106
        //On requete la base et on remplit le template
107
        setVotableResource(inputParameters.getDatasetApp(), inputParameters, model, dictionaryName);
108

    
109
        // On set le query_status à OK
110
        setQueryInfos(model);
111
   
112
    }
113
    // FONCTIONS PRIVATE
114
    /**
115
    * Creates the response based on Table.
116
    *
117
    * @param datasetApp Dataset application
118
    * @param inputParameters Input Parameters
119
    * @param model data model
120
    * @param dictionaryName TAP dictionary
121
    */
122
    private void setVotableResource(final DataSetApplication datasetApp, final TableAccessProtocolInputParameters inputParameters,
123
          final ResourceModel model, final String dictionaryName) {
124
        
125
        final List<Field> fieldList = new ArrayList<Field>();
126
        final List<String> columnStringList = new ArrayList<String>();
127
        final List<Column> columnList = datasetApp.getDataSet().getColumnModel();
128
        
129
        DatabaseRequest databaseRequest = null;
130
        try {
131
            // On récupère les columns
132

    
133
            // On récupere le mapping
134
            List<ColumnConceptMappingDTO> mappingList = getDicoFromConfiguration(datasetApp, dictionaryName);
135
            
136
            final DatabaseRequestParameters dbParams = setQueryParameters(datasetApp, model, inputParameters, mappingList);
137

    
138
            // On récupère les colonnes à requeter
139
            List<Column> listCol = getColumnToQuery(columnList);
140
            listCol = checkPrimaryKeyAndAddItColTQuery(columnList, listCol);
141
            // On envoie les colonnes à requeter
142
            dbParams.setSqlVisibleColumns(listCol);
143
            
144
            // S'il y a un parametre Limit on le rajoute au parametre de requete
145
            if(this.clauseLimitInt > 0)
146
            {
147
                dbParams.setMaxrows(this.clauseLimitInt);
148
            }   
149
            databaseRequest = DatabaseRequestFactory.getDatabaseRequest(dbParams);
150
            databaseRequest.checkRequest();
151
            // Execute query
152
            databaseRequest.createRequest();
153

    
154
            getCtx().getLogger().log(Level.FINEST, "-------- DB REQUEST : {0}", databaseRequest.getRequestAsString());
155

    
156
            setFields(fieldList, columnStringList, mappingList, listCol);
157
            
158
            final int count = (databaseRequest.getCount() > dbParams.getPaginationExtend()) ? dbParams.getPaginationExtend() : databaseRequest.getCount();
159
            dataModel.put("nrows", count);
160
            dataModel.put("fields", fieldList);
161
            dataModel.put("sqlColAlias", columnStringList);
162
            
163
            final ConverterChained converterChained = datasetApp.getConverterChained();
164
            
165
            //final TemplateSequenceModel rows = new DatabaseRequestModel(databaseRequest, converterChained);
166
            final TemplateSequenceModel rows = new DatabaseRequestIasModel(databaseRequest, converterChained);
167

    
168
            dataModel.put("rows", rows);
169
        } catch (SitoolsException ex) {
170
            Logger.getLogger(TableAccessProtocolResponse.class.getName()).log(Level.SEVERE, null, ex);
171
        }            
172
    }
173
    
174
    /**
175
   * Set Query parameters to the database.
176
   *
177
   * @param datasetApp Dataset Application
178
   * @param model Data model
179
   * @param inputParameters Input Parameters
180
   * @return DatabaseRequestParamerters object
181
   */
182
  @SuppressWarnings("empty-statement")
183
  private DatabaseRequestParameters setQueryParameters(final DataSetApplication datasetApp, final ResourceModel model,
184
          final TableAccessProtocolInputParameters inputParameters, List<ColumnConceptMappingDTO> mappingList) {
185

    
186
    // Get the dataset
187
    final DataSetExplorerUtil dsExplorerUtil = new DataSetExplorerUtil(datasetApp, inputParameters.getRequest(),
188
            inputParameters.getContext());
189

    
190
    // Get query parameters
191
    final DatabaseRequestParameters dbParams = dsExplorerUtil.getDatabaseParams();
192
    // Get dataset records
193
    final int nbRecordsInDataSet = datasetApp.getDataSet().getNbRecords();
194

    
195
    // Get max records that is defined by admin
196
    int nbMaxRecords = Integer.valueOf(model.getParameterByName(TableAccessProtocolLibrary.MAX_RECORDS).getValue());
197
    nbMaxRecords = (nbMaxRecords > nbRecordsInDataSet || nbMaxRecords == -1) ? nbRecordsInDataSet : nbMaxRecords;
198
    // if a limit clause is defined, used it.
199
    if(this.clauseLimit != null){        
200
        nbMaxRecords = Integer.parseInt(this.clauseLimit);
201
    }
202
    // Set max records
203
    dbParams.setPaginationExtend(nbMaxRecords);
204
    
205
    
206
    
207
    final List<Predicat> predicatList = dbParams.getPredicats();
208
    //String customQuery = "AND ra > 25 and dec < 180 and flux > 0.256";
209
    Predicat predicat = new Predicat();
210
    
211
    predicat.setStringDefinition(this.clauseWhereToQuery);
212
    predicatList.add(predicat);
213
    dbParams.setPredicats(predicatList);
214
    
215
    return dbParams;
216
  }
217

    
218
    
219
    private void setQueryInfos(final ResourceModel model){
220
        final List<Info> queryInfos = new ArrayList<Info>();
221
        
222
        Info info = new Info();
223
        info.setName("QUERY_STATUS");
224
        info.setValueAttribute("OK");
225
        queryInfos.add(info);
226
        info = new Info();
227
        info.setName("ADQL query");
228
        String query = this.adqlQuery.replaceAll("\"", "").replaceAll(">","&gt;").replaceAll("<","&lt;");
229
        info.setValueAttribute(query);
230
        
231
        queryInfos.add(info);
232

    
233
        this.dataModel.put("queryInfos", queryInfos);
234
    }
235
    /**
236
   * Sets VOTable parameters coming from administration configuration.
237
   *
238
   * @param dataModel data model to set
239
   * @param model parameters from administration
240
   */
241
  private void setVotableParametersFromConfiguration(final Map dataModel, final ResourceModel model) {
242
    final List<Param> params = new ArrayList<Param>();
243
    setVotableParam(params, model, TableAccessProtocolLibrary.INSTRUMENT, DataType.CHAR);
244
    setVotableParam(params, model, TableAccessProtocolLibrary.SERVICE_NAME, DataType.CHAR);
245
    if (Util.isSet(params)) {
246
      this.dataModel.put("params", params);
247
    }
248
  }
249

    
250
  /**
251
   * Sets Votable Param.
252
   *
253
   * @param params List of params
254
   * @param model data model
255
   * @param parameterName parameter name
256
   * @param datatype datatype
257
   */
258
  private void setVotableParam(final List<Param> params, final ResourceModel model, final String parameterName,
259
          final DataType datatype) {
260
    final String parameterValue = model.getParameterByName(parameterName).getValue();
261
    if (Util.isNotEmpty(parameterValue)) {
262
        final Param param = new Param();
263
        param.setName(parameterName);
264
        param.setValue(parameterValue);
265
        param.setDatatype(datatype);
266
        params.add(param);
267
    }
268
  }
269
    /**
270
    * Provide the mapping between SQL column/concept for a given dictionary.
271
    *
272
    * @param datasetApp Application where this service is attached
273
    * @param dicoToFind Dictionary name to find
274
    * @return Returns a mapping SQL column/Concept
275
    * @throws SitoolsException No mapping has been done or cannot find the dico
276
    */
277
    private List<ColumnConceptMappingDTO> getDicoFromConfiguration(final DataSetApplication datasetApp,
278
          final String dicoToFind) throws SitoolsException {
279
        List<ColumnConceptMappingDTO> colConceptMappingDTOList = null;
280
        
281
        // Get the list of dictionnaries related to the datasetApplication
282
        final List<DictionaryMappingDTO> dicoMappingList = datasetApp.getDictionaryMappings();
283
        if (!Util.isSet(dicoMappingList) || dicoMappingList.isEmpty()) {
284
          throw new SitoolsException("No mapping with VO concepts has been done. please contact the administrator");
285
        }
286

    
287
        // For each dictionary, find the interesting one and return the mapping SQLcolumn/concept
288
        for (DictionaryMappingDTO dicoMappingIter : dicoMappingList) {
289
          final String dicoName = dicoMappingIter.getDictionaryName();
290
          if (dicoToFind.equals(dicoName)) {
291
            colConceptMappingDTOList = dicoMappingIter.getMapping();
292
            break;
293
          }
294
        }
295
        return colConceptMappingDTOList;
296
    }
297
    
298
    
299
    private List<Column> getColumnToQuery(List<Column> columnList){
300
        List<Column> colsToQueryList = new ArrayList<Column>();
301
        String all = this.adqlQuery.split(TableAccessProtocolLibrary.SELECT)[1].split(TableAccessProtocolLibrary.FROM)[0];      
302
        if(this.colsToQuery.size() == 1 && all.contains("*")){
303
            for(Column colCol : columnList){ 
304
                colsToQueryList.add(colCol);
305
            }
306
            return colsToQueryList;
307
        }
308
        for(String col : this.colsToQuery){          
309
            for(Column colCol : columnList){            
310
                if(col.equalsIgnoreCase(colCol.getColumnAlias())){
311
                    colsToQueryList.add(colCol);
312
                }
313
            }
314
        }
315
        
316
        return colsToQueryList;
317
    }
318
    
319
    /**
320
   * Set Fields and columnSqlAliasList.
321
   *
322
   * @param fieldList List of fields to display on the VOTable
323
   * @param colToQuery List of column to query and so to display in VOTable
324
   * @param columnList List of SQL column
325
   * @param mappingList List of SQL column/concept
326
   */
327
  private void setFields(final List<Field> fieldList, final List<String> columnList, final List<ColumnConceptMappingDTO> mappingList, final List<Column> colToQuery) {
328
    
329
    List<Column> colToQuery2 = colToQuery;
330
    if(!isPrimaryKey){
331
        colToQuery2.remove(colToQuery2.size()-1);
332
    }
333
    for(Column col : colToQuery2){
334
        
335
        for (ColumnConceptMappingDTO mappingIter : mappingList) {
336
            if(col.getColumnAlias().equalsIgnoreCase(mappingIter.getColumnAlias())){
337
                
338
                String id = null;
339
                String name = null;
340
                String ucd = null;
341
                String utype = null;
342
                String ref = null;
343
                String datatype = null;
344
                String width = null;
345
                String precision = null;
346
                String unit = null;
347
                String type = null;
348
                String xtype = null;
349
                String arraysize = null;
350
                String descriptionValue = null;
351
                columnList.add(mappingIter.getColumnAlias());
352
                final Concept concept = mappingIter.getConcept();
353
                if (concept.getName() != null) {
354
                  name = concept.getName();
355
                }
356
                if (concept.getPropertyFromName("ID").getValue() != null) {
357
                  id = concept.getPropertyFromName("ID").getValue();
358
                }
359
                if (concept.getPropertyFromName("ucd").getValue() != null) {
360
                  ucd = concept.getPropertyFromName("ucd").getValue();
361
                }
362
                if (concept.getPropertyFromName("utype").getValue() != null) {
363
                  utype = concept.getPropertyFromName("utype").getValue();
364
                }
365
                if (concept.getPropertyFromName("ref").getValue() != null) {
366
                  ref = concept.getPropertyFromName("ref").getValue();
367
                }
368
                if (concept.getPropertyFromName("datatype").getValue() != null) {
369
                  datatype = concept.getPropertyFromName("datatype").getValue();
370
                }
371
                if (concept.getPropertyFromName("width").getValue() != null) {
372
                  width = concept.getPropertyFromName("width").getValue();
373
                }
374
                if (concept.getPropertyFromName("precision").getValue() != null) {
375
                  precision = concept.getPropertyFromName("precision").getValue();
376
                }
377
                if (concept.getPropertyFromName("unit").getValue() != null) {
378
                  unit = concept.getPropertyFromName("unit").getValue();
379
                }
380
                if (concept.getPropertyFromName("type").getValue() != null) {
381
                  type = concept.getPropertyFromName("type").getValue();
382
                }
383
                if (concept.getPropertyFromName("xtype").getValue() != null) {
384
                  xtype = concept.getPropertyFromName("xtype").getValue();
385
                }
386
                if (concept.getPropertyFromName("arraysize").getValue() != null) {
387
                  arraysize = concept.getPropertyFromName("arraysize").getValue();
388
                }
389
                if (concept.getDescription() != null) {
390
                  descriptionValue = concept.getDescription();
391
                }
392
                final Field field = new Field();
393
                field.setID(id);
394
                field.setName(name);
395
                field.setUcd(ucd);
396
                field.setUtype(utype);
397
                field.setRef(ref);
398
                field.setDatatype(DataType.fromValue(datatype));
399
                if (width != null) {
400
                  field.setWidth(BigInteger.valueOf(Long.valueOf(width)));
401
                }
402
                field.setPrecision(precision);
403
                field.setUnit(unit);
404
                field.setType(type);
405
                field.setXtype(xtype);
406
                field.setArraysize(arraysize);
407
                final AnyTEXT anyText = new AnyTEXT();
408
                anyText.getContent().add(descriptionValue);
409
                field.setDESCRIPTION(anyText);
410
                fieldList.add(field);
411
            }
412
        }
413
    }
414
  }
415
  //List<Column> columnList = datasetApp.getDataSet().getColumnModel();
416
  private List<Column> checkPrimaryKeyAndAddItColTQuery(List<Column> columnList, List<Column> colToQuery){
417
      Column colPrimKey = null;
418
      for(Column co : columnList){
419
          if(co.isPrimaryKey()){
420
              colPrimKey = co;
421
          }
422
      }
423
      for(Column col : colToQuery){
424
          if(col.isPrimaryKey()){
425
              isPrimaryKey = true; 
426
          }
427
      }
428
      if(!isPrimaryKey &&  "" != colPrimKey.getColumnAlias()){
429
          colToQuery.add(colPrimKey);
430
      }
431
      
432
      return colToQuery;
433
  }
434
    
435
    private void processQuery(){
436
        try {
437
            // On crée un parser pour transformer notre string query en adql query
438
            ADQLParser parser = new ADQLParser();
439
            ADQLQuery adqlQueryValue = parser.parseQuery(this.adqlQuery);
440
            // On traduit l'adql query en psql query
441
            ADQLTranslator translator = new PostgreSQLTranslator();
442

    
443
            this.psqlQuery = translator.translate(adqlQueryValue);
444
            ctx.getLogger().log(Level.SEVERE, "#### ADQL request : "+this.adqlQuery);
445
            ctx.getLogger().log(Level.SEVERE, "#### PSQL request : "+this.psqlQuery);
446

    
447
            if(this.psqlQuery.contains("Limit ")){
448
                this.clauseLimit = this.psqlQuery.split("Limit ")[1];
449
                this.clauseLimitInt = Integer.parseInt(this.clauseLimit.replaceAll(" ", ""));
450
                this.psqlQuery = this.psqlQuery.split("Limit ")[0];
451
            }else{
452
                this.clauseLimit = null;
453
                this.clauseLimitInt = -1;
454
            }
455

    
456
            this.clauseWhereToQuery = "AND"+ this.psqlQuery.split(TableAccessProtocolLibrary.FROM)[1].split(TableAccessProtocolLibrary.WHERE)[1];  
457

    
458
            String[] colsToQueryTmp = this.psqlQuery.split(TableAccessProtocolLibrary.FROM)[0].split(TableAccessProtocolLibrary.SELECT)[1].split(",");
459
            for(String col : colsToQueryTmp){
460
                if(col.equalsIgnoreCase(TableAccessProtocolLibrary.SELECT_ALL)){
461
                    colsToQuery.add(col.replaceAll(TableAccessProtocolLibrary.BLANCK, ""));
462
                    break;
463
                }else{
464
                    colsToQuery.add(col.split("AS")[0].replaceAll(TableAccessProtocolLibrary.BLANCK, ""));
465
                }
466
            }
467
            if(format == null || format.equalsIgnoreCase("")){
468
                // TO DO
469
            }else{
470
                ctx.getLogger().log(Level.INFO, "format = "+format);
471
            }
472
        } catch (TranslationException ex) {
473
            Logger.getLogger(TableAccessProtocolResponse.class.getName()).log(Level.SEVERE, null, ex);
474
        } catch (ParseException ex) {
475
            Logger.getLogger(TableAccessProtocolResponse.class.getName()).log(Level.SEVERE, null, ex);
476
        }
477
  }
478
    @Override
479
    public final Map getDataModel() {
480
        return Collections.unmodifiableMap(this.dataModel);
481
    }
482
    
483
    // GETTER DE LA CLASSE
484
    public Context getCtx() {
485
        return ctx;
486
    }
487
}