Package org.geoserver.wms.eo

Source Code of org.geoserver.wms.eo.EoCatalogBuilder

/* (c) 2014 Open Source Geospatial Foundation - all rights reserved
* (c) 2013 OpenPlans
* This code is licensed under the GPL 2.0 license, available at the root
* application directory.
*/
package org.geoserver.wms.eo;

import java.io.BufferedInputStream;
import java.io.File;
import java.io.FileInputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.Serializable;
import java.net.URL;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Properties;
import java.util.logging.Level;
import java.util.logging.Logger;

import org.apache.commons.lang.StringUtils;
import org.geoserver.catalog.Catalog;
import org.geoserver.catalog.CatalogBuilder;
import org.geoserver.catalog.CoverageInfo;
import org.geoserver.catalog.CoverageStoreInfo;
import org.geoserver.catalog.DataStoreInfo;
import org.geoserver.catalog.DimensionInfo;
import org.geoserver.catalog.DimensionPresentation;
import org.geoserver.catalog.FeatureTypeInfo;
import org.geoserver.catalog.LayerGroupInfo;
import org.geoserver.catalog.LayerInfo;
import org.geoserver.catalog.NamespaceInfo;
import org.geoserver.catalog.PublishedInfo;
import org.geoserver.catalog.ResourceInfo;
import org.geoserver.catalog.StoreInfo;
import org.geoserver.catalog.StyleInfo;
import org.geoserver.catalog.WorkspaceInfo;
import org.geoserver.catalog.impl.DimensionInfoImpl;
import org.geoserver.catalog.util.ReaderDimensionsAccessor;
import org.geotools.coverage.grid.io.DimensionDescriptor;
import org.geotools.coverage.grid.io.GridCoverage2DReader;
import org.geotools.coverage.grid.io.StructuredGridCoverage2DReader;
import org.geotools.data.DataAccessFactory.Param;
import org.geotools.data.DataStore;
import org.geotools.data.DataStoreFactorySpi;
import org.geotools.data.DataUtilities;
import org.geotools.data.shapefile.ShapefileDataStoreFactory;
import org.geotools.data.simple.SimpleFeatureSource;
import org.geotools.gce.imagemosaic.Utils;
import org.geotools.jdbc.JDBCDataStoreFactory;
import org.geotools.util.NullProgressListener;
import org.geotools.util.Utilities;
import org.geotools.util.logging.Logging;

/**
* Builder class which provides convenience methods for managing EO stores, resources, layers and
* layer groups.
*
* @author Davide Savazzi - geo-solutions.it
*/
public class EoCatalogBuilder implements EoStyles {

    private Catalog catalog;

    private static final Logger LOGGER = Logging.getLogger(EoCatalogBuilder.class);

    /**
     * EoCatalogBuilder constructor
     *
     * @param catalog
     */
    public EoCatalogBuilder(Catalog catalog) {
        this.catalog = catalog;
    }

    /**
     * Create an EO Geophysical Parameters layer
     *
     * @param ws workspace
     * @param groupName group name
     * @param parametersName Geophysical Parameters name
     * @param parametersUrl Geophysical Parameters url
     * @return created layer
     */
    public LayerInfo createEoParametersLayer(WorkspaceInfo ws, String groupName,
            String parametersName, String parametersUrl) {
        String parametersLayerName = groupName + "_" + parametersName;
        return createEoMosaicLayer(ws, parametersLayerName, EoLayerType.GEOPHYSICAL_PARAMETER,
                parametersUrl, false);
    }

    /**
     * Create an EO Bitmasks layer
     *
     * @param ws workspace
     * @param groupName group name
     * @param masksName bitmasks name
     * @param masksUrl bitmasks url
     * @return created layer
     */
    public LayerInfo createEoMasksLayer(WorkspaceInfo ws, String groupName, String masksName,
            String masksUrl) {
        Utilities.ensureNonNull("groupName", groupName);
        String masksLayerName = groupName + "_" + masksName;
        LayerInfo masksLayer = createEoMosaicLayer(ws, masksLayerName, EoLayerType.BITMASK,
                masksUrl, false);
        if (masksLayer != null) {
            addEoStyles(masksLayer, DEFAULT_BITMASK_STYLE);
        }
        return masksLayer;
    }

