Statistics
| Revision:

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

History | View | Annotate | Download (48.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.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.Iterator;
12

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

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

    
68
        public final static int AUTOMATIC_OPENING = 1;
69

    
70
        public final static int DATA_WARE_DIRECT_MODE = 0;
71

    
72
        public final static int DATA_WARE_COHERENT_ROW_ORDER = 1;
73

    
74
        final static int DEFAULT_DELAY = 5000;
75

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

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

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

    
90
        private HashMap sourceInfoServerViewInfo = new HashMap();
91

    
92
        private DriverManager dm;
93

    
94
        private ModuleSupport ms = new ModuleSupport();
95

    
96
        private long delay = DEFAULT_DELAY;
97

    
98
        private boolean delegating = false;
99

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

    
102
        private WriterManager wm;
103

    
104
        /**
105
         * Get's a unique id in the tableSource and nameOperationDataSource key sets
106
         *
107
         * @return unique id
108
         */
109
        private String getUID() {
110
                String name = "gdbms" + System.currentTimeMillis();
111

    
112
                while (tableSource.get(name) != null) {
113
                        name = "gdbms" + System.currentTimeMillis();
114
                }
115

    
116
                return name;
117
        }
118

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

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

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

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

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

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

    
179
                sourceInfoServerViewInfo.clear();
180
        }
181

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

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

    
212
                return ret;
213
        }
214

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

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

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

    
271
                return info;
272
        }
273

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

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

    
305
                return ret;
306
        }
307

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

    
324
                return ret;
325
        }
326

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

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

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

    
357
                return (SourceInfo[]) ret.toArray(new SourceInfo[0]);
358
        }
359

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

    
396
        /**
397
         * Fills the info struct with the values passed in the parameters
398
         *
399
         * @param info
400
         *            struct to populate
401
         * @param name
402
         *            Name of the data source
403
         * @param host
404
         *            host where the data is
405
         * @param port
406
         *            port number
407
         * @param user
408
         *            user name or null.
409
         * @param password
410
         *            if user name is null is ignored
411
         * @param dbName
412
         *            database name
413
         * @param tableName
414
         *            table name
415
         * @param driverInfo
416
         *            name of the driver used to access the data
417
         */
418
        private void fillDBTableSourceInfo(DBTableSourceInfo info, String name,
419
                        String host, int port, String user, String password, String dbName,
420
                        String tableName, String driverInfo) {
421
                info.name = name;
422
                info.host = host;
423
                info.port = port;
424
                info.user = user;
425
                info.password = password;
426
                info.dbName = dbName;
427
                info.dbms = host + ":" + port + "/" + dbName + "," + user + ","
428
                                + password;
429
                info.tableName = tableName;
430
                info.driverName = driverInfo;
431
        }
432

    
433
        /**
434
         * Adds a spatial database data source
435
         *
436
         * @param name
437
         *            Name of the data source
438
         * @param host
439
         *            host where the data is
440
         * @param port
441
         *            port number
442
         * @param user
443
         *            user name or null.
444
         * @param password
445
         *            if user name is null is ignored
446
         * @param dbName
447
         *            database name
448
         * @param tableName
449
         *            table name
450
         * @param geometryFieldName
451
         *            name of the field that has the geometry
452
         * @param driverInfo
453
         *            name of the driver used to access the data
454
         */
455
        public void addSpatialDBDataSource(String name, String host, int port,
456
                        String user, String password, String dbName, String tableName,
457
                        String geometryFieldName, String driverInfo) {
458
                SpatialDBTableSourceInfo info = new SpatialDBTableSourceInfo();
459
                fillDBTableSourceInfo(info, name, host, port, user, password, dbName,
460
                                tableName, driverInfo);
461
                info.geometryField = geometryFieldName;
462
                tableSource.put(name, info);
463
                nameTable.put(name, tableName);
464
        }
465

    
466
        /**
467
         * Adds a spatial database data source
468
         *
469
         * @param host
470
         *            host where the data is
471
         * @param port
472
         *            port number
473
         * @param user
474
         *            user name or null.
475
         * @param password
476
         *            if user name is null is ignored
477
         * @param dbName
478
         *            database name
479
         * @param tableName
480
         *            table name
481
         * @param geometryFieldName
482
         *            name of the field that has the geometry
483
         * @param driverInfo
484
         *            name of the driver used to access the data
485
         *
486
         * @return generated name of the added data source
487
         */
488
        public String addSpatialDBDataSource(String host, int port, String user,
489
                        String password, String dbName, String tableName,
490
                        String geometryFieldName, String driverInfo) {
491
                String ret = getUID();
492
                addSpatialDBDataSource(ret, host, port, user, password, dbName,
493
                                tableName, geometryFieldName, driverInfo);
494

    
495
                return ret;
496
        }
497

    
498
        /**
499
         * A?ade un origen de datos de base de datos al sistema
500
         *
501
         * @param host
502
         *            Cadena de conexi?n para conectar con el sgbd donde se
503
         *            encuentra la tabla
504
         * @param port
505
         *            Nombre del sgbd capaz de ejecutar SQL en el que reside la
506
         *            tabla. Generalmente ser? la parte de la cadena de conexi?n
507
         *            correspondiente a host, puerto y nombre de la base de datos
508
         * @param user
509
         *            Nombre de usuario. Null para acceso sin usuario
510
         * @param password
511
         *            Si el usuario es null se ignora el password
512
         * @param dbName
513
         *            Nombre de la base de datos a la que se accede
514
         * @param tableName
515
         *            Nombre de la tabla en la base de datos
516
         * @param driverInfo
517
         *            Informaci?n para saber qu? driver debe acceder a la
518
         *            informaci?n. Se escoger? el driver cuyo valor de retorno del
519
         *            m?todo getType coincida con este valor
520
         *
521
         * @return Nombre de la tabla con el que se har? referencia en las
522
         *         instrucciones
523
         */
