Statistics
| Revision:

svn-gvsig-desktop / branches / org.gvsig.desktop-2018a / org.gvsig.desktop.compat.cdc / org.gvsig.fmap.dal / org.gvsig.fmap.dal.tilecache / org.gvsig.fmap.dal.tilecache.raster / src / main / java / org / gvsig / raster / tilecache / provider / FileTileCacheStructImage.java @ 43876

History | View | Annotate | Download (26.4 KB)

1
/* gvSIG. Desktop Geographic Information System.
2
 *
3
 * Copyright ? 2007-2016 gvSIG Association
4
 *
5
 * This program is free software; you can redistribute it and/or
6
 * modify it under the terms of the GNU General Public License
7
 * as published by the Free Software Foundation; either version 2
8
 * of the License, or (at your option) any later version.
9
 *
10
 * This program is distributed in the hope that it will be useful,
11
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
12
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
13
 * GNU General Public License for more details.
14
 *
15
 * You should have received a copy of the GNU General Public License
16
 * along with this program; if not, write to the Free Software
17
 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
18
 * MA  02110-1301, USA.
19
 *
20
 * For any additional information, do not hesitate to contact us
21
 * at info AT gvsig.com, or visit our website www.gvsig.com.
22
 */
23
package org.gvsig.raster.tilecache.provider;
24

    
25
import java.io.File;
26
import java.io.IOException;
27
import java.util.ArrayList;
28
import java.util.HashMap;
29
import java.util.Iterator;
30
import java.util.List;
31
import java.util.Map;
32
import java.util.Map.Entry;
33
import java.util.Set;
34
import java.util.TreeMap;
35

    
36
import javax.xml.parsers.DocumentBuilder;
37
import javax.xml.parsers.DocumentBuilderFactory;
38
import javax.xml.parsers.ParserConfigurationException;
39
import javax.xml.transform.OutputKeys;
40
import javax.xml.transform.Transformer;
41
import javax.xml.transform.TransformerException;
42
import javax.xml.transform.TransformerFactory;
43
import javax.xml.transform.dom.DOMSource;
44
import javax.xml.transform.stream.StreamResult;
45

    
46
import org.apache.commons.io.FileUtils;
47
import org.apache.commons.io.FilenameUtils;
48
import org.apache.commons.lang3.StringUtils;
49
import org.cresques.cts.IProjection;
50
import org.slf4j.Logger;
51
import org.slf4j.LoggerFactory;
52
import org.w3c.dom.Attr;
53
import org.w3c.dom.Document;
54
import org.w3c.dom.Element;
55
import org.w3c.dom.NamedNodeMap;
56
import org.w3c.dom.Node;
57
import org.w3c.dom.NodeList;
58

    
59
import org.gvsig.fmap.dal.DALFileLocator;
60
import org.gvsig.fmap.dal.DataServerExplorer;
61
import org.gvsig.fmap.dal.DataServerExplorerParameters;
62
import org.gvsig.fmap.dal.DataStore;
63
import org.gvsig.fmap.dal.DataStoreProviderFactory;
64
import org.gvsig.fmap.dal.exception.DataException;
65
import org.gvsig.fmap.dal.exception.ServerExplorerAddException;
66
import org.gvsig.fmap.dal.exception.ValidateDataParametersException;
67
import org.gvsig.fmap.dal.raster.NewRasterStoreParameters;
68
import org.gvsig.fmap.dal.raster.RasterQuery;
69
import org.gvsig.fmap.dal.raster.RasterSet;
70
import org.gvsig.fmap.dal.raster.RasterStore;
71
import org.gvsig.fmap.dal.raster.spi.RasterStoreProvider;
72
import org.gvsig.fmap.dal.serverexplorer.filesystem.spi.FilesystemServerExplorerManager;
73
import org.gvsig.fmap.dal.serverexplorer.filesystem.spi.FilesystemServerExplorerProviderFactory;
74
import org.gvsig.fmap.dal.spi.DALSPILocator;
75
import org.gvsig.fmap.dal.spi.DataManagerProviderServices;
76
import org.gvsig.fmap.geom.Geometry.DIMENSIONS;
77
import org.gvsig.fmap.geom.Geometry.SUBTYPES;
78
import org.gvsig.fmap.geom.GeometryLocator;
79
import org.gvsig.fmap.geom.GeometryManager;
80
import org.gvsig.fmap.geom.exception.CreateEnvelopeException;
81
import org.gvsig.fmap.geom.primitive.Envelope;
82
import org.gvsig.raster.lib.buffer.api.Band;
83
import org.gvsig.raster.lib.buffer.api.Buffer;
84
import org.gvsig.raster.lib.buffer.api.BufferLocator;
85
import org.gvsig.raster.lib.buffer.api.BufferManager;
86
import org.gvsig.raster.lib.buffer.api.TileStruct;
87
import org.gvsig.raster.lib.buffer.api.exceptions.BufferException;
88
import org.gvsig.raster.lib.buffer.spi.DefaultTileStruct;
89
import org.gvsig.tools.ToolsLocator;
90
import org.gvsig.tools.dispose.Disposable;
91
import org.gvsig.tools.dispose.DisposeUtils;
92
import org.gvsig.tools.dynobject.DynObject;
93
import org.gvsig.tools.exception.BaseException;
94
import org.gvsig.tools.extensionpoint.ExtensionPoint.Extension;
95

    
96
/**
97
 * Represents a tiled image
98
 *
99
 * @author dmartinezizquierdo
100
 *
101
 */
