Statistics
| Revision:

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

History | View | Annotate | Download (54.6 KB)

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

    
3
import java.io.ByteArrayInputStream;
4
import java.io.File;
5
import java.io.IOException;
6
import java.rmi.server.UID;
7
import java.sql.Connection;
8
import java.sql.SQLException;
9
import java.sql.Statement;
10
import java.util.ArrayList;
11
import java.util.HashMap;
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.engine.data.db.DBDataSource;
19
import com.hardcode.gdbms.engine.data.db.DBDataSourceFactory;
20
import com.hardcode.gdbms.engine.data.db.DBQuerySourceInfo;
21
import com.hardcode.gdbms.engine.data.db.DBSourceInfo;
22
import com.hardcode.gdbms.engine.data.db.DBTableSourceInfo;
23
import com.hardcode.gdbms.engine.data.db.SpatialDBTableSourceInfo;
24
import com.hardcode.gdbms.engine.data.driver.AlphanumericDBDriver;
25
import com.hardcode.gdbms.engine.data.driver.DBDriver;
26
import com.hardcode.gdbms.engine.data.driver.DriverException;
27
import com.hardcode.gdbms.engine.data.driver.FileDriver;
28
import com.hardcode.gdbms.engine.data.driver.GDBMSDriver;
29
import com.hardcode.gdbms.engine.data.driver.ObjectDriver;
30
import com.hardcode.gdbms.engine.data.file.FileCreationSourceInfo;
31
import com.hardcode.gdbms.engine.data.file.FileDataSource;
32
import com.hardcode.gdbms.engine.data.file.FileDataSourceFactory;
33
import com.hardcode.gdbms.engine.data.file.FileSourceInfo;
34
import com.hardcode.gdbms.engine.data.object.ObjectDataSource;
35
import com.hardcode.gdbms.engine.data.object.ObjectDataSourceFactory;
36
import com.hardcode.gdbms.engine.data.object.ObjectSourceInfo;
37
import com.hardcode.gdbms.engine.data.persistence.DataSourceLayerMemento;
38
import com.hardcode.gdbms.engine.data.persistence.Memento;
39
import com.hardcode.gdbms.engine.data.persistence.OperationLayerMemento;
40
import com.hardcode.gdbms.engine.instruction.Adapter;
41
import com.hardcode.gdbms.engine.instruction.ColRefAdapter;
42
import com.hardcode.gdbms.engine.instruction.CustomAdapter;
43
import com.hardcode.gdbms.engine.instruction.EvaluationException;
44
import com.hardcode.gdbms.engine.instruction.SelectAdapter;
45
import com.hardcode.gdbms.engine.instruction.SemanticException;
46
import com.hardcode.gdbms.engine.instruction.TableRefAdapter;
47
import com.hardcode.gdbms.engine.instruction.UnionAdapter;
48
import com.hardcode.gdbms.engine.instruction.Utilities;
49
import com.hardcode.gdbms.engine.strategies.OperationDataSource;
50
import com.hardcode.gdbms.engine.strategies.Strategy;
51
import com.hardcode.gdbms.engine.strategies.StrategyManager;
52
import com.hardcode.gdbms.parser.Node;
53
import com.hardcode.gdbms.parser.ParseException;
54
import com.hardcode.gdbms.parser.SQLEngine;
55
import com.hardcode.gdbms.parser.SimpleNode;
56

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

    
69
        public final static int AUTOMATIC_OPENING = 1;
70

    
71
        public final static int DATA_WARE_DIRECT_MODE = 0;
72

    
73
        public final static int DATA_WARE_COHERENT_ROW_ORDER = 1;
74

    
75
        final static int DEFAULT_DELAY = 5000;
76

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

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

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

    
91
        private HashMap sourceInfoServerViewInfo = new HashMap();
92

    
93
        private DriverManager dm;
94

    
95
        private ModuleSupport ms = new ModuleSupport();
96

    
97
        private long delay = DEFAULT_DELAY;
98

    
99
        private boolean delegating = false;
100

    
101
        private File tempDir = new File(".");
102

    
103
        private WriterManager wm;
104

    
105
        /**
106
         * Get's a unique id in the tableSource and nameOperationDataSource key sets
107
         *
108
         * @return unique id
109
         */
110
        private String getUID() {
111
                UID uid = new UID();
112
                
113
                String name = "gdbms" + uid.toString().replace(':','_');
114
                return name;
115
        }
116
        
117
        /**
118
         * Removes all associations between names and data sources of any layer.
119
         */
120
        public void removeAllDataSources() {
121
                tableSource.clear();
122
                nameOperationDataSource.clear();
123
        }
124

    
125
        /**
126
         * Removes the association between the name and the data sources
127
         *
128
         * @param ds
129
         *            Name of the data source to remove
130
         *
131
         * @throws DriverException
132
         *             If ds is a database data source it's associated view must be
133
         *             deleted. Thrown if could not be deleted.
134
         * @throws RuntimeException
135
         *             If there is no data source registered with that name
136
         */
137
        public void remove(DataSource ds) throws DriverException {
138
                String name = ds.getName();
139

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

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

    
163
        /**
164
         * Removes the views created at query delegation
165
         *
166
         * @throws DriverException
167
         *             If any view could not be removed
168
         */
169
        public void clearViews() throws DriverException {
170
                Iterator i = sourceInfoServerViewInfo.values().iterator();
171

    
172
                while (i.hasNext()) {
173
                        ServerViewInfo svi = (ServerViewInfo) i.next();
174
                        clearView(svi.adapter);
175
                }
176

    
177
                sourceInfoServerViewInfo.clear();
178
        }
179

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

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

    
210
                return ret;
211
        }
