001: /*
002: * Copyright 2005-2007 Noelios Consulting.
003: *
004: * The contents of this file are subject to the terms of the Common Development
005: * and Distribution License (the "License"). You may not use this file except in
006: * compliance with the License.
007: *
008: * You can obtain a copy of the license at
009: * http://www.opensource.org/licenses/cddl1.txt See the License for the specific
010: * language governing permissions and limitations under the License.
011: *
012: * When distributing Covered Code, include this CDDL HEADER in each file and
013: * include the License file at http://www.opensource.org/licenses/cddl1.txt If
014: * applicable, add the following below this CDDL HEADER, with the fields
015: * enclosed by brackets "[]" replaced with your own identifying information:
016: * Portions Copyright [yyyy] [name of copyright owner]
017: */
018:
019: package com.noelios.restlet.util;
020:
021: import java.io.ByteArrayInputStream;
022: import java.io.IOException;
023: import java.io.InputStream;
024: import java.io.UnsupportedEncodingException;
025: import java.util.ArrayList;
026: import java.util.List;
027: import java.util.Map;
028: import java.util.logging.Level;
029: import java.util.logging.Logger;
030:
031: import org.restlet.data.CharacterSet;
032: import org.restlet.data.Form;
033: import org.restlet.data.Parameter;
034: import org.restlet.resource.Representation;
035: import org.restlet.util.Series;
036:
037: /**
038: * Form reader.
039: *
040: * @author Jerome Louvel (contact@noelios.com)
041: */
042: public class FormReader {
043: /** The form stream. */
044: private InputStream stream;
045:
046: /** The logger to use. */
047: private Logger logger;
048:
049: /** The encoding to use. */
050: private CharacterSet characterSet;
051:
052: /**
053: * Constructor.<br/>In case the representation does not define a character
054: * set, the UTF-8 character set is used.
055: *
056: * @param logger
057: * The logger.
058: * @param representation
059: * The web form content.
060: */
061: public FormReader(Logger logger, Representation representation)
062: throws IOException {
063: this .logger = logger;
064: this .stream = representation.getStream();
065: if (representation.getCharacterSet() != null) {
066: this .characterSet = representation.getCharacterSet();
067: } else {
068: this .characterSet = CharacterSet.UTF_8;
069: }
070: }
071:
072: /**
073: * Constructor.
074: *
075: * @param logger
076: * The logger.
077: * @param query
078: * The query string.
079: * @param characterSet
080: * The supported character encoding.
081: */
082: public FormReader(Logger logger, String query,
083: CharacterSet characterSet) throws IOException {
084: this .logger = logger;
085: this .stream = new ByteArrayInputStream(query.getBytes());
086: this .characterSet = characterSet;
087: }
088:
089: /**
090: * Reads the parameters with the given name. If multiple values are found, a
091: * list is returned created.
092: *
093: * @param name
094: * The parameter name to match.
095: * @return The parameter value or list of values.
096: */
097: @SuppressWarnings("unchecked")
098: public Object readParameter(String name) throws IOException {
099: Parameter param = readNextParameter();
100: Object result = null;
101:
102: while (param != null) {
103: if (param.getName().equals(name)) {
104: if (result != null) {
105: List<Object> values = null;
106:
107: if (result instanceof List) {
108: // Multiple values already found for this parameter
109: values = (List) result;
110: } else {
111: // Second value found for this parameter
112: // Create a list of values
113: values = new ArrayList<Object>();
114: values.add(result);
115: result = values;
116: }
117:
118: if (param.getValue() == null) {
119: values.add(Series.EMPTY_VALUE);
120: } else {
121: values.add(param.getValue());
122: }
123: } else {
124: if (param.getValue() == null) {
125: result = Series.EMPTY_VALUE;
126: } else {
127: result = param.getValue();
128: }
129: }
130: }
131:
132: param = readNextParameter();
133: }
134:
135: this .stream.close();
136: return result;
137: }
138:
139: /**
140: * Reads the first parameter with the given name.
141: *
142: * @param name
143: * The parameter name to match.
144: * @return The parameter value.
145: * @throws IOException
146: */
147: public Parameter readFirstParameter(String name) throws IOException {
148: Parameter param = readNextParameter();
149: Parameter result = null;
150:
151: while ((param != null) && (result == null)) {
152: if (param.getName().equals(name)) {
153: result = param;
154: }
155:
156: param = readNextParameter();
157: }
158:
159: this .stream.close();
160: return result;
161: }
162:
163: /**
164: * Reads the parameters whose name is a key in the given map. If a matching
165: * parameter is found, its value is put in the map. If multiple values are
166: * found, a list is created and set in the map.
167: *
168: * @param parameters
169: * The parameters map controlling the reading.
170: */
171: @SuppressWarnings("unchecked")
172: public void readParameters(Map<String, Object> parameters)
173: throws IOException {
174: Parameter param = readNextParameter();
175: Object currentValue = null;
176:
177: while (param != null) {
178: if (parameters.containsKey(param.getName())) {
179: currentValue = parameters.get(param.getName());
180:
181: if (currentValue != null) {
182: List<Object> values = null;
183:
184: if (currentValue instanceof List) {
185: // Multiple values already found for this parameter
186: values = (List) currentValue;
187: } else {
188: // Second value found for this parameter
189: // Create a list of values
190: values = new ArrayList<Object>();
191: values.add(currentValue);
192: parameters.put(param.getName(), values);
193: }
194:
195: if (param.getValue() == null) {
196: values.add(Series.EMPTY_VALUE);
197: } else {
198: values.add(param.getValue());
199: }
200: } else {
201: if (param.getValue() == null) {
202: parameters.put(param.getName(),
203: Series.EMPTY_VALUE);
204: } else {
205: parameters.put(param.getName(), param
206: .getValue());
207: }
208: }
209: }
210:
211: param = readNextParameter();
212: }
213:
214: this .stream.close();
215: }
216:
217: /**
218: * Reads the next parameter available or null.
219: *
220: * @return The next parameter available or null.
221: */
222: public Parameter readNextParameter() throws IOException {
223: Parameter result = null;
224:
225: try {
226: boolean readingName = true;
227: boolean readingValue = false;
228: StringBuilder nameBuffer = new StringBuilder();
229: StringBuilder valueBuffer = new StringBuilder();
230:
231: int nextChar = 0;
232: while ((result == null) && (nextChar != -1)) {
233: nextChar = this .stream.read();
234:
235: if (readingName) {
236: if (nextChar == '=') {
237: if (nameBuffer.length() > 0) {
238: readingName = false;
239: readingValue = true;
240: } else {
241: throw new IOException(
242: "Empty parameter name detected. Please check your form data");
243: }
244: } else if ((nextChar == '&') || (nextChar == -1)) {
245: if (nameBuffer.length() > 0) {
246: result = FormUtils.create(nameBuffer, null,
247: characterSet);
248: } else if (nextChar == -1) {
249: // Do nothing return null preference
250: } else {
251: throw new IOException(
252: "Empty parameter name detected. Please check your form data");
253: }
254: } else {
255: nameBuffer.append((char) nextChar);
256: }
257: } else if (readingValue) {
258: if ((nextChar == '&') || (nextChar == -1)) {
259: if (valueBuffer.length() > 0) {
260: result = FormUtils.create(nameBuffer,
261: valueBuffer, characterSet);
262: } else {
263: result = FormUtils.create(nameBuffer, null,
264: characterSet);
265: }
266: } else {
267: valueBuffer.append((char) nextChar);
268: }
269: }
270: }
271: } catch (UnsupportedEncodingException uee) {
272: throw new IOException(
273: "Unsupported encoding. Please contact the administrator");
274: }
275:
276: return result;
277: }
278:
279: /**
280: * Reads all the parameters.
281: *
282: * @return The form read.
283: */
284: public Form read() throws IOException {
285: Form result = new Form();
286: Parameter param = readNextParameter();
287:
288: while (param != null) {
289: result.add(param);
290: param = readNextParameter();
291: }
292:
293: this .stream.close();
294: return result;
295: }
296:
297: /**
298: * Adds the parameters into a given form.
299: *
300: * @param form
301: * The target form.
302: */
303: public void addParameters(Form form) {
304: boolean readNext = true;
305: Parameter param = null;
306:
307: // Let's read all form parameters
308: while (readNext) {
309: try {
310: param = readNextParameter();
311:
312: if (param != null) {
313: // Add parsed parameter to the form
314: form.add(param);
315: } else {
316: // Last parameter parsed
317: readNext = false;
318: }
319: } catch (IOException ioe) {
320: getLogger()
321: .log(
322: Level.WARNING,
323: "Unable to parse a form parameter. Skipping it.",
324: ioe);
325: }
326: }
327:
328: try {
329: this .stream.close();
330: } catch (IOException ioe) {
331: getLogger().log(Level.WARNING,
332: "Unable to close the form input stream", ioe);
333: }
334: }
335:
336: /**
337: * Returns the logger.
338: *
339: * @return The logger.
340: */
341: private Logger getLogger() {
342: if (this .logger == null)
343: this .logger = Logger.getLogger(FormReader.class
344: .getCanonicalName());
345: return this.logger;
346: }
347:
348: }
|