Package com.boundlessgeo.geoserver.api.controllers

Source Code of com.boundlessgeo.geoserver.api.controllers.IO

/* (c) 2014 Boundless, http://boundlessgeo.com
* This code is licensed under the GPL 2.0 license.
*/
package com.boundlessgeo.geoserver.api.controllers;

import java.io.File;
import java.io.IOException;
import java.io.Serializable;
import java.net.URL;
import java.text.SimpleDateFormat;
import java.util.Date;
import java.util.HashSet;
import java.util.Map;
import java.util.Set;
import java.util.TimeZone;
import java.util.logging.Level;
import java.util.logging.Logger;

import javax.servlet.http.HttpServletRequest;

import com.boundlessgeo.geoserver.util.RecentObjectCache.Ref;
import org.apache.commons.httpclient.util.DateUtil;
import org.apache.commons.lang.WordUtils;
import org.geoserver.catalog.CoverageInfo;
import org.geoserver.catalog.CoverageStoreInfo;
import org.geoserver.catalog.DataStoreInfo;
import org.geoserver.catalog.FeatureTypeInfo;
import org.geoserver.catalog.Info;
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.WMSLayerInfo;
import org.geoserver.catalog.WMSStoreInfo;
import org.geoserver.catalog.WorkspaceInfo;
import org.geoserver.ows.URLMangler.URLType;
import org.geoserver.ows.util.ResponseUtils;
import org.geoserver.wms.WMSInfo;
import org.geotools.data.DataAccessFactory;
import org.geotools.data.DataAccessFactory.Param;
import org.geotools.data.Parameter;
import org.geotools.feature.FeatureTypes;
import org.geotools.filter.text.ecql.ECQL;
import org.geotools.filter.visitor.DuplicatingFilterVisitor;
import org.geotools.geometry.jts.Geometries;
import org.geotools.geometry.jts.ReferencedEnvelope;
import org.geotools.referencing.CRS;
import org.geotools.referencing.crs.DefaultGeographicCRS;
import org.geotools.resources.coverage.FeatureUtilities;
import org.geotools.util.logging.Logging;
import org.ocpsoft.pretty.time.PrettyTime;
import org.opengis.coverage.grid.Format;
import org.opengis.feature.simple.SimpleFeatureType;
import org.opengis.feature.type.AssociationDescriptor;
import org.opengis.feature.type.AttributeDescriptor;
import org.opengis.feature.type.FeatureType;
import org.opengis.feature.type.GeometryDescriptor;
import org.opengis.feature.type.PropertyDescriptor;
import org.opengis.feature.type.PropertyType;
import org.opengis.filter.Filter;
import org.opengis.filter.expression.PropertyName;
import org.opengis.referencing.FactoryException;
import org.opengis.referencing.ReferenceIdentifier;
import org.opengis.referencing.crs.CoordinateReferenceSystem;
import org.opengis.referencing.crs.GeographicCRS;
import org.opengis.referencing.crs.ProjectedCRS;
import org.opengis.referencing.operation.TransformException;
import org.opengis.util.GenericName;

import com.boundlessgeo.geoserver.Proj;
import com.boundlessgeo.geoserver.json.JSONArr;
import com.boundlessgeo.geoserver.json.JSONObj;
import com.google.common.base.Throwables;
import com.vividsolutions.jts.geom.Coordinate;
import com.vividsolutions.jts.geom.Envelope;
import com.vividsolutions.jts.geom.Geometry;

/**
* Helper for encoding/decoding objects to/from JSON.
*/
public class IO {

    static final String DATE_FORMAT = "yyyy-MM-dd'T'HH:mm:ssXXX";