212

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

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

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

    
269
                return info;
270
        }
271

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

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

    
303
                return ret;
304
        }
305

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

    
322
                return ret;
323
        }
324

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

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

    
350
                while (it.hasNext()) {
351
                        SourceInfo di = (SourceInfo) it.next();
352
                        ret.add(di);
353
                }
354

    
355
                return (SourceInfo[]) ret.toArray(new SourceInfo[0]);
356
        }
357

    
358
        /**
359
         * A?ade un origen de datos de base de datos al sistema
360
         *
361
         * @param name
362
         *            Nombre de la tabla con el que se har? referencia en las
363
         *            instrucciones
364
         * @param host
365
         *            Cadena de conexi?n para conectar con el sgbd donde se
366
         *            encuentra la tabla
367
         * @param port
368
         *            Nombre del sgbd capaz de ejecutar SQL en el que reside la
369
         *            tabla. Generalmente ser? la parte de la cadena de conexi?n
370
         *            correspondiente a host, puerto y nombre de la base de datos
371
         * @param user
372
         *            Nombre de usuario. Null para acceso sin usuario
373
         * @param password
374
         *            Si el usuario es null se ignora el password
375
         * @param dbName
376
         *            Nombre de la base de datos a la que se accede
377
         * @param tableName
378
         *            Nombre de la tabla en la base de datos
379
         * @param driverInfo
380
         *            Informaci?n para saber qu? driver debe acceder a la
381
         *            informaci?n. Se escoger? el driver cuyo valor de retorno del
382
         *            m?todo getType coincida con este valor
383
         */
384
        public void addDBDataSourceByTable(String name, String host, int port,
385
                        String user, String password, String dbName, String tableName,
386
                        String driverInfo) {
387
                DBTableSourceInfo info = new DBTableSourceInfo();
388
                fillDBTableSourceInfo(info, name, host, port, user, password, dbName,
389
                                tableName, driverInfo);
390
                tableSource.put(name, info);
391
                nameTable.put(name, tableName);
392
        }
393
        
394
        
395
        /**
396
         * A?ade un origen de datos de base de datos al sistema
397
         *
398
         * @param name
399
         *            Nombre de la tabla con el que se har? referencia en las
400
         *            instrucciones
401
         * @param Connection
402
         *            Conexion JDBC a la Base de datos ya abierta (el DataSource
403
         *            la usara, pero no la abrira/cerrara)
404
         * @param tableName
405
         *            Nombre de la tabla en la base de datos
406
         * @param driverInfo
407
         *            Informaci?n para saber qu? driver debe acceder a la
408
         *            informaci?n. Se escoger? el driver cuyo valor de retorno del
409
         *            m?todo getType coincida con este valor
410
         */
411
        public void addDBDataSourceByTable(String name, Connection connection, String tableName,
412
                        String driverInfo) {
413
                DBTableSourceInfo info = new DBTableSourceInfo();
414
                fillDBTableSourceInfo(info, name, connection,
415
                                tableName, driverInfo);
416
                tableSource.put(name, info);
417
                nameTable.put(name, tableName);
418
        }
419
        
420
        
421
        
422

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

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

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

    
536
        
537
        /**
538
         * Adds a spatial database data source
539
         *
540
         * @param connection
541
         *
542
         * @param tableName
543
         *            table name
544
         * @param geometryFieldName
545
         *            name of the field that has the geometry
546
         * @param driverInfo
547
         *            name of the driver used to access the data
548
         */
549
        public void addSpatialDBDataSource(String name, Connection connection, String tableName,
550
                        String geometryFieldName, String driverInfo) {
551
                SpatialDBTableSourceInfo info = new SpatialDBTableSourceInfo();
552
                fillDBTableSourceInfo(info, name, connection,
553
                                tableName, driverInfo);
554
                info.geometryField = geometryFieldName;
555
                tableSource.put(name, info);
556
                nameTable.put(name, tableName);
557
        }        
558
        
559
        
560
        
561
        
562
        
563
        
564
        
565
        
566
        /**
567
         * Adds a spatial database data source
568
         *
569
         * @param host
570
         *            host where the data is
571
         * @param port
572
         *            port number
573
         * @param user
574
         *            user name or null.
575
         * @param password
576
         *            if user name is null is ignored
577
         * @param dbName
578
         *            database name
579
         * @param tableName
580
         *            table name
581
         * @param geometryFieldName
582
         *            name of the field that has the geometry
583
         * @param driverInfo
584
         *            name of the driver used to access the data
585
         *
586
         * @return generated name of the added data source
587
         */
588
        public String addSpatialDBDataSource(String host, int port, String user,
589
                        String password, String dbName, String tableName,
590
                        String geometryFieldName, String driverInfo) {
591
                String ret = getUID();
592
                addSpatialDBDataSource(ret, host, port, user, password, dbName,
593
                                tableName, geometryFieldName, driverInfo);
594

    
595
                return ret;
596
        }
597

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

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

    
658
                return name;
659
        }
660

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

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

    
750
        
