📄 getmapkvprequestreader.java
字号:
/* Copyright (c) 2001 - 2007 TOPP - www.openplans.org. All rights reserved.
* This code is licensed under the GPL 2.0 license, availible at the root
* application directory.
*/
package org.geoserver.wms.kvp;
import java.io.ByteArrayInputStream;
import java.io.IOException;
import java.io.InputStream;
import java.net.MalformedURLException;
import java.net.URL;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collections;
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 javax.servlet.http.HttpServletRequest;
import org.geoserver.ows.HttpServletRequestAware;
import org.geoserver.ows.KvpRequestReader;
import org.geoserver.ows.util.KvpUtils;
import org.geotools.data.DataStore;
import org.geotools.data.DefaultQuery;
import org.geotools.data.FeatureReader;
import org.geotools.data.FeatureSource;
import org.geotools.data.Query;
import org.geotools.data.Transaction;
import org.geotools.data.crs.ForceCoordinateSystemFeatureReader;
import org.geotools.data.memory.MemoryDataStore;
import org.geotools.data.wfs.WFSDataStore;
import org.geotools.data.wfs.WFSDataStoreFactory;
import org.geotools.factory.CommonFactoryFinder;
import org.geotools.feature.FeatureType;
import org.geotools.referencing.CRS;
import org.geotools.referencing.crs.DefaultGeographicCRS;
import org.geotools.styling.FeatureTypeConstraint;
import org.geotools.styling.NamedLayer;
import org.geotools.styling.NamedStyle;
import org.geotools.styling.RemoteOWS;
import org.geotools.styling.SLDParser;
import org.geotools.styling.Style;
import org.geotools.styling.StyleAttributeExtractor;
import org.geotools.styling.StyleFactory;
import org.geotools.styling.StyledLayer;
import org.geotools.styling.StyledLayerDescriptor;
import org.geotools.styling.UserLayer;
import org.opengis.filter.Filter;
import org.opengis.filter.FilterFactory;
import org.opengis.referencing.crs.CoordinateReferenceSystem;
import org.vfny.geoserver.global.CoverageInfo;
import org.vfny.geoserver.global.Data;
import org.vfny.geoserver.global.FeatureTypeInfo;
import org.vfny.geoserver.global.MapLayerInfo;
import org.vfny.geoserver.global.TemporaryFeatureTypeInfo;
import org.vfny.geoserver.global.WMS;
import org.vfny.geoserver.util.Requests;
import org.vfny.geoserver.util.SLDValidator;
import org.vfny.geoserver.wms.WmsException;
import org.vfny.geoserver.wms.requests.GetMapKvpReader;
import org.vfny.geoserver.wms.requests.GetMapRequest;
import org.vfny.geoserver.wms.servlets.GetMap;
public class GetMapKvpRequestReader extends KvpRequestReader implements
HttpServletRequestAware {
/**
* get map
*/
GetMap getMap;
/**
* current request
*/
HttpServletRequest httpRequest;
/**
* style factory
*/
StyleFactory styleFactory = CommonFactoryFinder.getStyleFactory(null);
/**
* filter factory
*/
FilterFactory filterFactory = CommonFactoryFinder.getFilterFactory(null);
/**
* Flag to control wether styles are mandatory
*/
boolean styleRequired;
/**
* The WMS service, that we use to pick up base layer definitions
*/
WMS wms;
/**
* The data catalog
*/
Data catalog;
public GetMapKvpRequestReader(GetMap getMap, WMS wms) {
super(GetMapRequest.class);
this.getMap = getMap;
this.wms = wms;
this.catalog = wms.getData();
}
public void setHttpRequest(HttpServletRequest httpRequest) {
this.httpRequest = httpRequest;
}
public void setStyleFactory(StyleFactory styleFactory) {
this.styleFactory = styleFactory;
}
public void setFilterFactory(FilterFactory filterFactory) {
this.filterFactory = filterFactory;
}
public boolean isStyleRequired() {
return styleRequired;
}
public void setStyleRequired(boolean styleRequired) {
this.styleRequired = styleRequired;
}
public Object createRequest() throws Exception {
GetMapRequest request = new GetMapRequest(getMap);
request.setHttpServletRequest(httpRequest);
return request;
}
public Object read(Object request, Map kvp, Map rawKvp) throws Exception {
GetMapRequest getMap = (GetMapRequest) super.read(request, kvp, rawKvp);
// do some additional checks
// srs
String epsgCode = getMap.getSRS();
if (epsgCode != null) {
try {
// set the crs as well
CoordinateReferenceSystem mapcrs = CRS.decode(epsgCode);
getMap.setCrs(mapcrs);
} catch (Exception e) {
// couldnt make it - we send off a service exception with the
// correct info
throw new WmsException(e.getLocalizedMessage(), "InvalidSRS");
}
}
// remote OWS
String remoteOwsType = getMap.getRemoteOwsType();
remoteOwsType = remoteOwsType != null ? remoteOwsType.toUpperCase() : null;
if(remoteOwsType != null && !"WFS".equals(remoteOwsType)) {
throw new WmsException("Unsupported remote OWS type '" + remoteOwsType + "'");
}
// remote OWS url
URL remoteOwsUrl = getMap.getRemoteOwsURL();
if(remoteOwsUrl != null && remoteOwsType == null)
throw new WmsException("REMOTE_OWS_URL specified, but REMOTE_OWS_TYPE is missing");
// layers
String layerParam = (String) kvp.get("LAYERS");
if(layerParam != null)
getMap.setLayers(parseLayers(KvpUtils.readFlat(layerParam), remoteOwsUrl, remoteOwsType));
// raw styles parameter
String stylesParam = (String) kvp.get("STYLES");
List styleNameList = Collections.EMPTY_LIST;
if(stylesParam != null)
styleNameList = KvpUtils.readFlat(stylesParam);
// styles
// process SLD_BODY, SLD, then STYLES parameter
if (getMap.getSldBody() != null) {
if (LOGGER.isLoggable(Level.FINE)) {
LOGGER.fine("Getting layers and styles from SLD_BODY");
}
if (getMap.getValidateSchema().booleanValue()) {
List errors = validateSld(new ByteArrayInputStream(getMap
.getSldBody().getBytes()));
if (errors.size() != 0) {
throw new WmsException(SLDValidator.getErrorMessage(
new ByteArrayInputStream(getMap.getSldBody()
.getBytes()), errors));
}
}
StyledLayerDescriptor sld = parseSld(new ByteArrayInputStream(
getMap.getSldBody().getBytes()));
processSld(getMap, sld, styleNameList);
} else if (getMap.getSld() != null) {
if (LOGGER.isLoggable(Level.FINE)) {
LOGGER.fine("Getting layers and styles from reomte SLD");
}
URL sldUrl = getMap.getSld();
if (getMap.getValidateSchema().booleanValue()) {
InputStream input = Requests.getInputStream(sldUrl);
List errors = null;
try {
errors = validateSld(input);
} finally {
input.close();
}
if ((errors != null) && (errors.size() != 0)) {
input = Requests.getInputStream(sldUrl);
try {
throw new WmsException(SLDValidator.getErrorMessage(
input, errors));
} finally {
input.close();
}
}
}
// JD: GEOS-420, Wrap the sldUrl in getINputStream method in order
// to do compression
InputStream input = Requests.getInputStream(sldUrl);
try {
StyledLayerDescriptor sld = parseSld(input);
processSld(getMap, sld, styleNameList);
} finally {
input.close();
}
} else {
if (LOGGER.isLoggable(Level.FINE)) {
LOGGER.fine("Getting layers and styles from LAYERS and STYLES");
}
// ok, parse the styles parameter in isolation
if(styleNameList.size() > 0)
getMap.setStyles(parseStyles(styleNameList));
// first, expand base layers and default styles
if (getMap.getLayers() != null) {
List oldLayers = new ArrayList(Arrays
.asList(getMap.getLayers()));
List oldStyles = getMap.getStyles() != null ? new ArrayList(
getMap.getStyles()) : new ArrayList();
List newLayers = new ArrayList();
List newStyles = new ArrayList();
for (int i = 0; i < oldLayers.size(); i++) {
MapLayerInfo info = (MapLayerInfo) oldLayers.get(i);
Style style = oldStyles.isEmpty() ? null
: (Style) oldStyles.get(i);
if (info.getType() == MapLayerInfo.TYPE_BASEMAP) {
List subLayers = info.getSubLayers();
newLayers.addAll(subLayers);
List currStyles = info.getStyles();
for (int j = 0; j < subLayers.size(); j++) {
MapLayerInfo currLayer = (MapLayerInfo) subLayers
.get(j);
Style currStyle = currStyles.isEmpty() ? null
: (Style) currStyles.get(j);
if (currStyle != null)
newStyles.add(currStyle);
else
newStyles.add(currLayer.getDefaultStyle());
}
} else {
newLayers.add(info);
if (style != null)
newStyles.add(style);
else
newStyles.add(info.getDefaultStyle());
}
}
getMap.setLayers(newLayers);
getMap.setStyles(newStyles);
}
// then proceed with standard processing
MapLayerInfo[] layers = getMap.getLayers();
if ((layers != null) && (layers.length > 0)) {
List styles = getMap.getStyles();
if (layers.length != styles.size()) {
String msg = layers.length + " layers requested, but found "
+ styles.size() + " styles specified. ";
throw new WmsException(msg, getClass().getName());
}
for (int i = 0; i < getMap.getStyles().size(); i++) {
Style currStyle = (Style) getMap.getStyles().get(i);
if(currStyle == null)
throw new WmsException("Could not find a style for layer "
+ getMap.getLayers()[i].getName()
+ ", either none was specified or no default style is available for it",
"NoDefaultStyle");
checkStyle(currStyle, layers[i]);
if (LOGGER.isLoggable(Level.FINE)) {
LOGGER.fine(new StringBuffer("establishing ")
.append(currStyle.getName()).append(
" style for ").append(
layers[i].getName()).toString());
}
}
}
}
// filters
// in case of a mixed request, get with sld in post body, layers
// are not parsed, so we can't parse filters neither...
if ((getMap.getLayers() != null) && (getMap.getLayers().length > 0)) {
List filters = (getMap.getFilter() != null) ? getMap.getFilter()
: Collections.EMPTY_LIST;
List cqlFilters = (getMap.getCQLFilter() != null) ? getMap
.getCQLFilter() : Collections.EMPTY_LIST;
List featureId = (getMap.getFeatureId() != null) ? getMap
.getFeatureId() : Collections.EMPTY_LIST;
if (!featureId.isEmpty()) {
if (!filters.isEmpty()) {
throw new WmsException("GetMap KVP request contained "
+ "conflicting filters. Filter: " + filters
+ ", fid: " + featureId);
}
Set ids = new HashSet();
for (Iterator i = featureId.iterator(); i.hasNext();) {
ids.add(filterFactory.featureId((String) i.next()));
}
filters = Collections.singletonList(filterFactory.id(ids));
}
if (!cqlFilters.isEmpty()) {
if (!filters.isEmpty()) {
throw new WmsException("GetMap KVP request contained "
+ "conflicting filters. Filter: " + filters
+ ", fid: " + featureId + ", cql: " + cqlFilters);
}
filters = cqlFilters;
}
int numLayers = getMap.getLayers().length;
if (!filters.isEmpty() && (numLayers != filters.size())) {
// as in wfs getFeatures, perform lenient parsing, if just one
// filter, it gets
// applied to all layers
if (filters.size() == 1) {
Filter f = (Filter) filters.get(0);
filters = new ArrayList(numLayers);
for (int i = 0; i < numLayers; i++) {
filters.add(f);
}
} else {
String msg = numLayers
+ " layers requested, but found "
+ filters.size()
+ " filters specified. "
+ "When you specify the FILTER parameter, you must provide just one, \n"
+ " that will be applied to all layers, or exactly one for each requested layer";
throw new WmsException(msg, getClass().getName());
}
}
getMap.setFilter(filters);
}
// set the raw params used to create the request
getMap.setRawKvp(rawKvp);
return getMap;
}
/**
* validates an sld document.
*
*/
private List validateSld(InputStream input) {
// user requested to validate the schema.
SLDValidator validator = new SLDValidator();
return validator.validateSLD(input, httpRequest.getSession()
.getServletContext());
}
/**
* Parses an sld document.
*/
private StyledLayerDescriptor parseSld(InputStream input) {
SLDParser parser = new SLDParser(styleFactory, input);
return parser.parseSLD();
}
public void processSld(final GetMapRequest request,
final StyledLayerDescriptor sld, final List styleNames) throws WmsException {
if(request.getLayers() == null || request.getLayers().length == 0) {
processStandaloneSld(request, sld);
} else {
processLibrarySld(request, sld, styleNames);
}
}
/**
* Looks in <code>sld</code> for the layers and styles to use in the map
* composition and sets them to the <code>request</code>
*
* <p>
* This method processes SLD in library mode
* Library mode engages when "SLD" or "SLD_BODY" are used in conjuction with
* LAYERS and STYLES. From the spec: <br>
* <cite> When an SLD is used as a style
* library, the STYLES CGI parameter is interpreted in the usual way in the
* GetMap request, except that the handling of the style names is organized
* so that the styles defined in the SLD take precedence over the named
* styles stored within the map server. The user-defined SLD styles can be
* given names and they can be marked as being the default style for a
* layer. To be more specific, if a style named 揅enterLine
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -