Statistics
| Revision:

svn-gvsig-desktop / trunk / libraries / libGDBMS / src / main / java / com / hardcode / gdbms / engine / data / DataSourceFactory.java @ 10665

History | View | Annotate | Download (53.4 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
                        throw new NoSuchTableException(oldName);
864
                }
865

    
866
                tableSource.put(newName, di);
867
        }
868

    
869
        /**
870
         * Gets the data source passed by adding the AutomaticDataSource decorator
871
         * if factory mode is AUTOMATIC.
872
         *
873
         * @param ds
874
         *            DataSource
875
         * @param mode
876
         *            opening mode
877
         *
878
         * @return DataSource
879
         */
880
        private DataSource getModedDataSource(DataSource ds, int mode) {
881
                if (mode == AUTOMATIC_OPENING) {
882
                        return new AutomaticDataSource(ds, delay);
883
                } else {
884
                        return ds;
885
                }
886
        }
887

    
888
        /**
889
         * Sets the minimum delay between accesses needed to close the DataSource.
890
         * If accesses are delayed more than 'delay' the DataSource MAY be closed.
891
         * Only applies when the mode is set to AUTOMATIC_MODE
892
         *
893
         * @param delay
894
         *            time un milliseconds
895
         */
896
        public void setClosingDelay(long delay) {
897
                this.delay = delay;
898
        }
899

    
900
        /**
901
         * Dado el nombre de una tabla, se busca la fuente de datos asociada a dicha
902
         * tabla y se obtiene un datasource adecuado en funcion del tipo de fuente
903
         * de datos accediendo al subsistema de drivers
904
         *
905
         * @param tableName
906
         *            Nombre de la fuente de datos
907
         *
908
         * @return DataSource que accede a dicha fuente
909
         * @throws DriverLoadException
910
         * @throws NoSuchTableException
911
         * @throws ReadDriverException TODO
912
         */
913
        public DataSource createRandomDataSource(String tableName)
914
                        throws DriverLoadException, NoSuchTableException, ReadDriverException {
915
                return createRandomDataSource(tableName, tableName, MANUAL_OPENING);
916
        }
917

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

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

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

    
997
                if (o == null) {
998
                        // may be a operation layer DataSource
999
                        OperationDataSource ret = (OperationDataSource) nameOperationDataSource
1000
                                        .get(tableName);
1001

    
1002
                        if (ret != null) {
1003
                                ret.setName(tableAlias);
1004

    
1005
                                return getModedDataSource(ret, mode);
1006
                        }
1007

    
1008
                        // table not found
1009
                        throw new NoSuchTableException(tableName);
1010
                }
1011

    
1012
                SourceInfo info = (SourceInfo) o;
1013
                info.name = tableAlias;
