org.polymap.rhei.fulltext.servlet.GeoRssEncoder.java Source code

Java tutorial

Introduction

Here is the source code for org.polymap.rhei.fulltext.servlet.GeoRssEncoder.java

Source

/* 
 * polymap.org
 * Copyright (C) 2009-2014, Polymap GmbH. All rights reserved.
 *
 * This is free software; you can redistribute it and/or modify it
 * under the terms of the GNU Lesser General Public License as
 * published by the Free Software Foundation; either version 2.1 of
 * the License, or (at your option) any later version.
 *
 * This software is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
 * Lesser General Public License for more details.
 */
package org.polymap.rhei.fulltext.servlet;

import static org.polymap.rhei.fulltext.FulltextIndex.FIELD_GEOM;
import static org.polymap.rhei.fulltext.FulltextIndex.FIELD_SRS;
import static org.polymap.rhei.fulltext.FulltextIndex.FIELD_TITLE;

import java.util.Collection;
import java.util.Date;
import java.util.LinkedList;
import java.util.List;
import java.util.Set;

import java.io.DataOutputStream;
import java.io.IOException;
import java.io.ObjectOutput;
import java.io.OutputStream;
import java.io.StringWriter;

import org.geotools.geometry.jts.JTSFactoryFinder;
import org.geotools.referencing.CRS;
import org.json.JSONObject;
import org.opengis.feature.Property;
import org.opengis.feature.simple.SimpleFeature;
import org.opengis.referencing.FactoryException;
import org.opengis.referencing.crs.CoordinateReferenceSystem;
import org.opengis.referencing.operation.MathTransform;

import org.apache.commons.lang3.StringUtils;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.apache.lucene.document.Document;

import com.sun.syndication.feed.module.georss.GeoRSSModule;
import com.sun.syndication.feed.module.georss.SimpleModuleImpl;
import com.sun.syndication.feed.module.georss.geometries.Position;
import com.sun.syndication.feed.synd.SyndContentImpl;
import com.sun.syndication.feed.synd.SyndEntry;
import com.sun.syndication.feed.synd.SyndEntryImpl;
import com.sun.syndication.feed.synd.SyndFeed;
import com.sun.syndication.feed.synd.SyndFeedImpl;
import com.sun.syndication.io.FeedException;
import com.sun.syndication.io.SyndFeedOutput;
import com.vividsolutions.jts.geom.Geometry;
import com.vividsolutions.jts.geom.GeometryFactory;
import com.vividsolutions.jts.geom.Point;

import org.polymap.core.data.pipeline.PipelineProcessor;
import org.polymap.core.data.util.Geometries;

/**
 * This stream encodes {@link SimpleFeature} and {@link Document} objects into
 * GeoRSS stream. Later this may also extend to be a {@link PipelineProcessor}
 * 
 * @author <a href="http://www.polymap.de">Falko Braeutigam</a>
 * @version POLYMAP3 ($Revision$)
 * @since 3.0
 */