524
        public String addDBDataSourceByTable(String host, int port, String user,
525
                        String password, String dbName, String tableName, String driverInfo) {
526
                String name = getUID();
527
                addDBDataSourceByTable(name, host, port, user, password, dbName,
528
                                tableName, driverInfo);
529

    
530
                return name;
531
        }
532

    
533
        /**
534
         * A?ade un origen de datos de base de datos al sistema
535
         *
536
         * @param name
537
         *            Nombre de la tabla con el que se har? referencia en las
538
         *            instrucciones
539
         * @param host
540
         *            Cadena de conexi?n para conectar con el sgbd donde se
541
         *            encuentra la tabla
542
         * @param port
543
         *            Nombre del sgbd capaz de ejecutar SQL en el que reside la
544
         *            tabla. Generalmente ser? la parte de la cadena de conexi?n
545
         *            correspondiente a host, puerto y nombre de la base de datos
546
         * @param user
547
         *            Nombre de usuario. Null para acceso sin usuario
548
         * @param password
549
         *            Si el usuario es null se ignora el password
550
         * @param dbName
551
         *            Nombre de la base de datos a la que se accede
552
         * @param sql
553
         *            Instrucci?n SQL que define los datos de la tabla
554
         * @param driverInfo
555
         *            Informaci?n para saber qu? driver debe acceder a la
556
         *            informaci?n. Se escoger? el driver cuyo valor de retorno del
557
         *            m?todo getType coincida con este valor
558
         */
559
        public void addDBDataSourceBySQL(String name, String host, int port,
560
                        String user, String password, String dbName, String sql,
561
                        String driverInfo) {
562
                DBQuerySourceInfo info = new DBQuerySourceInfo();
563
                info.name = name;
564
                info.host = host;
565
                info.port = port;
566
                info.user = user;
567
                info.password = password;
568
                info.dbName = dbName;
569
                info.dbms = host + ":" + port + "/" + dbName + "," + user + ","
570
                                + password;
571
                info.sql = sql;
572
                info.driverName = driverInfo;
573
                tableSource.put(name, info);
574
        }
575

    
576
        /**
577
         * A?ade un origen de datos de base de datos al sistema
578
         *
579
         * @param host
580
         *            Cadena de conexi?n para conectar con el sgbd donde se
581
         *            encuentra la tabla
582
         * @param port
583
         *            Nombre del sgbd capaz de ejecutar SQL en el que reside la
584
         *            tabla. Generalmente ser? la parte de la cadena de conexi?n
585
         *            correspondiente a host, puerto y nombre de la base de datos
586
         * @param user
587
         *            Nombre de usuario. Null para acceso sin usuario
588
         * @param password
589
         *            Si el usuario es null se ignora el password
590
         * @param dbName
591
         *            Nombre de la base de datos a la que se accede
592
         * @param sql
593
         *            Instrucci?n SQL que define los datos de la tabla
594
         * @param driverInfo
595
         *            Informaci?n para saber qu? driver debe acceder a la
596
         *            informaci?n. Se escoger? el driver cuyo valor de retorno del
597
         *            m?todo getType coincida con este valor
598
         *
599
         * @return Nombre de la tabla con el que se har? referencia en las
600
         *         instrucciones
601
         */
602
        public String addDBDataSourceBySQL(String host, int port, String user,
603
                        String password, String dbName, String sql, String driverInfo) {
604
                String ret = getUID();
605
                addDBDataSourceBySQL(ret, host, port, user, password, dbName, sql,
606
                                driverInfo);
607

    
608
                return ret;
609
        }
610

    
611
        /**
612
         * Cambia el nombre de una fuente de datos. Las consultas SQL que se
613
         * ejecuten con el nombre anterior fallar?n
614
         *
615
         * @param oldName
616
         *            Nombre actual de la fuente de datos que se quiere cambiar
617
         * @param newName
618
         *            Nombre que se le quiere poner a la fuente de datos
619
         *
620
         * @throws NoSuchTableException
621
         *             Si no hay ninguna fuente de datos de nombre 'oldName'
622
         */
623
        public void changeDataSourceName(String oldName, String newName)
624
                        throws NoSuchTableException {
625
                SourceInfo di = (SourceInfo) tableSource.remove(oldName);
626

    
627
                if (di == null) {
628
                        throw new NoSuchTableException(oldName);
629
                }
630

    
631
                tableSource.put(newName, di);
632
        }
633

    
634
        /**
635
         * Gets the data source passed by adding the AutomaticDataSource decorator
636
         * if factory mode is AUTOMATIC.
637
         *
638
         * @param ds
639
         *            DataSource
640
         * @param mode
641
         *            opening mode
642
         *
643
         * @return DataSource
644
         */
645
        private DataSource getModedDataSource(DataSource ds, int mode) {
646
                if (mode == AUTOMATIC_OPENING) {
647
                        return new AutomaticDataSource(ds, delay);
648
                } else {
649
                        return ds;
650
                }
651
        }
652

    
653
        /**
654
         * Sets the minimum delay between accesses needed to close the DataSource.
655
         * If accesses are delayed more than 'delay' the DataSource MAY be closed.
656
         * Only applies when the mode is set to AUTOMATIC_MODE
657
         *
658
         * @param delay
659
         *            time un milliseconds
660
         */
661
        public void setClosingDelay(long delay) {
662
                this.delay = delay;
663
        }
664

    
665
        /**
666
         * Dado el nombre de una tabla, se busca la fuente de datos asociada a dicha
667
         * tabla y se obtiene un datasource adecuado en funcion del tipo de fuente
668
         * de datos accediendo al subsistema de drivers
669
         *
670
         * @param tableName
671
         *            Nombre de la fuente de datos
672
         *
673
         * @return DataSource que accede a dicha fuente
674
         *
675
         * @throws DriverLoadException
676
         * @throws NoSuchTableException
677
         * @throws DriverException
678
         */