751
        /**
752
         * A?ade un origen de datos de base de datos al sistema
753
         *
754
         * @param name
755
         *            Nombre de la tabla con el que se har? referencia en las
756
         *            instrucciones
757
         * @param connection
758
         *            Conexion de JDBC a la base de datos ya abierta (el 
759
         *            DataSource la usara, pero no la abrira/cerrara)
760
         * @param sql
761
         *            Instrucci?n SQL que define los datos de la tabla
762
         * @param driverInfo
763
         *            Informaci?n para saber qu? driver debe acceder a la
764
         *            informaci?n. Se escoger? el driver cuyo valor de retorno del
765
         *            m?todo getType coincida con este valor
766
         */
767
        public void addDBDataSourceBySQL(String name, Connection connection, String sql,
768
                        String driverInfo) {
769
                DBQuerySourceInfo info = new DBQuerySourceInfo();
770
                info.name = name;
771
                info.host = "";
772
                info.port = -1;
773
                info.user = "";
774
                info.password = "";
775
                info.dbName = "";
776
                info.dbms ="";
777
                info.connection = connection;
778
                info.sql = sql;
779
                info.driverName = driverInfo;
780
                tableSource.put(name, info);
781
        }
782
        
783
        
784
        
785
        
786
        
787
        
788
        
789
        /**
790
         * A?ade un origen de datos de base de datos al sistema
791
         *
792
         * @param host
793
         *            Cadena de conexi?n para conectar con el sgbd donde se
794
         *            encuentra la tabla
795
         * @param port
796
         *            Nombre del sgbd capaz de ejecutar SQL en el que reside la
797
         *            tabla. Generalmente ser? la parte de la cadena de conexi?n
798
         *            correspondiente a host, puerto y nombre de la base de datos
799
         * @param user
800
         *            Nombre de usuario. Null para acceso sin usuario
801
         * @param password
802
         *            Si el usuario es null se ignora el password
803
         * @param dbName
804
         *            Nombre de la base de datos a la que se accede
805
         * @param sql
806
         *            Instrucci?n SQL que define los datos de la tabla
807
         * @param driverInfo
808
         *            Informaci?n para saber qu? driver debe acceder a la
809
         *            informaci?n. Se escoger? el driver cuyo valor de retorno del
810
         *            m?todo getType coincida con este valor
811
         *
812
         * @return Nombre de la tabla con el que se har? referencia en las
813
         *         instrucciones
814
         */
815
        public String addDBDataSourceBySQL(String host, int port, String user,
816
                        String password, String dbName, String sql, String driverInfo) {
817
                String ret = getUID();
818
                addDBDataSourceBySQL(ret, host, port, user, password, dbName, sql,
819
                                driverInfo);
820

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

    
845
                return ret;
846
        }
847
        
848

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

    
865
                if (di == null) {
866
                        throw new NoSuchTableException(oldName);
867
                }
868

    
869
                tableSource.put(newName, di);
870
        }
871

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

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

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

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

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

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

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

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

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

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

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

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

    
1029
                        Driver d = dm.getDriver(fileInfo.driverName);
1030

    
1031
                        if (info instanceof FileCreationSourceInfo) {
1032
                                FileCreationSourceInfo creationInfo = (FileCreationSourceInfo) info;
1033
                                try {
1034
                                        if (!new File(creationInfo.file).exists()) {
1035
                                                ((FileDriver) d).createSource(creationInfo.file,
1036
                                                                creationInfo.fieldNames,
1037
                                                                creationInfo.fieldTypes);
1038
                                        }
1039
                                } catch (IOException e) {
1040
                                        throw new DriverException(e);
1041
                                }
1042
                        }
1043

    
1044
                        FileDataSource adapter;
1045

    
1046
                        if (fileInfo.spatial) {
1047
                                adapter = FileDataSourceFactory.newSpatialInstance();
1048
                        } else {
1049
                                adapter = FileDataSourceFactory.newInstance();
1050
                        }
1051

    
1052
                        ((GDBMSDriver) d).setDataSourceFactory(this);
1053
                        adapter.setDriver((FileDriver) d);
1054
                        adapter.setSourceInfo(fileInfo);
1055
                        adapter.setDataSourceFactory(this);
1056

    
1057
                        return getModedDataSource(adapter, mode);
1058
                } else if (info instanceof DBQuerySourceInfo) {
1059
                        DBQuerySourceInfo dbInfo = (DBQuerySourceInfo) info;
1060

    
1061
                        String driverInfo = dbInfo.driverName;
1062
                        Driver d = dm.getDriver(driverInfo);
1063

    
1064
                        ((GDBMSDriver) d).setDataSourceFactory(this);
1065
                        return getModedDataSource(getDataSourceByQuery(dbInfo.sql,
1066
                                        (AlphanumericDBDriver) d, dbInfo), mode);
1067
                } else if (info instanceof DBTableSourceInfo) {
1068
                        DBTableSourceInfo dbInfo = (DBTableSourceInfo) info;
1069

    
1070
                        String driverInfo = dbInfo.driverName;
1071
                        Driver d = dm.getDriver(driverInfo);
1072

    
1073
                        DBDataSource adapter;
1074

    
1075
                        if (info instanceof SpatialDBTableSourceInfo) {
1076
                                adapter = DBDataSourceFactory.newSpatialDataSourceInstance();
1077
                        } else {
1078
                                adapter = DBDataSourceFactory.newDataSourceInstance();
1079
                        }
1080

    
1081
                        ((GDBMSDriver) d).setDataSourceFactory(this);
1082
                        adapter.setDriver((DBDriver) d);
1083
                        adapter.setSourceInfo(dbInfo);
1084
                        adapter.setDataSourceFactory(this);
1085

    
1086
                        return getModedDataSource(adapter, mode);
1087
                } else if (info instanceof ObjectSourceInfo) {
1088
                        ObjectSourceInfo driverInfo = (ObjectSourceInfo) o;
1089
                        ObjectDataSource adapter = ObjectDataSourceFactory.newInstance();
1090
                        driverInfo.driver.setDataSourceFactory(this);
1091
                        adapter.setDriver(driverInfo.driver);
1092
                        adapter.setSourceInfo((ObjectSourceInfo) driverInfo);
1093
                        adapter.setDataSourceFactory(this);
1094

    
1095
                        return getModedDataSource(adapter, mode);
1096
                } else {
1097
                        throw new RuntimeException();
1098
                }