1014

    
1015
                if (info instanceof FileSourceInfo) {
1016
                        FileSourceInfo fileInfo = (FileSourceInfo) info;
1017

    
1018
                        Driver d = this.getDriver(fileInfo.driverName);
1019

    
1020
                        if (info instanceof FileCreationSourceInfo) {
1021
                                FileCreationSourceInfo creationInfo = (FileCreationSourceInfo) info;
1022
                                        if (!new File(creationInfo.file).exists()) {
1023
                                                ((FileDriver) d).createSource(creationInfo.file,
1024
                                                                creationInfo.fieldNames,
1025
                                                                creationInfo.fieldTypes);
1026
                                        }
1027
                        }
1028

    
1029
                        FileDataSource adapter;
1030

    
1031
                        if (fileInfo.spatial) {
1032
                                adapter = FileDataSourceFactory.newSpatialInstance();
1033
                        } else {
1034
                                adapter = FileDataSourceFactory.newInstance();
1035
                        }
1036

    
1037
                        ((GDBMSDriver) d).setDataSourceFactory(this);
1038
                        adapter.setDriver((FileDriver) d);
1039
                        adapter.setSourceInfo(fileInfo);
1040
                        adapter.setDataSourceFactory(this);
1041

    
1042
                        return getModedDataSource(adapter, mode);
1043
                } else if (info instanceof DBQuerySourceInfo) {
1044
                        DBQuerySourceInfo dbInfo = (DBQuerySourceInfo) info;
1045

    
1046
                        String driverInfo = dbInfo.driverName;
1047
                        Driver d = this.getDriver(driverInfo);
1048

    
1049
                        ((GDBMSDriver) d).setDataSourceFactory(this);
1050
                        return getModedDataSource(getDataSourceByQuery(dbInfo.sql,
1051
                                        (AlphanumericDBDriver) d, dbInfo), mode);
1052
                } else if (info instanceof DBTableSourceInfo) {
1053
                        DBTableSourceInfo dbInfo = (DBTableSourceInfo) info;
1054

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

    
1058
                        DBDataSource adapter;
1059

    
1060
                        if (info instanceof SpatialDBTableSourceInfo) {
1061
                                adapter = DBDataSourceFactory.newSpatialDataSourceInstance();
1062
                        } else {
1063
                                adapter = DBDataSourceFactory.newDataSourceInstance();
1064
                        }
1065

    
1066
                        ((GDBMSDriver) d).setDataSourceFactory(this);
1067
                        adapter.setDriver((DBDriver) d);
1068
                        adapter.setSourceInfo(dbInfo);
1069
                        adapter.setDataSourceFactory(this);
1070

    
1071
                        return getModedDataSource(adapter, mode);
1072
                } else if (info instanceof ObjectSourceInfo) {
1073
                        ObjectSourceInfo driverInfo = (ObjectSourceInfo) o;
1074
                        ObjectDataSource adapter = ObjectDataSourceFactory.newInstance();
1075
                        driverInfo.driver.setDataSourceFactory(this);
1076
                        adapter.setDriver(driverInfo.driver);
1077
                        adapter.setSourceInfo((ObjectSourceInfo) driverInfo);
1078
                        adapter.setDataSourceFactory(this);
1079

    
1080
                        return getModedDataSource(adapter, mode);
1081
                } else {
1082
                        throw new RuntimeException();
1083
                }
1084
        }
1085

    
1086
        /**
1087
         * Creates a DataSource from a memento object with the manual opening mode
1088
         *
1089
         * @param m
1090
         *            memento
1091
         *
1092
         * @return DataSource
1093
         *
1094
         * @throws RuntimeException
1095
         *             If the DataSource class cannot be instatiated
1096
         */
1097
        public DataSource createRandomDataSource(Memento m) {
1098
                return createRandomDataSource(m, DataSourceFactory.MANUAL_OPENING);
1099
        }
1100

    
1101
        /**
1102
         * Creates a DataSource from a memento object with the specified opening
1103
         * mode
1104
         *
1105
         * @param m
1106
         *            memento
1107
         * @param mode
1108
         *            opening mode
1109
         *
1110
         * @return DataSource
1111
         *
1112
         * @throws RuntimeException
1113
         *             If the DataSource class cannot be instatiated
1114
         */
1115
        public DataSource createRandomDataSource(Memento m, int mode) {
1116
                if (m instanceof DataSourceLayerMemento) {
1117
                        DataSourceLayerMemento mem = (DataSourceLayerMemento) m;
1118

    
1119
                        try {
1120
                                return createRandomDataSource(mem.getTableName(), mem
1121
                                                .getTableAlias(), mode);
1122
                        } catch (DriverLoadException e) {
1123
                                throw new RuntimeException(
1124
                                                "La informaci?n guardada no es consistente", e);
1125
                        } catch (NoSuchTableException e) {
1126
                                throw new RuntimeException(
1127
                                                "La informaci?n guardada no es consistente", e);
1128
                        } catch (ReadDriverException e) {
1129
                                throw new RuntimeException(e);
1130
                        }
1131
                } else {
1132
                        OperationLayerMemento mem = (OperationLayerMemento) m;
1133

    
1134
                        try {
1135
                                return executeSQL(mem.getSql(), mode);
1136
                        } catch (DriverLoadException e) {
1137
                                throw new RuntimeException(
1138
                                                "La informaci?n guardada no es consistente", e);
1139
                        } catch (ParseException e) {
1140
                                throw new RuntimeException(
1141
                                                "La informaci?n guardada no es consistente", e);
1142
                        } catch (SemanticException e) {
1143
                                throw new RuntimeException(
1144
                                                "La informaci?n guardada no es consistente", e);
1145
                        } catch (EvaluationException e) {
1146
                                throw new RuntimeException(
1147
                                                "La informaci?n guardada no es consistente", e);
1148
                        } catch (ReadDriverException e) {
1149
                                throw new RuntimeException(
1150
                                                "La informaci?n guardada no es consistente", e);
1151
                        }
1152
                }
1153
        }
