org.geoserver.wfs.response.DXFOutputFormat.java Source code

Java tutorial

Introduction

Here is the source code for org.geoserver.wfs.response.DXFOutputFormat.java

Source

/* Copyright (c) 2001 - 2013 OpenPlans - www.openplans.org. All rights reserved.
 * This code is licensed under the GPL 2.0 license, available at the root
 * application directory.
 */
package org.geoserver.wfs.response;

import java.io.BufferedWriter;
import java.io.IOException;
import java.io.OutputStream;
import java.io.OutputStreamWriter;
import java.util.ArrayList;
import java.util.HashSet;
import java.util.Iterator;
import java.util.List;
import java.util.Set;
import java.util.logging.Level;
import java.util.logging.Logger;
import java.util.zip.ZipEntry;
import java.util.zip.ZipOutputStream;

import javax.xml.namespace.QName;

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

import org.apache.commons.lang.StringUtils;
import org.geoserver.config.GeoServer;
import org.geoserver.ows.util.OwsUtils;
import org.geoserver.platform.Operation;
import org.geoserver.platform.ServiceException;
import org.geoserver.wfs.WFSGetFeatureOutputFormat;
import org.geoserver.wfs.request.FeatureCollectionResponse;
import org.geoserver.wfs.request.GetFeatureRequest;
import org.geoserver.wfs.response.dxf.DXFWriter;
import org.geoserver.wfs.response.dxf.DXFWriterFinder;
import org.geoserver.wfs.response.dxf.LineType;
import org.geotools.util.logging.Logging;

/**
 * This class returns a dxf  encoded results of the users's query
 * (optionally zipped).
 * Several format options are available to control output generation.
 *  - version: (number) creates a DXF in the specified version format (a DXFWriter
 *    implementation supporting the requested version needs to be available
 *    or an exception will be thrown); the default implementation creates
 *    a version 14 DXF.
 *  - asblock: (true/false) if true, all geometries are written 
 *    as blocks and then inserted as entities. If false, simple geometries
 *    are directly written as entities.
 *  - colors: (comma delimited list of numbers): colors to be used for 
 *    the DXF layers, in sequence. If layers are more than the specified
 *    colors, they will be reused many times. A set of default colors is
 *    used if the option is not used. Colors are AutoCad color numbers
 *    (7=white, etc.).
 *  - ltypes: (comma delimited list of line type descriptors): line types
 *    to be used for the DXF layers, in sequence. If layers are more than 
 *    the specified line types, they will be reused many times. If not specified,
 *    all layers will be given a solid, continuous line type. A descriptor
 *    has the following format: <name>!<repeatable pattern>[!<base length>], where 
 *    <name> is the name assigned to the line type, <base length> (optional) 
 *    is a real number that tells how long is each part of the line pattern 
 *    (defaults to 0.125), and <repeatable pattern> is a visual description
 *    of the repeatable part of the line pattern, as a sequence of - (solid line),
 *    * (dot) and _ (empty space).
 *  - layers: (comma delimited list of strings) names to be assigned to
 *    the DXF layers. If specified, must contain a name for each requested
 *    query. By default a standard name will be assigned to layers.
 *    
 *  A different layer will be generated for each requested query.
 *  Layer names can be chosen using the layers format option, or 
 *  in POST mode, using the handle attribute of the Query tag.
 *  The name of the resulting file can be chosen using the handle
 *  attribute of the GetFeature tag. By default, the names of layers
 *  concatenated with _ will be used.  
 * 
 * @author Mauro Bartolomeoli, mbarto@infosia.it
 *
 */
public class DXFOutputFormat extends WFSGetFeatureOutputFormat {

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

    public static final Set<String> formats = new HashSet<String>();

    static {
        // list of supported output formats
        formats.add("DXF");
        formats.add("DXF-ZIP");
    }

    public DXFOutputFormat(GeoServer gs) {
        super(gs, formats);
    }

    /**
     * Gets current request extension (dxf or zip).
     * 
     * @param operation
     * @return
     */
    public String getDxfExtension(Operation operation) {
        GetFeatureType request = (GetFeatureType) OwsUtils.parameter(operation.getParameters(),
                GetFeatureType.class);

        String outputFormat = request.getOutputFormat().toUpperCase();
        // DXF
        if (outputFormat.equals("DXF"))
            return "dxf";
        // DXF-ZIP
        return "zip";
    }

    /**
     * Mime type: application/dxf or application/zip
     */
    @Override
    public String getMimeType(Object value, Operation operation) throws ServiceException {
        return "application/" + getDxfExtension(operation);
    }

    @Override
    public String getPreferredDisposition(Object value, Operation operation) {
        return DISPOSITION_ATTACH;
    }

    /**
     * Gets output filename.
     * If the handle attribute is defined on the GetFeature tag it
     * will be used, else the name is obtained concatenating layer names
     * with underscore as a separator (up to a maximum name length).
     */
    private String getFileName(Operation operation) {
        GetFeatureType request = (GetFeatureType) OwsUtils.parameter(operation.getParameters(),
                GetFeatureType.class);

        if (request.getHandle() != null) {
            LOGGER.log(Level.FINE, "Using handle for file name: " + request.getHandle());
            return request.getHandle();
        }

        StringBuffer sb = new StringBuffer();
        for (Iterator f = request.getQuery().iterator(); f.hasNext();) {
            QueryType query = (QueryType) f.next();
            sb.append(getLayerName(query) + "_");
        }
        sb.setLength(sb.length() - 1);
        LOGGER.log(Level.FINE, "Using layer names for file name: " + sb.toString());
        if (sb.length() > 20) {
            LOGGER.log(Level.WARNING,
                    "Calculated filename too long. Returing a shorter one: " + sb.toString().substring(0, 20));
            return sb.toString().substring(0, 20);
        }
        return sb.toString();
    }

