view gnv-artifacts/src/main/java/de/intevation/gnv/state/profile/horizontalcrosssection/HorizontalCrossSectionMeshOutputState.java @ 481:20dde2b6f1b5

Added end of life support for artifact states. Implemented ZIP download for "Horizontalschnitte". Laid some tracks for WMS (un-)publishing. gnv-artifacts/trunk@554 c6561f87-3c4e-4783-a992-168aeb5c3f6f
author Sascha L. Teichmann <sascha.teichmann@intevation.de>
date Sun, 17 Jan 2010 16:34:11 +0000
parents 211cad2fb5ba
children 64e65daa65e9
line wrap: on
line source
package de.intevation.gnv.state.profile.horizontalcrosssection;

import com.vividsolutions.jts.geom.Coordinate;
import com.vividsolutions.jts.geom.Envelope;
import com.vividsolutions.jts.geom.Polygon;

import de.intevation.artifactdatabase.Config;
import de.intevation.artifactdatabase.XMLUtils;

import de.intevation.artifacts.ArtifactNamespaceContext;
import de.intevation.artifacts.CallContext;

import de.intevation.gnv.artifacts.cache.CacheFactory;

import de.intevation.gnv.artifacts.context.GNVArtifactContext;

import de.intevation.gnv.geobackend.base.Result;
import de.intevation.gnv.geobackend.base.ResultDescriptor;

import de.intevation.gnv.geobackend.base.query.QueryExecutor;
import de.intevation.gnv.geobackend.base.query.QueryExecutorFactory;

import de.intevation.gnv.geobackend.base.query.exception.QueryException;

import de.intevation.gnv.geobackend.sde.datasources.RasterObject;

import de.intevation.gnv.math.AttributedPoint2ds;

import de.intevation.gnv.state.InputData;
import de.intevation.gnv.state.OutputStateBase;

import de.intevation.gnv.state.exception.StateException;

import de.intevation.gnv.state.timeseries.TimeSeriesOutputState;

import de.intevation.gnv.utils.FileUtils;
import de.intevation.gnv.utils.StringUtils;
import de.intevation.gnv.utils.WKTUtils;

import java.io.File;
import java.io.IOException;
import java.io.OutputStream;

import java.util.Collection;

import org.apache.log4j.Logger;

import org.w3c.dom.Document;
import org.w3c.dom.Element;
import org.w3c.dom.Node;

/**
 * @author Tim Englich         (tim.englich@intevation.de)
 * @author Sascha L. Teichmann (sascha.teichmann@intevation.de)
 */