1154

    
1155
        /**
1156
         * Devuelve true si todas las tablas provienen del mismo data base
1157
         * management system
1158
         *
1159
         * @param tables
1160
         *            Array de tablas
1161
         *
1162
         * @return boolean
1163
         */
1164
        private boolean sameDBMS(DataSource[] tables) {
1165
                if (!(tables[0] instanceof DBDataSource)) {
1166
                        return false;
1167
                }
1168

    
1169
                String dbms = ((DBDataSource) tables[0]).getDBMS();
1170

    
1171
                for (int i = 1; i < tables.length; i++) {
1172
                        if (!(tables[i] instanceof DBDataSource)) {
1173
                                return false;
1174
                        }
1175

    
1176
                        if (!dbms.equals(((DBDataSource) tables[1]).getDBMS())) {
1177
                                return false;
1178
                        }
1179
                }
1180

    
1181
                return true;
1182
        }
1183

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

    
1207
        /**
1208
         * Creates a view in the database management system that hosts the data
1209
         * source 'dbds'. The view is defined by the sql parameter
1210
         *
1211
         * @param dbds
1212
         *            DataSource used to execute the query
1213
         * @param sql
1214
         *            The SQL query defining the view
1215
         *
1216
         * @return Name of the view
1217
         * @throws ReadDriverException TODO
1218
         * @throws DriverException
1219
         *             If the view cannot be created
1220
         */
1221
        private String getView(DBDataSource dbds, String sql)
1222
                        throws ReadDriverException {
1223
                ServerViewInfo svi = (ServerViewInfo) sourceInfoServerViewInfo.get(dbds
1224
                                .getSourceInfo());
1225

    
1226
                /*
1227
                 * Return the view name if it's already created or create the view if
1228
                 * it's not created
1229
                 */
1230
                if (svi != null) {
1231
                        return svi.viewName;
1232
                } else {
1233
                        // create the view
1234
                        String viewName = getUID();
1235
                        String viewQuery = "CREATE VIEW " + viewName + " AS " + sql;
1236
                        dbds.execute(viewQuery);
1237

    
1238
                        // Register the view created
1239
                        sourceInfoServerViewInfo.put(dbds.getSourceInfo(),
1240
                                        new ServerViewInfo(dbds, viewName));
1241

    
1242
                        return viewName;
1243
                }
1244
        }
1245

    
1246
        /**
1247
         * Gets a DataSource implementation with the sql instruction as the data
1248
         * source by creating a view in the underlaying datasource management system
1249
         *
1250
         * @param sql
1251
         *            Instruction definig the data source
1252
         * @param driver
1253
         *            Driver used to access the data source
1254
         * @param dbInfo
1255
         *            data source info
1256
         *
1257
         * @return DataSource
1258
         * @throws ReadDriverException TODO
1259
         */
1260
        private DBDataSource getDataSourceByQuery(String sql,
1261
                        AlphanumericDBDriver driver, DBTableSourceInfo dbInfo)
1262
                        throws ReadDriverException {
1263
                // Create the adapter
1264
                DBDataSource adapter = DBDataSourceFactory.newDataSourceInstance();
1265

    
1266
                // set the driver
1267
                adapter.setDriver(driver);
1268

    
1269
                // Create the query
1270
                adapter.setSourceInfo(dbInfo);
1271

    
1272
                // Gets the view name
1273
                String viewName = getView(adapter, sql);
1274

    
1275
                // Complete the source info with the view name
1276
                dbInfo.tableName = viewName;
1277

    
1278
                // Register the name association
1279
                nameTable.put(dbInfo.name, viewName);
1280

    
1281
                // setup the adapter
1282
                adapter.setSourceInfo(dbInfo);
1283
                adapter.setDataSourceFactory(this);
1284

    
1285
                return adapter;
1286
        }
1287

    
1288
        /**
1289
         * A partir de una instrucci?n select se encarga de obtener el DataSource
1290
         * resultado de la ejecuci?n de dicha instrucci?n
1291
         *
1292
         * @param instr
1293
         *            Instrucci?n select origen del datasource
1294
         *
1295
         * @return DataSource que accede a los datos resultado de ejecutar la select
1296
         * @throws SemanticException
1297
         * @throws EvaluationException
1298
         * @throws ReadDriverException TODO
1299
         * @throws RuntimeException
1300
         *             bug
1301
         */