1099
        }
1100

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

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

    
1134
                        try {
1135
                                return createRandomDataSource(mem.getTableName(), mem
1136
                                                .getTableAlias(), mode);
1137
                        } catch (DriverLoadException e) {
1138
                                throw new RuntimeException(
1139
                                                "La informaci?n guardada no es consistente", e);
1140
                        } catch (NoSuchTableException e) {
1141
                                throw new RuntimeException(
1142
                                                "La informaci?n guardada no es consistente", e);
1143
                        } catch (DriverException e) {
1144
                                throw new RuntimeException(e);
1145
                        }
1146
                } else {
1147
                        OperationLayerMemento mem = (OperationLayerMemento) m;
1148

    
1149
                        try {
1150
                                return executeSQL(mem.getSql(), mode);
1151
                        } catch (DriverLoadException e) {
1152
                                throw new RuntimeException(
1153
                                                "La informaci?n guardada no es consistente", e);
1154
                        } catch (ParseException e) {
1155
                                throw new RuntimeException(
1156
                                                "La informaci?n guardada no es consistente", e);
1157
                        } catch (DriverException e) {
1158
                                throw new RuntimeException(
1159
                                                "La informaci?n guardada no es consistente", e);
1160
                        } catch (SemanticException e) {
1161
                                throw new RuntimeException(
1162
                                                "La informaci?n guardada no es consistente", e);
1163
                        } catch (IOException e) {
1164
                                throw new RuntimeException(
1165
                                                "La informaci?n guardada no es consistente", e);
1166
                        } catch (EvaluationException e) {
1167
                                throw new RuntimeException(
1168
                                                "La informaci?n guardada no es consistente", e);
1169
                        }
1170
                }
1171
        }
1172

    
1173
        /**
1174
         * Devuelve true si todas las tablas provienen del mismo data base
1175
         * management system
1176
         *
1177
         * @param tables
1178
         *            Array de tablas
1179
         *
1180
         * @return boolean
1181
         */
1182
        private boolean sameDBMS(DataSource[] tables) {
1183
                if (!(tables[0] instanceof DBDataSource)) {
1184
                        return false;
1185
                }
1186

    
1187
                String dbms = ((DBDataSource) tables[0]).getDBMS();
1188

    
1189
                for (int i = 1; i < tables.length; i++) {
1190
                        if (!(tables[i] instanceof DBDataSource)) {
1191
                                return false;
1192
                        }
1193

    
1194
                        if (!dbms.equals(((DBDataSource) tables[1]).getDBMS())) {
1195
                                return false;
1196
                        }
1197
                }
1198

    
1199
                return true;
1200
        }
1201

    
1202
        /**
1203
         * A partir de una instrucci?n select se encarga de obtener el DataSource
1204
         * resultado de la ejecuci?n de dicha instrucci?n
1205
         *
1206
         * @param instr
1207
         *            Instrucci?n select origen del datasource
1208
         * @param mode
1209
         *            opening mode
1210
         *
1211
         * @return DataSource que accede a los datos resultado de ejecutar la select
1212
         *
1213
         * @throws DriverLoadException
1214
         * @throws DriverException
1215
         *             Si fallo la lectura de la fuente de datos por parte del
1216
         *             driver
1217
         * @throws SemanticException
1218
         *             Si la instrucci?n tiene errores sem?nticos
1219
         * @throws IOException
1220
         *             Si se produce un error accediendo a las estructuras de datos
1221
         *             internas
1222
         * @throws EvaluationException
1223
         *             If there's an error evaluating any expression
1224
         */
1225
        public DataSource createRandomDataSource(SelectAdapter instr, int mode)
1226
                        throws DriverLoadException, DriverException, SemanticException,
1227
                        IOException, EvaluationException {
1228
                return getModedDataSource(getDataSource(instr), mode);
1229
        }
1230

    
1231
        /**
1232
         * Creates a view in the database management system that hosts the data
1233
         * source 'dbds'. The view is defined by the sql parameter
1234
         *
1235
         * @param dbds
1236
         *            DataSource used to execute the query
1237
         * @param sql
1238
         *            The SQL query defining the view
1239
         *
1240
         * @return Name of the view
1241
         *
1242
         * @throws DriverException
1243
         *             If the view cannot be created
1244
         */
1245
        private String getView(DBDataSource dbds, String sql)
1246
                        throws DriverException {
1247
                ServerViewInfo svi = (ServerViewInfo) sourceInfoServerViewInfo.get(dbds
1248
                                .getSourceInfo());
1249

    
1250
                /*
1251
                 * Return the view name if it's already created or create the view if
1252
                 * it's not created
1253
                 */
1254
                if (svi != null) {
1255
                        return svi.viewName;
1256
                } else {
1257
                        // create the view
1258
                        String viewName = getUID();
1259
                        String viewQuery = "CREATE VIEW " + viewName + " AS " + sql;
1260
                        dbds.execute(viewQuery);
1261

    
1262
                        // Register the view created
1263
                        sourceInfoServerViewInfo.put(dbds.getSourceInfo(),
1264
                                        new ServerViewInfo(dbds, viewName));
1265

    
1266
                        return viewName;
1267
                }
1268
        }