679
        public DataSource createRandomDataSource(String tableName)
680
                        throws DriverLoadException, NoSuchTableException, DriverException {
681
                return createRandomDataSource(tableName, tableName, MANUAL_OPENING);
682
        }
683

    
684
        /**
685
         * Dado el nombre de una tabla, se busca la fuente de datos asociada a dicha
686
         * tabla y se obtiene un datasource adecuado en funcion del tipo de fuente
687
         * de datos accediendo al subsistema de drivers
688
         *
689
         * @param tableName
690
         *            Nombre de la fuente de datos
691
         * @param mode
692
         *            opening mode: AUTOMATIC_OPENING -> the DataSource opens
693
         *            automatically and closes after a while. It can be closed
694
         *            manually. MANUAL_OPENING -> the DataSource opens and closes
695
         *            manually
696
         *
697
         * @return DataSource que accede a dicha fuente
698
         *
699
         * @throws DriverLoadException
700
         * @throws NoSuchTableException
701
         * @throws DriverException
702
         */
703
        public DataSource createRandomDataSource(String tableName, int mode)
704
                        throws DriverLoadException, NoSuchTableException, DriverException {
705
                return createRandomDataSource(tableName, tableName, mode);
706
        }
707

    
708
        /**
709
         * Dado el nombre de una tabla, se busca la fuente de datos asociada a dicha
710
         * tabla y se obtiene un datasource adecuado en funcion del tipo de fuente
711
         * de datos accediendo al subsistema de drivers. Se utiliza internamente
712
         * como nombre del DataSource el alias que se pasa como par?metro
713
         *
714
         * @param tableName
715
         *            Nombre de la fuente de datos
716
         * @param tableAlias
717
         *            Alias que tiene el DataSource en una instrucci?n
718
         *
719
         * @return DataSource que accede a dicha fuente de datos si la fuente de
720
         *         datos es alfanum?rica o SpatialDataSource si la fuente de datos
721
         *         es espacial
722
         *
723
         * @throws NoSuchTableException
724
         *             Si no hay una fuente de datos registrada con ese nombre
725
         * @throws DriverLoadException
726
         *             Si hay alg?n error con el sistema de carga de drivers
727
         * @throws DriverException
728
         *             If the created DataSource have to access some data this
729
         *             access fails
730
         * @throws RuntimeException
731
         *             bug
732
         */
733
        public DataSource createRandomDataSource(String tableName, String tableAlias)
734
                        throws NoSuchTableException, DriverLoadException, DriverException {
735
                return createRandomDataSource(tableName, tableAlias, MANUAL_OPENING);
736
        }
737

    
738
        /**
739
         * Dado el nombre de una tabla, se busca la fuente de datos asociada a dicha
740
         * tabla y se obtiene un datasource adecuado en funcion del tipo de fuente
741
         * de datos accediendo al subsistema de drivers. Se utiliza internamente
742
         * como nombre del DataSource el alias que se pasa como par?metro
743
         *
744
         * @param tableName
745
         *            Nombre de la fuente de datos
746
         * @param tableAlias
747
         *            Alias que tiene el DataSource en una instrucci?n
748
         * @param mode
749
         *            openning mode
750
         *
751
         * @return DataSource que accede a dicha fuente de datos si la fuente de
752
         *         datos es alfanum?rica o SpatialDataSource si la fuente de datos
753
         *         es espacial
754
         *
755
         * @throws NoSuchTableException
756
         *             Si no hay una fuente de datos registrada con ese nombre
757
         * @throws DriverLoadException
758
         *             Si hay alg?n error con el sistema de carga de drivers
759
         * @throws DriverException
760
         *             If the created DataSource have to access some data this
761
         *             access fails
762
         * @throws RuntimeException
763
         *             bug
764
         */
765
        public DataSource createRandomDataSource(String tableName,
766
                        String tableAlias, int mode) throws NoSuchTableException,
767
                        DriverLoadException, DriverException {
768
                Object o = tableSource.get(tableName);
769

    
770
                if (o == null) {
771
                        // may be a operation layer DataSource
772
                        OperationDataSource ret = (OperationDataSource) nameOperationDataSource
773
                                        .get(tableName);
774

    
775
                        if (ret != null) {
776
                                ret.setName(tableAlias);
777

    
778
                                return getModedDataSource(ret, mode);
779
                        }
780

    
781
                        // table not found
782
                        throw new NoSuchTableException(tableName);
783
                }
784

    
785
                SourceInfo info = (SourceInfo) o;
786
                info.name = tableAlias;
787

    
788
                if (info instanceof FileSourceInfo) {
789
                        FileSourceInfo fileInfo = (FileSourceInfo) info;
790

    
791
                        Driver d = dm.getDriver(fileInfo.driverName);
792

    
793
                        if (info instanceof FileCreationSourceInfo) {
794
                                FileCreationSourceInfo creationInfo = (FileCreationSourceInfo) info;
795
                                try {
796
                                        if (!new File(creationInfo.file).exists()) {
797
                                                ((FileDriver) d).createSource(creationInfo.file,
798
                                                                creationInfo.fieldNames,
799
                                                                creationInfo.fieldTypes);
800
                                        }
801
                                } catch (IOException e) {
802
                                        throw new DriverException(e);
803
                                }
804
                        }
805

    
806
                        FileDataSource adapter;
807

    
808
                        if (fileInfo.spatial) {
809
                                adapter = FileDataSourceFactory.newSpatialInstance();
810
                        } else {
811
                                adapter = FileDataSourceFactory.newInstance();
812
                        }
813

    
814
                        ((GDBMSDriver) d).setDataSourceFactory(this);
815
                        adapter.setDriver((FileDriver) d);
816
                        adapter.setSourceInfo(fileInfo);
817
                        adapter.setDataSourceFactory(this);
818

    
819
                        return getModedDataSource(adapter, mode);
820
                } else if (info instanceof DBQuerySourceInfo) {
821
                        DBQuerySourceInfo dbInfo = (DBQuerySourceInfo) info;
822

    
823
                        String driverInfo = dbInfo.driverName;
824
                        Driver d = dm.getDriver(driverInfo);
825

    
826
                        ((GDBMSDriver) d).setDataSourceFactory(this);
827
                        return getModedDataSource(getDataSourceByQuery(dbInfo.sql,
828
                                        (AlphanumericDBDriver) d, dbInfo), mode);
829
                } else if (info instanceof DBTableSourceInfo) {
830
                        DBTableSourceInfo dbInfo = (DBTableSourceInfo) info;
831

    
832
                        String driverInfo = dbInfo.driverName;
833
                        Driver d = dm.getDriver(driverInfo);
834

    
835
                        DBDataSource adapter;
836

    
837
                        if (info instanceof SpatialDBTableSourceInfo) {
838
                                adapter = DBDataSourceFactory.newSpatialDataSourceInstance();
839
                        } else {
840
                                adapter = DBDataSourceFactory.newDataSourceInstance();
841
                        }
842

    
843
                        ((GDBMSDriver) d).setDataSourceFactory(this);
844
                        adapter.setDriver((DBDriver) d);
845
                        adapter.setSourceInfo(dbInfo);
846
                        adapter.setDataSourceFactory(this);
847

    
848
                        return getModedDataSource(adapter, mode);
849
                } else if (info instanceof ObjectSourceInfo) {
850
                        ObjectSourceInfo driverInfo = (ObjectSourceInfo) o;
851
                        ObjectDataSource adapter = ObjectDataSourceFactory.newInstance();
852
                        driverInfo.driver.setDataSourceFactory(this);
853
                        adapter.setDriver(driverInfo.driver);
854
                        adapter.setSourceInfo((ObjectSourceInfo) driverInfo);
855
                        adapter.setDataSourceFactory(this);
856

    
857
                        return getModedDataSource(adapter, mode);
858
                } else {
859
                        throw new RuntimeException();
860
                }
861
        }
862

    
863
        /**
864
         * Creates a DataSource from a memento object with the manual opening mode
865
         *
866
         * @param m
867
         *            memento
868
         *
869
         * @return DataSource
870
         *
871
         * @throws RuntimeException
872
         *             If the DataSource class cannot be instatiated
873
         */
874
        public DataSource createRandomDataSource(Memento m) {
875
                return createRandomDataSource(m, DataSourceFactory.MANUAL_OPENING);
876
        }
877

    
878
        /**
879
         * Creates a DataSource from a memento object with the specified opening
880
         * mode
881
         *
882
         * @param m
883
         *            memento
884
         * @param mode
885
         *            opening mode
886
         *
887
         * @return DataSource
888
         *
889
         * @throws RuntimeException
890
         *             If the DataSource class cannot be instatiated
891
         */
892
        public DataSource createRandomDataSource(Memento m, int mode) {
893
                if (m instanceof DataSourceLayerMemento) {
894
                        DataSourceLayerMemento mem = (DataSourceLayerMemento) m;
895

    
896
                        try {
897
                                return createRandomDataSource(mem.getTableName(), mem
898
                                                .getTableAlias(), mode);
899
                        } catch (DriverLoadException e) {
900
                                throw new RuntimeException(
901
                                                "La informaci?n guardada no es consistente", e);
902
                        } catch (NoSuchTableException e) {
903
                                throw new RuntimeException(
904
                                                "La informaci?n guardada no es consistente", e);
905
                        } catch (DriverException e) {
906
                                throw new RuntimeException(e);
907
                        }
908
                } else {
909
                        OperationLayerMemento mem = (OperationLayerMemento) m;
910

    
911
                        try {
912
                                return executeSQL(mem.getSql(), mode);
913
                        } catch (DriverLoadException e) {
914
                                throw new RuntimeException(
915
                                                "La informaci?n guardada no es consistente", e);
916
                        } catch (ParseException e) {
917
                                throw new RuntimeException(
918
                                                "La informaci?n guardada no es consistente", e);
919
                        } catch (DriverException e) {
920
                                throw new RuntimeException(
921
                                                "La informaci?n guardada no es consistente", e);
922
                        } catch (SemanticException e) {
923
                                throw new RuntimeException(
924
                                                "La informaci?n guardada no es consistente", e);
925
                        } catch (IOException e) {
926
                                throw new RuntimeException(
927
                                                "La informaci?n guardada no es consistente", e);
928
                        } catch (EvaluationException e) {
929
                                throw new RuntimeException(
930
                                                "La informaci?n guardada no es consistente", e);
931
                        }
932
                }
933
        }
934

    
935
        /**
936
         * Devuelve true si todas las tablas provienen del mismo data base
937
         * management system
938
         *
939
         * @param tables
940
         *            Array de tablas
941
         *
942
         * @return boolean
943
         */
944
        private boolean sameDBMS(DataSource[] tables) {
945
                if (!(tables[0] instanceof DBDataSource)) {
946
                        return false;
947
                }
948

    
949
                String dbms = ((DBDataSource) tables[0]).getDBMS();
950

    
951
                for (int i = 1; i < tables.length; i++) {
952
                        if (!(tables[i] instanceof DBDataSource)) {
953
                                return false;
954
                        }
955

    
956
                        if (!dbms.equals(((DBDataSource) tables[1]).getDBMS())) {
957
                                return false;
958
                        }
959
                }
960

    
961
                return true;
962
        }
963

    
964
        /**
965
         * A partir de una instrucci?n select se encarga de obtener el DataSource
966
         * resultado de la ejecuci?n de dicha instrucci?n
967
         *
968
         * @param instr
969
         *            Instrucci?n select origen del datasource
970
         * @param mode
971
         *            opening mode
972
         *
973
         * @return DataSource que accede a los datos resultado de ejecutar la select
974
         *
975
         * @throws DriverLoadException
976
         * @throws DriverException
977
         *             Si fallo la lectura de la fuente de datos por parte del
978
         *             driver
979
         * @throws SemanticException
980
         *             Si la instrucci?n tiene errores sem?nticos
981
         * @throws IOException
982
         *             Si se produce un error accediendo a las estructuras de datos
983
         *             internas
984
         * @throws EvaluationException
985
         *             If there's an error evaluating any expression
986
         */
987
        public DataSource createRandomDataSource(SelectAdapter instr, int mode)
988
                        throws DriverLoadException, DriverException, SemanticException,
989
                        IOException, EvaluationException {
990
                return getModedDataSource(getDataSource(instr), mode);
991
        }
992

    
993
        /**
994
         * Creates a view in the database management system that hosts the data
995
         * source 'dbds'. The view is defined by the sql parameter
996
         *
997
         * @param dbds
998
         *            DataSource used to execute the query
999
         * @param sql
1000
         *            The SQL query defining the view
1001
         *
1002
         * @return Name of the view
1003
         *
1004
         * @throws DriverException
1005
         *             If the view cannot be created
1006
         */
1007
        private String getView(DBDataSource dbds, String sql)
1008
                        throws DriverException {
1009
                ServerViewInfo svi = (ServerViewInfo) sourceInfoServerViewInfo.get(dbds
1010
                                .getSourceInfo());
1011

    
1012
                /*
1013
                 * Return the view name if it's already created or create the view if
1014
                 * it's not created
1015
                 */
1016
                if (svi != null) {
1017
                        return svi.viewName;
1018
                } else {
1019
                        // create the view
1020
                        String viewName = getUID();
1021
                        String viewQuery = "CREATE VIEW " + viewName + " AS " + sql;
1022
                        dbds.execute(viewQuery);
1023

    
1024
                        // Register the view created
1025
                        sourceInfoServerViewInfo.put(dbds.getSourceInfo(),
1026
                                        new ServerViewInfo(dbds, viewName));
1027

    
1028
                        return viewName;
1029
                }
1030
        }
1031

    
1032
        /**
1033
         * Gets a DataSource implementation with the sql instruction as the data
1034
         * source by creating a view in the underlaying datasource management system
1035
         *
1036
         * @param sql
1037
         *            Instruction definig the data source
1038
         * @param driver
1039
         *            Driver used to access the data source
1040
         * @param dbInfo
1041
         *            data source info
1042
         *
1043
         * @return DataSource
1044
         *
1045
         * @throws DriverException
1046
         *             If cannot create the view
1047
         */
1048
        private DBDataSource getDataSourceByQuery(String sql,
1049
                        AlphanumericDBDriver driver, DBTableSourceInfo dbInfo)
1050
                        throws DriverException {
1051
                // Create the adapter
1052
                DBDataSource adapter = DBDataSourceFactory.newDataSourceInstance();
1053

    
1054
                // set the driver
1055
                adapter.setDriver(driver);
1056

    
1057
                // Create the query
1058
                adapter.setSourceInfo(dbInfo);
1059

    
1060
                // Gets the view name
1061
                String viewName = getView(adapter, sql);
1062

    
1063
                // Complete the source info with the view name
1064
                dbInfo.tableName = viewName;
1065

    
1066
                // Register the name association
1067
                nameTable.put(dbInfo.name, viewName);
1068

    
1069
                // setup the adapter
1070
                adapter.setSourceInfo(dbInfo);
1071
                adapter.setDataSourceFactory(this);
1072

    
1073
                return adapter;
1074
        }
1075

    
1076
        /**
1077
         * A partir de una instrucci?n select se encarga de obtener el DataSource
1078
         * resultado de la ejecuci?n de dicha instrucci?n
1079
         *
1080
         * @param instr
1081
         *            Instrucci?n select origen del datasource
1082
         *
1083
         * @return DataSource que accede a los datos resultado de ejecutar la select
1084
         *
1085
         * @throws DriverException
1086
         * @throws SemanticException
1087
         * @throws IOException
1088
         * @throws EvaluationException
1089
         * @throws RuntimeException
1090
         *             bug
1091
         */
1092
        private DataSource getDataSource(SelectAdapter instr)
1093
                        throws DriverException, SemanticException, IOException,
1094
                        EvaluationException {
1095
                DataSource[] tables = instr.getTables();
1096

    
1097
                // Estrategia de delegaci?n de la instrucci?n en el sgbd original de la
1098
                // tabla
1099
                if (sameDBMS(tables) && delegating) {
1100
                        String sql = translateInstruction(instr, tables);
1101

    
1102
                        DBDataSource table = (DBDataSource) tables[0];
1103

    
1104
                        // Set the driver info
1105
                        DBSourceInfo source = (DBSourceInfo) table.getSourceInfo();
1106
                        String dataSourceName = addDBDataSourceBySQL(source.host,
1107
                                        source.port, source.user, source.password, source.dbName,
1108
                                        sql, source.driverName);
1109

    
1110
                        try {
1111
                                return createRandomDataSource(dataSourceName,
1112
                                                DataSourceFactory.MANUAL_OPENING);
1113
                        } catch (NoSuchTableException e) {
1114
                                throw new RuntimeException(e);
1115
                        } catch (DriverLoadException e) {
1116
                                throw new RuntimeException(e);
1117
                        } catch (DriverException e) {
1118
                                throw new RuntimeException(e);
1119
                        }
1120
                }
1121

    
1122
                // Estrategia normal
1123
                Strategy strategy = StrategyManager.getStrategy(instr);
1124

    
1125
                OperationDataSource ret = strategy.select(instr);
1126

    
1127
                ret.setName(getUID());
1128
                nameOperationDataSource.put(ret.getName(), ret);
1129

    
1130
                return ret;
1131
        }
1132

    
1133
        /**
1134
         * Translates the table references by changind the gdbms name with the
1135
         * underlaying database management system table name
1136
         *
1137
         * @param instr
1138
         *            root of the adapted tree
1139
         * @param tables
1140
         *            DataSources involved in the instruction
1141
         *
1142
         * @return The translated sql query
1143
         *
1144
         * @throws DriverException
1145
         *             If driver access fails
1146
         * @throws SemanticException
1147
         *             If the instruction is not semantically correct
1148
         */
1149
        private String translateInstruction(Adapter instr, DataSource[] tables)
1150
                        throws DriverException, SemanticException {
1151
                HashMap instrNameDBName = new HashMap();
1152

    
1153
                translateFromTables(instr, instrNameDBName);
1154
                translateColRefs(instr, instrNameDBName, tables);
1155

    
1156
                return Utilities.getText(instr.getEntity());
1157
        }
1158

    
1159
        /**
1160
         * Gets the name of the table where the field is in
1161
         *
1162
         * @param fieldName
1163
         *            field whose table wants to be guessed
1164
         * @param tables
1165
         *            tables involved in the search
1166
         *
1167
         * @return table name
1168
         *
1169
         * @throws DriverException
1170
         *             If driver access fails
1171
         * @throws SemanticException
1172
         *             If the instruction is not semantically correct
1173
         */
1174
        private String guessTableName(String fieldName, DataSource[] tables)
1175
                        throws DriverException, SemanticException {
1176
                int tableIndex = -1;
1177

    
1178
                for (int i = 0; i < tables.length; i++) {
1179
                        tables[i].start();
1180

    
1181
                        if (tables[i].getFieldIndexByName(fieldName) != -1) {
1182
                                if (tableIndex != -1) {
1183
                                        throw new SemanticException("ambiguous column reference: "
1184
                                                        + fieldName);
1185
                                } else {
1186
                                        tableIndex = i;
1187
                                }
1188
                        }
1189

    
1190
                        tables[i].stop();
1191
                }
1192

    
1193
                if (tableIndex == -1) {
1194
                        throw new SemanticException("Field not found: " + fieldName);
1195
                }
1196

    
1197
                return tables[tableIndex].getName();
1198
        }
1199

    
1200
        /**
1201
         * Translates the table references by changind the gdbms name with the
1202
         * underlaying database management system table name
1203
         *
1204
         * @param adapter
1205
         *            adapter processed
1206
         * @param instrNameDBName
1207
         *            hasmap with the gdbms names a s the keys and the database name
1208
         *            as the values.
1209
         * @param tables
1210
         *            tables involved in the instruction
1211
         *
1212
         * @throws DriverException
1213
         *             If driver access fails
1214
         * @throws SemanticException
1215
         *             If the instruction is not semantically correct
1216
         */
1217
        private void translateColRefs(Adapter adapter, HashMap instrNameDBName,
1218
                        DataSource[] tables) throws DriverException, SemanticException {
1219
                if (adapter instanceof ColRefAdapter) {
1220
                        ColRefAdapter tra = (ColRefAdapter) adapter;
1221
                        SimpleNode s = tra.getEntity();
1222

    
1223
                        if (s.first_token != s.last_token) {
1224
                                String name = s.first_token.image;
1225
                                s.first_token.image = instrNameDBName.get(name).toString();
1226
                        } else {
1227
                                String tableName = guessTableName(s.first_token.image, tables);
1228
                                s.first_token.image = instrNameDBName.get(tableName) + "."
1229
                                                + s.first_token.image;
1230
                        }
1231
                } else {
1232
                        Adapter[] hijos = adapter.getChilds();
1233

    
1234
                        for (int i = 0; i < hijos.length; i++) {
1235
                                translateColRefs(hijos[i], instrNameDBName, tables);
1236
                        }
1237
                }
1238
        }
1239

    
1240
        /**
1241
         * Translates the table references by changind the gdbms name with the
1242
         * underlaying database management system table name
1243
         *
1244
         * @param adapter
1245
         *            adapter processed
1246
         * @param instrNameDBName
1247
         *            hasmap with the gdbms names a s the keys and the database name
1248
         *            as the values.
1249
         */
1250
        private void translateFromTables(Adapter adapter, HashMap instrNameDBName) {
1251
                if (adapter instanceof TableRefAdapter) {
1252
                        TableRefAdapter tra = (TableRefAdapter) adapter;
1253
                        SimpleNode s = tra.getEntity();
1254

    
1255
                        if (s.first_token == s.last_token) {
1256
                                String alias = "gdbms" + System.currentTimeMillis();
1257
                                String name = s.first_token.image;
1258
                                s.first_token.image = nameTable.get(name) + " " + alias;
1259
                                instrNameDBName.put(name, alias);
1260
                        } else {
1261
                                String alias = s.last_token.image;
1262
                                String name = s.first_token.image;
1263
                                s.first_token.image = nameTable.get(name).toString();
1264
                                instrNameDBName.put(alias, alias);
1265
                        }
1266
                } else {
1267
                        Adapter[] hijos = adapter.getChilds();
1268

    
1269
                        for (int i = 0; i < hijos.length; i++) {
1270
                                translateFromTables(hijos[i], instrNameDBName);
1271
                        }
1272
                }
1273
        }
1274

    
1275
        /**
1276
         * Obtiene el DataSource resultado de ejecutar la instrucci?n de union
1277
         *
1278
         * @param instr
1279
         *            instrucci?n de union
1280
         * @param mode
1281
         *            opening mode
1282
         *
1283
         * @return DataSource
1284
         *
1285
         * @throws DriverException
1286
         *             Si fallo la lectura de la fuente de datos por parte del
1287
         *             driver
1288
         * @throws IOException
1289
         *             Si se produce un error de entrada/salida
1290
         * @throws SemanticException
1291
         *             Si la instrucci?n tiene errores sem?nticos
1292
         * @throws EvaluationException
1293
         *             If there's any problem during expresion evaluation
1294
         * @throws ParseException
1295
         *             If there is a select statement embeeded in the union
1296
         *             statement and its parse fails
1297
         */