1302
        private DataSource getDataSource(SelectAdapter instr)
1303
                        throws SemanticException, EvaluationException, ReadDriverException {
1304
                DataSource[] tables = instr.getTables();
1305

    
1306
                // Estrategia de delegaci?n de la instrucci?n en el sgbd original de la
1307
                // tabla
1308
                if (sameDBMS(tables) && delegating) {
1309
                        String sql = translateInstruction(instr, tables);
1310

    
1311
                        DBDataSource table = (DBDataSource) tables[0];
1312

    
1313
                        // Set the driver info
1314
                        DBSourceInfo source = (DBSourceInfo) table.getSourceInfo();
1315
                        String dataSourceName = addDBDataSourceBySQL(source.host,
1316
                                        source.port, source.user, source.password, source.dbName,
1317
                                        sql, source.driverName);
1318

    
1319
                        try {
1320
                                return createRandomDataSource(dataSourceName,
1321
                                                DataSourceFactory.MANUAL_OPENING);
1322
                        } catch (NoSuchTableException e) {
1323
                                throw new RuntimeException(e);
1324
                        } catch (DriverLoadException e) {
1325
                                throw new RuntimeException(e);
1326
                        }
1327
                }
1328

    
1329
                // Estrategia normal
1330
                Strategy strategy = StrategyManager.getStrategy(instr);
1331

    
1332
                OperationDataSource ret = strategy.select(instr);
1333

    
1334
                ret.setName(getUID());
1335
                nameOperationDataSource.put(ret.getName(), ret);
1336

    
1337
                return ret;
1338
        }
1339

    
1340
        /**
1341
         * Translates the table references by changind the gdbms name with the
1342
         * underlaying database management system table name
1343
         *
1344
         * @param instr
1345
         *            root of the adapted tree
1346
         * @param tables
1347
         *            DataSources involved in the instruction
1348
         *
1349
         * @return The translated sql query
1350
         * @throws SemanticException
1351
         *             If the instruction is not semantically correct
1352
         * @throws ReadDriverException TODO
1353
         */
1354
        private String translateInstruction(Adapter instr, DataSource[] tables)
1355
                        throws SemanticException, ReadDriverException {
1356
                HashMap instrNameDBName = new HashMap();
1357

    
1358
                translateFromTables(instr, instrNameDBName);
1359
                translateColRefs(instr, instrNameDBName, tables);
1360

    
1361
                return Utilities.getText(instr.getEntity());
1362
        }
1363

    
1364
        /**
1365
         * Gets the name of the table where the field is in
1366
         *
1367
         * @param fieldName
1368
         *            field whose table wants to be guessed
1369
         * @param tables
1370
         *            tables involved in the search
1371
         *
1372
         * @return table name
1373
         * @throws ReadDriverException TODO
1374
         * @throws SemanticException
1375
         */
1376
        private String guessTableName(String fieldName, DataSource[] tables)
1377
                        throws ReadDriverException, SemanticException {
1378
                int tableIndex = -1;
1379

    
1380
                for (int i = 0; i < tables.length; i++) {
1381
                        tables[i].start();
1382

    
1383
                        if (tables[i].getFieldIndexByName(fieldName) != -1) {
1384
                                if (tableIndex != -1) {
1385
                                        throw new SemanticException("ambiguous column reference: "
1386
                                                        + fieldName);
1387
                                } else {
1388
                                        tableIndex = i;
1389
                                }
1390
                        }
1391

    
1392
                        tables[i].stop();
1393
                }
1394

    
1395
                if (tableIndex == -1) {
1396
                        throw new SemanticException("Field not found: " + fieldName);
1397
                }
1398

    
1399
                return tables[tableIndex].getName();
1400
        }
1401

    
1402
        /**
1403
         * Translates the table references by changind the gdbms name with the
1404
         * underlaying database management system table name
1405
         *
1406
         * @param adapter
1407
         *            adapter processed
1408
         * @param instrNameDBName
1409
         *            hasmap with the gdbms names a s the keys and the database name
1410
         *            as the values.
1411
         * @param tables
1412
         *            tables involved in the instruction
1413
         * @throws SemanticException
1414
         *             If the instruction is not semantically correct
1415
         * @throws ReadDriverException TODO
1416
         */
