Project

General

Profile

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

git_sitools_idoc / hesiod / javaExt / src / fr / ias / sitools / vo / tap / TableAccessProtocolResponse.java @ 94284c9a

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.astro.representation.DatabaseRequestModel;
16
import fr.cnes.sitools.common.exception.SitoolsException;
17
import fr.cnes.sitools.dataset.DataSetApplication;
18
import fr.cnes.sitools.dataset.converter.business.ConverterChained;
19
import fr.cnes.sitools.dataset.database.DatabaseRequest;
20
import fr.cnes.sitools.dataset.database.DatabaseRequestFactory;
21
import fr.cnes.sitools.dataset.database.DatabaseRequestParameters;
22
import fr.cnes.sitools.dataset.database.common.DataSetExplorerUtil;
23
import fr.cnes.sitools.dataset.dto.ColumnConceptMappingDTO;
24
import fr.cnes.sitools.dataset.dto.DictionaryMappingDTO;
25
import fr.cnes.sitools.dataset.model.Column;
26
import fr.cnes.sitools.dataset.model.Predicat;
27
import fr.cnes.sitools.dictionary.model.Concept;
28
import fr.cnes.sitools.plugins.resources.model.ResourceModel;
29
import fr.cnes.sitools.util.Util;
30
import fr.ias.sitools.vo.representation.DatabaseRequestIasModel;
31
import freemarker.template.TemplateSequenceModel;
32
import java.math.BigInteger;
33

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

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

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

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

    
101

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

    
444
            this.psqlQuery = translator.translate(adqlQueryValue);
445

    
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
}