Statistics
| Revision:

gvsig-raster / org.gvsig.raster / branches / org.gvsig.raster.2.4 / org.gvsig.raster / org.gvsig.raster.googlemaps / org.gvsig.raster.googlemaps.provider / src / main / java / org / gvsig / raster / googlemaps / provider / GoogleMapsImage.java @ 6514

History | View | Annotate | Download (11.2 KB)

1
package org.gvsig.raster.googlemaps.provider;
2

    
3
import java.awt.image.BufferedImage;
4
import java.util.HashMap;
5
import java.util.Iterator;
6
import java.util.Map;
7
import java.util.Map.Entry;
8
import java.util.Set;
9

    
10
import org.slf4j.Logger;
11
import org.slf4j.LoggerFactory;
12

    
13
import org.gvsig.fmap.dal.DataStoreParameters;
14
import org.gvsig.fmap.dal.exception.DataException;
15
import org.gvsig.fmap.dal.exception.ValidateDataParametersException;
16
import org.gvsig.fmap.geom.Geometry.DIMENSIONS;
17
import org.gvsig.fmap.geom.Geometry.SUBTYPES;
18
import org.gvsig.fmap.geom.GeometryLocator;
19
import org.gvsig.fmap.geom.GeometryManager;
20
import org.gvsig.fmap.geom.exception.CreateEnvelopeException;
21
import org.gvsig.fmap.geom.exception.CreateGeometryException;
22
import org.gvsig.fmap.geom.primitive.Envelope;
23
import org.gvsig.fmap.geom.primitive.Point;
24
import org.gvsig.googlemaps.lib.api.GoogleMapsLocator;
25
import org.gvsig.googlemaps.lib.api.GoogleMapsManager;
26
import org.gvsig.googlemaps.lib.api.GoogleMapsRequest;
27
import org.gvsig.googlemaps.lib.api.GoogleMapsRequestParams;
28
import org.gvsig.googlemaps.lib.api.exceptions.DownloadingException;
29
import org.gvsig.googlemaps.lib.api.exceptions.URLFormatException;
30
import org.gvsig.raster.lib.buffer.api.Band;
31
import org.gvsig.raster.lib.buffer.api.Buffer;
32
import org.gvsig.raster.lib.buffer.api.BufferLocator;
33
import org.gvsig.raster.lib.buffer.api.TileStruct;
34
import org.gvsig.raster.lib.buffer.api.exceptions.BufferException;
35
import org.gvsig.tools.ToolsLocator;
36
import org.gvsig.tools.dispose.Disposable;
37
import org.gvsig.tools.dispose.DisposeUtils;
38
import org.gvsig.tools.dispose.impl.AbstractDisposable;
39
import org.gvsig.tools.exception.BaseException;
40
import org.gvsig.tools.locator.LocatorException;
41

    
42

    
43
/**
44
 * @author fdiaz
45
 *
46
 */