1417
        private void translateColRefs(Adapter adapter, HashMap instrNameDBName,
1418
                        DataSource[] tables) throws SemanticException, ReadDriverException {
1419
                if (adapter instanceof ColRefAdapter) {
1420
                        ColRefAdapter tra = (ColRefAdapter) adapter;
1421
                        SimpleNode s = tra.getEntity();
1422

    
1423
                        if (s.first_token != s.last_token) {
1424
                                String name = s.first_token.image;
1425
                                s.first_token.image = instrNameDBName.get(name).toString();
1426
                        } else {
1427
                                String tableName = guessTableName(s.first_token.image, tables);
1428
                                s.first_token.image = instrNameDBName.get(tableName) + "."
1429
                                                + s.first_token.image;
1430
                        }
1431
                } else {
1432
                        Adapter[] hijos = adapter.getChilds();
1433

    
1434
                        for (int i = 0; i < hijos.length; i++) {
1435
                                translateColRefs(hijos[i], instrNameDBName, tables);
1436
                        }
1437
                }
1438
        }
1439

    
1440
        /**
1441
         * Translates the table references by changind the gdbms name with the
1442
         * underlaying database management system table name
1443
         *
1444
         * @param adapter
1445
         *            adapter processed
1446
         * @param instrNameDBName
1447
         *            hasmap with the gdbms names a s the keys and the database name
1448
         *            as the values.
1449
         */
1450
        private void translateFromTables(Adapter adapter, HashMap instrNameDBName) {
1451
                if (adapter instanceof TableRefAdapter) {
1452
                        TableRefAdapter tra = (TableRefAdapter) adapter;
1453
                        SimpleNode s = tra.getEntity();
1454

    
1455
                        if (s.first_token == s.last_token) {
1456
                                String alias = "gdbms" + System.currentTimeMillis();
1457
                                String name = s.first_token.image;
1458
                                s.first_token.image = nameTable.get(name) + " " + alias;
1459
                                instrNameDBName.put(name, alias);
1460
                        } else {
1461
                                String alias = s.last_token.image;
1462
                                String name = s.first_token.image;
1463
                                s.first_token.image = nameTable.get(name).toString();
1464
                                instrNameDBName.put(alias, alias);
1465
                        }
1466
                } else {
1467
                        Adapter[] hijos = adapter.getChilds();
1468

    
1469
                        for (int i = 0; i < hijos.length; i++) {
1470
                                translateFromTables(hijos[i], instrNameDBName);
1471
                        }
1472
                }
1473
        }
1474

    
1475
        /**
1476
         * Obtiene el DataSource resultado de ejecutar la instrucci?n de union
1477
         *
1478
         * @param instr
1479
         *            instrucci?n de union
1480
         * @param mode
1481
         *            opening mode
1482
         *
1483
         * @return DataSource
1484
         * @throws SemanticException
1485
         *             Si la instrucci?n tiene errores sem?nticos
1486
         * @throws EvaluationException
1487
         *             If there's any problem during expresion evaluation
1488
         * @throws ParseException
1489
         *             If there is a select statement embeeded in the union
1490
         *             statement and its parse fails
1491
         * @throws ReadDriverException TODO
1492
         */
1493
        public DataSource createRandomDataSource(UnionAdapter instr, int mode)
1494
                        throws SemanticException,
1495
                        EvaluationException, ParseException, ReadDriverException {
1496
                return getModedDataSource(getDataSource(instr), mode);
1497
        }
1498

    
1499
        /**
1500
         * Obtiene el DataSource resultado de ejecutar la instrucci?n de union
1501
         *
1502
         * @param instr
1503
         *            instrucci?n de union
1504
         *
1505
         * @return DataSource
1506
         * @throws SemanticException
1507
         *             Si la instrucci?n tiene errores sem?nticos
1508
         * @throws ParseException
1509
         *             If there is a select statement embeeded in the union
1510
         *             statement and its parse fails
1511
         * @throws EvaluationException
1512
         *             If there's any problem during expresion evaluation
1513
         * @throws ReadDriverException TODO
1514
         */
1515
        private DataSource getDataSource(UnionAdapter instr)
1516
                        throws SemanticException,
