KickJava   Java API By Example, From Geeks To Geeks.

Java > Open Source Codes > org > directwebremoting > dwrp > ParseUtil


1 /*
2  * Copyright 2005 Joe Walker
3  *
4  * Licensed under the Apache License, Version 2.0 (the "License");
5  * you may not use this file except in compliance with the License.
6  * You may obtain a copy of the License at
7  *
8  * http://www.apache.org/licenses/LICENSE-2.0
9  *
10  * Unless required by applicable law or agreed to in writing, software
11  * distributed under the License is distributed on an "AS IS" BASIS,
12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13  * See the License for the specific language governing permissions and
14  * limitations under the License.
15  */

16 package org.directwebremoting.dwrp;
17
18 import java.io.BufferedReader JavaDoc;
19 import java.io.IOException JavaDoc;
20 import java.io.InputStreamReader JavaDoc;
21 import java.util.HashMap JavaDoc;
22 import java.util.Iterator JavaDoc;
23 import java.util.Map JavaDoc;
24 import java.util.StringTokenizer JavaDoc;
25
26 import javax.servlet.http.HttpServletRequest JavaDoc;
27
28 import org.directwebremoting.extend.ServerException;
29 import org.directwebremoting.util.LocalUtil;
30 import org.directwebremoting.util.Logger;
31 import org.directwebremoting.util.Messages;
32
33 /**
34  * Utilities to parse GET and POST requests from the DWR javascript section.
35  * @author Joe Walker [joe at getahead dot ltd dot uk]
36  */

37 public class ParseUtil
38 {
39     /**
40      * Parse an HTTP POST request to fill out the scriptName, methodName and
41      * paramList properties. This method should not fail unless it will not
42      * be possible to return any sort of error to the user. Failure cases should
43      * be handled by the <code>checkParams()</code> method.
44      * @param req The original browser's request
45      * @return The equivalent of HttpServletRequest.getParameterMap() for now
46      * @throws ServerException If reading from the request body stream fails
47      */

48     public static Map JavaDoc parsePost(HttpServletRequest JavaDoc req) throws ServerException
49     {
50         Map JavaDoc paramMap = new HashMap JavaDoc();
51
52         BufferedReader JavaDoc in = null;
53         try
54         {
55             // I've had reports of data loss in Tomcat 5.0 that relate to this bug
56
// http://issues.apache.org/bugzilla/show_bug.cgi?id=27447
57
// See mails to users@dwr.dev.java.net:
58
// Subject: "Tomcat 5.x read-ahead problem"
59
// From: CAKALIC, JAMES P [AG-Contractor/1000]
60
// It would be more normal to do the following:
61
// BufferedReader in = req.getReader();
62
in = new BufferedReader JavaDoc(new InputStreamReader JavaDoc(req.getInputStream()));
63
64             while (true)
65             {
66                 String JavaDoc line = in.readLine();
67
68                 if (line == null)
69                 {
70                     break;
71                 }
72
73                 if (line.indexOf('&') != -1)
74                 {
75                     // If there are any &s then this must be iframe post and all the
76
// parameters have got dumped on one line, split with &
77
log.debug("Using iframe POST mode");
78                     StringTokenizer JavaDoc st = new StringTokenizer JavaDoc(line, "&");
79                     while (st.hasMoreTokens())
80                     {
81                         String JavaDoc part = st.nextToken();
82                         part = LocalUtil.decode(part);
83
84                         parsePostLine(part, paramMap);
85                     }
86                 }
87                 else
88                 {
89                     // Horay, this is a normal one!
90
parsePostLine(line, paramMap);
91                 }
92             }
93         }
94         catch (Exception JavaDoc ex)
95         {
96             throw new ServerException(Messages.getString("ParseUtil.InputReadFailed"), ex);
97         }
98         finally
99         {
100             if (in != null)
101             {
102                 try
103                 {
104                     in.close();
105                 }
106                 catch (IOException JavaDoc ex)
107                 {
108                     // Ignore
109
}
110             }
111         }
112
113         // If there is only 1 param then this must be a broken Safari. All
114
// the parameters have got dumped on one line split with \n
115
// See: http://bugzilla.opendarwin.org/show_bug.cgi?id=3565
116
// https://dwr.dev.java.net/issues/show_bug.cgi?id=93
117
// http://jira.atlassian.com/browse/JRA-8354
118
// http://developer.apple.com/internet/safari/uamatrix.html
119
if (paramMap.size() == 1)
120         {
121             // This looks like a broken Mac where the line endings are confused
122
log.debug("Using Broken Safari POST mode");
123
124             // Iterators insist that we call hasNext() before we start
125
Iterator JavaDoc it = paramMap.keySet().iterator();
126             if (!it.hasNext())
127             {
128                 throw new IllegalStateException JavaDoc("No entries in non empty map!");
129             }
130
131             // So get the first
132
String JavaDoc key = (String JavaDoc) it.next();
133             String JavaDoc value = (String JavaDoc) paramMap.get(key);
134             String JavaDoc line = key + ProtocolConstants.INBOUND_DECL_SEPARATOR + value;
135
136             StringTokenizer JavaDoc st = new StringTokenizer JavaDoc(line, "\n");
137             while (st.hasMoreTokens())
138             {
139                 String JavaDoc part = st.nextToken();
140                 part = LocalUtil.decode(part);
141
142                 parsePostLine(part, paramMap);
143             }
144         }
145
146         return paramMap;
147     }
148
149     /**
150      * Sort out a single line in a POST request
151      * @param line The line to parse
152      * @param paramMap The map to add parsed parameters to
153      */

154     private static void parsePostLine(String JavaDoc line, Map JavaDoc paramMap)
155     {
156         if (line.length() == 0)
157         {
158             return;
159         }
160
161         int sep = line.indexOf(ProtocolConstants.INBOUND_DECL_SEPARATOR);
162         if (sep == -1)
163         {
164             log.warn("Missing separator in POST line: " + line);
165         }
166         else
167         {
168             String JavaDoc key = line.substring(0, sep);
169             String JavaDoc value = line.substring(sep + ProtocolConstants.INBOUND_DECL_SEPARATOR.length());
170
171             paramMap.put(key, value);
172         }
173     }
174
175     /**
176      * Parse an HTTP GET request to fill out the scriptName, methodName and
177      * paramList properties. This method should not fail unless it will not
178      * be possible to return any sort of error to the user. Failure cases should
179      * be handled by the <code>checkParams()</code> method.
180      * @param req The original browser's request
181      * @return Simply HttpRequest.getParameterMap() for now
182      * @throws ServerException If the parsing fails
183      */

184     public static Map JavaDoc parseGet(HttpServletRequest JavaDoc req) throws ServerException
185     {
186         Map JavaDoc convertedMap = new HashMap JavaDoc();
187         Map JavaDoc paramMap = req.getParameterMap();
188
189         for (Iterator JavaDoc it = paramMap.entrySet().iterator(); it.hasNext();)
190         {
191             Map.Entry JavaDoc entry = (Map.Entry JavaDoc) it.next();
192             String JavaDoc key = (String JavaDoc) entry.getKey();
193             String JavaDoc[] array = (String JavaDoc[]) entry.getValue();
194
195             if (array.length == 1)
196             {
197                 convertedMap.put(key, array[0]);
198             }
199             else
200             {
201                 throw new ServerException(Messages.getString("ParseUtil.MultiValues", key));
202             }
203         }
204
205         return convertedMap;
206     }
207
208     /**
209      * The javascript outbound marshaller prefixes the toString value with a
210      * colon and the original type information. This undoes that.
211      * @param data The string to be split up
212      * @return A string array containing the split data
213      */

214     public static String JavaDoc[] splitInbound(String JavaDoc data)
215     {
216         String JavaDoc[] reply = new String JavaDoc[2];
217
218         int colon = data.indexOf(ProtocolConstants.INBOUND_TYPE_SEPARATOR);
219         if (colon == -1)
220         {
221             log.error("Missing : in conversion data (" + data + ')');
222             reply[LocalUtil.INBOUND_INDEX_TYPE] = ProtocolConstants.TYPE_STRING;
223             reply[LocalUtil.INBOUND_INDEX_VALUE] = data;
224         }
225         else
226         {
227             reply[LocalUtil.INBOUND_INDEX_TYPE] = data.substring(0, colon);
228             reply[LocalUtil.INBOUND_INDEX_VALUE] = data.substring(colon + 1);
229         }
230
231         return reply;
232     }
233
234     /**
235      * The log stream
236      */

237     private static final Logger log = Logger.getLogger(ParseUtil.class);
238 }
239
Popular Tags