1269

    
1270
        /**
1271
         * Gets a DataSource implementation with the sql instruction as the data
1272
         * source by creating a view in the underlaying datasource management system
1273
         *
1274
         * @param sql
1275
         *            Instruction definig the data source
1276
         * @param driver
1277
         *            Driver used to access the data source
1278
         * @param dbInfo
1279
         *            data source info
1280
         *
1281
         * @return DataSource
1282
         *
1283
         * @throws DriverException
1284
         *             If cannot create the view
1285
         */
1286
        private DBDataSource getDataSourceByQuery(String sql,
1287
                        AlphanumericDBDriver driver, DBTableSourceInfo dbInfo)
1288
                        throws DriverException {
1289
                // Create the adapter
1290
                DBDataSource adapter = DBDataSourceFactory.newDataSourceInstance();
1291

    
1292
                // set the driver
1293
                adapter.setDriver(driver);
1294

    
1295
                // Create the query
1296
                adapter.setSourceInfo(dbInfo);
1297

    
1298
                // Gets the view name
1299
                String viewName = getView(adapter, sql);
1300

    
1301
                // Complete the source info with the view name
1302
                dbInfo.tableName = viewName;
1303

    
1304
                // Register the name association
1305
                nameTable.put(dbInfo.name, viewName);
1306

    
1307
                // setup the adapter
1308
                adapter.setSourceInfo(dbInfo);
1309
                adapter.setDataSourceFactory(this);
1310

    
1311
                return adapter;
1312
        }
1313

    
1314
        /**
1315
         * A partir de una instrucci?n select se encarga de obtener el DataSource
1316
         * resultado de la ejecuci?n de dicha instrucci?n
1317
         *
1318
         * @param instr
1319
         *            Instrucci?n select origen del datasource
1320
         *
1321
         * @return DataSource que accede a los datos resultado de ejecutar la select
1322
         *
1323
         * @throws DriverException
1324
         * @throws SemanticException
1325
         * @throws IOException
1326
         * @throws EvaluationException
1327
         * @throws RuntimeException
1328
         *             bug
1329
         */
1330
        private DataSource getDataSource(SelectAdapter instr)
1331
                        throws DriverException, SemanticException, IOException,
1332
                        EvaluationException {
1333
                DataSource[] tables = instr.getTables();
1334

    
1335
                // Estrategia de delegaci?n de la instrucci?n en el sgbd original de la
1336
                // tabla
1337
                if (sameDBMS(tables) && delegating) {
1338
                        String sql = translateInstruction(instr, tables);
1339

    
1340
                        DBDataSource table = (DBDataSource) tables[0];
1341

    
1342
                        // Set the driver info
1343
                        DBSourceInfo source = (DBSourceInfo) table.getSourceInfo();
1344
                        String dataSourceName = addDBDataSourceBySQL(source.host,
1345
                                        source.port, source.user, source.password, source.dbName,
1346
                                        sql, source.driverName);
1347

    
1348
                        try {
1349
                                return createRandomDataSource(dataSourceName,
1350
                                                DataSourceFactory.MANUAL_OPENING);
1351
                        } catch (NoSuchTableException e) {
1352
                                throw new RuntimeException(e);
1353
                        } catch (DriverLoadException e) {
1354
                                throw new RuntimeException(e);
1355
                        } catch (DriverException e) {
1356
                                throw new RuntimeException(e);
1357
                        }
1358
                }
1359

    
1360
                // Estrategia normal
1361
                Strategy strategy = StrategyManager.getStrategy(instr);
1362

    
1363
                OperationDataSource ret = strategy.select(instr);
1364

    
1365
                ret.setName(getUID());
1366
                nameOperationDataSource.put(ret.getName(), ret);
1367

    
1368
                return ret;
1369
        }
1370

    
1371
        /**
1372
         * Translates the table references by changind the gdbms name with the
1373
         * underlaying database management system table name
1374
         *
1375
         * @param instr
1376
         *            root of the adapted tree
1377
         * @param tables
1378
         *            DataSources involved in the instruction
1379
         *
1380
         * @return The translated sql query
1381
         *
1382
         * @throws DriverException
1383
         *             If driver access fails
1384
         * @throws SemanticException
1385
         *             If the instruction is not semantically correct
1386
         */
1387
        private String translateInstruction(Adapter instr, DataSource[] tables)
1388
                        throws DriverException, SemanticException {
1389
                HashMap instrNameDBName = new HashMap();
1390

    
1391
                translateFromTables(instr, instrNameDBName);
1392
                translateColRefs(instr, instrNameDBName, tables);
1393

    
1394
                return Utilities.getText(instr.getEntity());
1395
        }
1396

    
1397
        /**
1398
         * Gets the name of the table where the field is in
1399
         *
1400
         * @param fieldName
1401
         *            field whose table wants to be guessed
1402
         * @param tables
1403
         *            tables involved in the search
1404
         *
1405
         * @return table name
1406
         *
1407
         * @throws DriverException
1408
         *             If driver access fails
1409
         * @throws SemanticException
1410
         *             If the instruction is not semantically correct
1411
         */
1412
        private String guessTableName(String fieldName, DataSource[] tables)