1517
                        ParseException, EvaluationException, ReadDriverException {
1518
                try {
1519
                        Strategy strategy = StrategyManager.getStrategy(instr);
1520

    
1521
                        OperationDataSource ret;
1522
                        ret = strategy.union(instr);
1523

    
1524
                        ret.setName(getUID());
1525
                        nameOperationDataSource.put(ret.getName(), ret);
1526

    
1527
                        return ret;
1528
                } catch (DriverLoadException e) {
1529
                        throw new ReadDriverException("DataSourceFactory",e);
1530
                }
1531

    
1532
        }
1533

    
1534
        /**
1535
         * Creates a DataSource as a result of a custom query
1536
         *
1537
         * @param instr
1538
         *            Root node of the adapter tree of the custom query instruction
1539
         * @param mode
1540
         *            opening mode
1541
         *
1542
         * @return DataSource with the custom query result
1543
         *
1544
         * @throws SemanticException
1545
         *             if there is any semantic error in the instruction
1546
         */
1547
        public DataSource getDataSource(CustomAdapter instr, int mode)
1548
                        throws SemanticException {
1549
                return getModedDataSource(getDataSource(instr), mode);
1550
        }
1551

    
1552
        /**
1553
         * Creates a DataSource as a result of a custom query
1554
         *
1555
         * @param instr
1556
         *            Root node of the adapter tree of the custom query instruction
1557
         *
1558
         * @return DataSource with the custom query result
1559
         *
1560
         * @throws SemanticException
1561
         *             if there is any semantic error in the instruction
1562
         */
1563
        private DataSource getDataSource(CustomAdapter instr)
1564
                        throws SemanticException {
1565
                Strategy strategy = StrategyManager.getStrategy(instr);
1566

    
1567
                OperationDataSource ret = strategy.custom(instr);
1568

    
1569
                ret.setName(getUID());
1570
                nameOperationDataSource.put(ret.getName(), ret);
1571

    
1572
                return ret;
1573
        }
1574

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

    
1601
                parser.SQLStatement();
1602

    
1603
                Node root = parser.getRootNode();
1604
                Adapter rootAdapter = Utilities.buildTree(root.jjtGetChild(0), sql,
1605
                                this);
1606

    
1607
                Utilities.simplify(rootAdapter);
1608

    
1609
                DataSource result = null;
1610

    
1611
                if (rootAdapter instanceof SelectAdapter) {
1612
                        result = getDataSource((SelectAdapter) rootAdapter);
1613
                } else if (rootAdapter instanceof UnionAdapter) {
1614
                        result = getDataSource((UnionAdapter) rootAdapter);
1615
                } else if (rootAdapter instanceof CustomAdapter) {
1616
                        result = getDataSource((CustomAdapter) rootAdapter);
1617
                }
1618

    
1619
                // if operation was delegated it isn't a OperationDataSource
1620
                if (result instanceof OperationDataSource) {
1621
                        ((OperationDataSource) result).setSQL(sql);
1622
                }
1623

    
1624
                result.setDataSourceFactory(this);
1625

    
1626
                return getModedDataSource(result, mode);
1627
        }
1628

    
1629
        /**
1630
         * Establece el DriverManager que se usar? para instanciar DataSource's.
1631
         * Este metodo debe ser invocado antes que ning?n otro
1632
         *
1633
         * @param dm
1634
         *            El manager que se encarga de cargar los drivers
1635
         */
1636
        public void setDriverManager(DriverManager dm) {
1637
                this.dm = dm;
1638
        }
1639
        /**
1640
         * Establece el WriterManager 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 setWriterManager(WriterManager wm) {
1647
                this.wm = wm;
1648
        }
1649
        /**
1650
         * Get's the module with the specified name
1651
         *
1652
         * @param name
1653
         *            name of the wanted module
1654
         *
1655
         * @return instance of the module
1656
         */
1657
        public Object getModule(String name) {
1658
                return ms.getModule(name);
1659
        }
1660

    
1661
        /**
1662
         * Registers a module in the system with the specified name
1663
         *
1664
         * @param name
1665
         *            name of the module
1666
         * @param instance
1667
         *            module instance
1668
         */
1669
        public void registerModule(String name, Object instance) {
1670
                ms.registerModule(name, instance);
1671
        }
