001: /* Copyright (c) 2001 - 2007 TOPP - www.openplans.org. All rights reserved.
002: * This code is licensed under the GPL 2.0 license, availible at the root
003: * application directory.
004: */
005: package org.geoserver.wms.util;
006:
007: import java.lang.reflect.Array;
008: import java.util.Collection;
009: import java.util.HashMap;
010: import java.util.Iterator;
011: import java.util.List;
012: import java.util.Map;
013:
014: import javax.servlet.http.HttpServletRequest;
015:
016: import org.geoserver.ows.util.KvpUtils;
017: import org.geotools.map.MapLayer;
018: import org.geotools.styling.Style;
019: import org.vfny.geoserver.global.GeoServer;
020: import org.vfny.geoserver.global.MapLayerInfo;
021: import org.vfny.geoserver.util.Requests;
022: import org.vfny.geoserver.wms.WMSMapContext;
023: import org.vfny.geoserver.wms.requests.GetMapRequest;
024: import org.vfny.geoserver.wms.requests.WMSRequest;
025:
026: import com.vividsolutions.jts.geom.Envelope;
027:
028: /**
029: * Utility class for creating wms requests.
030: *
031: * @author Justin Deoliveira, The Open Planning Project, jdeolive@openplans.org
032: * @see Requests
033: */
034: public class WMSRequests {
035: /**
036: * Returns the base url for a wms request, something of the form:
037: * <pre><protocol>://<server>:<port>/<context>/wms</pre>
038: *
039: * @param request The request.
040: * @param geoServer GeoServer configuration.
041: *
042: * @return The base for wms requests.
043: */
044: public static String getBaseUrl(HttpServletRequest request,
045: GeoServer geoServer) {
046: String baseUrl = Requests.getBaseUrl(request, geoServer);
047: baseUrl = Requests.appendContextPath(baseUrl, "wms");
048:
049: return baseUrl;
050: }
051:
052: /**
053: * Returns the base url for a wms request, something of the form:
054: * <pre><protocol>://<server>:<port>/<context>/wms</pre>
055: *
056: * @param req The wms request.
057: *
058: * @return The base for wms requests.
059: */
060: public static String getBaseUrl(WMSRequest request) {
061: return getBaseUrl(request.getHttpServletRequest(), request
062: .getGeoServer());
063: }
064:
065: /**
066: * Returns the base url for a wms request, something of the form:
067: * <pre><protocol>://<server>:<port>/<context>/wms</pre>
068: *
069: * @param map A wms map context.
070: *
071: * @return The base for wms requests.
072: */
073: public static String getBaseUrl(WMSMapContext map) {
074: return getBaseUrl(map.getRequest());
075: }
076:
077: /**
078: * Encodes the url of a GetMap request pointing to a tile cache if one
079: * exists.
080: * <p>
081: * The tile cache location is determined from {@link GeoServer#getTileCache()}.
082: * If the above method returns null this method falls back to the behaviour
083: * of {@link #getGetMapUrl(WMSMapContext, MapLayer, Envelope, String[])}.
084: * </p>
085: * <p>
086: * If the <tt>layer</tt> argument is <code>null</code>, the request is
087: * made including all layers in the <tt>mapContexT</tt>.
088: * </p>
089: * <p>
090: * If the <tt>bbox</tt> argument is <code>null</code>. {@link WMSMapContext#getAreaOfInterest()}
091: * is used for the bbox parameter.
092: * </p>
093: *
094: * @param req The getMap request.
095: * @param layer The Map layer, may be <code>null</code>.
096: * @param bbox The bounding box of the request, may be <code>null</code>.
097: * @param kvp Additional or overidding kvp parameters, may be <code>null</code>
098: *
099: * @return The full url for a getMap request.
100: */
101: public static String getTiledGetMapUrl(GetMapRequest req,
102: MapLayer layer, Envelope bbox, String[] kvp) {
103: String baseUrl = Requests.getTileCacheBaseUrl(req
104: .getHttpServletRequest(), req.getGeoServer());
105:
106: if (baseUrl == null) {
107: return getGetMapUrl(req, layer, bbox, kvp);
108:
109: }
110:
111: return getGetMapUrl(baseUrl, req, layer.getTitle(), layer
112: .getStyle().getName(), bbox, kvp);
113: }
114:
115: /**
116: * Encodes the url of a GetMap request.
117: * <p>
118: * If the <tt>layer</tt> argument is <code>null</code>, the request is
119: * made including all layers in the <tt>mapContexT</tt>.
120: * </p>
121: * <p>
122: * If the <tt>bbox</tt> argument is <code>null</code>. {@link WMSMapContext#getAreaOfInterest()}
123: * is used for the bbox parameter.
124: * </p>
125: *
126: * @param req The getMap request
127: * @param layer The Map layer, may be <code>null</code>.
128: * @param bbox The bounding box of the request, may be <code>null</code>.
129: * @param kvp Additional or overidding kvp parameters, may be <code>null</code>
130: *
131: * @return The full url for a getMap request.
132: */
133: public static String getGetMapUrl(GetMapRequest req,
134: MapLayer layer, Envelope bbox, String[] kvp) {
135: //base url
136: String baseUrl = getBaseUrl(req);
137:
138: String layerName = layer != null ? layer.getTitle() : null;
139: String style = layer != null ? layer.getStyle().getTitle()
140: : null;
141:
142: return getGetMapUrl(baseUrl, req, layerName, style, bbox, kvp);
143: }
144:
145: /**
146: * Encodes the url of a GetMap request.
147: * <p>
148: * If the <tt>layer</tt> argument is <code>null</code>, the request is
149: * made including all layers in the <tt>mapContexT</tt>.
150: * </p>
151: * <p>
152: * If the <tt>style</tt> argument is not <code>null</code> and the <tt>layer</tt>
153: * argument is <code>null</code>, then the default style for that layer
154: * is used.
155: * </p>
156: * <p>
157: * If the <tt>bbox</tt> argument is <code>null</code>. {@link WMSMapContext#getAreaOfInterest()}
158: * is used for the bbox parameter.
159: * </p>
160: *
161: * @param req The getMap request
162: * @param layer The layer name, may be <code>null</code>.
163: * @param style The style name, may be <code>null</code>
164: * @param bbox The bounding box of the request, may be <code>null</code>.
165: * @param kvp Additional or overidding kvp parameters, may be <code>null</code>
166: *
167: * @return The full url for a getMap request.
168: */
169: public static String getGetMapUrl(GetMapRequest req, String layer,
170: String style, Envelope bbox, String[] kvp) {
171: //base url
172: String baseUrl = getBaseUrl(req);
173:
174: return getGetMapUrl(baseUrl, req, layer, style, bbox, kvp);
175: }
176:
177: /**
178: * Encodes the url of a GetLegendGraphic request.
179: *
180: * @param req The wms request.
181: * @param layer The Map layer, may not be <code>null</code>.
182: * @param kvp Additional or overidding kvp parameters, may be <code>null</code>
183: *
184: * @return The full url for a getMap request.
185: */
186: public static String getGetLegendGraphicUrl(WMSRequest req,
187: MapLayer layer, String[] kvp) {
188: //parameters
189: HashMap params = new HashMap();
190:
191: params.put("service", "wms");
192: params.put("request", "GetLegendGraphic");
193: params.put("version", "1.1.1");
194: params.put("format", "image/png");
195: params.put("layer", layer.getTitle());
196: params.put("style", layer.getStyle().getName());
197: params.put("height", "20");
198: params.put("width", "20");
199:
200: //overrides / additions
201: for (int i = 0; (kvp != null) && (i < kvp.length); i += 2) {
202: params.put(kvp[i], kvp[i + 1]);
203: }
204:
205: return encode(getBaseUrl(req), params);
206:
207: }
208:
209: /**
210: * Helper method for encoding GetMap request.
211: *
212: */
213: static String getGetMapUrl(String baseUrl, GetMapRequest req,
214: String layer, String style, Envelope bbox, String[] kvp) {
215: //parameters
216: HashMap params = new HashMap();
217:
218: params.put("service", "wms");
219: params.put("request", "GetMap");
220: params.put("version", "1.1.1");
221:
222: params.put("format", req.getFormat());
223:
224: StringBuffer layers = new StringBuffer();
225: StringBuffer styles = new StringBuffer();
226:
227: if (layer != null) {
228: layers.append(layer);
229: if (style != null) {
230: styles.append(style);
231: } else {
232: //use default for layer
233: for (int i = 0; i < req.getLayers().length; i++) {
234: if (layer.equals(req.getLayers()[i].getName())) {
235: styles.append(req.getLayers()[i]
236: .getDefaultStyle().getName());
237: }
238: }
239: }
240: } else {
241: //no layer specified, use layers+styles specified by request
242: for (int i = 0; i < req.getLayers().length; i++) {
243: MapLayerInfo mapLayer = req.getLayers()[i];
244: Style s = (Style) req.getStyles().get(0);
245:
246: layers.append(mapLayer.getName()).append(",");
247: styles.append(s.getName()).append(",");
248:
249: }
250:
251: layers.setLength(layers.length() - 1);
252: styles.setLength(styles.length() - 1);
253: }
254:
255: params.put("layers", layers.toString());
256: params.put("styles", styles.toString());
257:
258: //filters, we grab them from the original raw kvp since re-encoding
259: // them from objects is kind of silly
260: if (layer != null) {
261: //only get filters for hte layer
262: int index = 0;
263: for (; index < req.getLayers().length; index++) {
264: if (req.getLayers()[index].getName().equals(layer)) {
265: break;
266: }
267: }
268:
269: if (req.getRawKvp().get("filter") != null) {
270: //split out the filter we need
271: List filters = KvpUtils.readFlat((String) req
272: .getRawKvp().get("filter"),
273: KvpUtils.OUTER_DELIMETER);
274: params.put("filter", filters.get(index));
275: } else if (req.getRawKvp().get("cql_filter") != null) {
276: //split out the filter we need
277: List filters = KvpUtils.readFlat((String) req
278: .getRawKvp().get("cql_filter"),
279: KvpUtils.CQL_DELIMITER);
280: params.put("cql_filter", filters.get(index));
281: } else if (req.getRawKvp().get("featureid") != null) {
282: //semantics of feautre id slightly different, replicate entire value
283: params.put("featureid", req.getRawKvp()
284: .get("featureid"));
285: }
286:
287: } else {
288: //include all
289: if (req.getRawKvp().get("filter") != null) {
290: params.put("filter", req.getRawKvp().get("filter"));
291: } else if (req.getRawKvp().get("cql_filter") != null) {
292: params.put("cql_filter", req.getRawKvp().get(
293: "cql_filter"));
294: } else if (req.getRawKvp().get("featureid") != null) {
295: params.put("featureid", req.getRawKvp()
296: .get("featureid"));
297: }
298: }
299:
300: //image params
301: params.put("height", String.valueOf(req.getHeight()));
302: params.put("width", String.valueOf(req.getWidth()));
303: params.put("transparent", "" + req.isTransparent());
304:
305: //bbox
306: if (bbox == null) {
307: bbox = req.getBbox();
308: }
309: if (bbox != null) {
310: params.put("bbox", encode(bbox));
311: }
312:
313: //srs
314: params.put("srs", req.getSRS());
315:
316: //format options
317: if (req.getFormatOptions() != null
318: && !req.getFormatOptions().isEmpty()) {
319: params.put("format_options", encodeFormatOptions(req
320: .getFormatOptions()));
321: }
322:
323: //overrides / additions
324: for (int i = 0; (kvp != null) && (i < kvp.length); i += 2) {
325: params.put(kvp[i], kvp[i + 1]);
326: }
327:
328: return encode(baseUrl, params);
329: }
330:
331: /**
332: * Encodes a map of formation options to be used as the value in a kvp.
333: *
334: * @param formatOptions The map of formation options.
335: *
336: * @return A string of the form 'key1:value1,value2;key2:value1;...'
337: *
338: */
339: public static String encodeFormatOptions(Map formatOptions) {
340: StringBuffer sb = new StringBuffer();
341: for (Iterator e = formatOptions.entrySet().iterator(); e
342: .hasNext();) {
343: Map.Entry entry = (Map.Entry) e.next();
344: String key = (String) entry.getKey();
345: Object val = entry.getValue();
346:
347: sb.append(key).append(":");
348: if (val instanceof Collection) {
349: Iterator i = ((Collection) val).iterator();
350: while (i.hasNext()) {
351: sb.append(i.next()).append(",");
352: }
353: sb.setLength(sb.length() - 1);
354: } else if (val.getClass().isArray()) {
355: int len = Array.getLength(val);
356: for (int i = 0; i < len; i++) {
357: Object o = Array.get(val, i);
358: if (o != null) {
359: sb.append(o).append(",");
360: }
361: }
362: sb.setLength(sb.length() - 1);
363: } else {
364: sb.append(val.toString());
365: }
366: sb.append(";");
367: }
368:
369: sb.setLength(sb.length());
370: return sb.toString();
371: }
372:
373: /**
374: * Helper method to encode an envelope to be used in a wms request.
375: */
376: static String encode(Envelope box) {
377: return new StringBuffer().append(box.getMinX()).append(",")
378: .append(box.getMinY()).append(",")
379: .append(box.getMaxX()).append(",")
380: .append(box.getMaxY()).toString();
381: }
382:
383: /**
384: * Helper method for encoding a baseurl and some kvp params into a single
385: * url.
386: *
387: * @param baseUrl The base url of the encoded request.
388: * @param kvp The key value pairts of the request.
389: *
390: * @return The full request url.
391: */
392: static String encode(String baseUrl, Map kvp) {
393: StringBuffer query = new StringBuffer();
394:
395: for (Iterator e = kvp.entrySet().iterator(); e.hasNext();) {
396: Map.Entry entry = (Map.Entry) e.next();
397: query.append(entry.getKey()).append("=").append(
398: entry.getValue()).append("&");
399: }
400:
401: query.setLength(query.length() - 1);
402: return Requests.appendQueryString(baseUrl, query.toString());
403: }
404: }
|