    @Override
    public String getAttachmentFileName(Object value, Operation operation) {
        GetFeatureRequest request = GetFeatureRequest.adapt(operation.getParameters()[0]);
        return getFileName(operation) + '.' + getDxfExtension(operation);
    }

    /**
     * Actually write the given featurecollection as a dxf file to
     * the output stream.
     * 
     * @see org.geoserver.wfs.WFSGetFeatureOutputFormat#write(net.opengis.wfs.FeatureCollectionType,
     *      java.io.OutputStream, org.geoserver.platform.Operation)
     */
    @Override
    protected void write(FeatureCollectionResponse featureCollection, OutputStream output, Operation operation)
            throws IOException, ServiceException {
        // output format (zipped or not)
        String format = getDxfExtension(operation);
        BufferedWriter w = null;
        ZipOutputStream zipStream = null;
        // DXF: use a simple buffered writer
        if (format.equals("dxf")) {
            LOGGER.log(Level.FINE, "Plain DXF output");
            w = new BufferedWriter(new OutputStreamWriter(output));
        } else {
            LOGGER.log(Level.FINE, "Zipped DXF output");
            // DXF-ZIP: use a zip stream wrapped with the buffered writer
            zipStream = new ZipOutputStream(output);
            ZipEntry entry = new ZipEntry(getFileName(operation) + ".dxf");
            zipStream.putNextEntry(entry);
            w = new BufferedWriter(new OutputStreamWriter(zipStream));
        }
        // extract format_options (GET mode)
        GetFeatureType gft = (GetFeatureType) operation.getParameters()[0];
        String version = (String) gft.getFormatOptions().get("VERSION");
        String blocks = (String) gft.getFormatOptions().get("ASBLOCKS");
        String colors = (String) gft.getFormatOptions().get("COLORS");
        String ltypes = (String) gft.getFormatOptions().get("LTYPES");
        String layerNames = (String) gft.getFormatOptions().get("LAYERS");
        LOGGER.log(Level.FINE,
                "Format options: " + version + "; " + blocks + "; " + colors + "; " + ltypes + "; " + layerNames);
        // get a suitable DXFWriter, for the requested version (null -> get any writer)
        DXFWriter dxfWriter = DXFWriterFinder.getWriter(version, w);

        if (dxfWriter != null) {
            LOGGER.log(Level.INFO, "DXFWriter: " + dxfWriter.getDescription());
            String[] layers = null;
            if (layerNames != null)
                layers = layerNames.toUpperCase().split(",");
            else
                layers = getLayerNames(gft.getQuery().iterator());
            LOGGER.log(Level.FINE, "Layers names: " + StringUtils.join(layers, ","));
            dxfWriter.setOption("layers", layers);
            if (blocks != null && blocks.toLowerCase().equals("true"))
                dxfWriter.setOption("geometryasblock", true);
            // set optional colors
            if (colors != null) {
                try {
                    String[] sColors = colors.split(",");
                    int[] icolors = new int[sColors.length];
                    for (int count = 0; count < sColors.length; count++)
                        icolors[count] = Integer.parseInt(sColors[count]);
                    dxfWriter.setOption("colors", icolors);
                } catch (Throwable t) {
                    LOGGER.log(Level.WARNING,
                            "format option colors ignored by DXFOutputFormat due to a wrong format: "
                                    + t.getMessage());
                }
            }
            // set optional line types
            if (ltypes != null) {
                try {
                    String[] sLTypes = ltypes.split(",");
                    LineType[] ltypesArr = new LineType[sLTypes.length];
                    for (int count = 0; count < sLTypes.length; count++)
                        ltypesArr[count] = LineType.parse(sLTypes[count]);
                    dxfWriter.setOption("linetypes", ltypesArr);

                } catch (Throwable t) {
                    LOGGER.warning("format option ltypes ignored by DXFOutputFormat due to a wrong format: "
                            + t.getMessage());
                }
            }

            // do the real job, please
            dxfWriter.write(featureCollection.getFeature(), version);

            w.flush();
            if (zipStream != null) {
                zipStream.closeEntry();
                zipStream.close();
            }
            dxfWriter = null;
            zipStream = null;
            w = null;

        } else
            throw new UnsupportedOperationException("Version " + version + " not supported by dxf output format");

    }

    /**
     * Gets a list of names for layers, one
     * for each query.
     * @param it
     * @return
     */
    private String[] getLayerNames(Iterator it) {
        List<String> names = new ArrayList<String>();
        while (it.hasNext()) {
            QueryType query = (QueryType) it.next();
            names.add(getLayerName(query).toUpperCase());
        }

        return names.toArray(new String[] {});
    }

    /**
     * Gets a layer name from a query.
     * The name can be:
     *  - an handle, if available
     *  - the typename
     * @param query
     * @return
     */
    private String getLayerName(QueryType query) {
        if (query.getHandle() != null)
            return query.getHandle();
        return ((QName) query.getTypeName().get(0)).getLocalPart();

    }

}