/* (c) 2014 - 2016 Open Source Geospatial Foundation - all rights reserved
* (c) 2001 - 2013 OpenPlans
* This code is licensed under the GPL 2.0 license, available at the root
* application directory.
*/
package org.geoserver.wcs.web.demo;
import java.awt.Rectangle;
import java.awt.geom.AffineTransform;
import java.util.Arrays;
import java.util.Collections;
import java.util.logging.Level;
import java.util.logging.Logger;
import javax.servlet.http.HttpServletRequest;
import org.apache.wicket.Component;
import org.apache.wicket.Page;
import org.apache.wicket.ajax.AjaxRequestTarget;
import org.apache.wicket.ajax.form.AjaxFormSubmitBehavior;
import org.apache.wicket.extensions.ajax.markup.html.modal.ModalWindow;
import org.apache.wicket.markup.html.WebMarkupContainer;
import org.apache.wicket.markup.html.form.CheckBox;
import org.apache.wicket.markup.html.form.DropDownChoice;
import org.apache.wicket.markup.html.form.Form;
import org.apache.wicket.markup.html.form.ChoiceRenderer;
import org.apache.wicket.markup.html.panel.FeedbackPanel;
import org.apache.wicket.markup.html.panel.Panel;
import org.apache.wicket.model.Model;
import org.apache.wicket.model.PropertyModel;
import org.apache.wicket.model.StringResourceModel;
import org.geoserver.catalog.Catalog;
import org.geoserver.catalog.CoverageInfo;
import org.geoserver.ows.URLMangler.URLType;
import org.geoserver.ows.util.ResponseUtils;
import org.geoserver.wcs.responses.CoverageResponseDelegateFinder;
import org.geoserver.wcs.web.demo.GetCoverageRequest.Version;
import org.geoserver.web.GeoServerApplication;
import org.geoserver.web.demo.DemoRequest;
import org.geoserver.web.demo.DemoRequestResponse;
import org.geoserver.web.wicket.CRSPanel;
import org.geoserver.web.wicket.EnvelopePanel;
import org.geoserver.web.wicket.GeoServerAjaxFormLink;
import org.geotools.coverage.grid.GridEnvelope2D;
import org.geotools.coverage.grid.GridGeometry2D;
import org.geotools.geometry.jts.JTS;
import org.geotools.geometry.jts.ReferencedEnvelope;
import org.geotools.util.logging.Logging;
import org.opengis.referencing.datum.PixelInCell;
import org.opengis.referencing.operation.MathTransform;
import com.vividsolutions.jts.geom.Envelope;
/**
* Small embedded WCS client enabling users to visually build a WCS GetCoverage request
*
* @author Andrea Aime - OpenGeo
*/
@SuppressWarnings("serial")
public class WCSRequestBuilderPanel extends Panel {
/**
* How the WCS 1.1 target layout is going to be built
* @author Andrea Aime - GeoSolutions
*/
enum TargetLayout { Automatic, Resolution, Affine };
static final Logger LOGGER = Logging.getLogger(WCSRequestBuilderPanel.class);
GetCoverageRequest getCoverage;
String description;
ModalWindow responseWindow;
private Component feedback;
private WebMarkupContainer details;
private EnvelopePanel envelope;
private DropDownChoice<String> coverage;
private DropDownChoice<String> formats;
private CRSPanel targetCRS;
private CheckBox manualGrid;
private GridPanel sourceGridRange;
private AffineTransformPanel g2w;
private DropDownChoice<TargetLayout> targetLayoutChooser;
private WebMarkupContainer targetlayoutContainer;
private WebMarkupContainer sourceGridContainer;
private GeoServerAjaxFormLink describeLink;
public WCSRequestBuilderPanel(String id, GetCoverageRequest getCoverage) {
super(id);
setOutputMarkupId(true);
setDefaultModel(new Model(getCoverage));
this.getCoverage = getCoverage;
// the feedback panel, for validation errors
feedback = new FeedbackPanel("feedback");
feedback.setOutputMarkupId(true);
add(feedback);
// the version chooser
final DropDownChoice<Version> version = new DropDownChoice<Version>("version",
new PropertyModel<Version>(getCoverage, "version"),
Arrays.asList(Version.values()));
add(version);
// the action that will setup the form once the coverage has been chosen
version.add(new AjaxFormSubmitBehavior("change") {
@Override
protected void onError(AjaxRequestTarget target) {
onSubmit(target);
}
@Override
protected void onSubmit(AjaxRequestTarget target) {
if(version.getModelObject() == Version.v1_0_0) {
sourceGridContainer.setVisible(true);
targetlayoutContainer.setVisible(false);
manualGrid.setModelObject(false);
sourceGridRange.setVisible(false);
} else {
targetlayoutContainer.setVisible(true);
sourceGridContainer.setVisible(false);
targetLayoutChooser.setModelObject(TargetLayout.Automatic);
g2w.setModelObject(null);
g2w.setVisible(false);
}
target.add(WCSRequestBuilderPanel.this);
}
});
// the coverage id chooser
coverage = new DropDownChoice<String>("coverage", new PropertyModel<String>(getCoverage, "coverage"),
new CoverageNamesModel());
add(coverage);
// the action that will setup the form once the coverage has been chosen
coverage.add(new AjaxFormSubmitBehavior("change") {
@Override
protected void onError(AjaxRequestTarget target) {
onSubmit(target);
}
@Override
protected void onSubmit(AjaxRequestTarget target) {
details.setVisible(true);
String coverageName = coverage.getModelObject();
Catalog catalog = GeoServerApplication.get().getCatalog();
CoverageInfo ci = catalog.getCoverageByName(coverageName);
ReferencedEnvelope ri = ci.getNativeBoundingBox();
final GetCoverageRequest gc = WCSRequestBuilderPanel.this.getCoverage;
gc.bounds = ri;
gc.targetCRS = ri.getCoordinateReferenceSystem();
gc.sourceGridRange = null;
describeLink.setEnabled(true);
target.add(WCSRequestBuilderPanel.this);
}
});
// the details container
details = new WebMarkupContainer("details");
details.setOutputMarkupId(true);
details.setVisible(false);
add(details);
// the envelope chooser
envelope = new EnvelopePanel("envelope", new PropertyModel(getCoverage, "bounds"));
envelope.setCRSFieldVisible(true);
envelope.setCrsRequired(true);
details.add(envelope);
// the grid panel (for WCS 1.0 requests)
buildGridPanel();
// the format chooser
CoverageResponseDelegateFinder responseFactory = (CoverageResponseDelegateFinder) GeoServerApplication.get().getBean("coverageResponseDelegateFactory");
formats = new DropDownChoice<String>("format", new PropertyModel(getCoverage, "outputFormat"), responseFactory.getOutputFormats());
details.add(formats);
// the target CRS
targetCRS = new CRSPanel("targetCRS", new PropertyModel(getCoverage, "targetCRS"));
details.add(targetCRS);
// the target grid to world (for WCS 1.1 ones)
buildAffinePanel();
// the describe response window
responseWindow = new ModalWindow("responseWindow");
add(responseWindow);
responseWindow.setPageCreator(new ModalWindow.PageCreator() {
public Page createPage() {
DemoRequest request = new DemoRequest(null);
HttpServletRequest http = GeoServerApplication.get().servletRequest(getRequest());
String url = ResponseUtils.buildURL(ResponseUtils.baseURL(http), "ows", Collections
.singletonMap("strict", "true"), URLType.SERVICE);
request.setRequestUrl(url);
request.setRequestBody((String) responseWindow.getDefaultModelObject());
return new DemoRequestResponse(new Model(request));
}
});
// the describe coverage link
describeLink = new GeoServerAjaxFormLink("describeCoverage") {
@Override
protected void onClick(AjaxRequestTarget target, Form form) {
version.processInput();
coverage.processInput();
final String coverageName = WCSRequestBuilderPanel.this.getCoverage.coverage;
if (coverageName != null) {
responseWindow.setDefaultModel(new Model(getDescribeXML(coverageName)));
responseWindow.show(target);
}
}
};
describeLink.setEnabled(false);
describeLink.setOutputMarkupId(true);
add(describeLink);
}
protected String getDescribeXML(String processId) {
if(getCoverage.version == Version.v1_0_0) {
return "<DescribeCoverage\n" +
" version=\"1.0.0\"\n" +
" service=\"WCS\"\n" +
" xmlns=\"http://www.opengis.net/wcs\"\n" +
" xmlns:nurc=\"http://www.nurc.nato.int\"\n" +
" xmlns:xsi=\"http://www.w3.org/2001/XMLSchema-instance\"\n" +
" xsi:schemaLocation=\"http://www.opengis.net/wcs http://schemas.opengis.net/wcs/1.0.0/describeCoverage.xsd\">\n" +
" \n" +
" <Coverage>" + getCoverage.coverage + "</Coverage>\n" +
" \n" +
"</DescribeCoverage>";
} else {
return "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\r\n" + //
"<wcs:DescribeCoverage service=\"WCS\" " + //
"xmlns:ows=\"http://www.opengis.net/ows/1.1\"\r\n" + //
" xmlns:wcs=\"http://www.opengis.net/wcs/1.1.1\"\r\n" + //
" xmlns:xsi=\"http://www.w3.org/2001/XMLSchema-instance\" \r\n" + //
" version=\"1.1.1\" >\r\n" + //
" <wcs:Identifier>" + getCoverage.coverage + "</wcs:Identifier>\r\n" + //
"</wcs:DescribeCoverage>";
}
}
private void buildAffinePanel() {
targetlayoutContainer = new WebMarkupContainer("targetLayoutContainer");
details.add(targetlayoutContainer);
targetlayoutContainer.setVisible(false);
targetLayoutChooser = new DropDownChoice<TargetLayout>("targetLayout",
new Model(TargetLayout.Automatic),
Arrays.asList(TargetLayout.values()),
new TargetLayoutRenderer());
targetlayoutContainer.add(targetLayoutChooser);
g2w = new AffineTransformPanel("targetGridToWorld", new PropertyModel(getCoverage, "targetGridToWorld"));
targetlayoutContainer.add(g2w);
g2w.setVisible(false);
g2w.setOutputMarkupId(true);
targetLayoutChooser.add(new AjaxFormSubmitBehavior("change") {
@Override
protected void onError(AjaxRequestTarget target) {
onSubmit(target);
}
@Override
protected void onSubmit(AjaxRequestTarget target) {
if(targetLayoutChooser.getModelObject() == TargetLayout.Affine) {
AffineTransform at = guessGridToWorld(false);
g2w.setResolutionModeEnabled(false);
g2w.setModelObject(at);
g2w.setVisible(true);
} else if(targetLayoutChooser.getModelObject() == TargetLayout.Resolution) {
AffineTransform at = guessGridToWorld(true);
g2w.setResolutionModeEnabled(true);
g2w.setModelObject(at);
g2w.setVisible(true);
} else {
g2w.setModelObject(null);
g2w.setVisible(false);
}
target.add(WCSRequestBuilderPanel.this);
}
});
}
private void buildGridPanel() {
sourceGridContainer = new WebMarkupContainer("sourceGridContainer");
details.add(sourceGridContainer);
manualGrid = new CheckBox("manualGrid", new Model(Boolean.FALSE));
sourceGridContainer.add(manualGrid);
sourceGridRange = new GridPanel("sourceGrid", new PropertyModel(getCoverage, "sourceGridRange"));
sourceGridContainer.add(sourceGridRange);
sourceGridRange.setVisible(false);
sourceGridRange.setOutputMarkupId(true);
// the action that will setup the form once the coverage has been chosen
manualGrid.add(new AjaxFormSubmitBehavior("change") {
@Override
protected void onError(AjaxRequestTarget target) {
onSubmit(target);
}
@Override
protected void onSubmit(AjaxRequestTarget target) {
if(manualGrid.getModelObject() == Boolean.TRUE) {
GridEnvelope2D grid = guessGridLimits();
sourceGridRange.setModelObject(grid);
sourceGridRange.setVisible(true);
} else {
sourceGridRange.setModelObject(null);
sourceGridRange.setVisible(false);
}
target.add(WCSRequestBuilderPanel.this);
}
});
}
protected String getDescribeXML(String coverageId, Version version) {
return "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n"
+ "<DescribeProcess service=\"WPS\" version=\"1.0.0\" "
+ "xmlns=\"http://www.opengis.net/wps/1.0.0\" "
+ "xmlns:ows=\"http://www.opengis.net/ows/1.1\" "
+ "xmlns:xlink=\"http://www.w3.org/1999/xlink\" "
+ "xmlns:xsi=\"http://www.w3.org/2001/XMLSchema-instance\">\n"
+ " <ows:Identifier>" + coverageId + "</ows:Identifier>\n"
+ "</DescribeProcess>";
}
public Component getFeedbackPanel() {
return feedback;
}
GetCoverageRequest getCoverageRequest() {
if(getCoverage.version == Version.v1_0_0) {
if(manualGrid.getModelObject() != Boolean.TRUE) {
getCoverage.sourceGridRange = guessGridLimits();
}
} else {
if(targetLayoutChooser.getModelObject() == TargetLayout.Automatic) {
getCoverage.targetGridToWorld = guessGridToWorld(true);
}
}
return getCoverage;
}
GridEnvelope2D guessGridLimits() {
try {
String coverageName = coverage.getModelObject();
Catalog catalog = GeoServerApplication.get().getCatalog();
CoverageInfo ci = catalog.getCoverageByName(coverageName);
ReferencedEnvelope boundsNative = getCoverage.bounds.transform(ci.getCRS(), true);
MathTransform w2g = ci.getGrid().getGridToCRS().inverse();
Envelope ge = JTS.transform(boundsNative, w2g);
GridEnvelope2D grid = new GridEnvelope2D(new Rectangle(0, 0, (int) ge.getWidth(), (int) ge.getHeight()));
return grid;
} catch(Exception e) {
LOGGER.log(Level.SEVERE, "Failed to guess native grid", e);
error("Failed to guess native grid: " + e.getMessage());
return null;
}
}
AffineTransform guessGridToWorld(boolean resolutionMode) {
try {
String coverageName = coverage.getModelObject();
Catalog catalog = GeoServerApplication.get().getCatalog();
CoverageInfo ci = catalog.getCoverageByName(coverageName);
ReferencedEnvelope nativeBounds = getCoverage.bounds.transform(ci.getCRS(), true);
ReferencedEnvelope targetBounds = nativeBounds.transform(getCoverage.targetCRS, true);
GridEnvelope2D gridLimits = guessGridLimits();
GridGeometry2D gg = new GridGeometry2D(gridLimits, targetBounds);
AffineTransform at = (AffineTransform) gg.getGridToCRS(PixelInCell.CELL_CORNER);
if(resolutionMode) {
return AffineTransform.getScaleInstance(at.getScaleX(), at.getScaleY());
} else {
return at;
}
} catch(Exception e) {
LOGGER.log(Level.SEVERE, "Failed to guess target affine transform", e);
error("Failed to guess native grid: " + e.getMessage());
return null;
}
}
class TargetLayoutRenderer extends ChoiceRenderer {
public Object getDisplayValue(Object object) {
final String name = ((TargetLayout) object).name();
return new StringResourceModel("tl." + name, WCSRequestBuilderPanel.this, null).getString();
}
public String getIdValue(Object object, int index) {
return ((TargetLayout) object).name();
}
}
}