1298
        public DataSource createRandomDataSource(UnionAdapter instr, int mode)
1299
                        throws DriverException, IOException, SemanticException,
1300
                        EvaluationException, ParseException {
1301
                return getModedDataSource(getDataSource(instr), mode);
1302
        }
1303

    
1304
        /**
1305
         * Obtiene el DataSource resultado de ejecutar la instrucci?n de union
1306
         *
1307
         * @param instr
1308
         *            instrucci?n de union
1309
         *
1310
         * @return DataSource
1311
         *
1312
         * @throws DriverException
1313
         *             Si fallo la lectura de la fuente de datos por parte del
1314
         *             driver
1315
         * @throws IOException
1316
         *             Si se produce un error de entrada/salida
1317
         * @throws SemanticException
1318
         *             Si la instrucci?n tiene errores sem?nticos
1319
         * @throws ParseException
1320
         *             If there is a select statement embeeded in the union
1321
         *             statement and its parse fails
1322
         * @throws EvaluationException
1323
         *             If there's any problem during expresion evaluation
1324
         */
1325
        private DataSource getDataSource(UnionAdapter instr)
1326
                        throws DriverException, IOException, SemanticException,
1327
                        ParseException, EvaluationException {
1328
                try {
1329
                        Strategy strategy = StrategyManager.getStrategy(instr);
1330

    
1331
                        OperationDataSource ret;
1332
                        ret = strategy.union(instr);
1333

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

    
1337
                        return ret;
1338
                } catch (DriverLoadException e) {
1339
                        throw new DriverException(e);
1340
                }
1341

    
1342
        }
1343

    
1344
        /**
1345
         * Creates a DataSource as a result of a custom query
1346
         *
1347
         * @param instr
1348
         *            Root node of the adapter tree of the custom query instruction
1349
         * @param mode
1350
         *            opening mode
1351
         *
1352
         * @return DataSource with the custom query result
1353
         *
1354
         * @throws SemanticException
1355
         *             if there is any semantic error in the instruction
1356
         */
1357
        public DataSource getDataSource(CustomAdapter instr, int mode)
1358
                        throws SemanticException {
1359
                return getModedDataSource(getDataSource(instr), mode);
1360
        }
1361

    
1362
        /**
1363
         * Creates a DataSource as a result of a custom query
1364
         *
1365
         * @param instr
1366
         *            Root node of the adapter tree of the custom query instruction
1367
         *
1368
         * @return DataSource with the custom query result
1369
         *
1370
         * @throws SemanticException
1371
         *             if there is any semantic error in the instruction
1372
         */
1373
        private DataSource getDataSource(CustomAdapter instr)
1374
                        throws SemanticException {
1375
                Strategy strategy = StrategyManager.getStrategy(instr);
1376

    
1377
                OperationDataSource ret = strategy.custom(instr);
1378

    
1379
                ret.setName(getUID());
1380
                nameOperationDataSource.put(ret.getName(), ret);
1381

    
1382
                return ret;
1383
        }
1384

    
1385
        /**
1386
         * Ejecuta la instrucci?n SQL que se pasa como par?metro obteniendo un
1387
         * DataSource con el resultado de la ejecuci?n
1388
         *
1389
         * @param sql
1390
         *            instrucci?n sql que se quiere ejecutar
1391
         * @param mode
1392
         *            opening mode
1393
         *
1394
         * @return DataSource con el resultado
1395
         *
1396
         * @throws ParseException
1397
         *             Si se produce un error de parse de la instrucci?n
1398
         * @throws DriverLoadException
1399
         *             Si no se pueden cargar los drivers
1400
         * @throws DriverException
1401
         *             Si se produce un error accediendo a los drivers
1402
         * @throws SemanticException
1403
         *             Si la instrucci?n tiene alg?n error sem?ntico
1404
         * @throws IOException
1405
         *             Si se produce un error accediendo a las estructuras de datos
1406
         *             internas usadas para los c?lculos
1407
         * @throws EvaluationException
1408
         *             If there's an error evaluating any expression
1409
         */
1410
        public DataSource executeSQL(String sql, int mode) throws ParseException,
1411
                        DriverLoadException, DriverException, SemanticException,
1412
                        IOException, EvaluationException {
1413
                ByteArrayInputStream bytes = new ByteArrayInputStream(sql.getBytes());
1414
                SQLEngine parser = new SQLEngine(bytes);
1415

    
1416
                parser.SQLStatement();
1417

    
1418
                Node root = parser.getRootNode();
1419
                Adapter rootAdapter = Utilities.buildTree(root.jjtGetChild(0), sql,
1420
                                this);
1421

    
1422
                Utilities.simplify(rootAdapter);
1423

    
1424
                DataSource result = null;
1425

    
1426
                if (rootAdapter instanceof SelectAdapter) {
1427
                        result = getDataSource((SelectAdapter) rootAdapter);
1428
                } else if (rootAdapter instanceof UnionAdapter) {
1429
                        result = getDataSource((UnionAdapter) rootAdapter);
1430
                } else if (rootAdapter instanceof CustomAdapter) {
1431
                        result = getDataSource((CustomAdapter) rootAdapter);
1432
                }
1433

    
1434
                // if operation was delegated it isn't a OperationDataSource
1435
                if (result instanceof OperationDataSource) {
1436
                        ((OperationDataSource) result).setSQL(sql);
1437
                }
1438

    
1439
                result.setDataSourceFactory(this);
1440

    
1441
                return getModedDataSource(result, mode);
1442
        }
