org.geoserver.wms.featureinfo.GeoJSONFeatureInfoOutputFormat.java Source code

Java tutorial

Introduction

Here is the source code for org.geoserver.wms.featureinfo.GeoJSONFeatureInfoOutputFormat.java

Source

/* Copyright (c) 2001 - 2007 TOPP - www.openplans.org.  All rights reserved.
 * This code is licensed under the GPL 2.0 license, availible at the root
 * application directory.
 */
package org.geoserver.wms.featureinfo;

import java.io.IOException;
import java.io.OutputStream;
import java.io.OutputStreamWriter;
import java.net.URI;
import java.net.URISyntaxException;
import java.util.Collections;
import java.util.Map;

import javax.xml.namespace.QName;

import net.opengis.wfs.FeatureCollectionType;
import net.opengis.wfs.GetFeatureType;
import net.opengis.wfs.QueryType;
import net.opengis.wfs.WfsFactory;

import org.apache.commons.io.IOUtils;
import org.geoserver.config.GeoServer;
import org.geoserver.ows.Dispatcher;
import org.geoserver.ows.Request;
import org.geoserver.platform.Operation;
import org.geoserver.platform.Service;
import org.geoserver.platform.ServiceException;
import org.geoserver.wfs.json.JSONType;
import org.geoserver.wfs.response.GeoJSONOutputFormat;
import org.geoserver.wms.GetFeatureInfoRequest;
import org.geoserver.wms.WMS;
import org.geotools.feature.FeatureCollection;
import org.geotools.gml2.bindings.GML2EncodingUtils;
import org.opengis.feature.type.Name;

/**
 * A GetFeatureInfo response handler specialized in producing Json and JsonP data for a
 * GetFeatureInfo request.
 * 
 * <p>
 * This class does not deals directly with GML encoding. Instead, it works by taking the
 * FeatureResults produced in <code>execute()</code> and constructs a <code>GetFeaturesResult</code>
 * wich is passed to a <code>GML2FeatureResponseDelegate</code>, as if it where the result of a
 * GetFeature WFS request.
 * </p>
 * 
 * @author Simone Giannecchini, GeoSolutions
 */
public class GeoJSONFeatureInfoOutputFormat extends GetFeatureInfoOutputFormat {

    protected final WMS wms;

    /**
     * @param wms
     * @param outputFormat
     * @throws Exception if outputFormat is not a valid json mime type
     */
    public GeoJSONFeatureInfoOutputFormat(final WMS wms, final String outputFormat) throws Exception {
        super(outputFormat);
        if (JSONType.getJSONType(outputFormat) == null)
            throw new Exception("Illegal json mime type");
        this.wms = wms;
    }

    /**
     * Takes the <code>FeatureResult</code>s generated by the <code>execute</code> method in the
     * superclass and constructs a <code>GetFeaturesResult</code> wich is passed to a
     * <code>GML2FeatureResponseDelegate</code>.
     * 
     * @see AbstractFeatureInfoResponse#writeTo(OutputStream)
     */
    @SuppressWarnings({ "rawtypes", "unchecked" })
    @Override
    public void write(FeatureCollectionType results, GetFeatureInfoRequest fInfoReq, OutputStream out)
            throws ServiceException, IOException {

        // the 'response' object we'll pass to our OutputFormat
        FeatureCollectionType features = WfsFactory.eINSTANCE.createFeatureCollectionType();

        // the 'request' object we'll pass to our OutputFormat
        GetFeatureType gfreq = WfsFactory.eINSTANCE.createGetFeatureType();
        gfreq.setBaseUrl(fInfoReq.getBaseUrl());

        final int size = results.getFeature().size();
        for (int i = 0; i < size; i++) {

            FeatureCollection fc = (FeatureCollection) results.getFeature().get(i);
            Name name = FeatureCollectionDecorator.getName(fc);
            QName qname = new QName(name.getNamespaceURI(), name.getLocalPart());

            features.getFeature().add(fc);

            QueryType qt = WfsFactory.eINSTANCE.createQueryType();

            qt.setTypeName(Collections.singletonList(qname));

            String crs = GML2EncodingUtils.epsgCode(fc.getSchema().getCoordinateReferenceSystem());
            if (crs != null) {
                final String srsName = "EPSG:" + crs;
                try {
                    qt.setSrsName(new URI(srsName));

                } catch (URISyntaxException e) {
                    throw new ServiceException("Unable to determite coordinate system for featureType "
                            + fc.getSchema().getName().getLocalPart() + ".  Schema told us '" + srsName + "'", e);
                }
            }
            gfreq.getQuery().add(qt);

        }

        // this is a dummy wrapper around our 'request' object so that the new Dispatcher will
        // accept it.
        Service serviceDesc = new Service("wms", null, null, Collections.EMPTY_LIST);
        Operation opDescriptor = new Operation("", serviceDesc, null, new Object[] { gfreq });

        final GeoServer gs = wms.getGeoServer();
        GeoJSONOutputFormat format = new GeoJSONOutputFormat(gs);
        if (JSONType.isJsonMimeType(getContentType())) {
            writeJSON(out, features, opDescriptor, format);
        } else {
            writeJSONP(out, features, opDescriptor, format);
        }
    }

    private void writeJSONP(OutputStream out, FeatureCollectionType features, Operation opDescriptor,
            GeoJSONOutputFormat format) throws IOException {
        OutputStreamWriter outWriter = null;
        try {
            outWriter = new OutputStreamWriter(out, wms.getGeoServer().getSettings().getCharset());

            // preamble
            outWriter.write(getCallbackFunction() + "(");
            outWriter.flush();

            // call regular format
            format.write(features, out, opDescriptor);

            // postamble
            outWriter.write(")");
            outWriter.flush();
        } finally {
            IOUtils.closeQuietly(outWriter);
        }
    }

    private static void writeJSON(OutputStream out, FeatureCollectionType features, Operation opDescriptor,
            GeoJSONOutputFormat format) throws IOException {
        format.write(features, out, opDescriptor);
    }

    private String getCallbackFunction() {

        Request request = Dispatcher.REQUEST.get();
        if (request == null) {
            return JSONType.CALLBACK_FUNCTION;
        } else if (!(request.getKvp().get("FORMAT_OPTIONS") instanceof Map)) {
            return JSONType.CALLBACK_FUNCTION;
        }

        return JSONType.getCallbackFunction(request.getKvp());

    }

}