    /** Kind of provider */
    static public enum Kind {FILE,DATABASE,WEB,GENERIC;
        public String toString() {
            return name().toLowerCase();
        }
        static Kind of( ResourceInfo resource){
            return of( resource.getStore());
        }
        static Kind of( DataAccessFactory format){
            Set<String> params = new HashSet<String>();
            for (Param info : format.getParametersInfo()) {
                params.add(info.getName());
            }
            if (params.contains("dbtype")) {
                return Kind.DATABASE;
            }
            if (params.contains("directory") || params.contains("file") || params.contains("raster")) {
                return Kind.FILE;
            }
            if (params.contains("wms")
                    || params.contains("WFSDataStoreFactory:GET_CAPABILITIES_URL")) {
                return Kind.WEB;
            }
            if( params.contains("url") ){
                return Kind.FILE;
            }
            return Kind.GENERIC;
        }
        static Kind of( StoreInfo store ){
            if( store instanceof CoverageStoreInfo){
                String url = ((CoverageStoreInfo)store).getURL();
                if( url.startsWith("file")){
                    return Kind.FILE;
                }
                else if( url.startsWith("http") ||
                         url.startsWith("https") ||
                         url.startsWith("ftp") ||
                         url.startsWith("sftp")){
                    return Kind.WEB;
                }
            }
            Map<String, Serializable> params = store.getConnectionParameters();
            if(params == null ){
                return Kind.GENERIC;
            }
            else if( params.containsKey("dbtype")){
                return Kind.DATABASE;
            }
            else if( store instanceof WMSStoreInfo){
                return Kind.WEB;
            }
            else if( params.keySet().contains("directory") ||
                params.keySet().contains("file") ){
               
                return Kind.FILE;
            }
            for( Object value : params.values()){
                if( value == null ) continue;
                if( value instanceof File ||
                    (value instanceof String && ((String)value).startsWith("file:")) ||
                    (value instanceof URL && ((URL)value).getProtocol().equals("file"))){
                    return Kind.FILE;
                }
                if( (value instanceof String && ((String)value).startsWith("http:")) ||
                    (value instanceof URL && ((URL)value).getProtocol().equals("http"))){
                    return Kind.WEB;
                }
                if( value instanceof String && ((String)value).startsWith("jdbc:")){
                    return Kind.DATABASE;
                }
            }
            return Kind.GENERIC;
        }
    }
    /** Type of content: raster, vector, service(wms layer), generic resource */
    static public enum Type {RASTER,VECTOR,SERVICE,RESOURCE;
        public String toString() {
            return name().toLowerCase();
        }
        static Type of( String resource ){
            return valueOf(resource.toUpperCase());
        }
        static Type of( ResourceInfo resource ){
            if( resource instanceof CoverageInfo){
                return Type.RASTER;
            }
            else if( resource instanceof FeatureTypeInfo){
                return Type.VECTOR;
            }
            else if(resource instanceof WMSLayerInfo){
                return Type.SERVICE;
            }
            return Type.RESOURCE;
        }
        static Type of( StoreInfo store ){
            if( store instanceof CoverageStoreInfo){
                return Type.RASTER;
            }
            else if( store instanceof DataStoreInfo){
                return Type.VECTOR;
            }
            else if(store instanceof WMSStoreInfo){
                return Type.SERVICE;
            }
            return Type.RESOURCE;
        }
    }

    static Logger LOG = Logging.getLogger(IO.class);

    /**
     * Encodes a projection within the specified object.
     *
     * @return The object passed in.
     */
    public static JSONObj proj(JSONObj obj, CoordinateReferenceSystem crs, String srs) {
        if (srs == null && crs != null) {
            try {
                srs = CRS.lookupIdentifier(crs, false);
            } catch (Exception e) {
                LOG.log(Level.WARNING, "Unable to determine srs from crs: " + crs, e);
            }
        }
       
        if (crs != null && crs.getName() != null) {
            ReferenceIdentifier name = crs.getName();
            if (name instanceof GenericName) {
                obj.put("title", ((GenericName) name).tip().toString());
            } else {
                obj.put("title", name.toString());
            }
        }
       
        if (srs != null) {
            obj.put("srs", srs);
        }
        else {
            obj.put("srs", "UNKNOWN");
        }

        if (crs == null && srs != null) {
            try {
                crs = CRS.decode(srs);
            } catch (Exception e) {
                LOG.log(Level.WARNING, "Unable to determine crs from srs: " + srs, e);
            }
        }

        if (crs != null) {
            // type
            obj.put("type",
                    crs instanceof ProjectedCRS ? "projected" : crs instanceof GeographicCRS ? "geographic" : "other");

            // units
            String units = null;
            try {
                // try to determine from actual crs
                String unit = crs.getCoordinateSystem().getAxis(0).getUnit().toString();
                if ("ft".equals(unit) || "feets".equals(unit))
                    units = "ft";
            } catch (Exception e) {
                LOG.log(Level.WARNING, "Unable to determine units from crs", e);
            }
            if (units == null) {
                // fallback: meters for projected, otherwise degrees
                units = crs instanceof ProjectedCRS ? "m" : "degrees";
            }
            obj.put("unit", units);
            obj.put("wkt", crs.toWKT());
        }

        return obj;
    }

