Package org.geowebcache.arcgis.layer

Source Code of org.geowebcache.arcgis.layer.ArcGISCacheLayer

package org.geowebcache.arcgis.layer;

import java.io.File;
import java.io.FileNotFoundException;
import java.io.FileReader;
import java.io.IOException;
import java.util.Arrays;
import java.util.Collections;
import java.util.Hashtable;
import java.util.List;

import javax.servlet.http.HttpServletResponse;

import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.geowebcache.GeoWebCacheException;
import org.geowebcache.arcgis.config.CacheInfo;
import org.geowebcache.arcgis.config.CacheInfoPersister;
import org.geowebcache.arcgis.config.LODInfo;
import org.geowebcache.arcgis.config.TileCacheInfo;
import org.geowebcache.conveyor.Conveyor.CacheResult;
import org.geowebcache.conveyor.ConveyorTile;
import org.geowebcache.grid.BoundingBox;
import org.geowebcache.grid.Grid;
import org.geowebcache.grid.GridSet;
import org.geowebcache.grid.GridSetBroker;
import org.geowebcache.grid.GridSubset;
import org.geowebcache.grid.GridSubsetFactory;
import org.geowebcache.grid.OutsideCoverageException;
import org.geowebcache.io.FileResource;
import org.geowebcache.io.Resource;
import org.geowebcache.layer.AbstractTileLayer;
import org.geowebcache.mime.MimeException;
import org.geowebcache.mime.MimeType;
import org.geowebcache.storage.StorageException;

/**
*
* @author Gabriel Roldan
*
*/
public class ArcGISCacheLayer extends AbstractTileLayer {

    private static final Log log = LogFactory.getLog(ArcGISCacheLayer.class);

    /*
     * configuration properties
     */

    private Boolean enabled;

    /**
     * The location of the conf.xml tiling scheme configuration file
     */
    private File tilingScheme;

    /**
     * Optional, location of the actual tiles folder. If not provided defaults to the
     * {@code _alllayers} directory at the same location than the {@link #getTilingScheme()
     * conf.xml} tiling scheme.
     */
    private File tileCachePath;

    private transient CacheInfo cacheInfo;

    private transient BoundingBox layerBounds;

    @Override
    public boolean isEnabled() {
        return enabled;
    }

    @Override
    public void setEnabled(boolean enabled) {
        this.enabled = enabled;
    }

    public File getTilingScheme() {
        return tilingScheme;
    }

    public void setTilingScheme(final File tilingScheme) {
        this.tilingScheme = tilingScheme;
    }

    /**
     * Returns the location of the actual tiles folder, or {@code null} if not provided, in which
     * case defaults internally to the {@code _alllayers} directory at the same location than the
     * {@link #getTilingScheme() conf.xml} tiling scheme.
     */
    public File getTileCachePath() {
        return tileCachePath;
    }

    /**
     * Options, location of the actual tiles folder. If not provided defaults to the
     * {@code _alllayers} directory at the same location than the {@link #getTilingScheme()
     * conf.xml} tiling scheme.
     */
    public void setTileCachePath(File tileCachePath) {
        this.tileCachePath = tileCachePath;
    }

    /**
     * @see org.geowebcache.layer.TileLayer#initialize(org.geowebcache.grid.GridSetBroker)
     * @return {@code true} if success. Note this method's return type should be void. It's not
     *         checked anywhere
     */
    @Override
    protected boolean initializeInternal(GridSetBroker gridSetBroker) {
        if (this.enabled == null) {
            this.enabled = true;
        }
        if (this.tilingScheme == null) {
            throw new IllegalStateException(
                    "tilingScheme has not been set. It should point to the ArcGIS "
                            + "cache tiling scheme file for this layer (conf.xml)");
        }
        if (tileCachePath != null) {
            if (!tileCachePath.exists() || !tileCachePath.isDirectory() || !tileCachePath.canRead()) {
                throw new IllegalStateException("tileCachePath property for layer '" + getName()
                        + "' is set to '" + tileCachePath
                        + "' but the directory either does not exist or is not readable");
            }
        }
        try {
            CacheInfoPersister tilingSchemeLoader = new CacheInfoPersister();
            cacheInfo = tilingSchemeLoader.load(new FileReader(tilingScheme));
            File layerBoundsFile = new File(tilingScheme.getParentFile(), "conf.cdi");
            if (!layerBoundsFile.exists()) {
                throw new RuntimeException("Layer bounds file not found: "
                        + layerBoundsFile.getAbsolutePath());
            }
            log.info("Parsing layer bounds for " + getName());
            this.layerBounds = tilingSchemeLoader.parseLayerBounds(new FileReader(layerBoundsFile));
            log.info("Parsed layer bounds for " + getName() + ": " + layerBounds);
        } catch (FileNotFoundException e) {
            throw new IllegalStateException("Tiling scheme file not found: "
                    + tilingScheme.getAbsolutePath());
        }
        log.info("Configuring layer " + getName() + " out of the ArcGIS tiling scheme "
                + tilingScheme.getAbsolutePath());

        super.subSets = createGridSubsets(gridSetBroker);
        super.formats = loadMimeTypes();
        return true;
    }