1413
                        throws DriverException, SemanticException {
1414
                int tableIndex = -1;
1415

    
1416
                for (int i = 0; i < tables.length; i++) {
1417
                        tables[i].start();
1418

    
1419
                        if (tables[i].getFieldIndexByName(fieldName) != -1) {
1420
                                if (tableIndex != -1) {
1421
                                        throw new SemanticException("ambiguous column reference: "
1422
                                                        + fieldName);
1423
                                } else {
1424
                                        tableIndex = i;
1425
                                }
1426
                        }
1427

    
1428
                        tables[i].stop();
1429
                }
1430

    
1431
                if (tableIndex == -1) {
1432
                        throw new SemanticException("Field not found: " + fieldName);
1433
                }
1434

    
1435
                return tables[tableIndex].getName();
1436
        }
1437

    
1438
        /**
1439
         * Translates the table references by changind the gdbms name with the
1440
         * underlaying database management system table name
1441
         *
1442
         * @param adapter
1443
         *            adapter processed
1444
         * @param instrNameDBName
1445
         *            hasmap with the gdbms names a s the keys and the database name
1446
         *            as the values.
1447
         * @param tables
1448
         *            tables involved in the instruction
1449
         *
1450
         * @throws DriverException
1451
         *             If driver access fails
1452
         * @throws SemanticException
1453
         *             If the instruction is not semantically correct
1454
         */
1455
        private void translateColRefs(Adapter adapter, HashMap instrNameDBName,
1456
                        DataSource[] tables) throws DriverException, SemanticException {
1457
                if (adapter instanceof ColRefAdapter) {
1458
                        ColRefAdapter tra = (ColRefAdapter) adapter;
1459
                        SimpleNode s = tra.getEntity();
1460

    
1461
                        if (s.first_token != s.last_token) {
1462
                                String name = s.first_token.image;
1463
                                s.first_token.image = instrNameDBName.get(name).toString();
1464
                        } else {
1465
                                String tableName = guessTableName(s.first_token.image, tables);
1466
                                s.first_token.image = instrNameDBName.get(tableName) + "."
1467
                                                + s.first_token.image;
1468
                        }
1469
                } else {
1470
                        Adapter[] hijos = adapter.getChilds();
1471

    
1472
                        for (int i = 0; i < hijos.length; i++) {
1473
                                translateColRefs(hijos[i], instrNameDBName, tables);
1474
                        }
1475
                }
1476
        }
1477

    
1478
        /**
1479
         * Translates the table references by changind the gdbms name with the
1480
         * underlaying database management system table name
1481
         *
1482
         * @param adapter
1483
         *            adapter processed
1484
         * @param instrNameDBName
1485
         *            hasmap with the gdbms names a s the keys and the database name
1486
         *            as the values.
1487
         */
1488
        private void translateFromTables(Adapter adapter, HashMap instrNameDBName) {
1489
                if (adapter instanceof TableRefAdapter) {
1490
                        TableRefAdapter tra = (TableRefAdapter) adapter;
1491
                        SimpleNode s = tra.getEntity();
1492

    
1493
                        if (s.first_token == s.last_token) {
1494
                                String alias = "gdbms" + System.currentTimeMillis();
1495
                                String name = s.first_token.image;
1496
                                s.first_token.image = nameTable.get(name) + " " + alias;
1497
                                instrNameDBName.put(name, alias);
1498
                        } else {
1499
                                String alias = s.last_token.image;
1500
                                String name = s.first_token.image;
1501
                                s.first_token.image = nameTable.get(name).toString();
1502
                                instrNameDBName.put(alias, alias);
1503
                        }
1504
                } else {
1505
                        Adapter[] hijos = adapter.getChilds();
1506

    
1507
                        for (int i = 0; i < hijos.length; i++) {
1508
                                translateFromTables(hijos[i], instrNameDBName);
1509
                        }
1510
                }
1511
        }
1512

    
1513
        /**
1514
         * Obtiene el DataSource resultado de ejecutar la instrucci?n de union
1515
         *
1516
         * @param instr
1517
         *            instrucci?n de union
1518
         * @param mode
1519
         *            opening mode
1520
         *
1521
         * @return DataSource
1522
         *
1523
         * @throws DriverException
1524
         *             Si fallo la lectura de la fuente de datos por parte del
1525
         *             driver
1526
         * @throws IOException
1527
         *             Si se produce un error de entrada/salida
1528
         * @throws SemanticException
1529
         *             Si la instrucci?n tiene errores sem?nticos
1530
         * @throws EvaluationException
1531
         *             If there's any problem during expresion evaluation
1532
         * @throws ParseException
1533
         *             If there is a select statement embeeded in the union
1534
         *             statement and its parse fails
1535
         */
1536
        public DataSource createRandomDataSource(UnionAdapter instr, int mode)
1537
                        throws DriverException, IOException, SemanticException,
1538
                        EvaluationException, ParseException {
1539
                return getModedDataSource(getDataSource(instr), mode);
1540
        }
1541

    
1542
        /**
1543
         * Obtiene el DataSource resultado de ejecutar la instrucci?n de union
1544
         *
1545
         * @param instr
1546
         *            instrucci?n de union
1547
         *
1548
         * @return DataSource
1549
         *
1550
         * @throws DriverException
1551
         *             Si fallo la lectura de la fuente de datos por parte del
1552
         *             driver
1553
         * @throws IOException
1554
         *             Si se produce un error de entrada/salida
1555
         * @throws SemanticException
1556
         *             Si la instrucci?n tiene errores sem?nticos
1557
         * @throws ParseException
1558
         *             If there is a select statement embeeded in the union
1559
         *             statement and its parse fails
1560
         * @throws EvaluationException
1561
         *             If there's any problem during expresion evaluation
1562
         */