    /**
     * Encodes a bounding box within the specified object.
     *
     * @return The object passed in.
     */
    public static JSONObj bounds(JSONObj obj, Envelope bbox) {
        obj.put("west", bbox.getMinX())
            .put("south", bbox.getMinY())
            .put("east", bbox.getMaxX())
            .put("north", bbox.getMaxY());

        if (!bbox.isNull()) {
            Coordinate center = bbox.centre();
            obj.putArray("center").add(center.x).add(center.y);
        }

        return obj;
    }

    /**
     * Decodes a bounding box within the specified object.
     *
     * The parsed envelope.
     */
    public static Envelope bounds(JSONObj obj) {
        return new Envelope(obj.doub("west"), obj.doub("east"), obj.doub("south"), obj.doub("north"));
    }

    /**
     * Decodes a projection within the specified object.
     *
     * @return The parsed projection, or null.
     *
     * @throws java.lang.IllegalArgumentException If the object has no 'srs' property or there was an error decoding
     * the srs.
     */
    public static CoordinateReferenceSystem crs(JSONObj obj) throws Exception {
        return Proj.get().crs(srs(obj));
    }

    /**
     * Decodes am srs within the specified projection object.
     *
     * @param obj JSON object with same structure as produced by {@link #proj(JSONObj,CoordinateReferenceSystem, String)}.
     *
     * @return The srs.
     *
     * @throws java.lang.IllegalArgumentException If the object has no 'srs' property.
     */
    public static String srs(JSONObj obj) {
        String srs = obj.str("srs");
        if (srs == null) {
            throw new IllegalArgumentException("Projection must have an 'srs' property");
        }
        return srs;
    }

    /**
     * Encodes a workspace within the specified object.
     *
     * @param obj The object to encode within.
     * @param workspace The workspace to encode.
     * @param namespace The namespace corresponding to the workspace.
     * @param isDefault Flag indicating whether the workspace is the default.
     *
     * @return The object passed in.
     */
    public static JSONObj workspace(JSONObj obj, WorkspaceInfo workspace, NamespaceInfo namespace, boolean isDefault) {
        obj.put("name", workspace.getName());
        if (namespace != null) {
            obj.put("uri", namespace.getURI());
        }
        obj.put("default", isDefault);
        return metadata(obj, workspace);
    }
   
    static Object title(LayerInfo layer) {
        ResourceInfo r = layer.getResource();
        return layer.getTitle() != null ? layer.getTitle() : r != null ? r.getTitle() : null;
    }

    static Object description(LayerInfo layer) {
        ResourceInfo r = layer.getResource();
        return layer.getAbstract() != null ? layer.getAbstract() : r != null ? r.getAbstract() : null;
    }

    public static JSONObj layer(JSONObj obj, PublishedInfo layer, HttpServletRequest req) {
        if( layer == null ){
            return obj;
        }
        if( layer instanceof LayerInfo){
            return layer( obj, (LayerInfo) layer, req );
        }
        else if ( layer instanceof LayerGroupInfo ){
            return layer( obj, (LayerGroupInfo) layer, req );
        }
        else {
            return obj;
        }
    }
   