    public LayerInfo createEoBandsLayer(WorkspaceInfo ws, String groupName, String bandsUrl) {
        Utilities.ensureNonNull("groupName", groupName);
        String bandsLayerName = groupName + "_BANDS";
        return createEoMosaicLayer(ws, bandsLayerName, EoLayerType.BAND_COVERAGE, bandsUrl, true);
    }

    public LayerInfo createEoBrowseImageLayer(WorkspaceInfo ws, String groupName,
            String browseImageUrl) {
        /*
         * Browse Image layer name must be different from EO group name (otherwise GWC will
         * complain) In GetCapabilities this name will not appear
         */
        Utilities.ensureNonNull("groupName", groupName);
        String browseLayerName = groupName + "_BROWSE";
        return createEoMosaicLayer(ws, browseLayerName, EoLayerType.BROWSE_IMAGE, browseImageUrl,
                false);
    }

    /**
     * Create an EO layer group
     *
     * @param ws workspace
     * @param groupName group name
     * @param groupTitle group title
     * @param browseImageUrl Browse Image url
     * @param bandsUrl Band Coverage url
     * @param masksName Bitmasks name
     * @param masksUrl Bitmasks url
     * @param parametersName Geophysical Parameters name
     * @param parametersUrl Geophysical Parameters url
     * @return created group
     */
    public LayerGroupInfo createEoLayerGroup(WorkspaceInfo ws, String groupName, String groupTitle,
            String browseImageUrl, String bandsUrl, String masksName, String masksUrl,
            String parametersName, String parametersUrl) {

        LayerInfo bandsLayer = createEoBandsLayer(ws, groupName, bandsUrl);
        LayerInfo browseLayer = createEoBrowseImageLayer(ws, groupName, browseImageUrl);
        LayerInfo paramsLayer = createEoParametersLayer(ws, groupName, parametersName,
                parametersUrl);
        LayerInfo masksLayer = createEoMasksLayer(ws, groupName, masksName, masksUrl);

        LayerInfo outlineLayer;
        try {
            StructuredGridCoverage2DReader reader = (StructuredGridCoverage2DReader) ((CoverageInfo) bandsLayer.getResource()).getGridCoverageReader(null, null);
            outlineLayer = createEoOutlineLayer(bandsUrl, ws, groupName, null, reader);
        } catch (Exception e) {
            throw new IllegalArgumentException(
                    "The Outline layer could not be created. Failure message: " + e.getMessage(), e);
        }

        // create layer group
        LayerGroupInfo layerGroup = catalog.getFactory().createLayerGroup();
        layerGroup.setWorkspace(ws);
        layerGroup.setName(groupName);
        layerGroup.setTitle(groupTitle);
        layerGroup.setMode(LayerGroupInfo.Mode.EO);
        layerGroup.setRootLayer(browseLayer);
        layerGroup.setRootLayerStyle(browseLayer.getDefaultStyle());
        layerGroup.getLayers().add(outlineLayer);
        layerGroup.getStyles().add(outlineLayer.getDefaultStyle());
        layerGroup.getLayers().add(bandsLayer);
        layerGroup.getStyles().add(bandsLayer.getDefaultStyle());
        if (masksLayer != null) {
            layerGroup.getLayers().add(masksLayer);
            layerGroup.getStyles().add(masksLayer.getDefaultStyle());
        }
        if (paramsLayer != null) {
            layerGroup.getLayers().add(paramsLayer);
            layerGroup.getStyles().add(paramsLayer.getDefaultStyle());
        }

        try {
            CatalogBuilder builder = new CatalogBuilder(catalog);
            builder.calculateLayerGroupBounds(layerGroup);

            catalog.add(layerGroup);
            return layerGroup;
        } catch (Exception e) {
            throw new IllegalArgumentException("The layer group '" + groupName
                    + "' could not be created. Failure message: " + e.getMessage(), e);
        }
    }

