1 /***
2 * Redistribution and use of this software and associated documentation
3 * ("Software"), with or without modification, are permitted provided
4 * that the following conditions are met:
5 *
6 * 1. Redistributions of source code must retain copyright
7 * statements and notices. Redistributions must also contain a
8 * copy of this document.
9 *
10 * 2. Redistributions in binary form must reproduce the
11 * above copyright notice, this list of conditions and the
12 * following disclaimer in the documentation and/or other
13 * materials provided with the distribution.
14 *
15 * 3. The name "Exolab" must not be used to endorse or promote
16 * products derived from this Software without prior written
17 * permission of Exoffice Technologies. For written permission,
18 * please contact info@exolab.org.
19 *
20 * 4. Products derived from this Software may not be called "Exolab"
21 * nor may "Exolab" appear in their names without prior written
22 * permission of Exoffice Technologies. Exolab is a registered
23 * trademark of Exoffice Technologies.
24 *
25 * 5. Due credit should be given to the Exolab Project
26 * (http://www.exolab.org/).
27 *
28 * THIS SOFTWARE IS PROVIDED BY EXOFFICE TECHNOLOGIES AND CONTRIBUTORS
29 * ``AS IS'' AND ANY EXPRESSED OR IMPLIED WARRANTIES, INCLUDING, BUT
30 * NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
31 * FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL
32 * EXOFFICE TECHNOLOGIES OR ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT,
33 * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
34 * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
35 * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
36 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
37 * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
38 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED
39 * OF THE POSSIBILITY OF SUCH DAMAGE.
40 *
41 * Copyright 2003-2005 (C) Exoffice Technologies Inc. All Rights Reserved.
42 *
43 * $Id: URIHelper.java,v 1.4 2005/12/01 13:44:38 tanderson Exp $
44 */
45 package org.exolab.jms.net.uri;
46
47 import java.net.InetAddress;
48 import java.net.UnknownHostException;
49 import java.util.HashMap;
50 import java.util.Iterator;
51 import java.util.Map;
52 import java.util.StringTokenizer;
53
54 import org.exolab.jms.common.security.BasicPrincipal;
55
56
57 /***
58 * Helper for operations on URIs.
59 *
60 * @author <a href="mailto:tma@netspace.net.au">Tim Anderson</a>
61 * @version $Revision: 1.4 $ $Date: 2005/12/01 13:44:38 $
62 * @see URI
63 */
64 public final class URIHelper {
65
66 /***
67 * Prevent construction of helper class.
68 */
69 private URIHelper() {
70 }
71
72 /***
73 * Helper to create an URI.
74 *
75 * @param scheme the URI scheme
76 * @param host the host
77 * @param port the port
78 * @return a new URI
79 * @throws InvalidURIException if any argument is invalid
80 */
81 public static URI create(String scheme, String host, int port)
82 throws InvalidURIException {
83 return create(scheme, host, port, "/");
84 }
85
86 /***
87 * Helper to create an URI.
88 *
89 * @param scheme the URI scheme
90 * @param host the host
91 * @param port the port
92 * @param path the path
93 * @return a new URI
94 * @throws InvalidURIException if any argument is invalid
95 */
96 public static URI create(String scheme, String host, int port, String path)
97 throws InvalidURIException {
98 URI result;
99 try {
100 result = new URI(scheme, null, host, port, path, null, null);
101 } catch (URI.MalformedURIException exception) {
102 throw new InvalidURIException(exception.getMessage());
103 }
104 return result;
105 }
106
107 /***
108 * Helper to create an URI.
109 *
110 * @param scheme the URI scheme
111 * @param host the host
112 * @param port the port
113 * @param path the path
114 * @param params a map of key/value pairs used to construct a query string
115 * @return a new URI
116 * @throws InvalidURIException if any argument is invalid
117 */
118 public static URI create(String scheme, String host, int port, String path,
119 Map params)
120 throws InvalidURIException {
121 Iterator iter = params.entrySet().iterator();
122 StringBuffer query = new StringBuffer();
123 for (int i = 0; iter.hasNext(); ++i) {
124 if (i > 0) {
125 query.append('&');
126 }
127 Map.Entry entry = (Map.Entry) iter.next();
128 query.append(entry.getKey());
129 query.append('=');
130 query.append(entry.getValue());
131 }
132 return create(scheme, host, port, path, query.toString());
133 }
134
135
136 /***
137 * Helper to create an URI.
138 *
139 * @param scheme the URI scheme
140 * @param host the host
141 * @param port the port
142 * @param path the path
143 * @param query the query
144 * @return a new URI
145 * @throws InvalidURIException if any argument is invalid
146 */
147 public static URI create(String scheme, String host, int port, String path,
148 String query)
149 throws InvalidURIException {
150 URI result;
151 try {
152 result = new URI(scheme, null, host, port, path, query, null);
153 } catch (URI.MalformedURIException exception) {
154 throw new InvalidURIException(exception.getMessage());
155 }
156 return result;
157 }
158
159 /***
160 * Helper to parse a String to an URI. If no path was specified in, the URI,
161 * it will default to <code>"/"</code>.
162 *
163 * @param uri the URI to parse
164 * @return the parsed URI
165 * @throws InvalidURIException if <code>uri</code> is invalid
166 */
167 public static URI parse(String uri) throws InvalidURIException {
168 URI result;
169 try {
170 result = new URI(uri);
171 fixPath(result);
172 } catch (URI.MalformedURIException exception) {
173 throw new InvalidURIException(exception.getMessage());
174 }
175 return result;
176 }
177
178 /***
179 * Helper to parse an URI, verifying that it has the correct scheme.
180 *
181 * @param uri the URI to parse
182 * @param scheme the expected scheme
183 * @return the parsed URI
184 * @throws InvalidURIException if <code>uri</code> is invalid
185 */
186 public static URI parse(String uri, String scheme)
187 throws InvalidURIException {
188 URI result = parse(uri);
189 if (!result.getScheme().equals(scheme)) {
190 throw new InvalidURIException(
191 "Invalid scheme: " + result.getScheme());
192 }
193 return result;
194 }
195
196 /***
197 * Helper to parse an URI, verifying that it has the correct scheme, host
198 * and port specification, and no path.
199 *
200 * @param uri the URI to parse
201 * @param scheme the expected scheme
202 * @return the parsed URI
203 * @throws InvalidURIException if <code>uri</code> is invalid
204 */
205 public static URI parseHostPort(String uri, String scheme)
206 throws InvalidURIException {
207 URI result = parse(uri, scheme);
208 if (result.getHost() == null) {
209 throw new InvalidURIException("No host specified in URI: " + uri);
210 }
211 if (result.getPort() == -1) {
212 throw new InvalidURIException("No port specified in URI: " + uri);
213 }
214 if (result.getPath() != null && !result.getPath().equals("")
215 && !result.getPath().equals("/")) {
216 throw new InvalidURIException(
217 "URI must not specify a path: " + uri);
218 }
219 return result;
220 }
221
222 /***
223 * Helper to convert the host name portion of a URI to its corresponding IP
224 * address. If the URI doesn't contain a host, or the host is specified as
225 * an IP address, or the IP address can't be determined, then the URI is
226 * returned unchanged.
227 *
228 * @param uri the uri to convert
229 * @return the converted URI
230 */
231 public static URI convertHostToAddress(URI uri) {
232 URI result = uri;
233 String host = uri.getHost();
234 if (host != null && !host.equals("")) {
235 try {
236 InetAddress address = InetAddress.getByName(host);
237 result = new URI(uri.getScheme(), uri.getUserinfo(),
238 address.getHostAddress(), uri.getPort(),
239 uri.getPath(), uri.getQueryString(),
240 uri.getFragment());
241 fixPath(result);
242 } catch (UnknownHostException ignore) {
243 } catch (URI.MalformedURIException exception) {
244
245 throw new IllegalArgumentException("Failed to construct URI: "
246 + exception.getMessage());
247 }
248 }
249 return result;
250 }
251
252 /***
253 * Returns a {@link BasicPrincipal} corresponding to the user info specified
254 * in a URI.
255 *
256 * @param uri the URI to get the user info from
257 * @return a new BasicPrincipal containing the user info, or
258 * <code>null</code> if none was specified
259 */
260 public static BasicPrincipal getPrincipal(URI uri) {
261 BasicPrincipal principal = null;
262 String userinfo = uri.getUserinfo();
263 if (userinfo != null && userinfo.length() != 0) {
264 int index = userinfo.indexOf(":");
265 String user;
266 String password = "";
267 if (index != -1) {
268 user = userinfo.substring(0, index);
269 password = userinfo.substring(index + 1);
270 } else {
271 user = userinfo;
272 }
273 principal = new BasicPrincipal(user, password);
274 }
275 return principal;
276 }
277
278 /***
279 * Returns a URI minus query/fragment.
280 *
281 * @param uri the URI
282 * @return the URI minus query/fragment or <code>uri</code> if there is
283 * no query/fragment
284 */
285 public static URI getURISansQuery(URI uri) {
286 URI result = uri;
287 if (uri.getQueryString() != null || uri.getFragment() != null) {
288 try {
289 result = new URI(uri.getScheme(), uri.getUserinfo(),
290 uri.getHost(), uri.getPort(),
291 uri.getPath(), null, null);
292 } catch (URI.MalformedURIException exception) {
293
294 throw new IllegalArgumentException("Failed to construct URI: "
295 + exception.getMessage());
296
297 }
298 }
299 return result;
300 }
301
302 /***
303 * Parse a query string.
304 * <p/>
305 * Note that this implementation doesn't support multiple parameters.
306 * with the same name. The value of the last will be returned.
307 *
308 * @param query the query to parse
309 * @return the parsed parameters
310 * @throws InvalidURIException if <code>query</code> is invalid
311 */
312 public static Map parseQuery(String query) throws InvalidURIException {
313 Map result = new HashMap();
314 StringTokenizer tokens = new StringTokenizer(query, "&");
315 while (tokens.hasMoreTokens()) {
316 String pair = (String) tokens.nextToken();
317 int pos = pair.indexOf('=');
318 if (pos == -1) {
319 throw new InvalidURIException("Invalid query=" + query);
320 }
321 String key = pair.substring(0, pos);
322 String value = pair.substring(pos + 1, pair.length());
323 result.put(key, value);
324 }
325 return result;
326 }
327
328 /***
329 * Ensures that the path is set to <code>"/"</code> if not specified in a
330 * URI, so equality tests return true for instances of the form a://b:1234
331 * == a://b:1234/
332 *
333 * @param uri the URI the fix the path for
334 * @throws URI.MalformedURIException if the path can't be set
335 */
336 private static void fixPath(URI uri) throws URI.MalformedURIException {
337 String path = uri.getPath();
338 if (path == null || path.equals("")) {
339 uri.setPath("/");
340 }
341 }
342
343 }