View Javadoc

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                 // should *never* happen
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                 // should *never* happen
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 }