Statistics
| Revision:

gvsig-raster / org.gvsig.raster.postgis / trunk / org.gvsig.raster.postgis / org.gvsig.raster.postgis.io / src / main / java / org / gvsig / raster / postgis / io / PostGISRasterProvider.java @ 1866

History | View | Annotate | Download (19.6 KB)

1
/* gvSIG. Geographic Information System of the Valencian Government
2
 *
3
 * Copyright (C) 2007-2008 Infrastructures and Transports Department
4
 * of the Valencian Government (CIT)
5
 *
6
 * This program is free software; you can redistribute it and/or
7
 * modify it under the terms of the GNU General Public License
8
 * as published by the Free Software Foundation; either version 2
9
 * of the License, or (at your option) any later version.
10
 *
11
 * This program is distributed in the hope that it will be useful,
12
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
14
 * GNU General Public License for more details.
15
 *
16
 * You should have received a copy of the GNU General Public License
17
 * along with this program; if not, write to the Free Software
18
 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
19
 * MA  02110-1301, USA.
20
 *
21
 */
22
package org.gvsig.raster.postgis.io;
23

    
24
import java.awt.geom.AffineTransform;
25
import java.awt.geom.Rectangle2D;
26
import java.io.File;
27
import java.util.ArrayList;
28
import java.util.Collections;
29
import java.util.Iterator;
30
import java.util.List;
31

    
32
import org.gvsig.fmap.dal.DALLocator;
33
import org.gvsig.fmap.dal.DataManager;
34
import org.gvsig.fmap.dal.DataStore;
35
import org.gvsig.fmap.dal.coverage.RasterLocator;
36
import org.gvsig.fmap.dal.coverage.dataset.Buffer;
37
import org.gvsig.fmap.dal.coverage.datastruct.BandList;
38
import org.gvsig.fmap.dal.coverage.datastruct.DatasetBand;
39
import org.gvsig.fmap.dal.coverage.datastruct.Extent;
40
import org.gvsig.fmap.dal.coverage.exception.BandAccessException;
41
import org.gvsig.fmap.dal.coverage.exception.BandNotFoundInListException;
42
import org.gvsig.fmap.dal.coverage.exception.NotSupportedExtensionException;
43
import org.gvsig.fmap.dal.coverage.exception.ProcessInterruptedException;
44
import org.gvsig.fmap.dal.coverage.exception.RasterDriverException;
45
import org.gvsig.fmap.dal.coverage.exception.RemoteServiceException;
46
import org.gvsig.fmap.dal.coverage.store.parameter.RasterDataParameters;
47
import org.gvsig.fmap.dal.coverage.util.FileUtils;
48
import org.gvsig.fmap.dal.exception.DataException;
49
import org.gvsig.fmap.dal.exception.InitializeException;
50
import org.gvsig.fmap.dal.exception.ProviderNotRegisteredException;
51
import org.gvsig.fmap.dal.exception.ValidateDataParametersException;
52
import org.gvsig.fmap.dal.serverexplorer.db.DBServerExplorer;
53
import org.gvsig.fmap.dal.spi.DataManagerProviderServices;
54
import org.gvsig.fmap.dal.spi.DataStoreProviderServices;
55
import org.gvsig.fmap.dal.store.db.DBStoreParameters;
56
import org.gvsig.metadata.MetadataLocator;
57
import org.gvsig.raster.cache.tile.provider.TileListener;
58
import org.gvsig.raster.cache.tile.provider.TileServer;
59
import org.gvsig.raster.gdal.io.GdalDataParameters;
60
import org.gvsig.raster.gdal.io.GdalNative;
61
import org.gvsig.raster.gdal.io.GdalProvider;
62
import org.gvsig.raster.impl.buffer.DefaultRasterQuery;
63
import org.gvsig.raster.impl.datastruct.BandListImpl;
64
import org.gvsig.raster.impl.datastruct.DatasetBandImpl;
65
import org.gvsig.raster.impl.provider.DefaultRasterProvider;
66
import org.gvsig.raster.impl.provider.RemoteRasterProvider;
67
import org.gvsig.raster.impl.store.AbstractRasterDataParameters;
68
import org.gvsig.raster.impl.store.DefaultStoreFactory;
69
import org.gvsig.raster.postgis.io.downloader.PostGISRasterTileServer;
70
import org.gvsig.tools.ToolsLocator;
71
import org.gvsig.tools.task.TaskStatus;
72
import org.slf4j.Logger;
73
import org.slf4j.LoggerFactory;
74
/**
75
 * This class represents the data access just for PostGIS raster databases.
76
 * @author Nacho Brodin (nachobrodin@gmail.com)
77
 */