    public static JSONObj layer(JSONObj obj, LayerGroupInfo group, HttpServletRequest req) {
        String wsName = group.getWorkspace().getName();
        obj.put("name", group.getName())
           .put("workspace", wsName)
           .put("url", IO.url(req,"/maps/%s/%s",wsName,group.getName()) )
           .put("title", group.getTitle() )
           .put("description", group.getAbstract() )
           .put("type", "map" )
           .put("group", group.getMode().name());
       
        proj(obj.putObject("proj"), group.getBounds().getCoordinateReferenceSystem(), null);
        bbox(obj.putObject("bbox"), group);
       
        return obj;
    }
    /**
     * Encodes a layer within the specified object.
     *
     * @return The object passed in.
     */
    @SuppressWarnings("unchecked")
    public static JSONObj layer(JSONObj obj, LayerInfo layer, HttpServletRequest req) {
        String wsName = layer.getResource().getNamespace().getPrefix();
        ResourceInfo r = layer.getResource();
        Type type = IO.Type.of(r); //IO.type(r);
       
        obj.put("name", layer.getName())
                .put("workspace", wsName)
                .put("title", title(layer))
                .put("description", description(layer))
                .put("type", type.toString());
       
        StoreInfo store = r.getStore();
        if( req != null ){
            obj.putObject("resource")
                .put("name",r.getName())
                .put("store",store.getName())
                .put("workspace",wsName)
                .put("url",
                     url(req, "/stores/%s/%s/%s",wsName, store.getName(),r.getName())
                );
        }
       
        JSONArr keywords = new JSONArr();
        keywords.raw().addAll( r.keywordValues() );
        obj.put("keywords", keywords);
        proj(obj.putObject("proj"), r.getCRS(), r.getSRS());
        bbox( obj.putObject("bbox"), r );
       
        if (r instanceof FeatureTypeInfo) {
            FeatureTypeInfo ft = (FeatureTypeInfo) r;
            FeatureType schema;
            try {
                schema = ft.getFeatureType();
                obj.put("geometry", geometry(schema));
                IO.schema(obj.putObject("schema"), schema, true );
            } catch (IOException e) {
                LOG.log(Level.WARNING, "Error looking up schema "+ft.getNativeName(), e);
            }
        }
        else if( r instanceof CoverageInfo) {
            obj.put("geometry", "raster");
            IO.schemaGrid(obj.putObject("schema"), ((CoverageInfo)r), true );
        }
        else if( r instanceof WMSInfo) {
            obj.put("geometry", "layer");
        }
        return metadata(obj, layer);
    }

    static String type(ResourceInfo r)  {
        if (r instanceof CoverageInfo) {
            return "raster";
        }
        else if (r instanceof FeatureTypeInfo){
            return "vector";
        }
        else if (r instanceof WMSLayerInfo){
            return "wms";
        }
        else {
            return "resource";
        }
    }

    static String geometry(FeatureType ft) {
        GeometryDescriptor gd = ft.getGeometryDescriptor();
        if (gd == null) {
            return "Vector";
        }
        @SuppressWarnings("unchecked")
        Geometries geomType = Geometries.getForBinding((Class<? extends Geometry>) gd.getType().getBinding());
        return geomType.getName();
    }
   
    public static JSONObj bbox( JSONObj bbox, LayerGroupInfo l ){
        ReferencedEnvelope bounds = l.getBounds();
        if (bounds != null) {
            bounds(bbox.putObject("native"), bounds );
           
            try {
                ReferencedEnvelope latLonBounds = bounds.transform(DefaultGeographicCRS.WGS84, true);
                bounds(bbox.putObject("lonlat"), latLonBounds);
            } catch (TransformException e) {
            } catch (FactoryException e) {
            }
        }
        return bbox;
    }
   
    public static JSONObj bbox( JSONObj bbox, ResourceInfo r ){
        if (r.getNativeBoundingBox() != null) {
            bounds(bbox.putObject("native"), r.getNativeBoundingBox());
        }
        else {
            // check if the crs is geographic, if so use lat lon
            if (r.getCRS() instanceof GeographicCRS && r.getLatLonBoundingBox() != null) {
                bounds(bbox.putObject("native"), r.getLatLonBoundingBox());
            }
        }

        if (r.getLatLonBoundingBox() != null) {
            bounds(bbox.putObject("lonlat"), r.getLatLonBoundingBox());
        }
        else {
            if (r.getNativeCRS() instanceof GeographicCRS && r.getLatLonBoundingBox() != null) {
                bounds(bbox.putObject("lonlat"), r.getLatLonBoundingBox());
            }
        }
        return bbox;
    }
   