1443

    
1444
        /**
1445
         * Establece el DriverManager que se usar? para instanciar DataSource's.
1446
         * Este metodo debe ser invocado antes que ning?n otro
1447
         *
1448
         * @param dm
1449
         *            El manager que se encarga de cargar los drivers
1450
         */
1451
        public void setDriverManager(DriverManager dm) {
1452
                this.dm = dm;
1453
        }
1454
        /**
1455
         * Establece el WriterManager que se usar? para instanciar DataSource's.
1456
         * Este metodo debe ser invocado antes que ning?n otro
1457
         *
1458
         * @param dm
1459
         *            El manager que se encarga de cargar los drivers
1460
         */
1461
        public void setWriterManager(WriterManager wm) {
1462
                this.wm = wm;
1463
        }
1464
        /**
1465
         * Get's the module with the specified name
1466
         *
1467
         * @param name
1468
         *            name of the wanted module
1469
         *
1470
         * @return instance of the module
1471
         */
1472
        public Object getModule(String name) {
1473
                return ms.getModule(name);
1474
        }
1475

    
1476
        /**
1477
         * Registers a module in the system with the specified name
1478
         *
1479
         * @param name
1480
         *            name of the module
1481
         * @param instance
1482
         *            module instance
1483
         */
1484
        public void registerModule(String name, Object instance) {
1485
                ms.registerModule(name, instance);
1486
        }
1487

    
1488
        /**
1489
         * Gets a driver manager reference
1490
         *
1491
         * @return DriverManagers.
1492
         */
1493
        public DriverManager getDriverManager() {
1494
                return dm;
1495
        }
1496
        /**
1497
         * Gets a writer manager reference
1498
         *
1499
         * @return WriterManagers.
1500
         */
1501
        public WriterManager getWriterManager() {
1502
                return wm;
1503
        }
1504
        /**
1505
         * Sets if this factory will check for delegating instructions at the server
1506
         * (true) or will execute all queries internally (false). By delegating at
1507
         * the server, lots of queries will be defined in the database management
1508
         * system where the execution is delegated. Invoke clearViews to remove all
1509
         * created views.
1510
         *
1511
         * @param b
1512
         */
1513
        public void setDelegating(boolean b) {
1514
                this.delegating = b;
1515
        }
1516

    
1517
        /**
1518
         * Creates a new table on the specified database
1519
         *
1520
         * @param database
1521
         *            name of the database where the table will be created
1522
         * @param pkNames
1523
         *            Names of the primary key fields
1524
         * @param names
1525
         *            names of the fields
1526
         * @param types
1527
         *            types of the fields. Must have the same length than names
1528
         *
1529
         * @return the table name
1530
         *
1531
         * @throws SQLException
1532
         *             if the creation fails
1533
         */
1534
        public String createTable(String database, String[] pkNames,
1535
                        String[] names, int[] types) throws SQLException {
1536
                // Get a name for the table
1537
                String tableName = getUID();
1538

    
1539
                // Create the table
1540
                InnerDBUtils.execute(database, InnerDBUtils.getCreateStatementWithPK(
1541
                                tableName, pkNames, names, types));
1542

    
1543
                return tableName;
1544
        }
1545

    
1546
        /**
1547
         * Frees all resources used during execution
1548
         *
1549
         * @throws SQLException
1550
         *             If cannot free internal resources
1551
         * @throws DriverException
1552
         *             If drivers cannot free remote resources
1553
         */
1554
        public void finalize() throws SQLException, DriverException {
1555
                clearViews();
1556

    
1557
                Connection c = java.sql.DriverManager.getConnection(
1558
                                "jdbc:hsqldb:file:", "", "");
1559
                Statement st = c.createStatement();
1560
                st.execute("SHUTDOWN");
1561
                st.close();
1562
                c.close();
1563
        }
1564

    
1565
        /**
1566
         * Initializes the system.
1567
         *
1568
         * @throws InitializationException
1569
         *             If the initialization
1570
         */
1571
        public void initialize() throws InitializationException {
1572
                initialize(".");
1573
        }
1574

    
1575
        /**
1576
         * Initializes the system
1577
         *
1578
         * @param tempDir
1579
         *            temporary directory to write data
1580
         *
1581
         * @throws InitializationException
1582
         *             If the initialization fails
1583
         */
1584
        public void initialize(String tempDir) throws InitializationException {
1585
                try {
1586
                        this.tempDir = new File(tempDir);
1587

    
1588
                        if (!this.tempDir.exists()) {
1589
                                this.tempDir.mkdirs();
1590
                        }
1591

    
1592
                        Class.forName("org.hsqldb.jdbcDriver");
1593
                } catch (ClassNotFoundException e) {
1594
                        throw new InitializationException(e);
1595
                }
1596
        }
1597

    
1598
        /**
1599
         * Gets the URL of a file in the temporary directory. Does not creates any
1600
         * file
1601
         *
1602
         * @return String
1603
         */
1604
        public String getTempFile() {
1605
                return tempDir.getAbsolutePath() + File.separator + "gdmbs"
1606
                                + System.currentTimeMillis();
1607
        }
1608

    
1609
        /**
1610
         * Information to delete the view on the server: name of the view and the
1611
         * adapter to remove it
1612
         */
1613
        private class ServerViewInfo {
1614
                public DBDataSource adapter;
1615

    
1616
                public String viewName;
1617

    
1618
                /**
1619
                 * Crea un nuevo ServerViewInfo.
1620
                 *
1621
                 * @param ds
1622
                 *            DOCUMENT ME!
1623
                 * @param name
1624
                 *            DOCUMENT ME!
1625
                 */
1626
                public ServerViewInfo(DBDataSource ds, String name) {
1627
                        adapter = ds;
1628
                        viewName = name;
1629
                }
1630
        }
1631
}