Statistics
| Revision:

root / trunk / libraries / libGDBMS / src / main / java / com / hardcode / gdbms / engine / data / DataSourceFactory.java @ 38074

History | View | Annotate | Download (54 KB)

1
package com.hardcode.gdbms.engine.data;
2

    
3
import java.io.ByteArrayInputStream;
4
import java.io.File;
5
import java.rmi.server.UID;
6
import java.sql.Connection;
7
import java.sql.SQLException;
8
import java.sql.Statement;
9
import java.util.ArrayList;
10
import java.util.HashMap;
11
import java.util.Hashtable;
12
import java.util.Iterator;
13

    
14
import com.hardcode.driverManager.Driver;
15
import com.hardcode.driverManager.DriverLoadException;
16
import com.hardcode.driverManager.DriverManager;
17
import com.hardcode.driverManager.WriterManager;
18
import com.hardcode.gdbms.driver.exceptions.ReadDriverException;
19
import com.hardcode.gdbms.driver.exceptions.WriteDriverException;
20
import com.hardcode.gdbms.engine.data.db.DBDataSource;
21
import com.hardcode.gdbms.engine.data.db.DBDataSourceFactory;
22
import com.hardcode.gdbms.engine.data.db.DBQuerySourceInfo;
23
import com.hardcode.gdbms.engine.data.db.DBSourceInfo;
24
import com.hardcode.gdbms.engine.data.db.DBTableSourceInfo;
25
import com.hardcode.gdbms.engine.data.db.SpatialDBTableSourceInfo;
26
import com.hardcode.gdbms.engine.data.driver.AlphanumericDBDriver;
27
import com.hardcode.gdbms.engine.data.driver.DBDriver;
28
import com.hardcode.gdbms.engine.data.driver.DriverException;
29
import com.hardcode.gdbms.engine.data.driver.FileDriver;
30
import com.hardcode.gdbms.engine.data.driver.GDBMSDriver;
31
import com.hardcode.gdbms.engine.data.driver.ObjectDriver;
32
import com.hardcode.gdbms.engine.data.file.FileCreationSourceInfo;
33
import com.hardcode.gdbms.engine.data.file.FileDataSource;
34
import com.hardcode.gdbms.engine.data.file.FileDataSourceFactory;
35
import com.hardcode.gdbms.engine.data.file.FileSourceInfo;
36
import com.hardcode.gdbms.engine.data.object.ObjectDataSource;
37
import com.hardcode.gdbms.engine.data.object.ObjectDataSourceFactory;
38
import com.hardcode.gdbms.engine.data.object.ObjectSourceInfo;
39
import com.hardcode.gdbms.engine.data.persistence.DataSourceLayerMemento;
40
import com.hardcode.gdbms.engine.data.persistence.Memento;
41
import com.hardcode.gdbms.engine.data.persistence.OperationLayerMemento;
42
import com.hardcode.gdbms.engine.instruction.Adapter;
43
import com.hardcode.gdbms.engine.instruction.ColRefAdapter;
44
import com.hardcode.gdbms.engine.instruction.CustomAdapter;
45
import com.hardcode.gdbms.engine.instruction.EvaluationException;
46
import com.hardcode.gdbms.engine.instruction.SelectAdapter;
47
import com.hardcode.gdbms.engine.instruction.SemanticException;
48
import com.hardcode.gdbms.engine.instruction.TableRefAdapter;
49
import com.hardcode.gdbms.engine.instruction.UnionAdapter;
50
import com.hardcode.gdbms.engine.instruction.Utilities;
51
import com.hardcode.gdbms.engine.strategies.OperationDataSource;
52
import com.hardcode.gdbms.engine.strategies.Strategy;
53
import com.hardcode.gdbms.engine.strategies.StrategyManager;
54
import com.hardcode.gdbms.parser.Node;
55
import com.hardcode.gdbms.parser.ParseException;
56
import com.hardcode.gdbms.parser.SQLEngine;
57
import com.hardcode.gdbms.parser.SimpleNode;
58

    
59
/**
60
 * Clase factor?a de DataSources. Contiene m?todos para registrar las fuentes de
61
 * datos (addXXXDataSource) y para obtener los DataSource's asociados a estas
62
 * createRandomDataSource. Adem?s proporciona un m?todo para ejecutar consultas
63
 * SQL a partir de la instrucci?n como cadena o a partir de la instrucci?n como
64
 * ?rbol de adaptadores
65
 *
66
 * @author Fernando Gonz?lez Cort?s
67
 */