    private Properties loadProperties(File propertiesFile) throws IOException {
        Properties properties = new Properties();
        InputStream inputStream = new BufferedInputStream(new FileInputStream(propertiesFile));
        try {
            properties.load(inputStream);
        } finally {
            inputStream.close();
        }
        return properties;
    }

    protected DataStoreFactorySpi getOutlineDataStoreFactory(File dir) throws Exception {
        File datastorePropertiesFile = new File(dir, "datastore.properties");
        if (datastorePropertiesFile.exists()) {
            Properties datastoreProperties = loadProperties(datastorePropertiesFile);
            String SPIClass = datastoreProperties.getProperty("SPI");
            return (DataStoreFactorySpi) Class.forName(SPIClass).newInstance();
        } else {
            return new ShapefileDataStoreFactory();
        }
    }

    /**
     * Get database type from DataStoreFactorySpi
     *
     * @param dataStoreFactory
     * @return database type
     */
    protected String getDbType(DataStoreFactorySpi dataStoreFactory) {
        String dbType = null;
        Param[] params = dataStoreFactory.getParametersInfo();
        for (Param param : params) {
            if (JDBCDataStoreFactory.DBTYPE.key.equals(param.key)) {
                dbType = (String) param.getDefaultValue();
            }
        }

        if (dbType == null) {
            if (LOGGER.isLoggable(Level.WARNING)) {
                LOGGER.log(Level.WARNING, "dbtype parameter not found in dataStoreFactory "
                        + dataStoreFactory + ", using default.");
            }
        }

        return dbType;
    }

    /**
     * Create Outline store parameters
     *
     * @param dir mosaic directory
     * @param dataStoreFactory
     * @return parameters
     * @throws IOException
     */
    protected Map<String, Serializable> getOutlineDataStoreParameters(File dir,
            DataStoreFactorySpi dataStoreFactory) throws IOException {
        File datastorePropertiesFile = new File(dir, "datastore.properties");
        if (datastorePropertiesFile.exists()) {
            Properties datastoreProperties = loadProperties(datastorePropertiesFile);
            Map<String, Serializable> params = Utils.createDataStoreParamsFromPropertiesFile(
                    datastoreProperties, dataStoreFactory);
            String dbType = getDbType(dataStoreFactory);
            params.put("dbtype", dbType);
            if ("h2".equals(dbType)) {
                String dbParameter = (String) params.get("database");
                // if the reference is relative, we need to build the absolute path
                if (!new File(dbParameter).isAbsolute()) {
                    File actualPath = new File(dir, dbParameter).getCanonicalFile();
                    params.put("database", actualPath.getAbsolutePath());
                }
            }
            return params;
        } else {
            // shp store
            File shpFile = new File(dir, dir.getName() + ".shp");

            Map<String, Serializable> params = new HashMap<String, Serializable>();

            // TODO is there a better way to convert a path to a URL?
            // DataUtilities.fileToURL(file) doesn't work (GeoServer saves an empty url)
            params.put(ShapefileDataStoreFactory.URLP.key, "file://" + shpFile.getAbsolutePath());

            params.put(ShapefileDataStoreFactory.MEMORY_MAPPED.key, true);
            // TODO other params?
            // params.put(ShapefileDataStoreFactory.DBFTIMEZONE.key, Utils.UTC_TIME_ZONE);

            return params;
        }
    }