1563
        private DataSource getDataSource(UnionAdapter instr)
1564
                        throws DriverException, IOException, SemanticException,
1565
                        ParseException, EvaluationException {
1566
                try {
1567
                        Strategy strategy = StrategyManager.getStrategy(instr);
1568

    
1569
                        OperationDataSource ret;
1570
                        ret = strategy.union(instr);
1571

    
1572
                        ret.setName(getUID());
1573
                        nameOperationDataSource.put(ret.getName(), ret);
1574

    
1575
                        return ret;
1576
                } catch (DriverLoadException e) {
1577
                        throw new DriverException(e);
1578
                }
1579

    
1580
        }
1581

    
1582
        /**
1583
         * Creates a DataSource as a result of a custom query
1584
         *
1585
         * @param instr
1586
         *            Root node of the adapter tree of the custom query instruction
1587
         * @param mode
1588
         *            opening mode
1589
         *
1590
         * @return DataSource with the custom query result
1591
         *
1592
         * @throws SemanticException
1593
         *             if there is any semantic error in the instruction
1594
         */
1595
        public DataSource getDataSource(CustomAdapter instr, int mode)
1596
                        throws SemanticException {
1597
                return getModedDataSource(getDataSource(instr), mode);
1598
        }
1599

    
1600
        /**
1601
         * Creates a DataSource as a result of a custom query
1602
         *
1603
         * @param instr
1604
         *            Root node of the adapter tree of the custom query instruction
1605
         *
1606
         * @return DataSource with the custom query result
1607
         *
1608
         * @throws SemanticException
1609
         *             if there is any semantic error in the instruction
1610
         */
1611
        private DataSource getDataSource(CustomAdapter instr)
1612
                        throws SemanticException {
1613
                Strategy strategy = StrategyManager.getStrategy(instr);
1614

    
1615
                OperationDataSource ret = strategy.custom(instr);
1616

    
1617
                ret.setName(getUID());
1618
                nameOperationDataSource.put(ret.getName(), ret);
1619

    
1620
                return ret;
1621
        }
1622

    
1623
        /**
1624
         * Ejecuta la instrucci?n SQL que se pasa como par?metro obteniendo un
1625
         * DataSource con el resultado de la ejecuci?n
1626
         *
1627
         * @param sql
1628
         *            instrucci?n sql que se quiere ejecutar
1629
         * @param mode
1630
         *            opening mode
1631
         *
1632
         * @return DataSource con el resultado
1633
         *
1634
         * @throws ParseException
1635
         *             Si se produce un error de parse de la instrucci?n
1636
         * @throws DriverLoadException
1637
         *             Si no se pueden cargar los drivers
1638
         * @throws DriverException
1639
         *             Si se produce un error accediendo a los drivers
1640
         * @throws SemanticException
1641
         *             Si la instrucci?n tiene alg?n error sem?ntico
1642
         * @throws IOException
1643
         *             Si se produce un error accediendo a las estructuras de datos
1644
         *             internas usadas para los c?lculos
1645
         * @throws EvaluationException
1646
         *             If there's an error evaluating any expression
1647
         */
1648
        public DataSource executeSQL(String sql, int mode) throws ParseException,
1649
                        DriverLoadException, DriverException, SemanticException,
1650
                        IOException, EvaluationException {
1651
                ByteArrayInputStream bytes = new ByteArrayInputStream(sql.getBytes());
1652
                SQLEngine parser = new SQLEngine(bytes);
1653

    
1654
                parser.SQLStatement();
1655

    
1656
                Node root = parser.getRootNode();
1657
                Adapter rootAdapter = Utilities.buildTree(root.jjtGetChild(0), sql,
1658
                                this);
1659

    
1660
                Utilities.simplify(rootAdapter);
1661

    
1662
                DataSource result = null;
1663

    
1664
                if (rootAdapter instanceof SelectAdapter) {
1665
                        result = getDataSource((SelectAdapter) rootAdapter);
1666
                } else if (rootAdapter instanceof UnionAdapter) {
1667
                        result = getDataSource((UnionAdapter) rootAdapter);
1668
                } else if (rootAdapter instanceof CustomAdapter) {
1669
                        result = getDataSource((CustomAdapter) rootAdapter);
1670
                }
1671

    
1672
                // if operation was delegated it isn't a OperationDataSource
1673
                if (result instanceof OperationDataSource) {
1674
                        ((OperationDataSource) result).setSQL(sql);
1675
                }
1676

    
1677
                result.setDataSourceFactory(this);
1678

    
1679
                return getModedDataSource(result, mode);
1680
        }
1681

    
1682
        /**
1683
         * Establece el DriverManager que se usar? para instanciar DataSource's.
1684
         * Este metodo debe ser invocado antes que ning?n otro
1685
         *
1686
         * @param dm
1687
         *            El manager que se encarga de cargar los drivers
1688
         */
1689
        public void setDriverManager(DriverManager dm) {
1690
                this.dm = dm;
1691
        }
1692
        /**
1693
         * Establece el WriterManager que se usar? para instanciar DataSource's.
1694
         * Este metodo debe ser invocado antes que ning?n otro
1695
         *
1696
         * @param dm
1697
         *            El manager que se encarga de cargar los drivers
1698
         */
