⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 getmapkvprequestreader.java

📁 电子地图服务器,搭建自己的地图服务
💻 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 + -