102
public class FileTileCacheStructImage extends AbstractTileCacheStructImage {
103

    
104
    private static final Logger logger = LoggerFactory.getLogger(FileTileCacheStructImage.class);
105
    private static final int MAX_RECENT_ACCEDED_TILES_NUMBER = 50;
106

    
107
    private FilesystemServerExplorerProviderFactory factory;
108
    private String extension;
109
    private File tilesFolder;
110

    
111
    private IProjection crs;
112

    
113
    /**
114
     * @param folder
115
     * @param crs
116
     * @param innerProvider
117
     * @param query
118
     */
119
    public FileTileCacheStructImage(File folder, IProjection crs, RasterStoreProvider innerProvider, RasterQuery query) {
120
        super(innerProvider, query);
121
        this.crs = crs;
122
        GeometryManager geoManager = GeometryLocator.getGeometryManager();
123
        getTileStruct();
124

    
125
        // FIXME
126
        File tilePropertiesFile = new File(folder, "tileCacheStruct.xml");
127
        if (!tilePropertiesFile.exists()) {
128
            createTileCacheStructXMLFile(folder);
129
        }
130

    
131
        TreeMap<Integer, Double> pixelSizePerZoomLevel = new TreeMap<Integer, Double>();
132
        recentAccededTiles = new HashMap<String, Tile>();
133

    
134
        tilesFolder = new File(folder, "V" + File.separatorChar + "Z" + File.separatorChar + "T");
135
        if (!tilesFolder.exists()) {
136
            tilesFolder.mkdirs();
137
        }
138
        DocumentBuilderFactory dbFactory = DocumentBuilderFactory.newInstance();
139
        DocumentBuilder dBuilder;
140
        try {
141
            dBuilder = dbFactory.newDocumentBuilder();
142
            Document doc = dBuilder.parse(tilePropertiesFile);
143

    
144
            doc.getDocumentElement().normalize();
145

    
146
            NodeList nList = doc.getElementsByTagName("TileCacheStruct");
147
            for (int temp = 0; temp < nList.getLength(); temp++) {
148

    
149
                Node nNode = nList.item(temp);
150

    
151
                if (nNode.getNodeType() == Node.ELEMENT_NODE) {
152
                    Element eElement = (Element) nNode;
153

    
154
                    NamedNodeMap tileSizeAttributes = eElement.getElementsByTagName("tileSize").item(0).getAttributes();
155
                    tileStruct.setRowsPerTile(Integer.valueOf(tileSizeAttributes.getNamedItem("rows").getNodeValue()));
156
                    tileStruct.setColumnsPerTile(Integer.valueOf(tileSizeAttributes.getNamedItem("columns").getNodeValue()));
157

    
158
                    NodeList elementsByTagName = eElement.getElementsByTagName("format");
159
                    tileStruct.setProviderName(elementsByTagName.item(0).getTextContent());
160

    
161
                    NodeList structExtentList = eElement.getElementsByTagName("structExtent");
162
                    if (structExtentList.getLength() > 0) {
163
                        Element structExtentNode = (Element) structExtentList.item(0);
164
                        if (structExtentNode != null) {
165
                            Double minX =
166
                                Double.valueOf(structExtentNode.getElementsByTagName("minX").item(0).getTextContent());
167
                            Double minY =
168
                                Double.valueOf(structExtentNode.getElementsByTagName("minY").item(0).getTextContent());
169
                            Double maxX =
170
                                Double.valueOf(structExtentNode.getElementsByTagName("maxX").item(0).getTextContent());
171
                            Double maxY =
172
                                Double.valueOf(structExtentNode.getElementsByTagName("maxY").item(0).getTextContent());
173
                            tileStruct.setEnvelope(geoManager.createEnvelope(minX, minY, maxX, maxY, SUBTYPES.GEOM2D));                        }
174
                    }
175

    
176
                    FilesystemServerExplorerManager explorerManager =
177
                        DALFileLocator.getFilesystemServerExplorerManager();
178
                    @SuppressWarnings("unchecked")
179
                    Iterator<Extension> it = explorerManager.getRegisteredProviders();
180
                    while (it.hasNext()) {
181

    
182
                        Extension ext = it.next();
183
                        FilesystemServerExplorerProviderFactory providerFactory;
184
                        try {
185
                            providerFactory = (FilesystemServerExplorerProviderFactory) ext.create();
186
                            if (providerFactory.getName().equalsIgnoreCase(tileStruct.getProviderName())) {
187
                                this.factory = providerFactory;
188
                                break;
189
                            }
190
                        } catch (Exception e) {
191
                            throw new RuntimeException(e);// FIXME !!!
192
                        }
193
                    }
194

    
195
                    NodeList levelsTag = eElement.getElementsByTagName("levels");
196
                    Element levels = (Element) levelsTag.item(0);
197
                    NodeList levelList = levels.getElementsByTagName("level");
198
                    for (int i = 0; i < levelList.getLength(); i++) {
199
                        Element level = (Element) levelList.item(i);
200

    
201
                        NamedNodeMap levelAttributes = level.getAttributes();
202
                        int zoomLevel = Integer.valueOf(levelAttributes.getNamedItem("index").getNodeValue());
203
                        double pixelSize = Double.valueOf(levelAttributes.getNamedItem("pixelSize").getNodeValue());
204

    
205
                        pixelSizePerZoomLevel.put(zoomLevel, pixelSize);
206

    
207
                    }
208
                    this.tileStruct.setPixelSizePerZoomLevel(pixelSizePerZoomLevel);
209
                }
210
            }
211
        } catch (Exception e) {
212
            throw new RuntimeException();
213
        }
214
    }
215

    
216
    @Override
217
    public Band fetchTile(int bandNumber, int zoomLevel, int structRow, int structCol) {
218

    
219
        BufferManager bufferManager = BufferLocator.getBufferManager();
220

    
221
        String keyTile = composeKeyForRecentTiles(zoomLevel, structRow, structCol);
222
        Tile tile = recentAccededTiles.get(keyTile);
223

    
224
        if (tile != null) {
225
            // Devolver la banda del buffer del tile
226
            return tile.getBuffer().getBand(bandNumber);
227
        } else {
228
            // Cargar un tile nuevo
229
            Buffer rasterSet = null;
230
            RasterStore tileStore = null;
231
            RasterSet tileStoreRasterSet = null;
232
            Band band = null;
233
            try {
234
                tileStore = createTileStore(zoomLevel, structRow, structCol);
235
                tileStoreRasterSet = tileStore.getRasterSet();
236
                rasterSet = bufferManager.createBuffer(tileStoreRasterSet, false);
237

    
238
                if (recentAccededTiles.size() >= MAX_RECENT_ACCEDED_TILES_NUMBER) {
239
                    removeOlderTile();
240
                }
241
                recentAccededTiles.put(keyTile, new Tile(rasterSet, keyTile));
242

    
243
                band = rasterSet.getBand(bandNumber);
244
//                ToolsLocator.getDisposableManager().bind(band);
245
                return band;
246
            } catch (DataException | BufferException | ValidateDataParametersException | CreateEnvelopeException | CloneNotSupportedException e) {
247
                logger.warn("Can't fetch tile: zoomLevel = " + zoomLevel + ", tileRow = " + structRow
248
                    + ", tileColumn = " + structCol + ", band = " + bandNumber + ".", e);
249
                return null;
250
            } finally {
251
                DisposeUtils.dispose(tileStore);
252
                tileStore = null;
253
                DisposeUtils.dispose(tileStoreRasterSet);
254
                tileStoreRasterSet = null;
255
                DisposeUtils.dispose(rasterSet);
256
                rasterSet = null;
257
            }
258
        }
259
    }
260

    
261
    private RasterStore createTileStore(int zoomLevel, int structRow, int structCol) throws ValidateDataParametersException, CreateEnvelopeException, BufferException, DataException, CloneNotSupportedException {
262

    
263
        File tileFile = null;
264
        File zoomFolder = new File(tilesFolder, String.valueOf(zoomLevel));
265
        if (!zoomFolder.exists()) {
266
            zoomFolder.mkdirs();
267
        }
268
        File firstColumnFolder = new File(zoomFolder, String.valueOf(structCol));
269
        if (!firstColumnFolder.exists()) {
270
            tileFile = requestTileFile(zoomLevel, structRow, structCol);
271
            this.extension = FilenameUtils.getExtension(tileFile.getAbsolutePath());
272
        }
273
        String rowBaseName = String.valueOf(structRow);
274
        if (this.extension == null) {
275
            File[] providerAcceptedFiles = firstColumnFolder.listFiles(factory);
276
            for (int i = 0; i < providerAcceptedFiles.length; i++) {
277
                File providerAcceptedFile = providerAcceptedFiles[i];
278
                if (FilenameUtils.getBaseName(providerAcceptedFile.getAbsolutePath()).equalsIgnoreCase(rowBaseName)) {
279
                    tileFile = providerAcceptedFile;
280
                }
281
            }
282
            if (tileFile == null || !tileFile.exists()) {
283
                tileFile = requestTileFile(zoomLevel, structRow, structCol);
284
            }
285
            this.extension = FilenameUtils.getExtension(tileFile.getAbsolutePath());
286
        } else {
287
            if (tileFile == null) {
288
                tileFile =
289
                    new File(firstColumnFolder.getAbsolutePath() + File.separatorChar + rowBaseName + "."
290
                        + this.extension);
291
            }
292
        }
293
        if (!tileFile.exists()) {
294
            tileFile = requestTileFile(zoomLevel, structRow, structCol);
295
        }
296
        RasterStore tileStore = null;
297
        DataManagerProviderServices manager = DALSPILocator.getDataManagerProviderServices();
298
        DataStoreProviderFactory providerFactory = manager.getStoreProviderFactory(this.tileStruct.getProviderName());
299

    
300
        DynObject params = providerFactory.createParameters();
301
        if (params.getDynClass().getDynField("file") != null) {
302
            params.setDynValue("file", tileFile);
303
        }
304
        if (params.getDynClass().getDynField("crs") != null) {
305
            params.setDynValue("crs", this.crs);
306
        }
307

    
308
        tileStore = (RasterStore) manager.openStore(this.tileStruct.getProviderName(), params);
309
        return tileStore;
310
    }
311

    
312
    private File requestTileFile(int zoomLevel, int structRow, int structCol) throws CreateEnvelopeException,
313
        CloneNotSupportedException, BufferException, ValidateDataParametersException, DataException {
314

    
315
        RasterQuery rasterQuery = (RasterQuery) this.query.clone();
316

    
317
        Double pixelSize = this.tileStruct.getPixelSizePerZoomLevel().get(zoomLevel);
318
        rasterQuery.setPixelSize(pixelSize);
319

    
320
        GeometryManager geomManager = GeometryLocator.getGeometryManager();
321

    
322
        Envelope structExtent = this.tileStruct.getEnvelope();
323
        int rowsPerTile = this.tileStruct.getRowsPerTile();
324
        int columnsPerTile = this.tileStruct.getColumnsPerTile();
325
        double minX = structExtent.getMinimum(DIMENSIONS.X) + structCol * (pixelSize * columnsPerTile);
326
        double minY = structExtent.getMaximum(DIMENSIONS.Y) - ((structRow + 1) * (pixelSize * rowsPerTile));
327
        double maxX = minX + pixelSize * columnsPerTile;
328
        double maxY = minY + pixelSize * rowsPerTile;
329
        Envelope envelope = geomManager.createEnvelope(minX, minY, maxX, maxY, SUBTYPES.GEOM2D);
330
        rasterQuery.setClip(envelope);
331

    
332
        Buffer buffer = null;
333
        Buffer clippedBuffer = null;
334
        Buffer interpolatedBuffer = null;
335
        File destFile = null;
336
        DataServerExplorer serverExplorer = null;
337
        try {
338
            buffer = innerProvider.createBuffer(rasterQuery);
339
            clippedBuffer = buffer.clip(envelope);
340
            interpolatedBuffer =
341
                clippedBuffer.createInterpolated(
342
                    (int) (Math.round(clippedBuffer.getDimensions().getPixelSizeY() * clippedBuffer.getRows() / pixelSize)),
343
                    (int) (Math.round(clippedBuffer.getDimensions().getPixelSizeX() * clippedBuffer.getColumns() / pixelSize)),
344
                    Buffer.INTERPOLATION_Bilinear, null);
345

    
346
            String providerName = "GTiff";
347
            String extension = "tif";
348

    
349
            DataManagerProviderServices manager = DALSPILocator.getDataManagerProviderServices();
350
            DataServerExplorerParameters eparams;
351
            eparams = manager.createServerExplorerParameters("FilesystemExplorer");
352

    
353
            destFile = FileUtils.getFile(tilesFolder,Integer.toString(zoomLevel),Integer.toString(structCol),Integer.toString(structRow)+"."+extension);
354

    
355
            File parent = destFile.getParentFile();
356
            if (!parent.exists()) {
357
                parent.mkdirs();
358
            }
359
            eparams.setDynValue("initialpath", destFile);
360
//            DataServerExplorer serverExplorer = manager.createServerExplorer(eparams);
361
            serverExplorer = manager.openServerExplorer(eparams.getExplorerName(), eparams);
362

    
363
            NewRasterStoreParameters params = (NewRasterStoreParameters) serverExplorer.getAddParameters(providerName);
364
            params.setDynValue("file", destFile);
365

    
366
            params.setDynValue("compress", "NONE");
367
            params.setDynValue("tfw", false);
368

    
369
            // FIXME: Ver de coger estos dos valores del inner provider para que
370
            // los tiles sean homog?neos con el raster original
371
            int bands = innerProvider.getBands();
372
            switch (bands) {
373
            case 3:
374
                params.setDynValue("photometric", "RGB");
375
                break;
376
            case 4:
377
                params.setDynValue("photometric", "RGB");
378
                params.setDynValue("alpha", "NON-PREMULTIPLIED");
379
                break;
380
            default:
381
                params.setDynValue("photometric", "MINISBLACK");
382
                break;
383
            }
384

    
385
            params.setBuffer(interpolatedBuffer);
386
            serverExplorer.add(providerName, params, true);
387
        } finally {
388
            DisposeUtils.dispose(buffer);
389
            DisposeUtils.dispose(clippedBuffer);
390
            DisposeUtils.dispose(interpolatedBuffer);
391
            DisposeUtils.dispose(serverExplorer);
392
        }
393

    
394
        return destFile;
395
    }
396

    
397
    @Override
398
    protected void doDispose() throws BaseException {
399
        super.doDispose();
400
        factory = null;
401
        crs = null;
402
        tilesFolder = null;
403
        extension = null;
404
    }
405

    
406
    private void createTileCacheStructXMLFile(File folder) {
407

    
408
        TileStruct tileStructProvider = null;
409
        try {
410
            if (innerProvider != null) {
411
                tileStructProvider = innerProvider.getTileStruct();
412
                DisposeUtils.bind((Disposable) tileStructProvider);
413
            }
414

    
415
            int tileSizeX = TileCacheLibrary.DEFAULT_TILEWIDTH;
416
            if (tileStructProvider != null && tileStructProvider.getColumnsPerTile() != 0) {
417
                tileSizeX = tileStructProvider.getColumnsPerTile();
418
            }
419

    
420
            int tileSizeY = TileCacheLibrary.DEFAULT_TILEHEIGHT;
421
            if (tileStructProvider != null && tileStructProvider.getRowsPerTile() != 0) {
422
                tileSizeY = tileStructProvider.getRowsPerTile();
423
            }
424

    
425
            File file = new File(folder, "tileCacheStruct.xml");
426

    
427
            if (!file.exists()) {
428
                Buffer auxBuffer = null;
429
                try {
430
                    DocumentBuilderFactory docFactory = DocumentBuilderFactory.newInstance();
431
                    DocumentBuilder docBuilder = docFactory.newDocumentBuilder();
432

    
433
                    // root elements
434
                    Document doc = (Document) docBuilder.newDocument();
435
                    Element rootElement = doc.createElement("TileCacheStruct");
436
                    doc.appendChild(rootElement);
437

    
438
                    // tileSize
439
                    Element tileSize = doc.createElement("tileSize");
440
                    rootElement.appendChild(tileSize);
441

    
442
                    // tileSize Rows
443
                    Attr rows = doc.createAttribute("rows");
444
                    rows.setValue(String.valueOf(tileSizeY));
445
                    tileSize.setAttributeNode(rows);
446

    
447
                    // tileSize Columns
448
                    Attr columns = doc.createAttribute("columns");
449
                    columns.setValue(String.valueOf(tileSizeX));
450
                    tileSize.setAttributeNode(columns);
451

    
452
                    // format
453
                    Element format = doc.createElement("format");
454
                    if (tileStructProvider == null || StringUtils.isEmpty(tileStructProvider.getProviderName())) {
455
                        format.setTextContent("GTiff");
456
                    }
457
                    rootElement.appendChild(format);
458

    
459
                    // structExtent
460
                    Element structExtent = doc.createElement("structExtent");
461
                    rootElement.appendChild(structExtent);
462

    
463
                    Envelope envelope = (Envelope) innerProvider.getDynValue(DataStore.METADATA_ENVELOPE);
464

    
465
                    // structExtent minX
466
                    Element minX = doc.createElement("minX");
467
                    minX.setTextContent(String.valueOf(envelope.getMinimum(DIMENSIONS.X)));
468
                    structExtent.appendChild(minX);
469

    
470
                    // structExtent minY
471
                    Element minY = doc.createElement("minY");
472
                    minY.setTextContent(String.valueOf(envelope.getMinimum(DIMENSIONS.Y)));
473
                    structExtent.appendChild(minY);
474

    
475
                    // structExtent maxX
476
                    Element maxX = doc.createElement("maxX");
477
                    maxX.setTextContent(String.valueOf(envelope.getMaximum(DIMENSIONS.X)));
478
                    structExtent.appendChild(maxX);
479

    
480
                    // structExtent maxY
481
                    Element maxY = doc.createElement("maxY");
482
                    maxY.setTextContent(String.valueOf(envelope.getMaximum(DIMENSIONS.Y)));
483
                    structExtent.appendChild(maxY);
484

    
485
                    Element levels = doc.createElement("levels");
486
                    rootElement.appendChild(levels);
487

    
488
                    List<Double> pixelSizes = new ArrayList<Double>();
489
                    Map<Integer, Double> zoomLevels = new HashMap<Integer, Double>();
490

    
491
                    if (tileStructProvider == null || tileStructProvider.getPixelSizePerZoomLevel() == null) {
492
                        // FIXME: ?alguna otra forma de obtener el pixelSize del
493
                        // store completo?
494
                        auxBuffer = innerProvider.createBuffer(null);
495
                        int completeRows = auxBuffer.getRows();
496
                        int completeColumns = auxBuffer.getColumns();
497
                        double completePixelSizeX = auxBuffer.getDimensions().getPixelSizeX();
498
                        double completePixelSizeY = auxBuffer.getDimensions().getPixelSizeY();
499

    
500
                        int maximumLength = completeColumns;
501
                        int tileMaximumLength = tileSizeX;
502
                        double maximumPixelSize = completePixelSizeX;
503

    
504
                        if (completeRows * tileSizeY > completeColumns * tileSizeX) {
505
                            maximumLength = completeRows;
506
                            tileMaximumLength = tileSizeY;
507
                            maximumPixelSize = completePixelSizeY;
508
                        }
509

    
510
                        double pixelSize = maximumPixelSize;
511
                        while (maximumLength * maximumPixelSize / pixelSize > tileMaximumLength) {
512
                            pixelSizes.add(pixelSize);
513
                            pixelSize = pixelSize * 2;
514
                        }
515
                        pixelSizes.add(pixelSize);
516
                        int i = 0;
517
                        for (int zoomLevel = pixelSizes.size() - 1; zoomLevel >= 0; zoomLevel--) {
518
                            zoomLevels.put(i, pixelSizes.get(zoomLevel));
519
                            appendZoomLevel(doc, levels, i, pixelSizes.get(zoomLevel));
520
                            i++;
521
                        }
522
                    } else {
523
                        zoomLevels = tileStructProvider.getPixelSizePerZoomLevel();
524
                    }
525

    
526
                    for (Entry<Integer, Double> entry : zoomLevels.entrySet()) {
527
                        appendZoomLevel(doc, levels, entry.getKey(), entry.getValue());
528
                    }
529

    
530
                    // write the content into xml file
531

    
532
                    DOMSource source = new DOMSource(doc);
533
                    File parent = file.getParentFile();
534
                    if (!parent.exists()) {
535
                        parent.mkdirs();
536
                    }
537
                    file.createNewFile();
538
                    StreamResult result = new StreamResult(file.toURI().getPath());
539

    
540
                    TransformerFactory transformerFactory = TransformerFactory.newInstance();
541
                    Transformer transformer = transformerFactory.newTransformer();
542
                    transformer.setOutputProperty(OutputKeys.INDENT, "yes");
543
                    transformer.setOutputProperty("{http://xml.apache.org/xslt}indent-amount", "2");
544
                    transformer.transform(source, result);
545

    
546
                } catch (ParserConfigurationException | TransformerException | IOException | BufferException e) {
547
                    logger.warn("Can't create tileCacheStruct.xml file", e);
548
                } finally {
549
                    DisposeUtils.dispose(auxBuffer);
550
                    auxBuffer = null;
551
                }
552
            }
553
        } finally {
554
            DisposeUtils.disposeQuietly((Disposable) tileStructProvider);
555
            tileStructProvider = null;
556

    
557
        }
558
    }
559

    
560
    /**
561
     * @param doc
562
     * @param rootElement
563
     * @param levels
564
     * @param zoomLevel
565
     * @param pixelSize
566
     */
567
    private void appendZoomLevel(Document doc, Element levels, int zoomLevel, double pixelSize) {
568
        Element level = doc.createElement("level");
569
        levels.appendChild(level);
570

    
571
        // level zoomLevel
572
        Attr index = doc.createAttribute("index");
573
        index.setValue(String.valueOf(zoomLevel));
574
        level.setAttributeNode(index);
575

    
576
        // level pixelSize
577
        Attr pxSize = doc.createAttribute("pixelSize");
578
        pxSize.setValue(String.valueOf(pixelSize));
579
        level.setAttributeNode(pxSize);
580
    }
581

    
582
    /* (non-Javadoc)
583
     * @see org.gvsig.raster.tilecache.provider.ITileStructImage#getTileStruct()
584
     */
585
    @Override
586
    public TileStruct getTileStruct() {
587
        if(this.tileStruct==null){
588
            this.tileStruct = new DefaultTileStruct();
589
        }
590
        return this.tileStruct;
591
    }
592

    
593
    public void forgetCache() {
594
        super.forgetCache();
595
        if(tilesFolder.exists() && tilesFolder.isDirectory()){
596
            File[] files = tilesFolder.listFiles();
597
            for(int i=0; i<files.length; i++){
598
                try {
599
                    FileUtils.forceDelete(files[i]);
600
                } catch (IOException e) {
601
                    logger.warn("Can't delete the file "+files[i].getAbsolutePath(), e);
602
                }
603
            }
604
        }
605
    }
606
}