/* (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.web.demo;
import static org.geoserver.web.demo.PreviewLayerProvider.ALL;
import static org.geoserver.web.demo.PreviewLayerProvider.COMMON;
import static org.geoserver.web.demo.PreviewLayerProvider.NAME;
import static org.geoserver.web.demo.PreviewLayerProvider.TITLE;
import static org.geoserver.web.demo.PreviewLayerProvider.TYPE;
import java.util.ArrayList;
import java.util.Collections;
import java.util.Comparator;
import java.util.HashMap;
import java.util.HashSet;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
import java.util.Set;
import java.util.logging.Level;
import org.apache.wicket.AttributeModifier;
import org.apache.wicket.Component;
import org.apache.wicket.behavior.AttributeAppender;
import org.apache.wicket.markup.html.WebMarkupContainer;
import org.apache.wicket.markup.html.basic.Label;
import org.apache.wicket.markup.html.image.Image;
import org.apache.wicket.markup.html.link.ExternalLink;
import org.apache.wicket.markup.html.panel.Fragment;
import org.apache.wicket.markup.repeater.RepeatingView;
import org.apache.wicket.model.IModel;
import org.apache.wicket.model.Model;
import org.geoserver.catalog.PublishedType;
import org.geoserver.config.GeoServer;
import org.geoserver.ows.util.ResponseUtils;
import org.geoserver.web.GeoServerApplication;
import org.geoserver.web.GeoServerBasePage;
import org.geoserver.web.demo.PreviewLayer.GMLOutputParams;
import org.geoserver.web.demo.PreviewLayer.PreviewLayerType;
import org.geoserver.web.wicket.GeoServerDataProvider.Property;
import org.geoserver.web.wicket.GeoServerTablePanel;
import org.geoserver.wfs.WFSGetFeatureOutputFormat;
import org.geoserver.wfs.WFSInfo;
import org.geoserver.wms.GetMapOutputFormat;
/**
* Shows a paged list of the available layers and points to previews
* in various formats
*/
public class MapPreviewPage extends GeoServerBasePage {
private static final long serialVersionUID = 1L;
PreviewLayerProvider provider = new PreviewLayerProvider();
GeoServerTablePanel<PreviewLayer> table;
private transient List<String> availableWMSFormats;
//private transient List<String> availableWFSFormats;
/** GML output params computation may be expensive, results are cached in this map */
private transient Map<String, GMLOutputParams> gmlParamsCache = new HashMap<String, GMLOutputParams>();
public MapPreviewPage() {
// output formats for the drop downs
final List<String> wmsOutputFormats = getAvailableWMSFormats();
final List<String> wfsOutputFormats = getAvailableWFSFormats();
// build the table
table = new GeoServerTablePanel<PreviewLayer>("table", provider) {
private static final long serialVersionUID = 1L;
@Override
protected Component getComponentForProperty(String id, IModel<PreviewLayer> itemModel, Property<PreviewLayer> property) {
PreviewLayer layer = itemModel.getObject();
if (property == TYPE) {
Fragment f = new Fragment(id, "iconFragment", MapPreviewPage.this);
f.add(new Image("layerIcon", layer.getIcon()));
return f;
} else if (property == NAME) {
return new Label(id, property.getModel(itemModel));
} else if (property == TITLE) {
return new Label(id, property.getModel(itemModel));
} else if (property == COMMON) {
// openlayers preview
Fragment f = new Fragment(id, "commonLinks", MapPreviewPage.this);
final String olUrl = layer.getWmsLink() + "&format=application/openlayers";
f.add(new ExternalLink("ol", olUrl, "OpenLayers"));
// kml preview
final String kmlUrl = layer.getBaseUrl("wms") + "/kml?layers=" + layer.getName();
f.add(new ExternalLink("kml", kmlUrl, "KML"));
// gml preview (we actually want it only for vector layers)
final String gmlUrl = layer.getGmlLink(gmlParamsCache) + getMaxFeatures();
Component gmlLink = new ExternalLink("gml", gmlUrl, "GML");
f.add(gmlLink);
gmlLink.setVisible(layer.getType() == PreviewLayerType.Vector);
return f;
} else if (property == ALL) {
return buildJSWMSSelect(id, wmsOutputFormats, wfsOutputFormats, layer);
}
throw new IllegalArgumentException(
"Don't know a property named " + property.getName());
}
};
table.setOutputMarkupId(true);
add(table);
}
/**
* Generates the maxFeatures element of the WFS request using the value of
* maxNumberOfFeaturesForPreview. Values <= 0 give no limit.
* @return "&maxFeatures=${maxNumberOfFeaturesForPreview}" or "" if
* maxNumberOfFeaturesForPreview <= 0"
*/
private String getMaxFeatures() {
GeoServer geoserver = getGeoServer();
WFSInfo service = geoserver.getService(WFSInfo.class);
if (service.getMaxNumberOfFeaturesForPreview() > 0) {
return "&maxFeatures="+service.getMaxNumberOfFeaturesForPreview();
}
return "";
}
/**
* Finds out the list of available WMS output formats supported bye the enable
* {@link GetMapOutputFormat} implementations in the application context.
* <p>
* For format, either its {@link GetMapOutputFormat#getMimeType() MIME-Type} or one of its
* {@link GetMapOutputFormat#getOutputFormatNames() alias} will be added to the resulting list.
* If one of them is found to have a translation, that'll be used, otherwise the MIME-Type will
* be used as default.
* </p>
*
* @return the list of available WMS GetMap output formats, giving precedence to the ones for
* which there is a translation.
*/
private List<String> getAvailableWMSFormats() {
List<String> formats = this.availableWMSFormats;
if (formats != null) {
return formats;
}
formats = new ArrayList<String>();
final GeoServerApplication application = getGeoServerApplication();
final List<GetMapOutputFormat> outputFormats;
outputFormats = application.getBeansOfType(GetMapOutputFormat.class);
for (GetMapOutputFormat producer : outputFormats) {
Set<String> producerFormats = new HashSet<String>(producer.getOutputFormatNames());
producerFormats.add(producer.getMimeType());
String knownFormat = producer.getMimeType();
for (String formatName : producerFormats) {
String translatedFormatName = translateFormat("format.wms.", formatName);
if (!formatName.equals(translatedFormatName)) {
knownFormat = formatName;
break;
}
}
formats.add(knownFormat);
}
formats = new ArrayList<String>(new HashSet<String>(formats));
prepareFormatList(formats, new FormatComparator("format.wms."));
this.availableWMSFormats = formats;
return formats;
}
private List<String> getAvailableWFSFormats() {
List<String> formats = new ArrayList<String>();
final GeoServerApplication application = getGeoServerApplication();
for (WFSGetFeatureOutputFormat producer : application
.getBeansOfType(WFSGetFeatureOutputFormat.class)) {
for (String format : producer.getOutputFormats()) {
formats.add(format);
}
}
prepareFormatList(formats, new FormatComparator("format.wfs."));
return formats;
}
private void prepareFormatList(List<String> formats, FormatComparator comparator) {
Collections.sort(formats, comparator);
String prev = null;
for (Iterator<String> it = formats.iterator(); it.hasNext();) {
String format = it.next();
if(prev != null && comparator.compare(format, prev) == 0)
it.remove();
prev = format;
}
}
/**
* Builds a select that reacts like a menu, fully javascript based, for wms outputs
*/
private Component buildJSWMSSelect(String id,
List<String> wmsOutputFormats, List<String> wfsOutputFormats, PreviewLayer layer) {
Fragment f = new Fragment(id, "menuFragment", MapPreviewPage.this);
WebMarkupContainer menu = new WebMarkupContainer("menu");
RepeatingView wmsFormats = new RepeatingView("wmsFormats");
for (int i = 0; i < wmsOutputFormats.size(); i++) {
String wmsOutputFormat = wmsOutputFormats.get(i);
String label = translateFormat("format.wms.", wmsOutputFormat);
// build option with text and value
Label format = new Label(i + "", label);
format.add(new AttributeModifier("value", new Model<String>(ResponseUtils.urlEncode(wmsOutputFormat))));
wmsFormats.add(format);
}
menu.add(wmsFormats);
// the vector ones, it depends, we might have to hide them
boolean vector = layer.groupInfo == null && (layer.layerInfo.getType() == PublishedType.VECTOR
|| layer.layerInfo.getType() == PublishedType.REMOTE);
WebMarkupContainer wfsFormatsGroup = new WebMarkupContainer("wfs");
RepeatingView wfsFormats = new RepeatingView("wfsFormats");
if(vector) {
for (int i = 0; i < wfsOutputFormats.size(); i++) {
String wfsOutputFormat = wfsOutputFormats.get(i);
String label = translateFormat("format.wfs.", wfsOutputFormat);
// build option with text and value
Label format = new Label(i + "", label);
format.add(new AttributeModifier("value", new Model<String>(ResponseUtils.urlEncode(wfsOutputFormat))));
wfsFormats.add(format);
}
}
wfsFormatsGroup.add(wfsFormats);
menu.add(wfsFormatsGroup);
// build the wms request, redirect to it in a new window, reset the selection
String wmsUrl = "'" + layer.getWmsLink()
+ "&format=' + this.options[this.selectedIndex].value";
String wfsUrl = "'" + layer.getBaseUrl("ows") + "?service=WFS&version=1.0.0&request=GetFeature&typeName="
+ layer.getName()
+ getMaxFeatures()
+ "&outputFormat=' + this.options[this.selectedIndex].value";
String choice = "(this.options[this.selectedIndex].parentNode.label == 'WMS') ? " + wmsUrl + " : " + wfsUrl;
menu.add(new AttributeAppender("onchange", new Model<String>("window.open("
+ choice + ");this.selectedIndex=0"), ";"));
f.add(menu);
return f;
}
private String translateFormat(String prefix, String format) {
try {
return getLocalizer().getString(prefix + format, this);
} catch(Exception e) {
LOGGER.log(Level.WARNING, e.getMessage());
return format;
}
}
/**
* Sorts the formats using the i18n translated name
* @author aaime
*
*/
private class FormatComparator implements Comparator<String> {
String prefix;
public FormatComparator(String prefix) {
this.prefix = prefix;
}
public int compare(String f1, String f2) {
String t1 = translateFormat(prefix, f1);
String t2 = translateFormat(prefix, f2);
return t1.compareTo(t2);
}
}
}