    public static JSONObj schema( JSONObj schema, FeatureType type, boolean details){
        if( type != null ){
            schema.put("name", type.getName().getLocalPart() );
            schema.put("namespace", type.getName().getNamespaceURI() );
            schema.put("simple", type instanceof SimpleFeatureType );
            JSONArr attributes = schema.putArray("attributes");
            for( PropertyDescriptor d : type.getDescriptors() ){
                PropertyType t = d.getType();
                final String NAME = d.getName().getLocalPart();
                String kind;
                if (d instanceof GeometryDescriptor){
                    kind = "geometry";
                }
                else if( d instanceof AttributeDescriptor){
                    kind = "attribute";
                }
                else if (d instanceof AssociationDescriptor){
                    kind = "association";
                }
                else {
                    kind = "property";
                }
                JSONObj property = attributes.addObject()
                    .put("name", NAME )
                    .put("property", kind )
                    .put("type", t.getBinding().getSimpleName() );
               
                if( d instanceof GeometryDescriptor){
                    GeometryDescriptor g = (GeometryDescriptor) d;                   
                    proj( property.putObject("proj"), g.getCoordinateReferenceSystem(), null );
                }

                if( details){
                    property
                        .put("namespace", d.getName().getNamespaceURI() )
                        .put("description", t.getDescription() )
                        .put("min-occurs",d.getMinOccurs() )
                        .put("max-occurs",d.getMaxOccurs() )
                        .put("nillable",d.isNillable());
               
                    int length = FeatureTypes.getFieldLength(d);
                    if( length != FeatureTypes.ANY_LENGTH ){
                        property.put("length", length );
                    }
                   
                    if( d instanceof AttributeDescriptor){
                        AttributeDescriptor a = (AttributeDescriptor) d;
                        property.put("default-value", a.getDefaultValue() );
                    }
                    if( !t.getRestrictions().isEmpty() ){
                        JSONArr validate = property.putArray("validate");
                        for( Filter f : t.getRestrictions() ){
                            String cql;
                            try {
                                Filter clean = (Filter) f.accept( new DuplicatingFilterVisitor(){
                                    public PropertyName visit(PropertyName e, Object extraData ){
                                        String n = e.getPropertyName();
                                        return getFactory(extraData).property(
                                                ".".equals(n) ? NAME : n,
                                                e.getNamespaceContext());
                                    }
                                }, null );
                                cql = ECQL.toCQL(clean);
                            }
                            catch (Throwable ignore ){
                                ignore.printStackTrace();
                                cql = f.toString();
                            }
                            validate.add( cql );
                        }                   
                    }
                }
            }
        }
        return schema;
    }
   
    /**
     * Generate schema for GridCoverageSchema (see {@link FeatureUtilities#wrapGridCoverage}).
     */
    public static JSONObj schemaGrid( JSONObj schema, CoverageInfo info, boolean details ){
        if( info != null ){
            CoordinateReferenceSystem crs = info.getCRS() != null
                    ? info.getCRS()
                    : info.getNativeCRS();
            schemaGrid( schema, crs, details );
        }
        return schema;
    }
    public static JSONObj schemaGrid( JSONObj schema, CoordinateReferenceSystem crs, boolean details){
        schema.put("name", "GridCoverage" );
        schema.put("simple", true );
        JSONArr attributes = schema.putArray("attributes");
        JSONObj geom = attributes.addObject()
            .put("name", "geom" )
            .put("property", "geometry" )
            .put("type", "Polygon" );

        if( crs != null ){
            proj( geom.putObject("proj"), crs, null );
        }
       
        if( details ){
            geom
                .put("min-occurs",0)
                .put("max-occurs",1)
                .put("nillable",true)
                .put("default-value",null);  
       
        }
        JSONObj grid = attributes.addObject()
            .put("name", "grid" )
            .put("property", "attribute" )
            .put("type", "grid" );
       
        if( details ){
            grid
                .put("binding", "GridCoverage" )
                .put("min-occurs",0)
                .put("max-occurs",1)
                .put("nillable",true)
                .put("default-value",null);
        }
        return schema;
    }
   