    /**
     * Create EO Outline layer
     */
    public LayerInfo createEoOutlineLayer(String url, WorkspaceInfo ws, String groupName,
            String coverageName, StructuredGridCoverage2DReader reader) throws Exception {
        File dir = DataUtilities.urlToFile(new URL(url));

        if (ws == null) {
            ws = catalog.getDefaultWorkspace();
        }

        // store creation from bands directory
        String storeName = dir.getName();
        String layerName = groupName + "_outlines";

        CatalogBuilder builder = new CatalogBuilder(catalog);
        DataStoreInfo store = null;
        FeatureTypeInfo featureType = null;
        LayerInfo layer = null;
        boolean success = false;
        try {
            store = builder.buildDataStore(layerName);

            DataStoreFactorySpi dataStoreFactory = getOutlineDataStoreFactory(dir);

            Map<String, Serializable> parameters = getOutlineDataStoreParameters(dir,
                    dataStoreFactory);
            NamespaceInfo ns = catalog.getNamespaceByPrefix(ws.getName());
            parameters.put("namespace", ns.getURI());

            store.setType(dataStoreFactory.getDisplayName());
            store.setWorkspace(ws);
            store.getConnectionParameters().putAll(parameters);
            catalog.add(store);

            builder.setStore(store);

            // featuretyepinfo and layerinfo
            DataStore dataStore = (DataStore) store.getDataStore(new NullProgressListener());
            String featureTypeName = coverageName != null ? coverageName : storeName;
            SimpleFeatureSource featureSource = dataStore.getFeatureSource(featureTypeName);
            featureType = builder.buildFeatureType(featureSource);
            featureType.setName(layerName);
            featureType.setTitle(layerName);
            builder.setupBounds(featureType, featureSource);
            // dimensions
            boolean foundTime = enableDimensions(featureType, coverageName, reader);
            if (!foundTime) {
                throw new IllegalArgumentException(
                        "Unable to enable TIME dimension on outline layer:" + layerName);
            }
            catalog.add(featureType);

            // layer
            layer = builder.buildLayer(featureType);
            layer.setName(layerName);
            layer.setTitle(layerName);
            layer.setEnabled(true);
            layer.setQueryable(true);
            layer.setType(LayerInfo.Type.VECTOR);
            layer.getMetadata().put(EoLayerType.KEY, EoLayerType.COVERAGE_OUTLINE.name());
            addEoStyles(layer, DEFAULT_OUTLINE_STYLE);
            catalog.add(layer);

            success = true;

            return layer;
        } finally {
            // poor excuse for a rollback, but better than nothing
            if (!success) {
                if (layer != null) {
                    catalog.remove(layer);
                }
                if (featureType != null) {
                    catalog.remove(featureType);
                }
                if (store != null) {
                    catalog.remove(store);
                }
            }
        }
    }

    /**
     * Add EO styles to layer
     *
     * @param layer
     * @param defaultStyleName
     */
    private void addEoStyles(LayerInfo layer, String defaultStyleName) {
        StyleInfo defaultStyle = catalog.getStyleByName(defaultStyleName);
        if (defaultStyle != null) {
            layer.setDefaultStyle(defaultStyle);
        } else {
            if (LOGGER.isLoggable(Level.WARNING)) {
                LOGGER.log(Level.WARNING, "EO Style not found: " + defaultStyleName);
            }
        }

        for (String styleName : EO_STYLE_NAMES) {
            StyleInfo style = catalog.getStyleByName(styleName);
            if (style != null) {
                layer.getStyles().add(style);
            } else {
                if (LOGGER.isLoggable(Level.WARNING)) {
                    LOGGER.log(Level.WARNING, "EO Style not found: " + styleName);
                }
            }
        }
    }