    private List<MimeType> loadMimeTypes() {
        String cacheTileFormat = this.cacheInfo.getTileImageInfo().getCacheTileFormat();
        if ("mixed".equalsIgnoreCase(cacheTileFormat) || "jpg".equalsIgnoreCase(cacheTileFormat)) {
            cacheTileFormat = "JPEG";
        } else if (cacheTileFormat.toLowerCase().startsWith("png")) {
            cacheTileFormat = "png";
        }
        cacheTileFormat = "image/" + cacheTileFormat.toLowerCase();
        MimeType format;
        try {
            format = MimeType.createFromFormat(cacheTileFormat);
        } catch (MimeException e) {
            throw new RuntimeException(e);
        }
        return Collections.singletonList(format);
    }

    private Hashtable<String, GridSubset> createGridSubsets(final GridSetBroker gridSetBroker) {

        final CacheInfo info = this.cacheInfo;
        final TileCacheInfo tileCacheInfo = info.getTileCacheInfo();

        final String layerName = getName();
        final GridSetBuilder gsBuilder = new GridSetBuilder();
        GridSet gridSet = gsBuilder.buildGridset(layerName, info, layerBounds);

        gridSetBroker.put(gridSet);

        final List<LODInfo> lodInfos = tileCacheInfo.getLodInfos();
        Integer zoomStart = lodInfos.get(0).getLevelID();
        Integer zoomStop = lodInfos.get(lodInfos.size() - 1).getLevelID();

        GridSubset subSet = GridSubsetFactory.createGridSubSet(gridSet, this.layerBounds,
                zoomStart, zoomStop);

        Hashtable<String, GridSubset> subsets = new Hashtable<String, GridSubset>();
        subsets.put(gridSet.getName(), subSet);
        return subsets;
    }

    /**
     *
     * @see org.geowebcache.layer.TileLayer#getTile(org.geowebcache.conveyor.ConveyorTile)
     */
    @Override
    public ConveyorTile getTile(final ConveyorTile tile) throws GeoWebCacheException, IOException,
            OutsideCoverageException {

        String path = getTilePath(tile);
        File tileFile = new File(path);

        if (tileFile.exists()) {
            Resource tileContent = readFile(tileFile);
            tile.setCacheResult(CacheResult.HIT);
            tile.setBlob(tileContent);
        } else {
            tile.setCacheResult(CacheResult.MISS);
            if (!setLayerBlankTile(tile)) {
                throw new OutsideCoverageException(tile.getTileIndex(), 0, 0);
            }
        }
        return tile;
    }

    private boolean setLayerBlankTile(ConveyorTile tile) {
        // TODO cache result
        String layerPath = getLayerPath().append(File.separatorChar).toString();
        File png = new File(layerPath + "blank.png");
        Resource blank = null;
        try {
            if (png.exists()) {
                blank = readFile(png);
                tile.setBlob(blank);
                tile.setMimeType(MimeType.createFromFormat("image/png"));
            } else {
                File jpeg = new File(layerPath + "missing.jpg");
                if (jpeg.exists()) {
                    blank = readFile(jpeg);
                    tile.setBlob(blank);
                    tile.setMimeType(MimeType.createFromFormat("image/jpeg"));
                }
            }
        } catch (Exception e) {
            return false;
        }
        return blank != null;
    }

