package org.geoserver.geosync;
import net.opengis.wfs.DeleteElementType;
import net.opengis.wfs.InsertElementType;
import net.opengis.wfs.TransactionType;
import net.opengis.wfs.UpdateElementType;
import net.opengis.wfs.WfsFactory;
import org.springframework.web.servlet.mvc.AbstractController;
import org.springframework.web.servlet.ModelAndView;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.util.Iterator;
import java.util.List;
import java.util.ArrayList;
import java.util.Map;
import java.util.HashMap;
import java.util.NoSuchElementException;
import java.text.DateFormat;
import java.text.SimpleDateFormat;
import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.io.PrintWriter;
import com.sun.syndication.feed.synd.SyndFeed;
import com.sun.syndication.feed.synd.SyndFeedImpl;
import com.sun.syndication.feed.synd.SyndEntry;
import com.sun.syndication.feed.synd.SyndEntryImpl;
import com.sun.syndication.feed.synd.SyndContent;
import com.sun.syndication.feed.synd.SyndContentImpl;
import com.sun.syndication.feed.synd.SyndLink;
import com.sun.syndication.feed.synd.SyndLinkImpl;
import com.sun.syndication.io.SyndFeedOutput;
import com.sun.syndication.propono.atom.common.AtomService;
import com.sun.syndication.propono.atom.common.Workspace;
import com.sun.syndication.propono.atom.common.Collection;
import com.sun.syndication.feed.atom.Link;
import com.sun.syndication.feed.module.georss.GeoRSSModule;
import com.sun.syndication.feed.module.georss.W3CGeoModuleImpl;
import com.sun.syndication.feed.module.georss.geometries.PositionList;
import com.sun.syndication.feed.module.georss.geometries.LinearRing;
import com.sun.syndication.feed.module.georss.geometries.Polygon;
import org.apache.xml.serialize.OutputFormat;
import org.geoserver.wfs.TransactionEvent;
import org.geoserver.wfs.xml.v1_1_0.WFS;
import org.geoserver.wfs.xml.v1_1_0.WFSConfiguration;
import org.geoserver.ows.util.RequestUtils;
import org.geoserver.ows.util.ResponseUtils;
import org.geotools.xml.Encoder;
import org.vfny.geoserver.util.requests.readers.KvpRequestReader;
import org.vfny.geoserver.global.Data;
import org.vfny.geoserver.global.GeoServer;
import freemarker.template.Template;
import freemarker.template.Configuration;
import org.jdom.Document;
import org.jdom.output.Format;
import org.jdom.output.XMLOutputter;
public class GeoSyncController extends AbstractController {
static final DateFormat DATE_PARSER = new SimpleDateFormat("yyyy-MM-dd");
private GeoServer myGeoserver;
private Data catalog;
private RecordingTransactionListener myListener;
private WFSConfiguration xmlConfiguration;
public RecordingTransactionListener getListener(){
return myListener;
}
public void setListener(RecordingTransactionListener rtl){
myListener = rtl;
}
public void setGeoserver(GeoServer gs){
myGeoserver = gs;
}
public GeoServer getGeoserver(){
return myGeoserver;
}
public void setCatalog(Data catalog) {
this.catalog = catalog;
}
public void setXmlConfiguration(WFSConfiguration xmlConfiguration) {
this.xmlConfiguration = xmlConfiguration;
}
public ModelAndView handleRequestInternal(HttpServletRequest req, HttpServletResponse resp){
String path = req.getPathInfo();
//strip off query string
if ( path != null && path.indexOf( '?' ) > -1 ) {
path = path.substring(0, path.indexOf('?') );
}
//is this a requst for the serach template?
boolean search = false;
if ( path != null && path.endsWith( "/opensearch.xml" ) ) {
path = path.substring( 0, path.length() - "/opensearch.xml".length() );
search = true;
}
//figure out the layer of the request
String layer = null;
if ( path != null && !"".equals( path ) ) {
//requsting particular layer
layer = path.substring( 1 );
try {
catalog.getFeatureTypeInfo( layer );
}
catch( NoSuchElementException e ) {
layer = null;
}
}
if ( layer == null ) {
resp.setStatus( 404 );
return null;
}
try {
String baseUrl = RequestUtils.proxifiedBaseURL(
RequestUtils.baseURL(req), myGeoserver.getProxyBaseUrl());
baseUrl = ResponseUtils.appendPath( baseUrl, "history/"+ layer );
//generate the content
resp.setContentType("text/xml");
if ( search ) {
//send back the opensearch template
//write out the opensearch template
Configuration cfg = new Configuration();
cfg.setClassForTemplateLoading(getClass(), "");
Map ctx = new HashMap();
ctx.put("CONTACT_ADDRESS", myGeoserver.getContactEmail());
ctx.put( "LAYER", layer );
ctx.put( "BASE_URL", baseUrl );
Template t = cfg.getTemplate("opensearchdescription.ftl");
PrintWriter writer = resp.getWriter();
t.process(ctx, writer);
writer.flush();
}
else {
Map kvp = KvpRequestReader.parseKvpSet( req.getQueryString() );
SyndFeed feed = null;
if ( kvp.isEmpty() ) {
//send back a feed with a link to the opensearch template
feed = new SyndFeedImpl();
feed.setFeedType("atom_1.0");
SyndLink link = new SyndLinkImpl();
link.setRel( "search" );
link.setHref( ResponseUtils.appendPath(baseUrl, "opensearch.xml"));
link.setType( "application/opensearchdescription+xml");
feed.getLinks().add( link );
}
else {
//send back the actual feed
feed = myListener.filterFeed(layer,kvp,baseUrl,req);
}
//write out the feed
SyndFeedOutput out = new SyndFeedOutput();
out.output(feed, resp.getWriter());
resp.getWriter().flush();
}
} catch (Exception e){
resp.setStatus(500);
e.printStackTrace();
}
// if ( search ) {
//
// }
// else {
// //write out the actual content
//
// SyndFeed feed = generateFeed(kvp, baseUrl);
// SyndFeedOutput out = new SyndFeedOutput();
// PrintWriter writer = resp.getWriter();
// out.output(feed, writer);
// }
// }
// catch( Exception e ) {
// resp.setStatus(500);
// e.printStackTrace();
// }
//
// Map kvPairs = KvpRequestReader.parseKvpSet(req.getQueryString());
// String requestType = (String)kvPairs.get("REQUEST");
// String base = RequestUtils.proxifiedBaseURL(RequestUtils.baseURL(req), myGeoserver.getProxyBaseUrl());
//
// try{
// if ("GETCAPABILITIES".equalsIgnoreCase(requestType)){
// AtomService service = new AtomService();
//
// Workspace workspace = new Workspace(
// "GeoSync Workspace", "application/atom+xml;type=entry");
// service.addWorkspace(workspace);
//
// Collection entryCol = new Collection(
// "GeoSync Update Feed", "text", base + "/geosync/request=feed");
//
// List accepts = new ArrayList();
// accepts.add("application/atom+xml;type=entry");
// entryCol.setAccepts(accepts);
//
// workspace.addCollection( entryCol );
//
// resp.setContentType("application/atomsvc+xml");
//
// //TODO: Categories
// Document d = service.serviceToDocument();
// XMLOutputter outputter = new XMLOutputter(Format.getPrettyFormat());
// outputter.output(d, resp.getOutputStream());
// } else if ("FEED".equalsIgnoreCase(requestType)){
// SyndFeed feed = generateFeed(kvPairs, base);
// SyndFeedOutput out = new SyndFeedOutput();
// PrintWriter writer = resp.getWriter();
// out.output(feed, writer);
// } else if ("DESCRIBESEARCH".equalsIgnoreCase(requestType)){
// Configuration cfg = new Configuration();
// cfg.setClassForTemplateLoading(getClass(), "");
// Map ctx = new HashMap();
// ctx.put("GEOSERVER_URL", base);
// ctx.put("CONTACT_ADDRESS", myGeoserver.getContactEmail());
// Template t = cfg.getTemplate("opensearchdescription.ftl");
// PrintWriter writer = resp.getWriter();
// t.process(ctx, writer);
// } else {
// resp.setStatus(400);
// PrintWriter writer = resp.getWriter();
// writer.println("Bad request");
// }
// } catch (Exception e){
// resp.setStatus(500);
// e.printStackTrace();
// }
return null;
}
// public SyndFeed generateFeed(Map params, String base) throws Exception{
// params.remove("REQUEST");
// SyndFeed feed;
// if (params.isEmpty()){
// // do defaulty stuff
// feed = new SyndFeedImpl();
// feed.setFeedType("atom_1.0");
//
// SyndLink link = new SyndLinkImpl();
// link.setHref(base + "/history?request=DescribeSearch");
// link.setRel("search");
// link.setType("application/opensearchdescription+xml");
// List links = feed.getLinks();
// links.add(link);
// feed.setLinks(links);
// } else {
// feed = generateFeed(params);
// }
// return feed;
// }
public List encodeHistory(List history) throws Exception{
List entries = new ArrayList();
Iterator it = history.iterator();
while(it.hasNext()){
TransactionEvent e = (TransactionEvent) it.next();
//SyncItem item = (SyncItem)it.next();
SyndEntry entry = new SyndEntryImpl();
entry.setTitle("Feature A");
entry.setLink("http://geoserver.org/a");
entry.setPublishedDate(DATE_PARSER.parse("2004-06-08"));
//encode the content as the wfs transcation
SyndContent description = new SyndContentImpl();
description.setType("text/xml");
description.setValue(encodeTransaction( e ));
// GeoRSSModule geoInfo = new W3CGeoModuleImpl();
// Polygon bounds = new Polygon();
// PositionList exterior = new PositionList();
// double minLat = 0, minLong = 0, maxLat = 0, maxLong = 0;
// exterior.add(minLat, minLong);
// exterior.add(minLat, maxLong);
// exterior.add(maxLat, maxLong);
// exterior.add(maxLat, minLong);
// bounds.setExterior(new LinearRing(exterior));
// geoInfo.setGeometry(bounds);
// entry.getModules().add(geoInfo);
// TODO: use real data for Geo output
List contents = new ArrayList();
contents.add(description);
entry.setContents(contents);
entries.add(entry);
}
return entries;
}
String encodeTransaction( TransactionEvent e ) throws IOException {
TransactionType tx = WfsFactory.eINSTANCE.createTransactionType();
Object source = e.getSource();
if ( source instanceof InsertElementType ) {
tx.getInsert().add( source );
}
else if ( source instanceof UpdateElementType ) {
tx.getUpdate().add( source );
}
else if ( source instanceof DeleteElementType ) {
tx.getDelete().add( source );
}
Encoder encoder = new Encoder( xmlConfiguration );
OutputFormat of = new OutputFormat();
of.setOmitXMLDeclaration( true );
encoder.setOutputFormat( of );
ByteArrayOutputStream out = new ByteArrayOutputStream();
encoder.encode( tx, WFS.TRANSACTION, out );
return new String( out.toByteArray() );
}
}