1672

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

    
1702
        /**
1703
         * Creates a new table on the specified database
1704
         *
1705
         * @param database
1706
         *            name of the database where the table will be created
1707
         * @param pkNames
1708
         *            Names of the primary key fields
1709
         * @param names
1710
         *            names of the fields
1711
         * @param types
1712
         *            types of the fields. Must have the same length than names
1713
         *
1714
         * @return the table name
1715
         *
1716
         * @throws SQLException
1717
         *             if the creation fails
1718
         */
1719
        public String createTable(String database, String[] pkNames,
1720
                        String[] names, int[] types) throws SQLException {
1721
                // Get a name for the table
1722
                String tableName = getUID();
1723

    
1724
                // Create the table
1725
                InnerDBUtils.execute(database, InnerDBUtils.getCreateStatementWithPK(
1726
                                tableName, pkNames, names, types));
1727

    
1728
                return tableName;
1729
        }
1730

    
1731
        /**
1732
         * Frees all resources used during execution
1733
         * @throws SQLException
1734
         *             If cannot free internal resources
1735
         * @throws ReadDriverException TODO
1736
         */
1737
        public void finalizeThis()  throws SQLException, ReadDriverException {
1738

    
1739
                try {
1740
                        clearViews();
1741
                } finally {
1742
                        Connection c = null;
1743
                        try {
1744
                                c = java.sql.DriverManager.getConnection(
1745
                                                "jdbc:hsqldb:file:", "", "");
1746
                        } catch (Exception e) {
1747
                                return;
1748
                        }
1749
                        Statement st = c.createStatement();
1750
                        st.execute("SHUTDOWN");
1751
                        st.close();
1752
                        c.close();
1753
                }
1754

    
1755
        }
1756

    
1757
        /**
1758
         * Initializes the system.
1759
         *
1760
         * @throws InitializationException
1761
         *             If the initialization
1762
         */
1763
        public void initialize() throws InitializationException {
1764
                initialize(".");
1765
        }
1766

    
1767
        /**
1768
         * Initializes the system
1769
         *
1770
         * @param tempDir
1771
         *            temporary directory to write data
1772
         *
1773
         * @throws InitializationException
1774
         *             If the initialization fails
1775
         */
1776
        public void initialize(String tempDir) throws InitializationException {
1777
                try {
1778
                        this.tempDir = new File(tempDir);
1779

    
1780
                        if (!this.tempDir.exists()) {
1781
                                this.tempDir.mkdirs();
1782
                        }
1783

    
1784
                        Class.forName("org.hsqldb.jdbcDriver");
1785
                } catch (ClassNotFoundException e) {
1786
                        throw new InitializationException(e);
1787
                }
1788
                fillDriversNamesAliases();
1789
        }
1790

    
1791
        /**
1792
         * Gets the URL of a file in the temporary directory. Does not creates any
1793
         * file
1794
         *
1795
         * @return String
1796
         */
1797
        public String getTempFile() {
1798
                return tempDir.getAbsolutePath() + File.separator + "gdmbs"
1799
                                + System.currentTimeMillis();
1800
        }
1801

    
1802
        /**
1803
         * Registra alias de nombres de los drivers
1804
         * por si ha sido necesario modificar el nombre
1805
         * de alguno, y se necesita compatibilidad
1806
         *
1807
         */
1808
        private void fillDriversNamesAliases() {
1809

    
1810
        }
1811

    
1812
        private Driver getDriver(String name) throws DriverLoadException {
1813
                if (this.driversNamesAliases.containsKey(name)) {
1814
                        name = (String)this.driversNamesAliases.get(name);
1815
                }
1816
                return this.dm.getDriver(name);
1817

    
1818
        }
1819

    
1820
        /**
1821
         * Information to delete the view on the server: name of the view and the
1822
         * adapter to remove it
1823
         */
1824
        private class ServerViewInfo {
1825
                public DBDataSource adapter;
1826

    
1827
                public String viewName;
1828

    
1829
                /**
1830
                 * Crea un nuevo ServerViewInfo.
1831
                 *
1832
                 * @param ds
1833
                 *            DOCUMENT ME!
1834
                 * @param name
1835
                 *            DOCUMENT ME!
1836
                 */
1837
                public ServerViewInfo(DBDataSource ds, String name) {
1838
                        adapter = ds;
1839
                        viewName = name;
1840
                }
1841
        }
1842

    
1843
}