    /**
     * Create a new mosaic store
     *
     * @param ws workspace
     * @param name store name
     * @param url
     * @return created store
     */
    protected CoverageStoreInfo createEoMosaicStore(WorkspaceInfo ws, String name, String url) {
        CoverageStoreInfo storeInfo = catalog.getFactory().createCoverageStore();
        storeInfo.setWorkspace(ws);
        storeInfo.setType("ImageMosaic");
        storeInfo.setEnabled(true);
        storeInfo.setName(name);
        storeInfo.setURL(url);

        try {
            catalog.add(storeInfo);
            return storeInfo;
        } catch (RuntimeException e) {
            String msg = "The coverage store '" + name
                    + "' could not be created. Failure message: " + e.getMessage();
            if (LOGGER.isLoggable(Level.INFO)) {
                LOGGER.log(Level.INFO, msg, e);
            }

            throw new IllegalArgumentException(msg, e);
        }
    }

    /**
     * Create a new mosaic layer
     *
     * @param ws workspace
     * @param name store name and layer name
     * @param type EO layer type
     * @param url mosaic url
     * @param checkDimensions check time and at least another dimension is present
     * @return created layer
     */
    public LayerInfo createEoMosaicLayer(WorkspaceInfo ws, String name, EoLayerType type,
            String url, boolean checkDimensions) {
        if (StringUtils.isEmpty(url)) {
            return null;
        }

        CoverageStoreInfo store = createEoMosaicStore(ws, name, url);

        CatalogBuilder builder = new CatalogBuilder(catalog);
        builder.setStore(store);
        try {
            CoverageInfo resource = builder.buildCoverage();

            boolean dimensionsPresent = enableDimensions(resource);
            if (checkDimensions) {
                if (!dimensionsPresent) {
                    // rollback: delete store
                    catalog.remove(store);
                    throw new IllegalArgumentException("The layer '" + name
                            + "' could not be created: no dimensions found");
                }
            }

            resource.setName(name);
            resource.setTitle(name);
            catalog.add(resource);

            LayerInfo layer = builder.buildLayer(resource);
            layer.setName(name);
            layer.setTitle(name);
            layer.setEnabled(true);
            layer.setQueryable(true);
            layer.setType(LayerInfo.Type.RASTER);
            layer.getMetadata().put(EoLayerType.KEY, type.name());
            catalog.add(layer);

            return layer;
        } catch (Exception e) {
            throw new IllegalArgumentException("The layer '" + name
                    + "' could not be created. Failure message: " + e.getMessage(), e);
        }
    }

    /**
     * Check presence of TIME dimension and at least one custom dimension. Enable all dimensions
     * found.
     */
    private boolean enableDimensions(CoverageInfo ci) {
        boolean timeDimension = false;
        boolean customDimension = false;
        GridCoverage2DReader reader = null;
        try {
            // acquire a reader
            reader = (GridCoverage2DReader) ci.getGridCoverageReader(null, null);
            if (reader == null) {
                throw new RuntimeException("Unable to acquire reader for this coverageinfo: "
                        + ci.getName());
            }

            // inspect dimensions
            final ReaderDimensionsAccessor ra = new ReaderDimensionsAccessor(reader);
            for (String domain : ra.getCustomDomains()) {
                if (LOGGER.isLoggable(Level.FINE)) {
                    boolean hasRange = ra.hasRange(domain);
                    boolean hasResolution = ra.hasResolution(domain);
                    LOGGER.fine(ci.getName() + ": found " + domain + " dimension (hasRange: "
                            + hasRange + ", hasResolution: " + hasResolution + ")");
                }

                DimensionInfo dimension = new DimensionInfoImpl();
                dimension.setEnabled(true);
                dimension.setPresentation(DimensionPresentation.LIST);
                ci.getMetadata().put(ResourceInfo.CUSTOM_DIMENSION_PREFIX + domain, dimension);

                customDimension = true;
            }

            String elev = reader.getMetadataValue(GridCoverage2DReader.HAS_ELEVATION_DOMAIN);
            if (Boolean.parseBoolean(elev)) {
                if (LOGGER.isLoggable(Level.FINE)) {
                    LOGGER.fine(ci.getName() + ": found ELEVATION dimension");
                }

                DimensionInfo dimension = new DimensionInfoImpl();
                dimension.setEnabled(true);
                dimension.setPresentation(DimensionPresentation.LIST);
                ci.getMetadata().put(ResourceInfo.ELEVATION, dimension);

                customDimension = true;
            }

            String time = reader.getMetadataValue(GridCoverage2DReader.HAS_TIME_DOMAIN);
            if (Boolean.parseBoolean(time)) {
                if (LOGGER.isLoggable(Level.FINE)) {
                    LOGGER.fine(ci.getName() + ": found TIME dimension");
                }

                DimensionInfo dimension = new DimensionInfoImpl();
                dimension.setEnabled(true);
                dimension.setPresentation(DimensionPresentation.LIST);
                ci.getMetadata().put(ResourceInfo.TIME, dimension);

                timeDimension = true;
            }
        } catch (IOException e) {
            if (LOGGER.isLoggable(Level.SEVERE)) {
                LOGGER.log(Level.SEVERE, "Failed to access coverage reader custom dimensions", e);
            }

        }

        return timeDimension && customDimension;
    }