78
public class PostGISRasterProvider extends GdalProvider implements RemoteRasterProvider {
79
        public static String           NAME                     = "PostGIS Raster Store";
80
        public static String           DESCRIPTION              = "PostGIS Raster file";
81
        public static final String     METADATA_DEFINITION_NAME = "PostGISRasterStore";
82
        private static final String    OVERVIEW_PREFIX          = "o_";
83
        
84
        private DBServerExplorer       dbServerExplorer         = null;
85
        private DBStoreParameters      dbParameters             = null;
86
        private ArrayList<Overview>    overviews                = null;
87
        private DataManager            dataManager              = DALLocator.getDataManager();
88
        private DefaultRasterProvider  selectedProvider         = null;
89
        private Overview               mainOverview             = null;
90
        private static Logger          logger                   = LoggerFactory.getLogger(PostGISRasterProvider.class.getName());
91
        
92
        class Overview implements Comparable<Overview> {
93
                public int                         width               = 0;
94
                public int                         height              = 0;
95
                public int                         factor              = 0;
96
                public double                      pxSizeOverview      = 0;
97
                public DefaultRasterProvider       provider            = null;
98
                
99
                public Overview() {
100
                        
101
                }
102
                
103
                public Overview(int f, int w, int h, PostGISRasterDataParameters p) throws NotSupportedExtensionException {
104
                        this.width = w;
105
                        this.height = h;
106
                        this.factor = f;
107
                        if(p != null)
108
                                createProvider(p);
109
                        this.pxSizeOverview = getExtent().width() / (double)w;
110
                }
111
                
112
                public void createProvider(PostGISRasterDataParameters p) throws NotSupportedExtensionException {
113
                        GdalDataParameters gdalParams = new GdalDataParameters();
114
                        gdalParams.setURI(p.getURI());
115
                        try {
116
                                this.provider = new GdalProvider(gdalParams, storeServices);
117
                        } catch (NotSupportedExtensionException e) {
118
                                logger.info("===>" + gdalParams.getURI() + " " + e.getMessage(), e);
119
                        }
120
                        this.width = (int)provider.getWidth();
121
                        this.height = (int)provider.getHeight();
122
                        this.pxSizeOverview = provider.getExtent().width() / (double)this.width;
123
                }
124
                
125
                public int compareTo(Overview o) {
126
                        if(factor < o.factor)
127
                                return -1;
128
                        if(factor > o.factor)
129
                                return 1;
130
                        return 0;
131
                }
132
        }
133
        
134
        public static void register() {
135
                RasterLocator.getManager().getProviderServices().registerFileProvidersTiled(PostGISRasterProvider.class);
136
                
137
                DataManagerProviderServices dataman = (DataManagerProviderServices) DALLocator.getDataManager();
138
                if (dataman != null && !dataman.getStoreProviders().contains(NAME)) {
139
                        dataman.registerStoreProvider(NAME,
140
                                        PostGISRasterProvider.class, PostGISRasterDataParameters.class);
141
                }
142

    
143
                if (!dataman.getExplorerProviders().contains(PostGISRasterProvider.NAME)) {
144
                        dataman.registerExplorerProvider(PostGISRasterServerExplorer.NAME, PostGISRasterServerExplorer.class, PostGISRasterServerExplorerParameters.class);
145
                }
146
                dataman.registerStoreFactory(NAME, DefaultStoreFactory.class);
147
        }
148
        
149
        public PostGISRasterProvider() {
150
                
151
        }
152
        
153
        public PostGISRasterProvider (PostGISRasterDataParameters params,
154
                        DataStoreProviderServices storeServices) throws NotSupportedExtensionException {
155
                super(params, storeServices, ToolsLocator.getDynObjectManager()
156
                                .createDynObject(
157
                                                MetadataLocator.getMetadataManager().getDefinition(
158
                                                                DataStore.METADATA_DEFINITION_NAME)));
159
                init(params, storeServices);
160
        }
161
        
162
        /**
163
         * Creates data base references and loads structures with the information and metadata
164
         * @param params load parameters
165
         * @throws NotSupportedExtensionException
166
         */
167
        public void init (AbstractRasterDataParameters params,
168
                        DataStoreProviderServices storeServices) throws NotSupportedExtensionException {
169
                try {
170
                        setParam(storeServices, params);
171
                        mainOverview = new Overview();
172
                        mainOverview.createProvider((PostGISRasterDataParameters)param);
173
                        mainOverview.factor = 1;
174
                        file = ((GdalProvider)mainOverview.provider).getNative();
175
                        setColorInterpretation(file.getColorInterpretation());
176
                        setColorTable(file.getColorTable());
177
                        noData = file.getNoDataValue();
178
                        String wktProjection = file.getProjectionRef();
179
                        if(wktProjection != null && wktProjection != "") {
180
                                try {
181
                                        proj = RasterLocator.getManager().getCRSUtils().convertWktToIProjection(wktProjection);
182
                                } catch (Exception e) {
183
                                        logger.info("Error reading WKT from the raster provider", e);
184
                                }
185
                        }
186
                        //CrsWkt crs = new CrsWkt(wktProjection);
187
                        //IProjection proj = CRSFactory.getCRS("EPSG:23030");
188
                        ownTransformation = file.getOwnTransformation();
189
                        externalTransformation = (AffineTransform)ownTransformation.clone();
190
                        bandCount = file.getRasterCount();
191
                        load();
192
                } catch (Exception e) {
193
                        throw new NotSupportedExtensionException("Gdal library can't be initialized with this PostGIS raster parameters", e);
194
                } 
195

    
196
                //Obtenemos el tipo de dato de gdal y lo convertimos el de RasterBuf
197
                int[] dt = new int[file.getDataType().length];
198
                for (int i = 0; i < dt.length; i++)
199
                        dt[i] = GdalNative.getRasterBufTypeFromGdalType(file.getDataType()[i]);
200
                setDataType(dt);
201
                
202
                PostGISRasterDataParameters p = (PostGISRasterDataParameters)params;
203
                //Object obj = p.getDynValue(PostGISRasterDataParameters.FIELD_DBPARAMS);
204
                dbParameters = (DBStoreParameters)p.getDynValue(PostGISRasterDataParameters.FIELD_DBPARAMS);
205
                dbServerExplorer = (DBServerExplorer)p.getDynValue(PostGISRasterDataParameters.FIELD_DBEXPLORER);
206
        }
207
        
208
        public String getRMFFile() {
209
                return super.getRMFFileForRemoteServices(getTableName(uri));
210
        }
211
        
212
        /**
213
         * Reads overviews from database. The overviews in PostGIS raster are loaded 
214
         * in separated tables. The name of those tables is the same that the original table
215
         * with a overview prefix. Now this prefix is "o_X_" where the X is a factor scale.
216
         * 
217
         * For that reason the overview object contains the DataParameter which correspond
218
         * to each table.
219
         * @throws DataException 
220
         * @throws DataException
221
         */
222
        @SuppressWarnings("unchecked")
223
        private void readOverviews() throws DataException  {
224
                if(overviews == null) {
225
                        overviews = new ArrayList<Overview>();
226
                        String mainHost = ((PostGISRasterDataParameters)param).getURI();
227

    
228
                        String mainTable = dbParameters.getTable();
229
                        List parameters = dbServerExplorer.list();
230

    
231
                        int mainFactor = 1; 
232
                                
233
                        if(isOverview(mainTable, mainTable)) {
234
                                mainFactor = getFactor(mainTable);
235
                        }
236
                        overviews.add(mainOverview);
237
                        
238
                        Iterator iter = parameters.iterator();
239
                        while (iter.hasNext()) {
240
                                DBStoreParameters p = (DBStoreParameters) iter.next();
241
                                String tname = p.getTable();
242

    
243
                                try {
244
                                        if(isOverview(mainTable, tname)) {
245
                                                Overview o = new Overview();
246
                                                o.factor = (getFactor(tname) / mainFactor);
247
                                                o.width = (int)(getWidth() / o.factor);
248
                                                o.height = (int)(getHeight() / o.factor);
249
                                                o.pxSizeOverview = getExtent().width() / (double)o.width;
250
                                                o.createProvider(createParameters(mainHost, mainTable, tname));
251
                                                overviews.add(o);
252
                                        }
253
                                } catch (NumberFormatException e) {
254
                                } catch (PostGISRasterCoreException e) {
255
                                } catch (ValidateDataParametersException e) {
256
                                } catch (NotSupportedExtensionException e) {
257
                                }
258
                        }
259
                        Collections.sort(overviews);
260
                }
261
        }
262
        
263
        /**
264
         * Returns true if tname is an overview of mainTable
265
         * @param mainTable
266
         * @param tname
267
         * @return
268
         */
269
        private boolean isOverview(String mainTable, String tname) throws NumberFormatException {
270
                if(mainTable.compareTo(tname) != 0) {
271
                        return ((tname.endsWith(mainTable) && tname.startsWith(OVERVIEW_PREFIX)) ||
272
                                        (tname.startsWith(OVERVIEW_PREFIX) && mainTable.startsWith(OVERVIEW_PREFIX) && getFactor(tname) > getFactor(mainTable)));
273
                }
274
                return false;
275
        }
276
        
277
        /**
278
         * Gets the overview factor number reading the name of the table
279
         * @param tname
280
         * @return
281
         * @throws NumberFormatException
282
         */
283
        private int getFactor(String tname) throws NumberFormatException {
284
                String factor = tname.substring(tname.indexOf('_') + 1);
285
                factor = factor.substring(0, factor.indexOf('_'));
286
                return new Integer(factor);
287
        }
288
        
289
        /**
290
         * Creates the list of parameters
291
         * @param mainHost
292
         * @param mainTable
293
         * @param tableName
294
         * @return
295
         * @throws PostGISRasterCoreException 
296
         * @throws PostGISRasterCoreException
297
         * @throws ProviderNotRegisteredException 
298
         * @throws InitializeException 
299
         * @throws ValidateDataParametersException 
300
         */
301
        @SuppressWarnings("deprecation")
302
        private PostGISRasterDataParameters createParameters(String mainHost, String mainTable, String tableName) throws PostGISRasterCoreException, ValidateDataParametersException, InitializeException, ProviderNotRegisteredException {
303
                String newHost = mainHost.replaceFirst(mainTable, tableName);
304
                
305
                PostGISRasterServerExplorerParameters explorerParams = (PostGISRasterServerExplorerParameters) dataManager.createServerExplorerParameters(PostGISRasterServerExplorer.NAME);
306
                explorerParams.setHost(newHost);
307
                PostGISRasterServerExplorer explorer = (PostGISRasterServerExplorer) dataManager.createServerExplorer(explorerParams);
308
                RasterDataParameters storeParameters = (RasterDataParameters)explorer.getStoreParameters();
309
                storeParameters.setURI(newHost);
310
                return (PostGISRasterDataParameters)storeParameters;
311
        }
312
        
313
        /**
314
         * Selects the right overview. The right overview means the first 
315
         * one with a pixel size lesser or equals than the original. 
316
         * @param pixels
317
         * @param mts
318
         */
319
        private void overviewSelector(int pixels, double mts) {
320
                this.selectedProvider = overviews.get(overviews.size() - 1).provider;
321
                //System.out.println("*************" + overviews.get(overviews.size() - 1).pxSizeOverview + "**************");
322
                double pxSizeRequest = mts / (double)pixels;
323
                for (int i = overviews.size() - 1; i > 0; i--) {
324
                        Overview ovb = overviews.get(i);
325
                        if(pxSizeRequest <= ovb.pxSizeOverview) {
326
                                this.selectedProvider = ovb.provider;
327
                                //System.out.println(ovb.pxSizeOverview);
328
                        }
329
                }
330
                //System.out.println("***************************");
331
                logger.info("...Overview selected: " + getTableName(selectedProvider.getURI()) + " W:" + selectedProvider.getWidth() + " H:" + selectedProvider.getHeight());
332
        }
333
        
334
        public int getOverviewCount(int band) throws BandAccessException, RasterDriverException {
335
                if(band >= getBandCount())
336
                        throw new BandAccessException("Wrong band");
337
                return overviews.size();
338
        }
339
        
340
        public int getOverviewWidth(int band, int overview) throws BandAccessException, RasterDriverException {
341
                if (band >= getBandCount())
342
                        throw new BandAccessException("Wrong band");
343
                if (overview >= overviews.size())
344
                        throw new BandAccessException("Wrong overview count");
345
                return overviews.get(overview).width;
346
        }
347

    
348
        public int getOverviewHeight(int band, int overview) throws BandAccessException, RasterDriverException {
349
                if (band >= getBandCount())
350
                        throw new BandAccessException("Wrong band");
351
                if (overview >= overviews.size())
352
                        throw new BandAccessException("Wrong overview count");
353
                return overviews.get(overview).height;
354
        }
355
        
356
        public void getWindow(
357
                        Extent ex, 
358
                        int bufWidth, 
359
                        int bufHeight, 
360
                        BandList bandList, 
361
                        TileListener listener, 
362
                        TaskStatus status) throws ProcessInterruptedException, RasterDriverException {
363
//                PostGISRasterDataParameters p = (PostGISRasterDataParameters)param;
364
//                Buffer buf = RasterLocator.getManager().createBuffer(getDataType()[0], bufWidth, bufHeight, getBandCount(), true);
365
//                TileCacheManager m = TileCacheLocator.getManager();
366
//                Tile tile = m.createTile(-1, 0, 0);
367
//                
368
//                //Creamos un BandList con todas las bandas del fichero
369
//                BandList bl = new BandListImpl();
370
//                for(int i = 0; i < getBandCount(); i++) {
371
//                        try {
372
//                                DatasetBand band = new DatasetBandImpl(selectedProvider.getURIOfFirstProvider(), i, getDataType()[i], getBandCount());
373
//                                bl.addBand(band, i);
374
//                        } catch(BandNotFoundInListException e) {
375
//                                //No a?adimos la banda
376
//                        }
377
//                }
378
//                
379
//                if(p.getNumberOfBlocks() > 1) {
380
//                        for (int i = 0; i < p.getNumberOfBlocks(); i++) {
381
//                                GdalNative gdal;
382
//                                try {
383
//                                        gdal = new GdalNative(p.getURI() + " column='rast' where='rid = " + i + "'");
384
//                                        gdal.readWindow(buf, bandList, 0, 0, gdal.width, gdal.height, bufWidth, bufHeight);
385
//                                        Extent ext = gdal.getExtentWithoutRot();
386
//                                        tile.setUl(new Point2D.Double(ext.getULX(), ext.getULY()));
387
//                                        tile.setLr(new Point2D.Double(ext.getLRX(), ext.getLRY()));
388
//                                        tile.setData(new Object[]{buf, null, null});
389
//                                        listener.tileReady(tile);
390
//                                } catch (GdalException e) {
391
//                                        throw new RasterDriverException("", e);
392
//                                } catch (IOException e) {
393
//                                        throw new RasterDriverException("", e);
394
//                                } catch (TileGettingException e) {
395
//                                        throw new RasterDriverException("", e);
396
//                                }
397
//                        }
398
//                }
399
                super.getWindow(ex, bufWidth, bufHeight, bandList, listener, status);
400
        }
401

    
402
        public Buffer getWindow(
403
                        Extent ex, 
404
                        BandList bandList, 
405
                        Buffer rasterBuf, 
406
                        TaskStatus status) 
407
                throws ProcessInterruptedException, RasterDriverException {
408
                return super.getWindow(ex, bandList, rasterBuf, status);
409
        }
410

    
411
        public Buffer getWindow(
412
                        double ulx, 
413
                        double uly, 
414
                        double w, 
415
                        double h, 
416
                        BandList bandList, 
417
                        Buffer rasterBuf, 
418
                        boolean adjustToExtent, 
419
                        TaskStatus status) throws ProcessInterruptedException, RasterDriverException {
420
                return super.getWindow(ulx, uly, w, h, bandList, rasterBuf, adjustToExtent, status);
421
        }
422

    
423
        public Buffer getWindow(
424
                        Extent extent, 
425
                        int bufWidth, 
426
                        int bufHeight, 
427
                        BandList bandList, 
428
                        Buffer rasterBuf, 
429
                        boolean adjustToExtent, 
430
                        TaskStatus status) throws ProcessInterruptedException, RasterDriverException {
431
                try {
432
                        readOverviews();
433
                } catch (DataException e) {
434
                        throw new RasterDriverException("Overviews can't be read", e);
435
                }
436

    
437
                overviewSelector(bufWidth, extent.width());
438
                
439
                //Creamos un BandList con todas las bandas del fichero
440
                BandList bl = new BandListImpl();
441
                for(int i = 0; i < getBandCount(); i++) {
442
                        try {
443
                                FileUtils fUtil = RasterLocator.getManager().getFileUtils(); 
444
                                DatasetBand band = new DatasetBandImpl(fUtil.getFormatedRasterFileName(selectedProvider.getDataParameters().getURI()), i, getDataType()[i], getBandCount());
445
                                bl.addBand(band);
446
                        } catch(BandNotFoundInListException e) {
447
                                //No a?adimos la banda
448
                        }
449
                }
450
                bl.setDrawableBands(bandList.getDrawableBands());
451

    
452
                DefaultRasterQuery q = (DefaultRasterQuery)RasterLocator.getManager().createQuery();
453
                q.setAreaOfInterest(extent, bufWidth, bufHeight);
454
                q.setBandList(bl);
455
                q.setBuffer(rasterBuf);
456
                q.setAdjustToExtent(adjustToExtent);
457
                q.setTaskStatus(status);
458
                return selectedProvider.getDataSet(q);
459
        }
460

    
461
        public Buffer getWindow(
462
                        int x, 
463
                        int y, 
464
                        int w, 
465
                        int h, 
466
                        int bufWidth, 
467
                        int bufHeight, 
468
                        BandList bandList, 
469
                        Buffer rasterBuf, 
470
                        TaskStatus status) throws ProcessInterruptedException, RasterDriverException {
471
                return super.getWindow(x, y, w, h, bandList, rasterBuf, status);
472
        }
473
        
474
        /**
475
         * When the remote layer has fixed size this method downloads the file and return its reference. 
476
         * File layer has in the long side FIXED_SIZE pixels and the bounding box is complete. This file could be
477
         * useful to build an histogram or calculate statistics. This represents a sample of data.
478
         * @return
479
         * @throws RasterDriverException
480
         */
481
        public File getFileLayer() throws RasterDriverException {
482
                return null;
483
        }
484
        
485
        public File getLastRequest() {
486
                return null;
487
        }
488

    
489
        public Buffer getBufferLastRequest() throws ProcessInterruptedException,
490
                        RasterDriverException {
491
                return null;
492
        }
493

    
494
        public Rectangle2D getLayerExtent(String layerName, String srs)
495
                        throws RemoteServiceException {
496
                return null;
497
        }
498
        
499
        /**
500
         * Gets the name of a raster file
501
         */
502
        private String getTableName(String name) {
503
                String newName = "";
504
                String schema = null;
505
                String table = null;
506
                int index = name.indexOf(" schema='") + 8;
507
                if(index != -1) {
508
                        try {
509
                                schema = name.substring(index + 1, name.indexOf("'", index + 1)); 
510
                                newName += schema + ".";
511
                        } catch (StringIndexOutOfBoundsException e) {
512
                        }
513
                }
514
                index = name.indexOf(" table='") + 7;
515
                if(index != -1) {
516
                        try {
517
                                table = name.substring(index + 1, name.indexOf("'", index + 1));
518
                                newName += table;
519
                        } catch (StringIndexOutOfBoundsException e) {
520
                        }
521
                }
522
                return newName;
523
        }
524
        
525
        public TileServer getTileServer() {
526
                if(tileServer == null)
527
                        tileServer = new PostGISRasterTileServer(this);
528
                return tileServer;
529
        }
530

    
531
}