public class HorizontalCrossSectionMeshOutputState 
extends      OutputStateBase
{
    private static Logger log = Logger
        .getLogger(HorizontalCrossSectionMeshOutputState.class);
    
    /**
     * The UID of this Class
     */
    private static final long serialVersionUID = 3233620652465061860L;
    
    private String ijkQueryID;

    private Boolean shapeFileLock = new Boolean(true);

    private String shapeFilePath;

    /**
     * Constructor
     */
    public HorizontalCrossSectionMeshOutputState() {
    }

    public String getShapeFilePath() {
        synchronized (shapeFileLock) {
            return shapeFilePath;
        }
    }

    public void setShapeFilePath(String shapeFilePath) {
        synchronized (shapeFileLock) {
            this.shapeFilePath = shapeFilePath;
        }
    }

    public String resetShapeFilePath() {
        synchronized (shapeFileLock) {
            String path = shapeFilePath;
            shapeFilePath = null;
            return path;
        }
    }

    public void endOfLife(Object globalContext) {
        super.endOfLife(globalContext);

        // do it in background
        new Thread() {
            public void run() {
                // TODO: Do the un-publishing WMS stuff.
                String path = resetShapeFilePath();

                if (path == null) {
                    return;
                }

                File dir = new File(path);

                for (int i = 0; i < 10; ++i) {
                    if (!dir.exists() || FileUtils.deleteRecursive(dir)) {
                        return;
                    }
                    try {
                        Thread.sleep(10000L);
                    }
                    catch (InterruptedException ie) {
                    }
                }

                log.error("failed to remove directory '" + path + "'");
            } // run
        }.start();
    }

    public void out(
        Document              format, 
        Collection<InputData> inputData,
        OutputStream          outputStream,
        String                uuid,
        CallContext           callContext
    )
    throws StateException 
    {
        String outputMode = XMLUtils.xpathString(
            format, XPATH_OUTPUT_MODE, ArtifactNamespaceContext.INSTANCE);

        String mimeType = XMLUtils.xpathString(
            format, XPATH_MIME_TYPE, ArtifactNamespaceContext.INSTANCE);

        if (outputMode == null || mimeType == null) {
            throw new StateException("cannot find outputMode or mime");
        }

        outputMode = outputMode.toLowerCase();

        log.debug("---- asking for: " + outputMode);

        if ("zip".equals(outputMode)) {
            writeZip(uuid, callContext, outputStream);
        }
        else if ("wms".equals(outputMode)) {
            XMLUtils.toStream(
                getWMS(uuid, callContext),
                outputStream);
        }
        else if ("statistics".equals(outputMode)) {
            // TODO: REMOVE THIS!
            try { outputStream.write("<fake/>\n".getBytes()); }
            catch (IOException ioe) {}
        }
        else {
            throw new StateException("unsupported output mode");
        }
    }

    protected void writeZip(
        String       uuid,
        CallContext  callContext,
        OutputStream output
    ) 
    throws StateException
    {
        try {
            String p = getShapeFilePath();
            if (p != null) {
                File dir = new File(p);
                if (dir.isDirectory()) {
                    FileUtils.createZipArchive(dir, output);
                }
            }
            AttributedPoint2ds result = getResult(uuid, callContext);
            if (result != null
            && (p = writeToShapeFile(uuid, result, callContext)) != null) {
                FileUtils.createZipArchive(new File(p), output);
            }
        }
        catch (IOException ioe) {
            log.error(ioe.getLocalizedMessage(), ioe);
        }
    }

    protected Document getWMS(String uuid, CallContext callContext) 
    throws StateException
    {
        // TODO: Do the real WMS publishing here!
        Document document = XMLUtils.newDocument();

        Element pathElement = document.createElement("path");
        document.appendChild(pathElement);

        String path = getShapeFilePath();

        if (path != null && new File(path).isDirectory()) {
            pathElement.setTextContent(path);
        }
        else {
            AttributedPoint2ds result = getResult(uuid, callContext);
            if (result != null
            && (path = writeToShapeFile(uuid, result, callContext)) != null) {
                pathElement.setTextContent(path);
            }
        }

        return document;
    }

    protected String writeToShapeFile(
        String             uuid,
        AttributedPoint2ds result,
        CallContext        callContext
    ) {
        File baseDir = shapefileDirectory(callContext);

        File shapeDir = new File(baseDir, uuid);

        int count = 0;

        synchronized (shapeFileLock) {
            while (shapeDir.exists()) {
                shapeDir = new File(baseDir, uuid + "-" + count);
                ++count;
            }

            if (!shapeDir.mkdirs()) {
                log.error("cannot create directory '" 
                    + shapeDir.getAbsolutePath() + "'");
                return null;
            }
            shapeFilePath = shapeDir.getAbsolutePath();
        }

        // TODO: Do the writing

        return shapeFilePath;
    }

    protected AttributedPoint2ds getResult(String uuid, CallContext callContext)
    throws StateException
    {
        CacheFactory cf  = CacheFactory.getInstance();
        String       key = uuid + super.getID();

        if (cf.isInitialized()) {
            net.sf.ehcache.Element value = cf.getCache().get(key);
            if (value != null) {
                 return (AttributedPoint2ds)value.getObjectValue();
            }
        }

        AttributedPoint2ds result = produceResult(callContext);

        if (result != null && cf.isInitialized()) {
            cf.getCache().put(new net.sf.ehcache.Element(key, result));
        }

        return result;
    }
    
    protected AttributedPoint2ds produceResult(CallContext callContext) 
    throws StateException
    {
        InputData meshPolygon = inputData.get("mesh_polygon");
        InputData meshId      = inputData.get("meshid");

        if (meshPolygon == null) {
            log.error("mesh_polygon is not defined");
            throw new StateException("missing mesh_linestring");
        }

        if (meshId == null) {
            log.error("meshid is not defined");
            throw new StateException("missing meshid");
        }

        Polygon p = WKTUtils.toPolygon(meshPolygon.getValue());

        if (p == null) {
            log.error("no valid polygon");
            throw new StateException("no valid polygon");
        }

        try {
            Envelope env  = p.getEnvelopeInternal();

            Coordinate [] coords = new Coordinate [] {
                new Coordinate(env.getMinX(), env.getMinY()),
                new Coordinate(env.getMinX(), env.getMaxY()),
                new Coordinate(env.getMaxX(), env.getMaxY()),
                new Coordinate(env.getMaxX(), env.getMinY()) };

            String additionWhere =
                WKTUtils.worldEnvelopeCoordinatesToIndex(
                    coords,
                    meshId.getValue(),
                    ijkQueryID);

            String[] addedFilterValues = StringUtils.append(
                generateFilterValuesFromInputData(),
                additionWhere);

            QueryExecutor queryExecutor = QueryExecutorFactory
                .getInstance()
                .getQueryExecutor();

            return process(
                env,
                p,
                numSamples(callContext),
                preprocess(
                    queryExecutor.executeQuery(
                        queryID,
                        addedFilterValues)));
        }
        catch (QueryException e) {
            log.error(e,e);
        }

        throw new StateException("no result produced");
    }

    public AttributedPoint2ds preprocess(Collection<Result> results) {

        boolean debug = log.isDebugEnabled();

        if (debug) {
            log.debug("--- preprocess: " + results.size() + " results");
        }

        AttributedPoint2ds ap2ds = new AttributedPoint2ds();

        boolean first = true;

        for (Result result: results) {

            if (debug && first) {
                first = false;
                ResultDescriptor rd = result.getResultDescriptor();
                log.debug(rd);
            }
        }

        // TODO: do the interpolation

        return ap2ds;
    }
    
    public AttributedPoint2ds process(
        Envelope           env,
        Polygon            polygon,
        int                numSamples,
        AttributedPoint2ds input
    ) {
        return input;
    }

    
    /**
     * @see de.intevation.gnv.state.timeseries.TimeSeriesOutputState#setup(org.w3c.dom.Node)
     */
    @Override
    public void setup(Node configuration) {
        super.setup(configuration);
        this.ijkQueryID = Config.getStringXPath(configuration,"queryID-ijk");
        
    }
    
    private static int numSamples(CallContext callContext) {
        GNVArtifactContext context =
            (GNVArtifactContext)callContext.globalContext();
        Integer samples = (Integer)context.get(
            GNVArtifactContext.HORIZONTAL_CROSS_SECTION_SAMPLES_KEY);
        return samples != null
            ? samples.intValue()
            : GNVArtifactContext.DEFAULT_HORIZONTAL_CROSS_SECTION_SAMPLES;
    }

    private static File shapefileDirectory(CallContext callContext) {
        GNVArtifactContext context =
            (GNVArtifactContext)callContext.globalContext();
        File dir = (File)context.get(
            GNVArtifactContext.HORIZONTAL_CROSS_SECTION_RESULT_SHAPEFILE_PATH_KEY);
        return dir != null
            ? dir
            : GNVArtifactContext.DEFAULT_HORIZONTAL_CROSS_SECTION_PROFILE_SHAPEFILE_PATH;
    }

    private static int getGroundInterpolation(CallContext callContext) {
        GNVArtifactContext context = 
            (GNVArtifactContext)callContext.globalContext();

        String interpolation = (String)context.get(
            GNVArtifactContext.HORIZONTAL_CROSS_SECTION_GROUND_INTERPOLATION_KEY);

        return RasterObject.getInterpolationType(interpolation);
    }
}
// vim:set ts=4 sw=4 si et sta sts=4 fenc=utf8 :

http://dive4elements.wald.intevation.org