/* * GeoTools - The Open Source Java GIS Toolkit * http://geotools.org * * (C) 2004-2008, Open Source Geospatial Foundation (OSGeo) * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; * version 2.1 of the License. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. */ package org.geotools.data.ows; import java.io.IOException; import java.io.OutputStream; import java.net.MalformedURLException; import java.net.URL; import java.util.Iterator; import java.util.Map; import java.util.Properties; import java.util.StringTokenizer; /** * A class that provides functionality for performing basic requests * * @author Richard Gould * * @source $URL$ */ public abstract class AbstractRequest implements Request{ /** Represents OGC Exception MIME types */ public static final String EXCEPTION_XML = "application/vnd.ogc.se_xml"; //$NON-NLS-1$ protected URL onlineResource; protected Properties properties; /** * Creates an AbstractRequest. * * If properties isn't <code>null</code>, it will use them instead of * creating a new Properties object. * * This constructor will strip all the query parameters off of * onlineResource and put them in the properties map. This allows clients * to provide their own parameters and have them saved and used along with * the OWS specific ones. * * However, certain parameters will be over-written by individual requests * themselves. Examples of such parameters include, but are not limited to: * <ul> * <li>WMTVER * <li>REQUEST * <li>VERSION * <li>SERVICE * </ul> * * @param onlineResource the URL to construct the Request for * @param properties a map of pre-set parameters to be used. Can be null. */ public AbstractRequest(URL onlineResource, Properties properties) { if (properties == null) { this.properties = new Properties(); } else { this.properties = properties; } // Need to strip off the query, as getFinalURL will add it back // on, with all the other properties. If we don't, elements will // be duplicated. int index = onlineResource.toExternalForm().lastIndexOf("?"); //$NON-NLS-1$ String urlWithoutQuery = null; if (index <= 0) { urlWithoutQuery = onlineResource.toExternalForm() + "?"; } else { urlWithoutQuery = onlineResource.toExternalForm().substring(0, index); boolean once=true; // Doing this preserves all of the query parameters while // enforcing the mandatory ones if (onlineResource.getQuery() != null) { StringTokenizer tokenizer = new StringTokenizer(onlineResource.getQuery(), "&"); //$NON-NLS-1$ while (tokenizer.hasMoreTokens()) { String token = tokenizer.nextToken(); String[] param = token.split("="); //$NON-NLS-1$' if (param != null && param.length>0 && param[0] != null) { String key=param[0]; String value; if( param.length==1 ){ // some servers like to keep a few additional settings in their URL // (even though this is not part of the specification we gotta // let them get away with it) if( once ){ urlWithoutQuery += "?"+param[0]+"&"; once = false; } else { urlWithoutQuery += param[0]+"&"; } } else { value = param[1]; setProperty(key.toUpperCase(), value); } } } } if( once ){ urlWithoutQuery += "?"; } } try { this.onlineResource = new URL(urlWithoutQuery); } catch (MalformedURLException e) { throw new RuntimeException("Error parsing URL. This is likely a bug in the code."); } initService(); initRequest(); initVersion(); } /** * @see org.geotools.data.wms.request.Request#getFinalURL() */ public URL getFinalURL() { if (onlineResource.getProtocol().equalsIgnoreCase("file")) { return onlineResource; } String url = onlineResource.toExternalForm(); if (!url.contains("?")) { //$NON-NLS-1$ url = url.concat("?"); //$NON-NLS-1$ } Iterator iter = properties.entrySet().iterator(); while (iter.hasNext()) { Map.Entry entry = (Map.Entry) iter.next(); String value = (String) entry.getValue(); /* * Some servers do not follow the rule that parameter names * must be case insensitive. We will let each specification * implementation deal with it in their own way. */ String param = processKey((String) entry.getKey()); if( value != null && param.length() != 0 ){ param += "=" + value; } if (iter.hasNext()) { param = param.concat("&"); //$NON-NLS-1$ } url = url.concat(param); } try { return new URL(url); } catch (MalformedURLException e) { e.printStackTrace(); //If something is wrong here, this is something wrong with the code above. } return null; } /** * Some Open Web Servers do not abide by the fact that parameter keys should * be case insensitive. * * This method will allow a specification to determine the way that the * parameter keys should be encoded in requests made by the server. * * @param key the key to be processed * @return the key, after being processed. (made upper case, for example) */ protected String processKey (String key ) { return key; } public void setProperty(String name, String value) { if (value == null) { properties.remove(name); } else { properties.setProperty(name, value); } } /** * @return a copy of this request's properties */ public Properties getProperties() { return (Properties) properties.clone(); } protected abstract void initRequest(); /** * Implementing subclass requests must specify their own "SERVICE" value. * Example: setProperty("SERVICE", "WFS"); */ protected abstract void initService(); /** * Sets up the version number for this request. Typically something like * setProperty("VERSION", "1.1.1"); */ protected abstract void initVersion(); /** * Default POST content type is xml */ public String getPostContentType() { return "application/xml"; } /** * Default to not requiring POST. Implementors can override if they need to. */ public void performPostOutput(OutputStream outputStream) throws IOException { } /** * Default to not requiring POST. Implementors can override if they need to. */ public boolean requiresPost() { return false; } }