47
public class GoogleMapsImage extends AbstractDisposable {
48

    
49
    private static final Logger logger = LoggerFactory.getLogger(GoogleMapsImage.class);
50
    private static final int MAX_RECENT_ACCEDED_TILES_NUMBER = 50;
51

    
52
    private Map<String, DownloadedTile> recentAccededTiles;
53

    
54
    private TileStruct tileStruct;
55
    private GoogleMapsRasterProvider provider;
56

    
57
    /**
58
     * @param provider
59
     * @param query
60
     * @param tileStruct
61
     */
62
    public GoogleMapsImage(TileStruct tileStruct, GoogleMapsRasterProvider provider) {
63
        this.tileStruct = tileStruct;
64
        this.provider = provider;
65

    
66
        recentAccededTiles = new HashMap<String, DownloadedTile>();
67
    }
68

    
69
    /**
70
     * @param bandNumber
71
     * @param zoomLevel
72
     * @param structRow
73
     * @param structCol
74
     * @return Band
75
     * @throws CreateEnvelopeException
76
     * @throws CloneNotSupportedException
77
     * @throws ValidateDataParametersException
78
     */
79
    public Band fetchTile(int bandNumber, int zoomLevel, int structRow, int structCol) throws CreateEnvelopeException,
80
        ValidateDataParametersException, CloneNotSupportedException {
81

    
82
//        BufferManager bufferManager = BufferLocator.getBufferManager();
83

    
84
        String keyTile = composeKeyForRecentTiles(zoomLevel, structRow, structCol);
85
        DownloadedTile tile = recentAccededTiles.get(keyTile);
86

    
87
        Buffer buffer = null;
88
        if (tile != null && tile.isDownloaded()) {
89
            // Devolver la banda del buffer del tile
90
            logger.info("Devolviendo la banda "+bandNumber+" del buffer del tile "+tile.getKey());
91
            try {
92
                buffer = tile.getBuffer();
93
                Band band = buffer.getBand(bandNumber);
94
                ToolsLocator.getDisposableManager().bind(band);
95
                return band;
96
            } catch (InterruptedException e) {
97
                logger.warn("Can't fetch tile: zoomLevel = " + zoomLevel + ", tileRow = " + structRow
98
                    + ", tileColumn = " + structCol + ", band = " + bandNumber + ".", e);
99
                return null;
100
            }
101
        } else {
102
            // Cargar un tile nuevo
103
            Band band = null;
104
            try {
105
                while(tile==null || !tile.isDownloaded()) {
106
                    tile = requestTile(zoomLevel, structRow, structCol, keyTile);
107
                }
108

    
109
                buffer = tile.getBuffer();
110

    
111
                if (recentAccededTiles.size() >= MAX_RECENT_ACCEDED_TILES_NUMBER) {
112
                    removeOlderTile();
113
                }
114
                recentAccededTiles.put(keyTile, tile);
115

    
116
                band = buffer.getBand(bandNumber);
117
                ToolsLocator.getDisposableManager().bind(band);
118
                return band;
119
            } catch (DataException | BufferException | CreateGeometryException | InterruptedException | URLFormatException | DownloadingException e) {
120
                logger.warn("Can't fetch tile: zoomLevel = " + zoomLevel + ", tileRow = " + structRow
121
                    + ", tileColumn = " + structCol + ", band = " + bandNumber + ".", e);
122
                return null;
123
            }
124
        }
125
    }
126

    
127
    private DownloadedTile requestTile(int zoomLevel, int structRow, int structCol, String key) throws CreateEnvelopeException,
128
        CloneNotSupportedException, BufferException, ValidateDataParametersException, DataException, CreateGeometryException, URLFormatException, DownloadingException {
129

    
130
        Double pixelSize = this.tileStruct.getPixelSizePerZoomLevel().get(zoomLevel);
131

    
132
        GeometryManager geomManager = GeometryLocator.getGeometryManager();
133

    
134
        Envelope structExtent = this.tileStruct.getEnvelope();
135
        int rowsPerTile = this.tileStruct.getRowsPerTile();
136
        int columnsPerTile = this.tileStruct.getColumnsPerTile();
137

    
138
        double minX = Math.max(structExtent.getMinimum(DIMENSIONS.X) + (structCol * (pixelSize * columnsPerTile)),structExtent.getMinimum(DIMENSIONS.X));
139
        double minY = Math.max(structExtent.getMaximum(DIMENSIONS.Y) - ((structRow + 1) * (pixelSize * rowsPerTile)),structExtent.getMinimum(DIMENSIONS.Y));
140
        double maxX = Math.min(structExtent.getMinimum(DIMENSIONS.X) + ((structCol + 1) * (pixelSize * columnsPerTile)),structExtent.getMaximum(DIMENSIONS.X));
141
        double maxY = Math.min(structExtent.getMaximum(DIMENSIONS.Y) - (structRow * (pixelSize * rowsPerTile)),structExtent.getMaximum(DIMENSIONS.Y));
142
        Envelope envelope = geomManager.createEnvelope(minX, minY, maxX, maxY, SUBTYPES.GEOM2D);
143
        Point center;
144

    
145
        center = geomManager.createPoint(envelope.getCenter(DIMENSIONS.X), envelope.getCenter(DIMENSIONS.Y), SUBTYPES.GEOM2D);
146

    
147
        GoogleMapsManager googleMapsManager = GoogleMapsLocator.getManager();
148
        GoogleMapsRequestParams requestParams = googleMapsManager.createRequestParams();
149

    
150
        DataStoreParameters storeParameters = provider.getParameters();
151
        requestParams.setHasApiKey((Boolean) storeParameters.getDynValue("hasApiKey"));
152
        requestParams.setApiKey((String) storeParameters.getDynValue("apiKey"));
153
        requestParams.setLanguage((String) storeParameters.getDynValue("language"));
154
        requestParams.setRegion((String) storeParameters.getDynValue("region"));
155
        requestParams.setURL("http://maps.google.com/maps/api/staticmap?");
156
        requestParams.setMapType((String) storeParameters.getDynValue("mapType"));
157
        requestParams.setFormat((String) storeParameters.getDynValue("format"));
158

    
159
        GoogleMapsRequest googleRequest=googleMapsManager.createRequest(requestParams);
160
        DownloadedTile downloadedTile = new DownloadedTile(key, envelope);
161
        downloadedTile.setImage(googleRequest.getTile(center, zoomLevel, (int)Math.round(envelope.getLength(DIMENSIONS.X)/pixelSize), (int)Math.round(envelope.getLength(DIMENSIONS.Y)/pixelSize)));
162

    
163
        return downloadedTile;
164
    }
165

    
166
    private String composeKeyForRecentTiles(int zoomLevel, int structRow, int structCol) {
167
        StringBuilder builder = new StringBuilder();
168
        builder.append(zoomLevel);
169
        builder.append(":");
170
        builder.append(structCol);
171
        builder.append(":");
172
        builder.append(structRow);
173
        return builder.toString();
174
    }
175

    
176
    private void removeOlderTile() {
177
        DownloadedTile olderTile = null;
178
        for (Iterator<DownloadedTile> iterator = recentAccededTiles.values().iterator(); iterator.hasNext();) {
179
            DownloadedTile tile = (DownloadedTile) iterator.next();
180
            if (olderTile == null || tile.getLastAccess() < olderTile.getLastAccess()) {
181
                olderTile = tile;
182
            }
183
        }
184
        if (olderTile != null) {
185
            recentAccededTiles.remove(olderTile.getKey());
186
            DisposeUtils.dispose(olderTile);
187
        }
188
    }
189

    
190

    
191
    private class DownloadedTile extends AbstractDisposable { //implements GoogleMapsRequestListener {
192

    
193
        private org.gvsig.raster.lib.buffer.api.Buffer buffer;
194
        long lastAccess;
195
        private String key;
196
        private Envelope envelope;
197
        private boolean downloaded;
198

    
199
        public DownloadedTile(String key, Envelope envelope) {
200
            logger
201
                .info("CONSTRUCTOR hashCode = " + this.hashCode() + " className = " + this.getClass().getSimpleName());
202
            this.key = key;
203
            this.envelope = envelope;
204
            lastAccess = System.currentTimeMillis();
205
            this.downloaded = false;
206
        }
207

    
208
        public String getKey() {
209
            return key;
210
        }
211

    
212
        public synchronized org.gvsig.raster.lib.buffer.api.Buffer getBuffer() throws InterruptedException {
213
            lastAccess = System.currentTimeMillis();
214
            while(!isDownloaded()){
215
                logger.info("Esperando al tile: "+this.key);
216
                this.wait();
217
            }
218
            logger.info("Sirviendo el tile: "+this.key);
219
            return buffer;
220
        }
221

    
222
        public long getLastAccess() {
223
            return lastAccess;
224
        }
225

    
226
        @Override
227
        protected void finalize() throws Throwable {
228
            super.finalize();
229
            logger.info("CLEANED key " + this.key + " hashCode = " + this.hashCode());
230
        }
231

    
232
        public synchronized void setImage(BufferedImage img) {
233

    
234
            downloaded = false;
235

    
236
            try {
237

    
238
                this.buffer =
239
                    BufferLocator.getBufferManager().createBuffer(img, GoogleMapsRasterProvider.GOOGLE_MAPS_PROJECTION,
240
                        this.envelope);
241

    
242
            } catch (LocatorException | BufferException e) {
243
                logger.warn("Can't create buffer to load downloaded image.", e);
244
            }
245

    
246
            this.downloaded = true;
247
            logger.info("Tile listo       : " + this.key);
248
            this.notify();
249
        }
250

    
251
        @Override
252
        protected void doDispose() throws BaseException {
253
            logger.info("DO DISPOSE key " + this.key + " hashCode = " + this.hashCode());
254
            DisposeUtils.dispose(buffer);
255
            buffer = null;
256
        }
257

    
258

    
259
        public boolean isDownloaded(){
260
            return this.downloaded;
261
        }
262
    }
263

    
264
    @Override
265
    protected void doDispose() throws BaseException {
266
        if (recentAccededTiles != null) {
267
            Set<Entry<String, DownloadedTile>> entrySet = recentAccededTiles.entrySet();
268
            for (Iterator<Entry<String, DownloadedTile>> iterator = entrySet.iterator(); iterator.hasNext();) {
269
                Entry<String, DownloadedTile> entry = (Entry<String, DownloadedTile>) iterator.next();
270
                DisposeUtils.dispose(entry.getValue());
271
            }
272
            recentAccededTiles.clear();
273
        }
274
        DisposeUtils.dispose((Disposable) tileStruct);
275
        tileStruct = null;
276
    }
277

    
278

    
279

    
280
}