public class GeoRssEncoder extends DataOutputStream
        //extends ObjectOutputStream
        implements ObjectOutput {

    private static final Log log = LogFactory.getLog(GeoRssEncoder.class);

    private static final GeometryFactory gf = JTSFactoryFinder.getGeometryFactory(null);

    private boolean streamStarted;

    private CoordinateReferenceSystem dataCRS, worldCRS;

    private MathTransform transform;

    private List<SyndEntry> feedEntries;

    private String baseURL;

    private String feadTitle;

    private String description;

    public GeoRssEncoder(OutputStream out, CoordinateReferenceSystem worldCRS, String baseURL, String title,
            String description) throws IOException {
        super(out);
        assert baseURL != null;
        this.worldCRS = worldCRS;
        this.baseURL = baseURL;
        this.feadTitle = title;
        this.description = description;
    }

    public void writeObject(Object obj) throws IOException {
        if (!streamStarted) {
            startStream();
        }
        try {
            if (obj instanceof SimpleFeature) {
                encodeFeature((SimpleFeature) obj);
            } else if (obj instanceof JSONObject) {
                encodeFeature((JSONObject) obj);
            } else {
                throw new RuntimeException("Unsupported object type: " + obj);
            }
        } catch (RuntimeException e) {
            throw e;
        } catch (Exception e) {
            throw new IOException(e.getMessage(), e);
        }
    }

    protected void startStream() {
        assert !streamStarted;
        streamStarted = true;
        feedEntries = new LinkedList();
    }

    private boolean aboutToFlush = false;

    public synchronized void flush() throws IOException {
        if (aboutToFlush) {
            super.flush();
            return;
        }
        aboutToFlush = true;
        log.debug("flush(): ...");

        SyndFeed feed = new SyndFeedImpl();
        feed.setFeedType("rss_2.0");

        feed.setTitle(feadTitle != null ? feadTitle : "POLYMAP3|Atlas");
        feed.setLink(baseURL);
        feed.setDescription(description != null ? description : "");

        feed.setEntries(feedEntries);
        //WireFeed wiredFeed = feed.createWireFeed();

        SyndFeedOutput output = new SyndFeedOutput();
        try {
            //output.output( feed, new OutputStreamWriter( out, "ISO-8859-1" ) );

            StringWriter buf = new StringWriter();
            output.output(feed, buf);
            buf.flush();
            write(buf.toString().getBytes("UTF-8"));
        } catch (FeedException e) {
            log.warn("unhandled: ", e);
        }

        aboutToFlush = false;
        super.flush();
        //        feedEntries.clear();
    }

    protected void encodeFeature(SimpleFeature feature) throws FactoryException {
        //
        CoordinateReferenceSystem featureCRS = feature.getFeatureType().getCoordinateReferenceSystem();
        if (!featureCRS.equals(dataCRS)) {
            boolean lenient = true; // allow for some error due to different datums
            transform = CRS.findMathTransform(dataCRS, worldCRS, lenient);
        }

        // entry
        SyndEntryImpl entry = new SyndEntryImpl();
        entry.setTitle("Entry");
        entry.setLink("http://polymap.org/");
        entry.setPublishedDate(new Date());

        // description
        StringBuffer buf = new StringBuffer(256);
        Collection<Property> props = feature.getProperties();
        Point point = null;
        for (Property prop : props) {
            //log.info( prop.getName() + ": " + prop.getValue().getClass() );
            if (prop.getValue().getClass().equals(Point.class)) {
                point = (Point) prop.getValue();
            } else {
                String value = prop.getValue().toString();
                if (value != null && value.length() > 0) {
                    buf.append("<b>").append(prop.getName()).append("</b>");
                    buf.append(": ").append(escapeHtml(value));
                    buf.append("<br/>");
                }
            }
        }
        SyndContentImpl descr = new SyndContentImpl();
        descr.setType("text/html");
        descr.setValue(buf.toString());
        entry.setDescription(descr);

        GeoRSSModule module = new SimpleModuleImpl();
        //GeometryAttribute geom = feature.getDefaultGeometryProperty();
        //geoRSSModule.setPosition( new Position( 54.2, 12.4 ) );

        // transform
        //point = (Point)JTS.transform( point, transform);

        module.setPosition(new Position(point.getY(), point.getX()));
        entry.getModules().add(module);

        feedEntries.add(entry);
        log.debug("Feed entry added: " + entry);
    }

    protected void encodeFeature(JSONObject obj) throws Exception {
        String title = obj.getString(FIELD_TITLE);
        Geometry geom = (Geometry) obj.get(FIELD_GEOM);
        String srs = obj.getString(FIELD_SRS);
        geom = Geometries.transform(geom, Geometries.crs(srs), worldCRS);
        log.debug("encoding: " + title);

        // entry
        SyndEntryImpl entry = new SyndEntryImpl();
        entry.setTitle(escapeHtml(title));
        entry.setLink(escapeHtml(baseURL + "?search=" + title));
        entry.setPublishedDate(new Date());

        //        // address
        //        Address address = obj.getAddress();
        //        StringBuffer addressBuf = new StringBuffer( 256 );
        //        if (address != null && address.getStreet() != null) {
        //            // postal code
        //            String postalCode = StringUtils.contains( address.getPostalCode(), "-" )
        //                    ? StringUtils.substringAfterLast( address.getPostalCode(), "-" )
        //                    : address.getPostalCode();
        //            
        //            addressBuf.append( "<p><em>" ).append( escapeHtml( address.getStreet() ) )
        //                    .append( " " ).append( escapeHtml( address.getNumber() ) )
        //                    .append( "<br/>" )
        //                    // remove country code from postal code
        //                    .append( escapeHtml( postalCode ) )
        //                    .append( " " ).append( escapeHtml( address.getCity() ) )
        //                    .append( "</em></p>" );
        //        }

        // geometry
        Point point = geom.getCentroid();
        Position pos = new Position(point.getY(), point.getX());

        // description
        StringBuilder buf = new StringBuilder(256);
        //        buf.append( addressBuf );
        for (String key : (Set<String>) obj.keySet()) {
            log.debug("    field: " + key);
            String value = obj.getString(key);
            if (value != null && value.length() > 0) {
                buf.append("<nobr><b>").append(escapeHtml(StringUtils.capitalize(key))).append("</b>");
                // URL?
                if (value.contains("www.") || value.contains(".de") || value.contains(".com")
                        || value.contains("http://")) {
                    buf.append(": ").append("<a href=\"").append(value).append("\" target=\"atlas_content\">")
                            .append(escapeHtml(value)).append("</a>");
                } else {
                    buf.append(": ").append(escapeHtml(value));
                }
                buf.append("</nobr><br/>");
            }
        }
        SyndContentImpl descr = new SyndContentImpl();
        descr.setType("text/html");
        descr.setValue(buf.toString());
        entry.setDescription(descr);

        GeoRSSModule module = new SimpleModuleImpl();
        //GeometryAttribute geom = feature.getDefaultGeometryProperty();
        //geoRSSModule.setPosition( new Position( 54.2, 12.4 ) );

        // transform
        //point = (Point)JTS.transform( point, transform);

        module.setPosition(pos);
        entry.getModules().add(module);

        feedEntries.add(entry);
        //log.info( "Feed entry added: " + entry );
    }

    protected String escapeHtml(String s) {
        //return StringEscapeUtils.escapeHtml( s );
        return s;
    }

}