    private String getTilePath(final ConveyorTile tile) {

        final MimeType mimeType = tile.getMimeType();
        final long[] tileIndex = tile.getTileIndex();
        final String gridSetId = tile.getGridSetId();
        final GridSubset gridSubset = this.getGridSubset(gridSetId);

        GridSet gridSet = gridSubset.getGridSet();
        final int z = (int) tileIndex[2];

        Grid grid = gridSet.getGrids()[z];

        // long[] coverage = gridSubset.getCoverage(z);
        // long coverageMinY = coverage[1];
        long coverageMaxY = grid.getExtent()[1] - 1;

        final long x = tileIndex[0];
        // invert the order of the requested Y ordinate, since ArcGIS caches are top-left to
        // bottom-right, and GWC computes tiles in bottom-left to top-right order
        final long y = (coverageMaxY - tileIndex[1]);

        String level = Integer.toHexString(z);
        level = zeroPadder(level, 2);

        String row = Long.toHexString(y);
        row = zeroPadder(row, 8);

        String col = Long.toHexString(x);
        col = zeroPadder(col, 8);

        StringBuilder path = getLayerPath();

        path.append(File.separatorChar).append('L').append(level).append(File.separatorChar)
                .append('R').append(row).append(File.separatorChar).append('C').append(col);

        String fileExtension = mimeType.getFileExtension();
        if ("jpeg".equalsIgnoreCase(fileExtension)) {
            fileExtension = "jpg";
        }
        path.append('.').append(fileExtension);

        return path.toString();
    }

    private StringBuilder getLayerPath() {
        StringBuilder path;
        if (tileCachePath == null) {
            path = new StringBuilder(this.tilingScheme.getParent());
            // note we're assuming it's a "fused" tile cache. When it comes to support multiple
            // layers
            // tile caches we'll need to parametrize the layer's cache directory
            path.append(File.separatorChar).append("_alllayers");
        } else {
            path = new StringBuilder(tileCachePath.getAbsolutePath());
        }
        return path;
    }

    private String zeroPadder(String s, int order) {
        if (s.length() >= order) {
            return s;
        }
        char[] data = new char[order];
        Arrays.fill(data, '0');

        for (int i = s.length() - 1, j = order - 1; i >= 0; i--, j--) {
            data[j] = s.charAt(i);
        }
        return String.valueOf(data);
    }

    private Resource readFile(File fh) throws StorageException {
        if (!fh.exists()) {
            return null;
        }
        Resource res = new FileResource(fh);
        return res;
    }

    /**
     *
     * @see org.geowebcache.layer.TileLayer#getNoncachedTile(org.geowebcache.conveyor.ConveyorTile)
     */
    @Override
    public ConveyorTile getNoncachedTile(ConveyorTile tile) throws GeoWebCacheException {
        throw new UnsupportedOperationException();
    }

    /**
     *
     * @see org.geowebcache.layer.TileLayer#seedTile(org.geowebcache.conveyor.ConveyorTile, boolean)
     */
    @Override
    public void seedTile(ConveyorTile tile, boolean tryCache) throws GeoWebCacheException,
            IOException {
        throw new UnsupportedOperationException();
    }

    /**
     *
     * @see org.geowebcache.layer.TileLayer#doNonMetatilingRequest(org.geowebcache.conveyor.ConveyorTile)
     */
    @Override
    public ConveyorTile doNonMetatilingRequest(ConveyorTile tile) throws GeoWebCacheException {
        throw new UnsupportedOperationException();
    }

    /**
     *
     * @see org.geowebcache.layer.TileLayer#getStyles()
     */
    @Override
    public String getStyles() {
        return null;
    }

    /**
     *
     * @see org.geowebcache.layer.TileLayer#acquireLayerLock()
     */
    @Override
    public void acquireLayerLock() {
        throw new UnsupportedOperationException();
    }

    /**
     *
     * @see org.geowebcache.layer.TileLayer#releaseLayerLock()
     */
    @Override
    public void releaseLayerLock() {
        throw new UnsupportedOperationException();
    }

    /**
     *
     * @see org.geowebcache.layer.TileLayer#setExpirationHeader(javax.servlet.http.HttpServletResponse,
     *      int)
     */
    @Override
    public void setExpirationHeader(HttpServletResponse response, int zoomLevel) {
        /*
         * NOTE: this method doesn't seem like belonging to TileLayer, but to GeoWebCacheDispatcher
         * itself
         */
        return;
    }

}
TOP

Related Classes of org.geowebcache.arcgis.layer.ArcGISCacheLayer

TOP
Copyright © 2018 www.massapi.com. All rights reserved.
All source code are property of their respective owners. Java is a trademark of Sun Microsystems, Inc and owned by ORACLE Inc. Contact coftware#gmail.com.