68
public class DataSourceFactory {
69
        public final static int MANUAL_OPENING = 0;
70

    
71
        public final static int AUTOMATIC_OPENING = 1;
72

    
73
        public final static int DATA_WARE_DIRECT_MODE = 0;
74

    
75
        public final static int DATA_WARE_COHERENT_ROW_ORDER = 1;
76

    
77
        final static int DEFAULT_DELAY = 5000;
78

    
79
        /**
80
         * Asocia los nombres de las tablas con la informaci?n del origen de datos
81
         */
82
        private HashMap tableSource = new HashMap();
83

    
84
        /** Associates a name with the operation layer DataSource with that name */
85
        private HashMap nameOperationDataSource = new HashMap();
86

    
87
        /**
88
         * Asocia los nombres de los or?genes de datos de base de datos con el
89
         * nombre de la tabla en el sistema de gesti?n original
90
         */
91
        private HashMap nameTable = new HashMap();
92

    
93
        private HashMap sourceInfoServerViewInfo = new HashMap();
94

    
95
        private DriverManager dm;
96

    
97
        private ModuleSupport ms = new ModuleSupport();
98

    
99
        private long delay = DEFAULT_DELAY;
100

    
101
        private boolean delegating = false;
102

    
103
        private File tempDir = new File(".");
104

    
105
        private WriterManager wm;
106

    
107
        private Hashtable driversNamesAliases = new Hashtable();
108

    
109
        /**
110
         * Get's a unique id in the tableSource and nameOperationDataSource key sets
111
         *
112
         * @return unique id
113
         */
114
        private String getUID() {
115
                UID uid = new UID();
116

    
117
                String name = "gdbms" + uid.toString().replace(':','_').replace('-','_');
118
                return name;
119
        }
120

    
121
        /**
122
         * Removes all associations between names and data sources of any layer.
123
         */
124
        public void removeAllDataSources() {
125
                tableSource.clear();
126
                nameOperationDataSource.clear();
127
        }
128

    
129
        /**
130
         * Removes the association between the name and the data sources
131
         *
132
         * @param ds
133
         *            Name of the data source to remove
134
         * @throws WriteDriverException TODO
135
         * @throws RuntimeException
136
         *             If there is no data source registered with that name
137
         */
138
        public void remove(DataSource ds) throws WriteDriverException {
139
                String name = ds.getName();
140

    
141
                if (tableSource.remove(name) == null) {
142
                        if (nameOperationDataSource.remove(name) == null) {
143
                                throw new RuntimeException(
144
                                                "No datasource with the name. Data source name changed since the DataSource instance was retrieved?");
145
                        }
146
                }
147
        }
148

    
149
        /**
150
         * Removes de View of the data source 'ds'
151
         *
152
         * @param ds
153
         *            DataSource whose view will be deleted
154
         * @throws ReadDriverException TODO
155
         */
156
        private void clearView(DBDataSource ds) throws ReadDriverException {
157
                DBTableSourceInfo dbInfo = (DBTableSourceInfo) ds.getSourceInfo();
158
                String sql = "DROP VIEW " + dbInfo.tableName;
159
                ds.execute(sql);
160
        }
161

    
162
        /**
163
         * Removes the views created at query delegation
164
         * @throws ReadDriverException TODO
165
         */
166
        public void clearViews() throws ReadDriverException {
167
                Iterator i = sourceInfoServerViewInfo.values().iterator();
168

    
169
                while (i.hasNext()) {
170
                        ServerViewInfo svi = (ServerViewInfo) i.next();
171
                        clearView(svi.adapter);
172
                }
173

    
174
                sourceInfoServerViewInfo.clear();
175
        }
176

    
177
        /**
178
         * A?ade una fuente de datos de objeto. Dado un objeto que implemente la
179
         * interfaz del driver, se toma como fuente de datos y se le asocia un
180
         * nombre
181
         *
182
         * @param rd
183
         *            objeto con la informaci?n
184
         * @param name
185
         *            Nombre de la fuente de datos
186
         */
187
        public void addDataSource(ObjectDriver rd, String name) {
188
                ObjectSourceInfo info = new ObjectSourceInfo();
189
                info.driver = rd;
190
                tableSource.put(name, info);
191
        }
192

    
193
        /**
194
         * A?ade una fuente de datos de objeto. Dado un objeto que implemente la
195
         * interfaz del driver, se toma como fuente de datos y se le asocia un
196
         * nombre
197
         *
198
         * @param rd
199
         *            objeto con la informaci?n
200
         *
201
         * @return the name of the data source
202
         */
203
        public String addDataSource(ObjectDriver rd) {
204
                String ret = getUID();
205
                addDataSource(rd, ret);
206

    
207
                return ret;
208
        }
209

    
210
        /**
211
         * Adds a new data source to the system. If the file doesn't exists it is
212
         * created when necessary
213
         *
214
         * @param driverName
215
         *            Nombre del driver asociado a la fuente de datos
216
         * @param name
217
         *            Nombre de la tabla con el que se har? referencia en las
218
         *            instrucciones
219
         * @param file
220
         *            Fichero con los datos
221
         */
222
        public void createFileDataSource(String driverName, String name,
223
                        String file, String[] fieldNames, int[] fieldTypes) {
224
                FileCreationSourceInfo info = (FileCreationSourceInfo) getFileSourceInfo(
225
                                new FileCreationSourceInfo(), driverName, name, file, false);
226
                info.fieldNames = fieldNames;
227
                info.fieldTypes = fieldTypes;
228
                tableSource.put(name, info);
229
        }
230

    
231
        /**
232
         * A?ade un origen de datos de fichero al sistema. Cuando se cree un
233
         * DataSource mediante la invocaci?n createRandomDataSource(String) se
234
         * crear? una instancia del driver cuyo nombre es driverName
235
         *
236
         * @param driverName
237
         *            Nombre del driver asociado a la fuente de datos
238
         * @param name
239
         *            Nombre de la tabla con el que se har? referencia en las
240
         *            instrucciones
241
         * @param file
242
         *            Fichero con los datos
243
         */
244
        public void addFileDataSource(String driverName, String name, String file) {
245
                FileSourceInfo info = getFileSourceInfo(new FileSourceInfo(),
246
                                driverName, name, file, false);
247
                tableSource.put(name, info);
248
        }
249

    
250
        /**
251
         * Gets a FileSourceInfo with the values passed in the parameters
252
         *
253
         * @param driverName
254
         * @param name
255
         * @param file
256
         *
257
         * @return FileSourceInfo
258
         */
259
        private FileSourceInfo getFileSourceInfo(FileSourceInfo info,
260
                        String driverName, String name, String file, boolean spatial) {
261
                info.name = name;
262
                info.file = file;
263
                info.driverName = driverName;
264
                info.spatial = spatial;
265

    
266
                return info;
267
        }
268

    
269
        /**
270
         * Adds a spatial file data source to the system.
271
         *
272
         * @param driverName
273
         *            driver used to obtain the data
274
         * @param name
275
         *            name of the data source
276
         * @param file
277
         *            file with the data
278
         */
279
        public void addSpatialFileDataSource(String driverName, String name,
280
                        String file) {
281
                FileSourceInfo info = getFileSourceInfo(new FileSourceInfo(),
282
                                driverName, name, file, true);
283
                tableSource.put(name, info);
284
        }
285

    
286
        /**
287
         * Adds a spatial file data source to the system.
288
         *
289
         * @param driverName
290
         *            driver used to obtain the data
291
         * @param file
292
         *            file with the data
293
         *
294
         * @return String Generated name of the added data source
295
         */
296
        public String addSpatialFileDataSource(String driverName, String file) {
297
                String ret = getUID();
298
                addSpatialFileDataSource(driverName, ret, file);
299

    
300
                return ret;
301
        }
302

    
303
        /**
304
         * A?ade un origen de datos de fichero al sistema. Cuando se cree un
305
         * DataSource mediante la invocaci?n createRandomDataSource(String) se
306
         * crear? una instancia del driver cuyo nombre es driverName
307
         *
308
         * @param driverName
309
         *            Nombre del driver asociado a la fuente de datos
310
         * @param file
311
         *            Fichero con los datos
312
         *
313
         * @return Nombre ?nico que se asocia a la tabla
314
         */
315
        public String addFileDataSource(String driverName, String file) {
316
                String ret = getUID();
317
                addFileDataSource(driverName, ret, file);
318

    
319
                return ret;
320
        }
321

    
322
        /**
323
         * Obtiene la informaci?n de la fuente de datos cuyo nombre se pasa como
324
         * par?metro
325
         *
326
         * @param dataSourceName
327
         *            Nombre de la base de datos
328
         *
329
         * @return Debido a las distintas formas en las que se puede registrar un
330
         *         datasource, se devuelve un Object, que podr? ser una instancia de
331
         *         DataSourceFactory.FileDriverInfo, DataSourceFactory.DBDriverInfo
332
         *         o ReadDriver
333
         */
334
        public SourceInfo getDriverInfo(String dataSourceName) {
335
                return (SourceInfo) tableSource.get(dataSourceName);
336
        }
337

    
338
        /**
339
         * Gets the information of all data sources registered in the system
340
         *
341
         * @return DriverInfo[]
342
         */
343
        public SourceInfo[] getDriverInfos() {
344
                ArrayList ret = new ArrayList();
345
                Iterator it = tableSource.values().iterator();
346

    
347
                while (it.hasNext()) {
348
                        SourceInfo di = (SourceInfo) it.next();
349
                        ret.add(di);
350
                }
351

    
352
                return (SourceInfo[]) ret.toArray(new SourceInfo[0]);
353
        }
354

    
355
        /**
356
         * A?ade un origen de datos de base de datos al sistema
357
         *
358
         * @param name
359
         *            Nombre de la tabla con el que se har? referencia en las
360
         *            instrucciones
361
         * @param host
362
         *            Cadena de conexi?n para conectar con el sgbd donde se
363
         *            encuentra la tabla
364
         * @param port
365
         *            Nombre del sgbd capaz de ejecutar SQL en el que reside la
366
         *            tabla. Generalmente ser? la parte de la cadena de conexi?n
367
         *            correspondiente a host, puerto y nombre de la base de datos
368
         * @param user
369
         *            Nombre de usuario. Null para acceso sin usuario
370
         * @param password
371
         *            Si el usuario es null se ignora el password
372
         * @param dbName
373
         *            Nombre de la base de datos a la que se accede
374
         * @param tableName
375
         *            Nombre de la tabla en la base de datos
376
         * @param driverInfo
377
         *            Informaci?n para saber qu? driver debe acceder a la
378
         *            informaci?n. Se escoger? el driver cuyo valor de retorno del
379
         *            m?todo getType coincida con este valor
380
         */
381
        public void addDBDataSourceByTable(String name, String host, int port,
382
                        String user, String password, String dbName, String tableName,
383
                        String driverInfo) {
384
                DBTableSourceInfo info = new DBTableSourceInfo();
385
                fillDBTableSourceInfo(info, name, host, port, user, password, dbName,
386
                                tableName, driverInfo);
387
                tableSource.put(name, info);
388
                nameTable.put(name, tableName);
389
        }
390

    
391

    
392
        /**
393
         * A?ade un origen de datos de base de datos al sistema
394
         *
395
         * @param name
396
         *            Nombre de la tabla con el que se har? referencia en las
397
         *            instrucciones
398
         * @param Connection
399
         *            Conexion JDBC a la Base de datos ya abierta (el DataSource
400
         *            la usara, pero no la abrira/cerrara)
401
         * @param tableName
402
         *            Nombre de la tabla en la base de datos
403
         * @param driverInfo
404
         *            Informaci?n para saber qu? driver debe acceder a la
405
         *            informaci?n. Se escoger? el driver cuyo valor de retorno del
406
         *            m?todo getType coincida con este valor
407
         */
408
        public void addDBDataSourceByTable(String name, Connection connection, String tableName,
409
                        String driverInfo) {
410
                DBTableSourceInfo info = new DBTableSourceInfo();
411
                fillDBTableSourceInfo(info, name, connection,
412
                                tableName, driverInfo);
413
                tableSource.put(name, info);
414
                nameTable.put(name, tableName);
415
        }
416

    
417

    
418

    
419

    
420
        /**
421
         * Fills the info struct with the values passed in the parameters
422
         *
423
         * @param info
424
         *            struct to populate
425
         * @param name
426
         *            Name of the data source
427
         * @param host
428
         *            host where the data is
429
         * @param port
430
         *            port number
431
         * @param user
432
         *            user name or null.
433
         * @param password
434
         *            if user name is null is ignored
435
         * @param dbName
436
         *            database name
437
         * @param tableName
438
         *            table name
439
         * @param driverInfo
440
         *            name of the driver used to access the data
441
         */
442
        private void fillDBTableSourceInfo(DBTableSourceInfo info, String name,
443
                        String host, int port, String user, String password, String dbName,
444
                        String tableName, String driverInfo) {
445
                info.name = name;
446
                info.host = host;
447
                info.port = port;
448
                info.user = user;
449
                info.password = password;
450
                info.dbName = dbName;
451
                info.dbms = host + ":" + port + "/" + dbName + "," + user + ","
452
                                + password;
453
                info.tableName = tableName;
454
                info.driverName = driverInfo;
455
        }
456

    
457
        /**
458
         * Fills the info struct with the values passed in the parameters
459
         *
460
         * @param info
461
         *            struct to populate
462
         * @param name
463
         *            Name of the data source
464
         * @param Connection
465
         *            JDBC opened data base Connection
466
         * @param port
467
         *            port number
468
         * @param user
469
         *            user name or null.
470
         * @param password
471
         *            if user name is null is ignored
472
         * @param dbName
473
         *            database name
474
         * @param tableName
475
         *            table name
476
         * @param driverInfo
477
         *            name of the driver used to access the data
478
         */
479
        private void fillDBTableSourceInfo(DBTableSourceInfo info, String name,
480
                        Connection conection, String tableName, String driverInfo) {
481
                info.name = name;
482
                info.host = "";
483
                info.port = -1;
484
                info.user = "";
485
                info.password = "";
486
                info.dbName = "";
487
                info.dbms = "";
488
                info.connection= conection;
489
                info.tableName = tableName;
490
                info.driverName = driverInfo;
491
        }
492

    
493

    
494

    
495

    
496

    
497

    
498

    
499

    
500
        /**
501
         * Adds a spatial database data source
502
         *
503
         * @param name
504
         *            Name of the data source
505
         * @param host
506
         *            host where the data is
507
         * @param port
508
         *            port number
509
         * @param user
510
         *            user name or null.
511
         * @param password
512
         *            if user name is null is ignored
513
         * @param dbName
514
         *            database name
515
         * @param tableName
516
         *            table name
517
         * @param geometryFieldName
518
         *            name of the field that has the geometry
519
         * @param driverInfo
520
         *            name of the driver used to access the data
521
         */
522
        public void addSpatialDBDataSource(String name, String host, int port,
523
                        String user, String password, String dbName, String tableName,
524
                        String geometryFieldName, String driverInfo) {
525
                SpatialDBTableSourceInfo info = new SpatialDBTableSourceInfo();
526
                fillDBTableSourceInfo(info, name, host, port, user, password, dbName,
527
                                tableName, driverInfo);
528
                info.geometryField = geometryFieldName;
529
                tableSource.put(name, info);
530
                nameTable.put(name, tableName);
531
        }
532

    
533

    
534
        /**
535
         * Adds a spatial database data source
536
         *
537
         * @param connection
538
         *
539
         * @param tableName
540
         *            table name
541
         * @param geometryFieldName
542
         *            name of the field that has the geometry
543
         * @param driverInfo
544
         *            name of the driver used to access the data
545
         */
546
        public void addSpatialDBDataSource(String name, Connection connection, String tableName,
547
                        String geometryFieldName, String driverInfo) {
548
                SpatialDBTableSourceInfo info = new SpatialDBTableSourceInfo();
549
                fillDBTableSourceInfo(info, name, connection,
550
                                tableName, driverInfo);
551
                info.geometryField = geometryFieldName;
552
                tableSource.put(name, info);
553
                nameTable.put(name, tableName);
554
        }
555

    
556

    
557

    
558

    
559

    
560

    
561

    
562

    
563
        /**
564
         * Adds a spatial database data source
565
         *
566
         * @param host
567
         *            host where the data is
568
         * @param port
569
         *            port number
570
         * @param user
571
         *            user name or null.
572
         * @param password
573
         *            if user name is null is ignored
574
         * @param dbName
575
         *            database name
576
         * @param tableName
577
         *            table name
578
         * @param geometryFieldName
579
         *            name of the field that has the geometry
580
         * @param driverInfo
581
         *            name of the driver used to access the data
582
         *
583
         * @return generated name of the added data source
584
         */
585
        public String addSpatialDBDataSource(String host, int port, String user,
586
                        String password, String dbName, String tableName,
587
                        String geometryFieldName, String driverInfo) {
588
                String ret = getUID();
589
                addSpatialDBDataSource(ret, host, port, user, password, dbName,
590
                                tableName, geometryFieldName, driverInfo);
591

    
592
                return ret;
593
        }
594

    
595

    
596
        /**
597
         * Adds a spatial database data source
598
         *
599
         * @param connection
600
         *
601
         * @param tableName
602
         *            table name
603
         * @param geometryFieldName
604
         *            name of the field that has the geometry
605
         * @param driverInfo
606
         *            name of the driver used to access the data
607
         *
608
         * @return generated name of the added data source
609
         */
610
        public String addSpatialDBDataSource(Connection connection, String tableName,
611
                        String geometryFieldName, String driverInfo) {
612
                String ret = getUID();
613
                addSpatialDBDataSource(ret, connection,
614
                                tableName, geometryFieldName, driverInfo);
615

    
616
                return ret;
617
        }
618

    
619

    
620

    
621

    
622

    
623
        /**
624
         * A?ade un origen de datos de base de datos al sistema
625
         *
626
         * @param host
627
         *            Cadena de conexi?n para conectar con el sgbd donde se
628
         *            encuentra la tabla
629
         * @param port
630
         *            Nombre del sgbd capaz de ejecutar SQL en el que reside la
631
         *            tabla. Generalmente ser? la parte de la cadena de conexi?n
632
         *            correspondiente a host, puerto y nombre de la base de datos
633
         * @param user
634
         *            Nombre de usuario. Null para acceso sin usuario
635
         * @param password
636
         *            Si el usuario es null se ignora el password
637
         * @param dbName
638
         *            Nombre de la base de datos a la que se accede
639
         * @param tableName
640
         *            Nombre de la tabla en la base de datos
641
         * @param driverInfo
642
         *            Informaci?n para saber qu? driver debe acceder a la
643
         *            informaci?n. Se escoger? el driver cuyo valor de retorno del
644
         *            m?todo getType coincida con este valor
645
         *
646
         * @return Nombre de la tabla con el que se har? referencia en las
647
         *         instrucciones
648
         */
649
        public String addDBDataSourceByTable(String host, int port, String user,
650
                        String password, String dbName, String tableName, String driverInfo) {
651
                String name = getUID();
652
                addDBDataSourceByTable(name, host, port, user, password, dbName,
653
                                tableName, driverInfo);
654

    
655
                return name;
656
        }
657

    
658

    
659

    
660
        /**
661
         * A?ade un origen de datos de base de datos al sistema
662
         *
663
         * @param connection
664
         *            Conexion JDBC abierta a la base de datos(el DataSource
665
         *            usara la conexion, pero no la abrira/cerrara)
666
         * @param tableName
667
         *            Nombre de la tabla en la base de datos
668
         * @param driverInfo
669
         *            Informaci?n para saber qu? driver debe acceder a la
670
         *            informaci?n. Se escoger? el driver cuyo valor de retorno del
671
         *            m?todo getType coincida con este valor
672
         *
673
         * @return Nombre de la tabla con el que se har? referencia en las
674
         *         instrucciones
675
         */
676
        public String addDBDataSourceByTable(Connection connection, String tableName, String driverInfo) {
677
                String name = getUID();
678
                addDBDataSourceByTable(name, connection,
679
                                tableName, driverInfo);
680

    
681
                return name;
682
        }
683

    
684

    
685

    
686

    
687

    
688

    
689

    
690

    
691

    
692

    
693

    
694

    
695

    
696

    
697

    
698

    
699

    
700

    
701

    
702

    
703

    
704
        /**
705
         * A?ade un origen de datos de base de datos al sistema
706
         *
707
         * @param name
708
         *            Nombre de la tabla con el que se har? referencia en las
709
         *            instrucciones
710
         * @param host
711
         *            Cadena de conexi?n para conectar con el sgbd donde se
712
         *            encuentra la tabla
713
         * @param port
714
         *            Nombre del sgbd capaz de ejecutar SQL en el que reside la
715
         *            tabla. Generalmente ser? la parte de la cadena de conexi?n
716
         *            correspondiente a host, puerto y nombre de la base de datos
717
         * @param user
718
         *            Nombre de usuario. Null para acceso sin usuario
719
         * @param password
720
         *            Si el usuario es null se ignora el password
721
         * @param dbName
722
         *            Nombre de la base de datos a la que se accede
723
         * @param sql
724
         *            Instrucci?n SQL que define los datos de la tabla
725
         * @param driverInfo
726
         *            Informaci?n para saber qu? driver debe acceder a la
727
         *            informaci?n. Se escoger? el driver cuyo valor de retorno del
728
         *            m?todo getType coincida con este valor
729
         */
730
        public void addDBDataSourceBySQL(String name, String host, int port,
731
                        String user, String password, String dbName, String sql,
732
                        String driverInfo) {
733
                DBQuerySourceInfo info = new DBQuerySourceInfo();
734
                info.name = name;
735
                info.host = host;
736
                info.port = port;
737
                info.user = user;
738
                info.password = password;
739
                info.dbName = dbName;
740
                info.dbms = host + ":" + port + "/" + dbName + "," + user + ","
741
                                + password;
742
                info.sql = sql;
743
                info.driverName = driverInfo;
744
                tableSource.put(name, info);
745
        }
746

    
747

    
748
        /**
749
         * A?ade un origen de datos de base de datos al sistema
750
         *
751
         * @param name
752
         *            Nombre de la tabla con el que se har? referencia en las
753
         *            instrucciones
754
         * @param connection
755
         *            Conexion de JDBC a la base de datos ya abierta (el
756
         *            DataSource la usara, pero no la abrira/cerrara)
757
         * @param sql
758
         *            Instrucci?n SQL que define los datos de la tabla
759
         * @param driverInfo
760
         *            Informaci?n para saber qu? driver debe acceder a la
761
         *            informaci?n. Se escoger? el driver cuyo valor de retorno del
762
         *            m?todo getType coincida con este valor
763
         */
764
        public void addDBDataSourceBySQL(String name, Connection connection, String sql,
765
                        String driverInfo) {
766
                DBQuerySourceInfo info = new DBQuerySourceInfo();
767
                info.name = name;
768
                info.host = "";
769
                info.port = -1;
770
                info.user = "";
771
                info.password = "";
772
                info.dbName = "";
773
                info.dbms ="";
774
                info.connection = connection;
775
                info.sql = sql;
776
                info.driverName = driverInfo;
777
                tableSource.put(name, info);
778
        }
779

    
780

    
781

    
782

    
783

    
784

    
785

    
786
        /**
787
         * A?ade un origen de datos de base de datos al sistema
788
         *
789
         * @param host
790
         *            Cadena de conexi?n para conectar con el sgbd donde se
791
         *            encuentra la tabla
792
         * @param port
793
         *            Nombre del sgbd capaz de ejecutar SQL en el que reside la
794
         *            tabla. Generalmente ser? la parte de la cadena de conexi?n
795
         *            correspondiente a host, puerto y nombre de la base de datos
796
         * @param user
797
         *            Nombre de usuario. Null para acceso sin usuario
798
         * @param password
799
         *            Si el usuario es null se ignora el password
800
         * @param dbName
801
         *            Nombre de la base de datos a la que se accede
802
         * @param sql
803
         *            Instrucci?n SQL que define los datos de la tabla
804
         * @param driverInfo
805
         *            Informaci?n para saber qu? driver debe acceder a la
806
         *            informaci?n. Se escoger? el driver cuyo valor de retorno del
807
         *            m?todo getType coincida con este valor
808
         *
809
         * @return Nombre de la tabla con el que se har? referencia en las
810
         *         instrucciones
811
         */
812
        public String addDBDataSourceBySQL(String host, int port, String user,
813
                        String password, String dbName, String sql, String driverInfo) {
814
                String ret = getUID();
815
                addDBDataSourceBySQL(ret, host, port, user, password, dbName, sql,
816
                                driverInfo);
817

    
818
                return ret;
819
        }
820

    
821
        /**
822
         * A?ade un origen de datos de base de datos al sistema
823
         *
824
         * @param connection
825
         *            Conexion de JDBC ya abierta (el DataSource la usara
826
         *            pero no la abrira/cerrara)
827
         * @param sql
828
         *            Instrucci?n SQL que define los datos de la tabla
829
         * @param driverInfo
830
         *            Informaci?n para saber qu? driver debe acceder a la
831
         *            informaci?n. Se escoger? el driver cuyo valor de retorno del
832
         *            m?todo getType coincida con este valor
833
         *
834
         * @return Nombre de la tabla con el que se har? referencia en las
835
         *         instrucciones
836
         */
837
        public String addDBDataSourceBySQL(Connection connection, String sql, String driverInfo) {
838
                String ret = getUID();
839
                addDBDataSourceBySQL(ret, connection, sql,
840
                                driverInfo);
841

    
842
                return ret;
843
        }
844

    
845

    
846
        /**
847
         * Cambia el nombre de una fuente de datos. Las consultas SQL que se
848
         * ejecuten con el nombre anterior fallar?n
849
         *
850
         * @param oldName
851
         *            Nombre actual de la fuente de datos que se quiere cambiar
852
         * @param newName
853
         *            Nombre que se le quiere poner a la fuente de datos
854
         *
855
         * @throws NoSuchTableException
856
         *             Si no hay ninguna fuente de datos de nombre 'oldName'
857
         */
858
        public void changeDataSourceName(String oldName, String newName)
859
                        throws NoSuchTableException {
860
                SourceInfo di = (SourceInfo) tableSource.remove(oldName);
861

    
862
                if (di == null) {
863
                        // may be a operation layer DataSource
864
                        OperationDataSource ret = (OperationDataSource) nameOperationDataSource
865
                                        .remove(oldName);
866
                        if (ret == null){
867
                                throw new NoSuchTableException(oldName);
868

    
869
                        }
870
                        nameOperationDataSource.put(newName, ret);
871

    
872

    
873
                } else {
874

    
875
                        tableSource.put(newName, di);
876
                }
877
        }
878

    
879
        /**
880
         * Gets the data source passed by adding the AutomaticDataSource decorator
881
         * if factory mode is AUTOMATIC.
882
         *
883
         * @param ds
884
         *            DataSource
885
         * @param mode
886
         *            opening mode
887
         *
888
         * @return DataSource
889
         */
890
        private DataSource getModedDataSource(DataSource ds, int mode) {
891
                if (mode == AUTOMATIC_OPENING) {
892
                        return new AutomaticDataSource(ds, delay);
893
                } else {
894
                        return ds;
895
                }
896
        }
897

    
898
        /**
899
         * Sets the minimum delay between accesses needed to close the DataSource.
900
         * If accesses are delayed more than 'delay' the DataSource MAY be closed.
901
         * Only applies when the mode is set to AUTOMATIC_MODE
902
         *
903
         * @param delay
904
         *            time un milliseconds
905
         */
906
        public void setClosingDelay(long delay) {
907
                this.delay = delay;
908
        }
909

    
910
        /**
911
         * Dado el nombre de una tabla, se busca la fuente de datos asociada a dicha
912
         * tabla y se obtiene un datasource adecuado en funcion del tipo de fuente
913
         * de datos accediendo al subsistema de drivers
914
         *
915
         * @param tableName
916
         *            Nombre de la fuente de datos
917
         *
918
         * @return DataSource que accede a dicha fuente
919
         * @throws DriverLoadException
920
         * @throws NoSuchTableException
921
         * @throws ReadDriverException TODO
922
         */
923
        public DataSource createRandomDataSource(String tableName)
924
                        throws DriverLoadException, NoSuchTableException, ReadDriverException {
925
                return createRandomDataSource(tableName, tableName, MANUAL_OPENING);
926
        }
927

    
928
        /**
929
         * Dado el nombre de una tabla, se busca la fuente de datos asociada a dicha
930
         * tabla y se obtiene un datasource adecuado en funcion del tipo de fuente
931
         * de datos accediendo al subsistema de drivers
932
         *
933
         * @param tableName
934
         *            Nombre de la fuente de datos
935
         * @param mode
936
         *            opening mode: AUTOMATIC_OPENING -> the DataSource opens
937
         *            automatically and closes after a while. It can be closed
938
         *            manually. MANUAL_OPENING -> the DataSource opens and closes
939
         *            manually
940
         *
941
         * @return DataSource que accede a dicha fuente
942
         * @throws DriverLoadException
943
         * @throws NoSuchTableException
944
         * @throws ReadDriverException TODO
945
         */
946
        public DataSource createRandomDataSource(String tableName, int mode)
947
                        throws DriverLoadException, NoSuchTableException, ReadDriverException {
948
                return createRandomDataSource(tableName, tableName, mode);
949
        }
950

    
951
        /**
952
         * Dado el nombre de una tabla, se busca la fuente de datos asociada a dicha
953
         * tabla y se obtiene un datasource adecuado en funcion del tipo de fuente
954
         * de datos accediendo al subsistema de drivers. Se utiliza internamente
955
         * como nombre del DataSource el alias que se pasa como par?metro
956
         *
957
         * @param tableName
958
         *            Nombre de la fuente de datos
959
         * @param tableAlias
960
         *            Alias que tiene el DataSource en una instrucci?n
961
         *
962
         * @return DataSource que accede a dicha fuente de datos si la fuente de
963
         *         datos es alfanum?rica o SpatialDataSource si la fuente de datos
964
         *         es espacial
965
         * @throws NoSuchTableException
966
         *             Si no hay una fuente de datos registrada con ese nombre
967
         * @throws DriverLoadException
968
         *             Si hay alg?n error con el sistema de carga de drivers
969
         * @throws ReadDriverException TODO
970
         * @throws RuntimeException
971
         *             bug
972
         */
973
        public DataSource createRandomDataSource(String tableName, String tableAlias)
974
                        throws NoSuchTableException, DriverLoadException, ReadDriverException {
975
                return createRandomDataSource(tableName, tableAlias, MANUAL_OPENING);
976
        }
977

    
978
        /**
979
         * Dado el nombre de una tabla, se busca la fuente de datos asociada a dicha
980
         * tabla y se obtiene un datasource adecuado en funcion del tipo de fuente
981
         * de datos accediendo al subsistema de drivers. Se utiliza internamente
982
         * como nombre del DataSource el alias que se pasa como par?metro
983
         *
984
         * @param tableName
985
         *            Nombre de la fuente de datos
986
         * @param tableAlias
987
         *            Alias que tiene el DataSource en una instrucci?n
988
         * @param mode
989
         *            openning mode
990
         *
991
         * @return DataSource que accede a dicha fuente de datos si la fuente de
992
         *         datos es alfanum?rica o SpatialDataSource si la fuente de datos
993
         *         es espacial
994
         * @throws NoSuchTableException
995
         *             Si no hay una fuente de datos registrada con ese nombre
996
         * @throws DriverLoadException
997
         *             Si hay alg?n error con el sistema de carga de drivers
998
         * @throws ReadDriverException TODO
999
         * @throws RuntimeException
1000
         *             bug
1001
         */
1002
        public DataSource createRandomDataSource(String tableName,
1003
                        String tableAlias, int mode) throws NoSuchTableException,
1004
                        DriverLoadException, ReadDriverException {
1005
                Object o = tableSource.get(tableName);
1006

    
1007
                if (o == null) {
1008
                        // may be a operation layer DataSource
1009
                        OperationDataSource ret = (OperationDataSource) nameOperationDataSource
1010
                                        .get(tableName);
1011

    
1012
                        if (ret != null) {
1013
                                ret.setName(tableAlias);
1014

    
1015
                                return getModedDataSource(ret, mode);
1016
                        }
1017

    
1018
                        // table not found
1019
                        throw new NoSuchTableException(tableName);
1020
                }
1021

    
1022
                SourceInfo info = (SourceInfo) o;
1023
                info.name = tableAlias;
1024

    
1025
                if (info instanceof FileSourceInfo) {
1026
                        FileSourceInfo fileInfo = (FileSourceInfo) info;
1027

    
1028
                        Driver d = this.getDriver(fileInfo.driverName);
1029

    
1030
                        if (info instanceof FileCreationSourceInfo) {
1031
                                FileCreationSourceInfo creationInfo = (FileCreationSourceInfo) info;
1032
                                        if (!new File(creationInfo.file).exists()) {
1033
                                                ((FileDriver) d).createSource(creationInfo.file,
1034
                                                                creationInfo.fieldNames,
1035
                                                                creationInfo.fieldTypes);
1036
                                        }
1037
                        }
1038

    
1039
                        FileDataSource adapter;
1040

    
1041
                        if (fileInfo.spatial) {
1042
                                adapter = FileDataSourceFactory.newSpatialInstance();
1043
                        } else {
1044
                                adapter = FileDataSourceFactory.newInstance();
1045
                        }
1046

    
1047
                        ((GDBMSDriver) d).setDataSourceFactory(this);
1048
                        adapter.setDriver((FileDriver) d);
1049
                        adapter.setSourceInfo(fileInfo);
1050
                        adapter.setDataSourceFactory(this);
1051

    
1052
                        return getModedDataSource(adapter, mode);
1053
                } else if (info instanceof DBQuerySourceInfo) {
1054
                        DBQuerySourceInfo dbInfo = (DBQuerySourceInfo) info;
1055

    
1056
                        String driverInfo = dbInfo.driverName;
1057
                        Driver d = this.getDriver(driverInfo);
1058

    
1059
                        ((GDBMSDriver) d).setDataSourceFactory(this);
1060
                        return getModedDataSource(getDataSourceByQuery(dbInfo.sql,
1061
                                        (AlphanumericDBDriver) d, dbInfo), mode);
1062
                } else if (info instanceof DBTableSourceInfo) {
1063
                        DBTableSourceInfo dbInfo = (DBTableSourceInfo) info;
1064

    
1065
                        String driverInfo = dbInfo.driverName;
1066
                        Driver d = this.getDriver(driverInfo);
1067

    
1068
                        DBDataSource adapter;
1069

    
1070
                        if (info instanceof SpatialDBTableSourceInfo) {
1071
                                adapter = DBDataSourceFactory.newSpatialDataSourceInstance();
1072
                        } else {
1073
                                adapter = DBDataSourceFactory.newDataSourceInstance();
1074
                        }
1075

    
1076
                        ((GDBMSDriver) d).setDataSourceFactory(this);
1077
                        adapter.setDriver((DBDriver) d);
1078
                        adapter.setSourceInfo(dbInfo);
1079
                        adapter.setDataSourceFactory(this);
1080

    
1081
                        return getModedDataSource(adapter, mode);
1082
                } else if (info instanceof ObjectSourceInfo) {
1083
                        ObjectSourceInfo driverInfo = (ObjectSourceInfo) o;
1084
                        ObjectDataSource adapter = ObjectDataSourceFactory.newInstance();
1085
                        driverInfo.driver.setDataSourceFactory(this);
1086
                        adapter.setDriver(driverInfo.driver);
1087
                        adapter.setSourceInfo((ObjectSourceInfo) driverInfo);
1088
                        adapter.setDataSourceFactory(this);
1089

    
1090
                        return getModedDataSource(adapter, mode);
1091
                } else {
1092
                        throw new RuntimeException();
1093
                }
1094
        }
1095

    
1096
        /**
1097
         * Creates a DataSource from a memento object with the manual opening mode
1098
         *
1099
         * @param m
1100
         *            memento
1101
         *
1102
         * @return DataSource
1103
         *
1104
         * @throws RuntimeException
1105
         *             If the DataSource class cannot be instatiated
1106
         */
1107
        public DataSource createRandomDataSource(Memento m) {
1108
                return createRandomDataSource(m, DataSourceFactory.MANUAL_OPENING);
1109
        }
1110

    
1111
        /**
1112
         * Creates a DataSource from a memento object with the specified opening
1113
         * mode
1114
         *
1115
         * @param m
1116
         *            memento
1117
         * @param mode
1118
         *            opening mode
1119
         *
1120
         * @return DataSource
1121
         *
1122
         * @throws RuntimeException
1123
         *             If the DataSource class cannot be instatiated
1124
         */
1125
        public DataSource createRandomDataSource(Memento m, int mode) {
1126
                if (m instanceof DataSourceLayerMemento) {
1127
                        DataSourceLayerMemento mem = (DataSourceLayerMemento) m;
1128

    
1129
                        try {
1130
                                return createRandomDataSource(mem.getTableName(), mem
1131
                                                .getTableAlias(), mode);
1132
                        } catch (DriverLoadException e) {
1133
                                throw new RuntimeException(
1134
                                                "La informaci?n guardada no es consistente", e);
1135
                        } catch (NoSuchTableException e) {
1136
                                throw new RuntimeException(
1137
                                                "La informaci?n guardada no es consistente", e);
1138
                        } catch (ReadDriverException e) {
1139
                                throw new RuntimeException(e);
1140
                        }
1141
                } else {
1142
                        OperationLayerMemento mem = (OperationLayerMemento) m;
1143

    
1144
                        try {
1145
                                return executeSQL(mem.getSql(), mode);
1146
                        } catch (DriverLoadException e) {
1147
                                throw new RuntimeException(
1148
                                                "La informaci?n guardada no es consistente", e);
1149
                        } catch (ParseException e) {
1150
                                throw new RuntimeException(
1151
                                                "La informaci?n guardada no es consistente", e);
1152
                        } catch (SemanticException e) {
1153
                                throw new RuntimeException(
1154
                                                "La informaci?n guardada no es consistente", e);
1155
                        } catch (EvaluationException e) {
1156
                                throw new RuntimeException(
1157
                                                "La informaci?n guardada no es consistente", e);
1158
                        } catch (ReadDriverException e) {
1159
                                throw new RuntimeException(
1160
                                                "La informaci?n guardada no es consistente", e);
1161
                        }
1162
                }
1163
        }
1164

    
1165
        /**
1166
         * Devuelve true si todas las tablas provienen del mismo data base
1167
         * management system
1168
         *
1169
         * @param tables
1170
         *            Array de tablas
1171
         *
1172
         * @return boolean
1173
         */
1174
        private boolean sameDBMS(DataSource[] tables) {
1175
                if (!(tables[0] instanceof DBDataSource)) {
1176
                        return false;
1177
                }
1178

    
1179
                String dbms = ((DBDataSource) tables[0]).getDBMS();
1180

    
1181
                for (int i = 1; i < tables.length; i++) {
1182
                        if (!(tables[i] instanceof DBDataSource)) {
1183
                                return false;
1184
                        }
1185

    
1186
                        if (!dbms.equals(((DBDataSource) tables[1]).getDBMS())) {
1187
                                return false;
1188
                        }
1189
                }
1190

    
1191
                return true;
1192
        }
1193

    
1194
        /**
1195
         * A partir de una instrucci?n select se encarga de obtener el DataSource
1196
         * resultado de la ejecuci?n de dicha instrucci?n
1197
         *
1198
         * @param instr
1199
         *            Instrucci?n select origen del datasource
1200
         * @param mode
1201
         *            opening mode
1202
         *
1203
         * @return DataSource que accede a los datos resultado de ejecutar la select
1204
         * @throws DriverLoadException
1205
         * @throws SemanticException
1206
         *             Si la instrucci?n tiene errores sem?nticos
1207
         * @throws EvaluationException
1208
         *             If there's an error evaluating any expression
1209
         * @throws ReadDriverException TODO
1210
         */
1211
        public DataSource createRandomDataSource(SelectAdapter instr, int mode)
1212
                        throws DriverLoadException, SemanticException,
1213
                        EvaluationException, ReadDriverException {
1214
                return getModedDataSource(getDataSource(instr), mode);
1215
        }
1216

    
1217
        /**
1218
         * Creates a view in the database management system that hosts the data
1219
         * source 'dbds'. The view is defined by the sql parameter
1220
         *
1221
         * @param dbds
1222
         *            DataSource used to execute the query
1223
         * @param sql
1224
         *            The SQL query defining the view
1225
         *
1226
         * @return Name of the view
1227
         * @throws ReadDriverException TODO
1228
         * @throws DriverException
1229
         *             If the view cannot be created
1230
         */
1231
        private String getView(DBDataSource dbds, String sql)
1232
                        throws ReadDriverException {
1233
                ServerViewInfo svi = (ServerViewInfo) sourceInfoServerViewInfo.get(dbds
1234
                                .getSourceInfo());
1235

    
1236
                /*
1237
                 * Return the view name if it's already created or create the view if
1238
                 * it's not created
1239
                 */
1240
                if (svi != null) {
1241
                        return svi.viewName;
1242
                } else {
1243
                        // create the view
1244
                        String viewName = getUID();
1245
                        String viewQuery = "CREATE VIEW " + viewName + " AS " + sql;
1246
                        dbds.execute(viewQuery);
1247

    
1248
                        // Register the view created
1249
                        sourceInfoServerViewInfo.put(dbds.getSourceInfo(),
1250
                                        new ServerViewInfo(dbds, viewName));
1251

    
1252
                        return viewName;
1253
                }
1254
        }
1255

    
1256
        /**
1257
         * Gets a DataSource implementation with the sql instruction as the data
1258
         * source by creating a view in the underlaying datasource management system
1259
         *
1260
         * @param sql
1261
         *            Instruction definig the data source
1262
         * @param driver
1263
         *            Driver used to access the data source
1264
         * @param dbInfo
1265
         *            data source info
1266
         *
1267
         * @return DataSource
1268
         * @throws ReadDriverException TODO
1269
         */
1270
        private DBDataSource getDataSourceByQuery(String sql,
1271
                        AlphanumericDBDriver driver, DBTableSourceInfo dbInfo)
1272
                        throws ReadDriverException {
1273
                // Create the adapter
1274
                DBDataSource adapter = DBDataSourceFactory.newDataSourceInstance();
1275

    
1276
                // set the driver
1277
                adapter.setDriver(driver);
1278

    
1279
                // Create the query
1280
                adapter.setSourceInfo(dbInfo);
1281

    
1282
                // Gets the view name
1283
                String viewName = getView(adapter, sql);
1284

    
1285
                // Complete the source info with the view name
1286
                dbInfo.tableName = viewName;
1287

    
1288
                // Register the name association
1289
                nameTable.put(dbInfo.name, viewName);
1290

    
1291
                // setup the adapter
1292
                adapter.setSourceInfo(dbInfo);
1293
                adapter.setDataSourceFactory(this);
1294

    
1295
                return adapter;
1296
        }
1297

    
1298
        /**
1299
         * A partir de una instrucci?n select se encarga de obtener el DataSource
1300
         * resultado de la ejecuci?n de dicha instrucci?n
1301
         *
1302
         * @param instr
1303
         *            Instrucci?n select origen del datasource
1304
         *
1305
         * @return DataSource que accede a los datos resultado de ejecutar la select
1306
         * @throws SemanticException
1307
         * @throws EvaluationException
1308
         * @throws ReadDriverException TODO
1309
         * @throws RuntimeException
1310
         *             bug
1311
         */
1312
        private DataSource getDataSource(SelectAdapter instr)
1313
                        throws SemanticException, EvaluationException, ReadDriverException {
1314
                DataSource[] tables = instr.getTables();
1315

    
1316
                // Estrategia de delegaci?n de la instrucci?n en el sgbd original de la
1317
                // tabla
1318
                if (sameDBMS(tables) && delegating) {
1319
                        String sql = translateInstruction(instr, tables);
1320

    
1321
                        DBDataSource table = (DBDataSource) tables[0];
1322

    
1323
                        // Set the driver info
1324
                        DBSourceInfo source = (DBSourceInfo) table.getSourceInfo();
1325
                        String dataSourceName = addDBDataSourceBySQL(source.host,
1326
                                        source.port, source.user, source.password, source.dbName,
1327
                                        sql, source.driverName);
1328

    
1329
                        try {
1330
                                return createRandomDataSource(dataSourceName,
1331
                                                DataSourceFactory.MANUAL_OPENING);
1332
                        } catch (NoSuchTableException e) {
1333
                                throw new RuntimeException(e);
1334
                        } catch (DriverLoadException e) {
1335
                                throw new RuntimeException(e);
1336
                        }
1337
                }
1338

    
1339
                // Estrategia normal
1340
                Strategy strategy = StrategyManager.getStrategy(instr);
1341

    
1342
                OperationDataSource ret = strategy.select(instr);
1343

    
1344
                ret.setName(getUID());
1345
                nameOperationDataSource.put(ret.getName(), ret);
1346

    
1347
                return ret;
1348
        }
1349

    
1350
        /**
1351
         * Translates the table references by changind the gdbms name with the
1352
         * underlaying database management system table name
1353
         *
1354
         * @param instr
1355
         *            root of the adapted tree
1356
         * @param tables
1357
         *            DataSources involved in the instruction
1358
         *
1359
         * @return The translated sql query
1360
         * @throws SemanticException
1361
         *             If the instruction is not semantically correct
1362
         * @throws ReadDriverException TODO
1363
         */
1364
        private String translateInstruction(Adapter instr, DataSource[] tables)
1365
                        throws SemanticException, ReadDriverException {
1366
                HashMap instrNameDBName = new HashMap();
1367

    
1368
                translateFromTables(instr, instrNameDBName);
1369
                translateColRefs(instr, instrNameDBName, tables);
1370

    
1371
                return Utilities.getText(instr.getEntity());
1372
        }
1373

    
1374
        /**
1375
         * Gets the name of the table where the field is in
1376
         *
1377
         * @param fieldName
1378
         *            field whose table wants to be guessed
1379
         * @param tables
1380
         *            tables involved in the search
1381
         *
1382
         * @return table name
1383
         * @throws ReadDriverException TODO
1384
         * @throws SemanticException
1385
         */
1386
        private String guessTableName(String fieldName, DataSource[] tables)
1387
                        throws ReadDriverException, SemanticException {
1388
                int tableIndex = -1;
1389

    
1390
                for (int i = 0; i < tables.length; i++) {
1391
                        tables[i].start();
1392

    
1393
                        if (tables[i].getFieldIndexByName(fieldName) != -1) {
1394
                                if (tableIndex != -1) {
1395
                                        throw new SemanticException("ambiguous column reference: "
1396
                                                        + fieldName);
1397
                                } else {
1398
                                        tableIndex = i;
1399
                                }
1400
                        }
1401

    
1402
                        tables[i].stop();
1403
                }
1404

    
1405
                if (tableIndex == -1) {
1406
                        throw new SemanticException("Field not found: " + fieldName);
1407
                }
1408

    
1409
                return tables[tableIndex].getName();
1410
        }
1411

    
1412
        /**
1413
         * Translates the table references by changind the gdbms name with the
1414
         * underlaying database management system table name
1415
         *
1416
         * @param adapter
1417
         *            adapter processed
1418
         * @param instrNameDBName
1419
         *            hasmap with the gdbms names a s the keys and the database name
1420
         *            as the values.
1421
         * @param tables
1422
         *            tables involved in the instruction
1423
         * @throws SemanticException
1424
         *             If the instruction is not semantically correct
1425
         * @throws ReadDriverException TODO
1426
         */
1427
        private void translateColRefs(Adapter adapter, HashMap instrNameDBName,
1428
                        DataSource[] tables) throws SemanticException, ReadDriverException {
1429
                if (adapter instanceof ColRefAdapter) {
1430
                        ColRefAdapter tra = (ColRefAdapter) adapter;
1431
                        SimpleNode s = tra.getEntity();
1432

    
1433
                        if (s.first_token != s.last_token) {
1434
                                String name = s.first_token.image;
1435
                                s.first_token.image = instrNameDBName.get(name).toString();
1436
                        } else {
1437
                                String tableName = guessTableName(s.first_token.image, tables);
1438
                                s.first_token.image = instrNameDBName.get(tableName) + "."
1439
                                                + s.first_token.image;
1440
                        }
1441
                } else {
1442
                        Adapter[] hijos = adapter.getChilds();
1443

    
1444
                        for (int i = 0; i < hijos.length; i++) {
1445
                                translateColRefs(hijos[i], instrNameDBName, tables);
1446
                        }
1447
                }
1448
        }
1449

    
1450
        /**
1451
         * Translates the table references by changind the gdbms name with the
1452
         * underlaying database management system table name
1453
         *
1454
         * @param adapter
1455
         *            adapter processed
1456
         * @param instrNameDBName
1457
         *            hasmap with the gdbms names a s the keys and the database name
1458
         *            as the values.
1459
         */
1460
        private void translateFromTables(Adapter adapter, HashMap instrNameDBName) {
1461
                if (adapter instanceof TableRefAdapter) {
1462
                        TableRefAdapter tra = (TableRefAdapter) adapter;
1463
                        SimpleNode s = tra.getEntity();
1464

    
1465
                        if (s.first_token == s.last_token) {
1466
                                String alias = "gdbms" + System.currentTimeMillis();
1467
                                String name = s.first_token.image;
1468
                                s.first_token.image = nameTable.get(name) + " " + alias;
1469
                                instrNameDBName.put(name, alias);
1470
                        } else {
1471
                                String alias = s.last_token.image;
1472
                                String name = s.first_token.image;
1473
                                s.first_token.image = nameTable.get(name).toString();
1474
                                instrNameDBName.put(alias, alias);
1475
                        }
1476
                } else {
1477
                        Adapter[] hijos = adapter.getChilds();
1478

    
1479
                        for (int i = 0; i < hijos.length; i++) {
1480
                                translateFromTables(hijos[i], instrNameDBName);
1481
                        }
1482
                }
1483
        }
1484

    
1485
        /**
1486
         * Obtiene el DataSource resultado de ejecutar la instrucci?n de union
1487
         *
1488
         * @param instr
1489
         *            instrucci?n de union
1490
         * @param mode
1491
         *            opening mode
1492
         *
1493
         * @return DataSource
1494
         * @throws SemanticException
1495
         *             Si la instrucci?n tiene errores sem?nticos
1496
         * @throws EvaluationException
1497
         *             If there's any problem during expresion evaluation
1498
         * @throws ParseException
1499
         *             If there is a select statement embeeded in the union
1500
         *             statement and its parse fails
1501
         * @throws ReadDriverException TODO
1502
         */
1503
        public DataSource createRandomDataSource(UnionAdapter instr, int mode)
1504
                        throws SemanticException,
1505
                        EvaluationException, ParseException, ReadDriverException {
1506
                return getModedDataSource(getDataSource(instr), mode);
1507
        }
1508

    
1509
        /**
1510
         * Obtiene el DataSource resultado de ejecutar la instrucci?n de union
1511
         *
1512
         * @param instr
1513
         *            instrucci?n de union
1514
         *
1515
         * @return DataSource
1516
         * @throws SemanticException
1517
         *             Si la instrucci?n tiene errores sem?nticos
1518
         * @throws ParseException
1519
         *             If there is a select statement embeeded in the union
1520
         *             statement and its parse fails
1521
         * @throws EvaluationException
1522
         *             If there's any problem during expresion evaluation
1523
         * @throws ReadDriverException TODO
1524
         */
1525
        private DataSource getDataSource(UnionAdapter instr)
1526
                        throws SemanticException,
1527
                        ParseException, EvaluationException, ReadDriverException {
1528
                try {
1529
                        Strategy strategy = StrategyManager.getStrategy(instr);
1530

    
1531
                        OperationDataSource ret;
1532
                        ret = strategy.union(instr);
1533

    
1534
                        ret.setName(getUID());
1535
                        nameOperationDataSource.put(ret.getName(), ret);
1536

    
1537
                        return ret;
1538
                } catch (DriverLoadException e) {
1539
                        throw new ReadDriverException("DataSourceFactory",e);
1540
                }
1541

    
1542
        }
1543

    
1544
        /**
1545
         * Creates a DataSource as a result of a custom query
1546
         *
1547
         * @param instr
1548
         *            Root node of the adapter tree of the custom query instruction
1549
         * @param mode
1550
         *            opening mode
1551
         *
1552
         * @return DataSource with the custom query result
1553
         *
1554
         * @throws SemanticException
1555
         *             if there is any semantic error in the instruction
1556
         */
1557
        public DataSource getDataSource(CustomAdapter instr, int mode)
1558
                        throws SemanticException {
1559
                return getModedDataSource(getDataSource(instr), mode);
1560
        }
1561

    
1562
        /**
1563
         * Creates a DataSource as a result of a custom query
1564
         *
1565
         * @param instr
1566
         *            Root node of the adapter tree of the custom query instruction
1567
         *
1568
         * @return DataSource with the custom query result
1569
         *
1570
         * @throws SemanticException
1571
         *             if there is any semantic error in the instruction
1572
         */
1573
        private DataSource getDataSource(CustomAdapter instr)
1574
                        throws SemanticException {
1575
                Strategy strategy = StrategyManager.getStrategy(instr);
1576

    
1577
                OperationDataSource ret = strategy.custom(instr);
1578

    
1579
                ret.setName(getUID());
1580
                nameOperationDataSource.put(ret.getName(), ret);
1581

    
1582
                return ret;
1583
        }
1584

    
1585
        /**
1586
         * Ejecuta la instrucci?n SQL que se pasa como par?metro obteniendo un
1587
         * DataSource con el resultado de la ejecuci?n
1588
         *
1589
         * @param sql
1590
         *            instrucci?n sql que se quiere ejecutar
1591
         * @param mode
1592
         *            opening mode
1593
         *
1594
         * @return DataSource con el resultado
1595
         * @throws ParseException
1596
         *             Si se produce un error de parse de la instrucci?n
1597
         * @throws DriverLoadException
1598
         *             Si no se pueden cargar los drivers
1599
         * @throws SemanticException
1600
         *             Si la instrucci?n tiene alg?n error sem?ntico
1601
         * @throws EvaluationException
1602
         *             If there's an error evaluating any expression
1603
         * @throws ReadDriverException TODO
1604
         */
1605
        public DataSource executeSQL(String sql, int mode) throws ParseException,
1606
                        DriverLoadException, SemanticException,
1607
                        EvaluationException, ReadDriverException {
1608
                ByteArrayInputStream bytes = new ByteArrayInputStream(sql.getBytes());
1609
                SQLEngine parser = new SQLEngine(bytes);
1610

    
1611
                parser.SQLStatement();
1612

    
1613
                Node root = parser.getRootNode();
1614
                Adapter rootAdapter = Utilities.buildTree(root.jjtGetChild(0), sql,
1615
                                this);
1616

    
1617
                Utilities.simplify(rootAdapter);
1618

    
1619
                DataSource result = null;
1620

    
1621
                if (rootAdapter instanceof SelectAdapter) {
1622
                        result = getDataSource((SelectAdapter) rootAdapter);
1623
                } else if (rootAdapter instanceof UnionAdapter) {
1624
                        result = getDataSource((UnionAdapter) rootAdapter);
1625
                } else if (rootAdapter instanceof CustomAdapter) {
1626
                        result = getDataSource((CustomAdapter) rootAdapter);
1627
                }
1628

    
1629
                // if operation was delegated it isn't a OperationDataSource
1630
                if (result instanceof OperationDataSource) {
1631
                        ((OperationDataSource) result).setSQL(sql);
1632
                }
1633

    
1634
                result.setDataSourceFactory(this);
1635

    
1636
                return getModedDataSource(result, mode);
1637
        }
1638

    
1639
        /**
1640
         * Establece el DriverManager que se usar? para instanciar DataSource's.
1641
         * Este metodo debe ser invocado antes que ning?n otro
1642
         *
1643
         * @param dm
1644
         *            El manager que se encarga de cargar los drivers
1645
         */
1646
        public void setDriverManager(DriverManager dm) {
1647
                this.dm = dm;
1648
        }
1649
        /**
1650
         * Establece el WriterManager que se usar? para instanciar DataSource's.
1651
         * Este metodo debe ser invocado antes que ning?n otro
1652
         *
1653
         * @param dm
1654
         *            El manager que se encarga de cargar los drivers
1655
         */
1656
        public void setWriterManager(WriterManager wm) {
1657
                this.wm = wm;
1658
        }
1659
        /**
1660
         * Get's the module with the specified name
1661
         *
1662
         * @param name
1663
         *            name of the wanted module
1664
         *
1665
         * @return instance of the module
1666
         */
1667
        public Object getModule(String name) {
1668
                return ms.getModule(name);
1669
        }
1670

    
1671
        /**
1672
         * Registers a module in the system with the specified name
1673
         *
1674
         * @param name
1675
         *            name of the module
1676
         * @param instance
1677
         *            module instance
1678
         */
1679
        public void registerModule(String name, Object instance) {
1680
                ms.registerModule(name, instance);
1681
        }
1682

    
1683
        /**
1684
         * Gets a driver manager reference
1685
         *
1686
         * @return DriverManagers.
1687
         */
1688
        public DriverManager getDriverManager() {
1689
                return dm;
1690
        }
1691
        /**
1692
         * Gets a writer manager reference
1693
         *
1694
         * @return WriterManagers.
1695
         */
1696
        public WriterManager getWriterManager() {
1697
                return wm;
1698
        }
1699
        /**
1700
         * Sets if this factory will check for delegating instructions at the server
1701
         * (true) or will execute all queries internally (false). By delegating at
1702
         * the server, lots of queries will be defined in the database management
1703
         * system where the execution is delegated. Invoke clearViews to remove all
1704
         * created views.
1705
         *
1706
         * @param b
1707
         */
1708
        public void setDelegating(boolean b) {
1709
                this.delegating = b;
1710
        }
1711

    
1712
        /**
1713
         * Creates a new table on the specified database
1714
         *
1715
         * @param database
1716
         *            name of the database where the table will be created
1717
         * @param pkNames
1718
         *            Names of the primary key fields
1719
         * @param names
1720
         *            names of the fields
1721
         * @param types
1722
         *            types of the fields. Must have the same length than names
1723
         *
1724
         * @return the table name
1725
         *
1726
         * @throws SQLException
1727
         *             if the creation fails
1728
         */
1729
        public String createTable(String database, String[] pkNames,
1730
                        String[] names, int[] types) throws SQLException {
1731
                // Get a name for the table
1732
                String tableName = getUID();
1733

    
1734
                // Create the table
1735
                InnerDBUtils.execute(database, InnerDBUtils.getCreateStatementWithPK(
1736
                                tableName, pkNames, names, types));
1737

    
1738
                return tableName;
1739
        }
1740

    
1741
        /**
1742
         * Frees all resources used during execution
1743
         * @throws SQLException
1744
         *             If cannot free internal resources
1745
         * @throws ReadDriverException TODO
1746
         */
1747
        public void finalizeThis()  throws SQLException, ReadDriverException {
1748

    
1749
                try {
1750
                        clearViews();
1751
                } finally {
1752
                        Connection c = null;
1753
                        try {
1754
                                c = java.sql.DriverManager.getConnection(
1755
                                                "jdbc:hsqldb:file:", "", "");
1756
                        } catch (Exception e) {
1757
                                return;
1758
                        }
1759
                        Statement st = c.createStatement();
1760
                        st.execute("SHUTDOWN");
1761
                        st.close();
1762
                        c.close();
1763
                }
1764

    
1765
        }
1766

    
1767
        /**
1768
         * Initializes the system.
1769
         *
1770
         * @throws InitializationException
1771
         *             If the initialization
1772
         */
1773
        public void initialize() throws InitializationException {
1774
                initialize(".");
1775
        }
1776

    
1777
        /**
1778
         * Initializes the system
1779
         *
1780
         * @param tempDir
1781
         *            temporary directory to write data
1782
         *
1783
         * @throws InitializationException
1784
         *             If the initialization fails
1785
         */
1786
        public void initialize(String tempDir) throws InitializationException {
1787
                try {
1788
                        this.tempDir = new File(tempDir);
1789

    
1790
                        if (!this.tempDir.exists()) {
1791
                                this.tempDir.mkdirs();
1792
                        }
1793

    
1794
                        Class.forName("org.hsqldb.jdbcDriver");
1795
                } catch (ClassNotFoundException e) {
1796
                        throw new InitializationException(e);
1797
                }
1798
                fillDriversNamesAliases();
1799
        }
1800

    
1801
        /**
1802
         * Gets the URL of a file in the temporary directory. Does not creates any
1803
         * file
1804
         *
1805
         * @return String
1806
         */
1807
        public String getTempFile() {
1808
                return tempDir.getAbsolutePath() + File.separator + "gdmbs"
1809
                                + System.currentTimeMillis();
1810
        }
1811

    
1812
        /**
1813
         * Registra alias de nombres de los drivers
1814
         * por si ha sido necesario modificar el nombre
1815
         * de alguno, y se necesita compatibilidad
1816
         *
1817
         */
1818
        private void fillDriversNamesAliases() {
1819
                this.driversNamesAliases.put("GDBMS HSQLDB driver", "HSQL");
1820
                this.driversNamesAliases.put("mysql", "MySQL Alphanumeric");
1821
                this.driversNamesAliases.put("odbc", "ODBC");
1822
                this.driversNamesAliases.put("mysql", "MySQL Alphanumeric");
1823
                this.driversNamesAliases.put("oracle", "Oracle Alphanumeric");
1824
                this.driversNamesAliases.put("postgresql", "PostgreSQL Alphanumeric");
1825
        }
1826

    
1827
        private Driver getDriver(String name) throws DriverLoadException {
1828
                if (this.driversNamesAliases.containsKey(name)) {
1829
                        name = (String)this.driversNamesAliases.get(name);
1830
                }
1831
                return this.dm.getDriver(name);
1832

    
1833
        }
1834

    
1835
        /**
1836
         * Information to delete the view on the server: name of the view and the
1837
         * adapter to remove it
1838
         */
1839
        private class ServerViewInfo {
1840
                public DBDataSource adapter;
1841

    
1842
                public String viewName;
1843

    
1844
                /**
1845
                 * Crea un nuevo ServerViewInfo.
1846
                 *
1847
                 * @param ds
1848
                 *            DOCUMENT ME!
1849
                 * @param name
1850
                 *            DOCUMENT ME!
1851
                 */
1852
                public ServerViewInfo(DBDataSource ds, String name) {
1853
                        adapter = ds;
1854
                        viewName = name;
1855
                }
1856
        }
1857

    
1858
}