KickJava   Java API By Example, From Geeks To Geeks.

Java > Open Source Codes > com > inversoft > verge > util > url > URLGenerator


1 /*
2  * Copyright (c) 2003, Inversoft
3  *
4  * This software is distribuable under the GNU Lesser General Public License.
5  * For more information visit gnu.org.
6  */

7 package com.inversoft.verge.util.url;
8
9
10 import java.io.UnsupportedEncodingException JavaDoc;
11 import java.net.URI JavaDoc;
12 import java.net.URISyntaxException JavaDoc;
13 import java.net.URLEncoder JavaDoc;
14
15 import javax.servlet.ServletRequest JavaDoc;
16 import javax.servlet.http.HttpServletRequest JavaDoc;
17 import javax.servlet.http.HttpServletResponse JavaDoc;
18
19 import com.inversoft.util.StringTools;
20 import com.inversoft.verge.util.url.config.CategoryConfig;
21 import com.inversoft.verge.util.url.config.URLConfigRegistry;
22
23
24 /**
25  * <p>
26  * This class generates URLs based on criteria. Rather than
27  * simply breaking URLs into all the categories that we could
28  * think of, we figured we would leave a little flexibility
29  * in there so that any new scenarios that might come up
30  * could easily be dealt with. Likewise, you can always write
31  * a helper class to simply all your scenarios.
32  * </p>
33  *
34  * <p>
35  * URLs are based on categories, which are just simple Strings.
36  * There are also URL components for each category that can
37  * be changed. For example, image URLs may be located on a
38  * remote server. So, you could create a image category and
39  * specify the host, port, and context for the URL.
40  * </p>
41  *
42  * <p>
43  * Categories can change for your needs, components can not.
44  * There are only four components of URLs that can vary:
45  * <ul>
46  * <li>Protocol</li>
47  * <li>Host</li>
48  * <li>Port</li>
49  * <li>Context</li>
50  * </ul>
51  * Context is the same as J2EE contexts. It is the path after
52  * the protocol, host and port.
53  * </p>
54  *
55  * <p>
56  * The configuration for URLs is put into the verge.xml
57  * configuration file.
58  * </p>
59  *
60  * @author Brian Pontarelli
61  * @since 2.0
62  * @version 2.0
63  */