    private static PrettyTime PRETTY_TIME = new PrettyTime();

    static JSONObj date(JSONObj obj, Date date) {
        String timestamp = new SimpleDateFormat(DATE_FORMAT).format(date);
        return obj.put("timestamp", timestamp).put("pretty", PRETTY_TIME.format(date));
    }

    /** Metadata: created and modified */
    static JSONObj metadata(JSONObj obj, Info i) {
        Date created = Metadata.created(i);
        if (created != null) {
            date(obj.putObject("created"), created);
        }
        Date modified = Metadata.modified(i);
        if (modified != null) {
            date(obj.putObject("modified"), modified);
        }
        return obj;
    }

    public static JSONObj error(JSONObj json, Throwable error) {
        if (error != null) {
            String message = null;
            JSONArr cause = new JSONArr();
            for (Throwable t : Throwables.getCausalChain(error)) {
                if (message == null && t.getMessage() != null) {
                    message = t.getMessage();
                }
                StringBuilder trace = new StringBuilder();
                for( StackTraceElement e : t.getStackTrace()){
                    trace.append( e.toString()).append('\n');
                }
                cause.addObject()
                    .put("exception", t.getClass().getSimpleName())
                    .put("message", t.getMessage())
                    .put("trace",trace.toString());
            }
            if (message == null) {
                message = error.getClass().getSimpleName();
            }
            json.put("message", message != null ? message : error.toString())
                .put("cause", cause)
                .put("trace",Throwables.getStackTraceAsString(error));
        }
        return json;
    }
   
    public static JSONObj param(JSONObj json, Parameter<?> p) {
        if (p != null) {
            String title = p.getTitle() != null ? p.getTitle().toString() : WordUtils.capitalize(p.getName());
            String description = p.getDescription() != null ? p.getDescription().toString() : null;

            JSONObj def = json.putObject(p.getName());
            def.put("title", title)
                .put("description",  description)
                .put("type", p.getType().getSimpleName())
                .put("default", safeValue(p.getDefaultValue()))
                .put("level", p.getLevel())
                .put("required", p.isRequired());
           
            if( !(p.getMinOccurs() == 1 && p.getMaxOccurs() == 1)){
                def.putArray("occurs")
                    .add( p.getMinOccurs())
                    .add(p.getMaxOccurs());
            }

           
            if (p.metadata != null) {
                for (String key : p.metadata.keySet()) {
                    if (Parameter.LEVEL.equals(key)) {
                        continue;
                    }
                    def.put(key, p.metadata.get(key));
                }
            }
        }
        return json;
    }
    public static void param(JSONObj json, Format g) {
        json.put("name","raster")
            .put("title","URL")
            .put("description",g.getDescription())
            .put("type",URL.class.getSimpleName())
            .put("default",null)
            .put("level","user")
            .put("required",true);
    }

    static private Object safeValue(Object value) {
        if(value == null){
            return null;
        }
        if (value instanceof String || value instanceof Number || value instanceof Boolean) {
            return value;
        }
        if (value instanceof java.util.TimeZone) {
            TimeZone zone = (TimeZone) value;
            return zone.getDisplayName();
        }
        return value.toString();
    }

    public static Object url(HttpServletRequest req, String path, Object ... args) {
        if (req == null) {
            return null;
        }
        String baseURL = ResponseUtils.baseURL(req);
        String relative = String.format("/api"+path, args );
        String resolved = ResponseUtils.buildURL(baseURL, relative, null, URLType.SERVICE);
        return resolved;
    }

    public static JSONObj ref(JSONObj obj, Ref ref) {
        obj.put("name", ref.name);
        if (ref.workspace != null) {
            obj.put("workspace", ref.workspace);
        }
        date(obj.putObject("modified"), ref.modified);
        return obj;
    }
}
TOP

Related Classes of com.boundlessgeo.geoserver.api.controllers.IO

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.