001: /*
002: * GeoTools - OpenSource mapping toolkit
003: * http://geotools.org
004: * (C) 2004-2006, GeoTools Project Managment Committee (PMC)
005: *
006: * This library is free software; you can redistribute it and/or
007: * modify it under the terms of the GNU Lesser General Public
008: * License as published by the Free Software Foundation;
009: * version 2.1 of the License.
010: *
011: * This library is distributed in the hope that it will be useful,
012: * but WITHOUT ANY WARRANTY; without even the implied warranty of
013: * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
014: * Lesser General Public License for more details.
015: */
016: package org.geotools.data.ows;
017:
018: import java.io.IOException;
019: import java.io.OutputStream;
020: import java.net.MalformedURLException;
021: import java.net.URL;
022: import java.util.Iterator;
023: import java.util.Map;
024: import java.util.Properties;
025: import java.util.StringTokenizer;
026:
027: /**
028: * A class that provides functionality for performing basic requests
029: *
030: * @author Richard Gould
031: * @source $URL: http://svn.geotools.org/geotools/tags/2.4.1/modules/library/main/src/main/java/org/geotools/data/ows/AbstractRequest.java $
032: */
033: public abstract class AbstractRequest implements Request {
034: /** Represents OGC Exception MIME types */
035: public static final String EXCEPTION_XML = "application/vnd.ogc.se_xml"; //$NON-NLS-1$
036:
037: protected URL onlineResource;
038: protected Properties properties;
039:
040: /**
041: * Creates an AbstractRequest.
042: *
043: * If properties isn't <code>null</code>, it will use them instead of
044: * creating a new Properties object.
045: *
046: * This constructor will strip all the query parameters off of
047: * onlineResource and put them in the properties map. This allows clients
048: * to provide their own parameters and have them saved and used along with
049: * the OWS specific ones.
050: *
051: * However, certain parameters will be over-written by individual requests
052: * themselves. Examples of such parameters include, but are not limited to:
053: * <ul>
054: * <li>WMTVER
055: * <li>REQUEST
056: * <li>VERSION
057: * <li>SERVICE
058: * </ul>
059: *
060: * @param onlineResource the URL to construct the Request for
061: * @param properties a map of pre-set parameters to be used. Can be null.
062: */
063: public AbstractRequest(URL onlineResource, Properties properties) {
064:
065: if (properties == null) {
066: this .properties = new Properties();
067: } else {
068: this .properties = properties;
069: }
070:
071: // Need to strip off the query, as getFinalURL will add it back
072: // on, with all the other properties. If we don't, elements will
073: // be duplicated.
074: int index = onlineResource.toExternalForm().lastIndexOf("?"); //$NON-NLS-1$
075: String urlWithoutQuery = null;
076:
077: if (index <= 0) {
078: urlWithoutQuery = onlineResource.toExternalForm();
079: } else {
080: urlWithoutQuery = onlineResource.toExternalForm()
081: .substring(0, index);
082: }
083:
084: try {
085: this .onlineResource = new URL(urlWithoutQuery);
086: } catch (MalformedURLException e) {
087: throw new RuntimeException(
088: "Error parsing URL. This is likely a bug in the code.");
089: }
090:
091: // Doing this preserves all of the query parameters while
092: // enforcing the mandatory ones
093: if (onlineResource.getQuery() != null) {
094: StringTokenizer tokenizer = new StringTokenizer(
095: onlineResource.getQuery(), "&"); //$NON-NLS-1$
096:
097: while (tokenizer.hasMoreTokens()) {
098: String token = tokenizer.nextToken();
099: String[] param = token.split("="); //$NON-NLS-1$'
100: if (param != null && param.length > 0
101: && param[0] != null) {
102: String key = param[0];
103: String value;
104: if (param.length == 1)
105: value = "";
106: else
107: value = param[1];
108: setProperty(key.toUpperCase(), value);
109: }
110: }
111: }
112:
113: initService();
114: initRequest();
115: initVersion();
116: }
117:
118: /**
119: * @see org.geotools.data.wms.request.Request#getFinalURL()
120: */
121: public URL getFinalURL() {
122: if (onlineResource.getProtocol().equalsIgnoreCase("file")) {
123: return onlineResource;
124: }
125: String url = onlineResource.toExternalForm();
126:
127: if (!url.endsWith("?")) { //$NON-NLS-1$
128: url = url.concat("?"); //$NON-NLS-1$
129: }
130:
131: Iterator iter = properties.entrySet().iterator();
132: while (iter.hasNext()) {
133: Map.Entry entry = (Map.Entry) iter.next();
134:
135: String value = (String) entry.getValue();
136: /*
137: * Some servers do not follow the rule that parameter names
138: * must be case insensitive. We will let each specification
139: * implementation deal with it in their own way.
140: */
141: String param = processKey((String) entry.getKey()) + "="
142: + value;
143:
144: if (iter.hasNext()) {
145: param = param.concat("&"); //$NON-NLS-1$
146: }
147:
148: url = url.concat(param);
149: }
150:
151: try {
152: return new URL(url);
153: } catch (MalformedURLException e) {
154: e.printStackTrace();
155: //If something is wrong here, this is something wrong with the code above.
156: }
157:
158: return null;
159: }
160:
161: /**
162: * Some Open Web Servers do not abide by the fact that parameter keys should
163: * be case insensitive.
164: *
165: * This method will allow a specification to determine the way that the
166: * parameter keys should be encoded in requests made by the server.
167: *
168: * @param key the key to be processed
169: * @return the key, after being processed. (made upper case, for example)
170: */
171: protected String processKey(String key) {
172: return key;
173: }
174:
175: public void setProperty(String name, String value) {
176: if (value == null) {
177: properties.remove(name);
178: } else {
179: properties.setProperty(name, value);
180: }
181: }
182:
183: /**
184: * @return a copy of this request's properties
185: */
186: public Properties getProperties() {
187: return (Properties) properties.clone();
188: }
189:
190: protected abstract void initRequest();
191:
192: /**
193: * Implementing subclass requests must specify their own "SERVICE" value.
194: * Example: setProperty("SERVICE", "WFS");
195: */
196: protected abstract void initService();
197:
198: /**
199: * Sets up the version number for this request. Typically something like
200: * setProperty("VERSION", "1.1.1");
201: */
202: protected abstract void initVersion();
203:
204: /**
205: * Default POST content type is xml
206: */
207: public String getPostContentType() {
208: return "application/xml";
209: }
210:
211: /**
212: * Default to not requiring POST. Implementors can override if they need to.
213: */
214: public void performPostOutput(OutputStream outputStream)
215: throws IOException {
216:
217: }
218:
219: /**
220: * Default to not requiring POST. Implementors can override if they need to.
221: */
222: public boolean requiresPost() {
223: return false;
224: }
225: }
|