64 public class URLGenerator {
65
66     /**
67      * Private constructor for URLGenerator.
68      */

69     private URLGenerator() {
70     }
71
72
73     /**
74      * Returns whether or not the given category is a valid category or not.
75      *
76      * @param request The ServletRequest used to lookup the request local
77      * configuration
78      * @param category The category to verify
79      * @return True if it is valid, false otherwise
80      */

81     public static boolean isCategoryValid(ServletRequest JavaDoc request, String JavaDoc category) {
82         return (URLConfigRegistry.getInstance(request).lookupCategory(category) != null);
83     }
84
85     /**
86      * Returns the {@link CategoryConfig CategoryConfig} object for the category
87      * name given.
88      *
89      * @param request The ServletRequest used to lookup the request local
90      * configuration
91      * @param category The category to lookup
92      * @return The CategoryConfig or null if it doesn't exist
93      */

94     public static CategoryConfig getCategory(ServletRequest JavaDoc request, String JavaDoc category) {
95         return URLConfigRegistry.getInstance(request).lookupCategory(category);
96     }
97
98     /**
99      * Returns the {@link CategoryConfig CategoryConfig} object for the category
100      * name given or for the defaultCategory name given if the category name given
101      * does not exist.
102      *
103      * @param request The ServletRequest used to lookup the request local
104      * configuration
105      * @param category The category to lookup
106      * @param defaultCategory The default category to lookup if the category
107      * parameter doesn't resolve to a valid CategoryConfig
108      * @return The CategoryConfig or null if it doesn't exist under either name
109      */

110     public static CategoryConfig getCategory(ServletRequest JavaDoc request, String JavaDoc category,
111             String JavaDoc defaultCategory) {
112         CategoryConfig cc =
113             URLConfigRegistry.getInstance(request).lookupCategory(category);
114         if (cc == null) {
115             cc = URLConfigRegistry.getInstance(request).lookupCategory(defaultCategory);
116         }
117
118         return cc;
119     }
120
121
122     //--------------------------------------------------------------------------
123
// Local URL methods (within WAR)
124
//--------------------------------------------------------------------------
125

126
127     /**
128      * This method calls {@link #generateLocalURL(StringBuffer, String, String)
129      * generateURL()} with a new StringBuffer instance and returns buf.toString().
130      */

131     public static String JavaDoc generateLocalURL(String JavaDoc baseURI, String JavaDoc context) {
132         StringBuffer JavaDoc buf = new StringBuffer JavaDoc(baseURI.length());
133         generateLocalURL(buf, baseURI, context);
134         return buf.toString();
135     }
136
137     /**
138      * Generates a simple URL based on the given baseURI and the given context.
139      * This does not make use of any categories. The URL is also local and the
140      * baseURI can not contain any protocol, host or port information.
141      *
142      * @param buf The StringBuffer to append to
143      * @param baseURI (Optional) The base URI definition to build the URL from
144      * @param context (Optional) The context path that may be appended, if
145      * specified, to the URL. This should mimic the HTTP specification
146      * and either be empty or begin with a / and not end with a /
147      */

148     public static void generateLocalURL(StringBuffer JavaDoc buf, String JavaDoc baseURI,
149             String JavaDoc context) {
150         // Since the baseURI can be a relative path, this first checks to see if
151
// anything else was added and if not, checks to see if the path is
152
// relative or not
153
boolean contextEmpty = StringTools.isTrimmedEmpty(context);
154         boolean empty = StringTools.isTrimmedEmpty(baseURI);
155         if (!contextEmpty) {
156             boolean relative = (!empty && (baseURI.charAt(0) != '/'));
157             if (!relative) {
158                 buf.append(context);
159             }
160         }
161
162         if (!empty) {
163             buf.append(baseURI);
164         }
165     }
166
167
168     //--------------------------------------------------------------------------
169
// URI based methods
170
//--------------------------------------------------------------------------
171

172
173     /**
174      * This method calls {@link #generateURL(StringBuffer, String, String)
175      * generateURL()} with a new StringBuffer instance and returns buf.toString().
176      */

177     public static String JavaDoc generateURL(String JavaDoc baseURI, String JavaDoc context)
178     throws URISyntaxException JavaDoc {
179         StringBuffer JavaDoc buf = new StringBuffer JavaDoc(baseURI.length());
180         generateURL(buf, baseURI, context);
181         return buf.toString();
182     }
183
184     /**
185      * Generates a simple URL based on the given baseURI and the given context.
186      * This does not make use of any categories.
187      *
188      * @param buf The StringBuffer to append to
189      * @param baseURI The base URI definition to build the URL from
190      * @param context (optional) The context path that may be appended, if
191      * specified, to the URL. This should mimic the HTTP specification
192      * and either be empty or begin with a / and not end with a /
193      * @throws URISyntaxException If the baseURI is invalid
194      */

195     public static void generateURL(StringBuffer JavaDoc buf, String JavaDoc baseURI, String JavaDoc context)
196     throws URISyntaxException JavaDoc {
197
198         boolean contextEmpty = StringTools.isTrimmedEmpty(context);
199
200         // Since baseURI is optional, if it is null, just add the context and
201
// bail
202
if (baseURI == null) {
203             if (!contextEmpty) {
204                 buf.append(context);
205             }
206
207             return;
208         }
209
210         // Pre-encode the query string and the fragment
211
URI JavaDoc uri = null;
212         int queryStart = baseURI.indexOf("?");
213         if (queryStart != -1) {
214             try {
215                 baseURI = baseURI.substring(0, queryStart + 1) +
216                     URLEncoder.encode(baseURI.substring(queryStart + 1),
217                         "UTF-8");
218             } catch (UnsupportedEncodingException JavaDoc uee) {
219                 // NEVER WILL
220
throw new AssertionError JavaDoc(uee);
221             }
222
223         }
224         uri = new URI JavaDoc(baseURI);
225
226         boolean absolute = uri.isAbsolute();
227         if (absolute) {
228             String JavaDoc scheme = uri.getScheme();
229             if (scheme != null) {
230                 buf.append(scheme);
231                 buf.append("://");
232             }
233
234             String JavaDoc host = uri.getHost();
235             if (host != null) {
236                 buf.append(host);
237             }
238
239             int port = uri.getPort();
240             if (port != -1) {
241                 buf.append(":");
242                 buf.append(port);
243             }
244         }
245
246         String JavaDoc path = uri.getPath();
247         generateLocalURL(buf, path, context);
248
249         String JavaDoc query = uri.getQuery();
250         if (query != null) {
251             buf.append("?");
252             buf.append(query);
253         }
254
255         String JavaDoc fragment = uri.getFragment();
256         if (fragment != null) {
257             buf.append("#");
258             buf.append(fragment);
259         }
260     }
261
262
263     //--------------------------------------------------------------------------
264
// Category based methods
265
//--------------------------------------------------------------------------
266

267
268     /**
269      * This method calls {@link #generateURL(StringBuffer, CategoryConfig,
270      * HttpServletRequest) generateURL()} method with a new StringBuffer and
271      * returns buf.toString().
272      */

273     public static String JavaDoc generateURL(CategoryConfig category,
274             HttpServletRequest JavaDoc request) {
275         StringBuffer JavaDoc buf = new StringBuffer JavaDoc();
276         generateURL(buf, category, request);
277         return buf.toString();
278     }
279
280     /**
281      * This method calls {@link #generateURL(StringBuffer, CategoryConfig, String,
282      * HttpServletRequest) generateURL()} method with a new StringBuffer and
283      * returns buf.toString().
284      */

285     public static String JavaDoc generateURL(CategoryConfig category, String JavaDoc baseURI,
286             HttpServletRequest JavaDoc request)
287     throws URISyntaxException JavaDoc {
288         StringBuffer JavaDoc buf = new StringBuffer JavaDoc();
289         generateURL(buf, category, baseURI, request);
290         return buf.toString();
291     }
292
293     /**
294      * Generates a URL by calling the {@link #generateURL(StringBuffer,
295      * CategoryConfig, String, boolean, HttpServletRequest) generateURL}
296      * method with a new StringBuffer and then returns buf.toString().
297      */

298     public static String JavaDoc generateURL(CategoryConfig category, String JavaDoc baseURI,
299             boolean context, HttpServletRequest JavaDoc request)
300     throws URISyntaxException JavaDoc {
301         StringBuffer JavaDoc buf = new StringBuffer JavaDoc();
302         generateURL(buf, category, baseURI, context, request);
303         return buf.toString();
304     }
305
306     /**
307      * Generates a URL by calling the {@link #generateURL(StringBuffer,
308      * CategoryConfig, String, boolean, HttpServletRequest, HttpServletResponse)
309      * generateURL} method with a new StringBuffer and then returns buf.toString().
310      */

311     public static String JavaDoc generateURL(CategoryConfig category, String JavaDoc baseURI,
312             boolean context, HttpServletRequest JavaDoc request, HttpServletResponse JavaDoc response)
313     throws URISyntaxException JavaDoc {
314         StringBuffer JavaDoc newBuf = new StringBuffer JavaDoc();
315         generateURL(newBuf, category, baseURI, context, request, response);
316         return newBuf.toString();
317     }
318
319     /**
320      * This method calls {@link #generateURL(StringBuffer, CategoryConfig, String,
321      * HttpServletRequest) generateURL()} passing null for the baseURI parameter.
322      */

323     public static void generateURL(StringBuffer JavaDoc buf, CategoryConfig category,
324             HttpServletRequest JavaDoc request) {
325         try {
326             generateURL(buf, category, null, request);
327         } catch (URISyntaxException JavaDoc use) {
328             throw new AssertionError JavaDoc("FATAL: threw URISyntaxException " +
329                 use.toString());
330         }
331     }
332
333     /**
334      * This method calls {@link #generateURL(StringBuffer, CategoryConfig, String,
335      * boolean, HttpServletRequest) generateURL()} passing in true for the
336      * context boolean.
337      */

338     public static void generateURL(StringBuffer JavaDoc buf, CategoryConfig category,
339             String JavaDoc baseURI, HttpServletRequest JavaDoc request)
340     throws URISyntaxException JavaDoc {
341         generateURL(buf, category, baseURI, true, request);
342     }
343
344     /**
345      * Generates a URL by calling the {@link #generateURL(StringBuffer,
346      * CategoryConfig, String, boolean, HttpServletRequest) generateURL}
347      * method and then encodes the URL using the response and puts this new URL
348      * into the StringBuffer given.
349      */

350     public static void generateURL(StringBuffer JavaDoc buf, CategoryConfig category,
351             String JavaDoc baseURI, boolean context, HttpServletRequest JavaDoc request,
352             HttpServletResponse JavaDoc response)
353     throws URISyntaxException JavaDoc {
354         StringBuffer JavaDoc newBuf = new StringBuffer JavaDoc();
355         generateURL(newBuf, category, baseURI, context, request);
356         buf.append(response.encodeURL(newBuf.toString()));
357     }
358
359     /**
360      * <p>
361      * Generates a new URL based on the category given. Whatever the configuration
362      * for the category is, it will be used when generating the URL. If the
363      * category is null, this method behaves identical to a call to {@link
364      * #generateURL(StringBuffer, String, String) generateURL()}. This is
365      * important to remember, because this method will not fail on null
366      * categories.
367      * </p>
368      *
369      * <p>
370      * If anything in the category is left out, the given baseURI is used. If the
371      * given baseURI has the same thing left out, this uses the value from the
372      * HttpServletRequest. There is one notable exception. If the port is not
373      * specified in the category, and the URI does not explicitly specify a port,
374      * but it does have a scheme, then the scheme is decoded to determine the
375      * port.
376      * </p>
377      *
378      * <p>
379      * For example:
380      * </p>
381      *
382      * <table>
383      * <tr>
384      * <th>Location</th>
385      * <th>Protocol</th>
386      * <th>Host</th>
387      * <th>Port</th>
388      * </tr>
389      * <tr>
390      * <td>Category</td>
391      * <td>https</td>
392      * <td>www.inversoft.com</td>
393      * <td></td>
394      * </tr>
395      * <tr>
396      * <td>Request</td>
397      * <td>http</td>
398      * <td>machine1.inversoft.com</td>
399      * <td>9001</td>
400      * </tr>
401      * <tr>
402      * <td>baseURI</td>
403      * <td>http</td>
404      * <td>www.yahoo.com</td>
405      * <td></td>
406      * </tr>
407      * </table>
408      *
409      * Based on this criteria, the generated URL will be:<br>
410      * <code>https://www.inversoft.com:80</code>
411      *
412      * <p>
413      * This is generated because the category gives us the protocol, https. The
414      * category also gives us the host, www.inversoft.com. The category does not
415      * give us a port. Therefore, the baseURI is used for the port. A port is
416      * not explicitly given in the baseURI, but since the protocol is http, this
417      * method will assume the port to be 80, which is what is used.
418      * </p>
419      *
420      * <p>
421      * One last thing to notice, the baseURI may end up being simply appended to
422      * the end. For example, if the baseURI is only a path, ie /foo/index.jsp,
423      * this will just be appended to the end of the generated URL. The reason is
424      * because URIs do not have the concept of context paths. Therefore, if you
425      * pass in http://www.yourdomain.com:8000/context/page.jsp, this context is
426      * actually considered part of the path rather than a context path. You can
427      * get around this by using the other generate method that takes a baseURI
428      * and a context path.
429      * </p>
430      *
431      * @param buf The StringBuffer to append to
432      * @param category (Optional) The name of the category
433      * @param baseURI (Optional) The baseURI that will be used when building
434      * the URL
435      * @param context True means that the context is appended to URLs created
436      * without the categories, false means no context is appended to
437      * URLs created without the categories
438      * @param request The HttpServletRequest used to fill in the gaps where the
439      * category does not specify. For example, if the category does not
440      * have a port, the port from the request is used
441      * @throws URISyntaxException If the baseURI is invalid
442      */

443     public static void generateURL(StringBuffer JavaDoc buf, CategoryConfig category,
444             String JavaDoc baseURI, boolean context, HttpServletRequest JavaDoc request)
445     throws URISyntaxException JavaDoc {
446
447         // Determine if their needs to be a context
448
String JavaDoc localContext = null;
449         if (context) {
450             localContext = request.getContextPath();
451         }
452
453         // Mutate the URL if needed
454
if (category != null) {
455             internalGenerate(buf, category, baseURI, localContext, request);
456         } else {
457             generateURL(buf, baseURI, localContext);
458         }
459     }
460
461     /**
462      * The method used internally to generate URLs
463      */

464     private static void internalGenerate(StringBuffer JavaDoc url, CategoryConfig cc,
465             String JavaDoc baseURI, String JavaDoc context, HttpServletRequest JavaDoc request)
466     throws URISyntaxException JavaDoc {
467
468         URI JavaDoc uri = null;
469         if (baseURI != null) {
470             int queryStart = baseURI.indexOf("?");
471             if (queryStart != -1) {
472                 try {
473                     baseURI = baseURI.substring(0, queryStart + 1) +
474                         URLEncoder.encode(baseURI.substring(queryStart + 1),
475                             "UTF-8");
476                 } catch (UnsupportedEncodingException JavaDoc uee) {
477                     // NEVER WILL
478
throw new AssertionError JavaDoc(uee);
479                 }
480
481             }
482
483             uri = new URI JavaDoc(baseURI);
484         }
485
486         // Append the protocol
487
String JavaDoc protocol = cc.getProtocol();
488         boolean https = false;
489         if (protocol != null) {
490             https = cc.isHttps();
491         } else {
492             protocol = (uri == null) ? null : uri.getScheme();
493             if (protocol == null) {
494                 protocol = request.getScheme();
495             }
496
497             protocol = protocol.toLowerCase();
498             https = protocol.equals("https");
499         }
500
501         url.append(protocol);
502         url.append("://");
503
504         // Append the host
505
String JavaDoc host = cc.getHost();
506         if (host == null) {
507             host = (uri == null) ? null : uri.getHost();
508             if (host == null) {
509                 host = request.getServerName();
510             }
511         }
512         url.append(host);
513
514         // Append the port
515
int port = cc.getPort();
516         if (port == -1) {
517
518             // Check the uri for the port, if the uri does not have a port, check
519
// if it has a host and if so, then check the scheme to determine the
520
// port. If any of this fails, check the request
521
port = (uri == null) ? -1 : uri.getPort();
522             if (port == -1) {
523                 String JavaDoc scheme = (uri == null) ? null : uri.getScheme();
524                 if (scheme != null && scheme.equals("http")) {
525                     port = 80;
526                 } else if (scheme != null && scheme.equals("https")) {
527                     port = 443;
528                 }
529
530                 if (port == -1) {
531                     port = request.getServerPort();
532                 }
533             }
534         }
535
536         if ((!https && port != 80) ||
537                 (https && port != 443)) {
538             url.append(":");
539             url.append(port);
540         }
541
542         // Append the context
543
String JavaDoc localContext = cc.getContext();
544         if (localContext == null) {
545             localContext = context;
546         }
547
548         if (localContext != null) {
549             if (!StringTools.isTrimmedEmpty(localContext) &&
550                     localContext.charAt(0) != '/') {
551                 url.append("/");
552             }
553             url.append(localContext);
554         }
555
556         // Append the path
557
String JavaDoc path = (uri == null) ? null : uri.getPath();
558         if (path != null) {
559             if (!StringTools.isTrimmedEmpty(path) && path.charAt(0) != '/') {
560                 url.append("/");
561             }
562             url.append(path);
563         }
564
565         // Append the query and fragment (if any)
566
String JavaDoc query = (uri == null) ? null : uri.getQuery();
567         if (query != null) {
568             url.append("?").append(query);
569         }
570
571         String JavaDoc fragment = (uri == null) ? null : uri.getFragment();
572         if (fragment != null) {
573             url.append("#").append(fragment);
574         }
575     }
576 }
Popular Tags