1699
        public void setWriterManager(WriterManager wm) {
1700
                this.wm = wm;
1701
        }
1702
        /**
1703
         * Get's the module with the specified name
1704
         *
1705
         * @param name
1706
         *            name of the wanted module
1707
         *
1708
         * @return instance of the module
1709
         */
1710
        public Object getModule(String name) {
1711
                return ms.getModule(name);
1712
        }
1713

    
1714
        /**
1715
         * Registers a module in the system with the specified name
1716
         *
1717
         * @param name
1718
         *            name of the module
1719
         * @param instance
1720
         *            module instance
1721
         */
1722
        public void registerModule(String name, Object instance) {
1723
                ms.registerModule(name, instance);
1724
        }
1725

    
1726
        /**
1727
         * Gets a driver manager reference
1728
         *
1729
         * @return DriverManagers.
1730
         */
1731
        public DriverManager getDriverManager() {
1732
                return dm;
1733
        }
1734
        /**
1735
         * Gets a writer manager reference
1736
         *
1737
         * @return WriterManagers.
1738
         */
1739
        public WriterManager getWriterManager() {
1740
                return wm;
1741
        }
1742
        /**
1743
         * Sets if this factory will check for delegating instructions at the server
1744
         * (true) or will execute all queries internally (false). By delegating at
1745
         * the server, lots of queries will be defined in the database management
1746
         * system where the execution is delegated. Invoke clearViews to remove all
1747
         * created views.
1748
         *
1749
         * @param b
1750
         */
1751
        public void setDelegating(boolean b) {
1752
                this.delegating = b;
1753
        }
1754

    
1755
        /**
1756
         * Creates a new table on the specified database
1757
         *
1758
         * @param database
1759
         *            name of the database where the table will be created
1760
         * @param pkNames
1761
         *            Names of the primary key fields
1762
         * @param names
1763
         *            names of the fields
1764
         * @param types
1765
         *            types of the fields. Must have the same length than names
1766
         *
1767
         * @return the table name
1768
         *
1769
         * @throws SQLException
1770
         *             if the creation fails
1771
         */
1772
        public String createTable(String database, String[] pkNames,
1773
                        String[] names, int[] types) throws SQLException {
1774
                // Get a name for the table
1775
                String tableName = getUID();
1776

    
1777
                // Create the table
1778
                InnerDBUtils.execute(database, InnerDBUtils.getCreateStatementWithPK(
1779
                                tableName, pkNames, names, types));
1780

    
1781
                return tableName;
1782
        }
1783

    
1784
        /**
1785
         * Frees all resources used during execution
1786
         *
1787
         * @throws SQLException
1788
         *             If cannot free internal resources
1789
         * @throws DriverException
1790
         *             If drivers cannot free remote resources
1791
         */
1792
        public void finalize() throws SQLException, DriverException {
1793
                finalizeThis();
1794
        }
1795
        
1796
        public void finalizeThis() {
1797
                try {
1798
                        clearViews();
1799
                } catch (Exception e) {
1800
                        e.printStackTrace();
1801
                }
1802
                
1803
                
1804
                try {
1805
                        Connection c = java.sql.DriverManager.getConnection(
1806
                                        "jdbc:hsqldb:file:", "", "");
1807
                        Statement st = c.createStatement();
1808
                        st.execute("SHUTDOWN");
1809
                        st.close();
1810
                        c.close();
1811
                } catch (Exception e) {
1812
                        e.printStackTrace();
1813
                }
1814
                
1815
        }
1816

    
1817
        /**
1818
         * Initializes the system.
1819
         *
1820
         * @throws InitializationException
1821
         *             If the initialization
1822
         */
1823
        public void initialize() throws InitializationException {
1824
                initialize(".");
1825
        }
1826

    
1827
        /**
1828
         * Initializes the system
1829
         *
1830
         * @param tempDir
1831
         *            temporary directory to write data
1832
         *
1833
         * @throws InitializationException
1834
         *             If the initialization fails
1835
         */
1836
        public void initialize(String tempDir) throws InitializationException {
1837
                try {
1838
                        this.tempDir = new File(tempDir);
1839

    
1840
                        if (!this.tempDir.exists()) {
1841
                                this.tempDir.mkdirs();
1842
                        }
1843

    
1844
                        Class.forName("org.hsqldb.jdbcDriver");
1845
                } catch (ClassNotFoundException e) {
1846
                        throw new InitializationException(e);
1847
                }
1848
        }
1849

    
1850
        /**
1851
         * Gets the URL of a file in the temporary directory. Does not creates any
1852
         * file
1853
         *
1854
         * @return String
1855
         */
1856
        public String getTempFile() {
1857
                return tempDir.getAbsolutePath() + File.separator + "gdmbs"
1858
                                + System.currentTimeMillis();
1859
        }
1860

    
1861
        /**
1862
         * Information to delete the view on the server: name of the view and the
1863
         * adapter to remove it
1864
         */
1865
        private class ServerViewInfo {
1866
                public DBDataSource adapter;
1867

    
1868
                public String viewName;
1869

    
1870
                /**
1871
                 * Crea un nuevo ServerViewInfo.
1872
                 *
1873
                 * @param ds
1874
                 *            DOCUMENT ME!
1875
                 * @param name
1876
                 *            DOCUMENT ME!
1877
                 */
1878
                public ServerViewInfo(DBDataSource ds, String name) {
1879
                        adapter = ds;
1880
                        viewName = name;
1881
                }
1882
        }
1883
}