    /**
     * Delete a layer, its resource and its store
     *
     * @param layer
     */
    private void delete(LayerInfo layer) {
        ResourceInfo resource = layer.getResource();
        StoreInfo store = resource.getStore();
        catalog.remove(layer);
        catalog.remove(resource);
        catalog.remove(store);
    }

    /**
     * Delete a layer group, all its layers and their respective stores
     *
     * @param group
     */
    public void delete(LayerGroupInfo group) {
        // load layers in group
        group = catalog.getLayerGroupByName(group.getWorkspace(), group.getName());
        try {
            catalog.remove(group);
            delete(group.getRootLayer());
            for (PublishedInfo p : group.getLayers()) {
                if (p instanceof LayerGroupInfo) {
                    delete(group);
                } else {
                    delete((LayerInfo) p);
                }
            }
        } catch (RuntimeException e) {
            throw new IllegalArgumentException("The group '" + group.getName()
                    + "' could not be removed. Failure message: " + e.getMessage(), e);
        }
    }

    /**
     * Check presence of TIME dimension . Enable all dimensions found.
     * @throws IOException
     */
    private boolean enableDimensions(FeatureTypeInfo fi, String coverageName, StructuredGridCoverage2DReader reader) throws IOException {
        Utilities.ensureNonNull("FeatureTypeInfo", fi);
        Utilities.ensureNonNull("reader", reader);
       
        List<DimensionDescriptor> dimensionDescriptors = reader.getDimensionDescriptors(coverageName == null ? reader.getGridCoverageNames()[0] : coverageName);
        boolean timeDimension = false;
        for (DimensionDescriptor dd : dimensionDescriptors) {
            DimensionInfo di = new DimensionInfoImpl();
            String key;
            String units = dd.getUnits();
            String symbol = dd.getUnitSymbol();
            if(ResourceInfo.TIME.equalsIgnoreCase(dd.getName())) {
                timeDimension = true;
                key = ResourceInfo.TIME;
                units = DimensionInfo.TIME_UNITS;
            } else if(ResourceInfo.ELEVATION.equalsIgnoreCase(dd.getName())) {
                key = ResourceInfo.ELEVATION;
                units = DimensionInfo.ELEVATION_UNITS;
                symbol = DimensionInfo.ELEVATION_UNIT_SYMBOL;
            } else {
                key = ResourceInfo.CUSTOM_DIMENSION_PREFIX + dd.getName();
            }
           
            di.setEnabled(true);
            di.setAttribute(dd.getStartAttribute());
            di.setEndAttribute(dd.getEndAttribute());
            di.setPresentation(DimensionPresentation.LIST);
            di.setUnits(units);
            di.setUnitSymbol(symbol);
            fi.getMetadata().put(key, di);
        }

        return timeDimension;
    }
}
TOP

Related Classes of org.geoserver.wms.eo.EoCatalogBuilder

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.