001: package com.meterware.servletunit;
002:
003: /********************************************************************************************************************
004: * $Id: ServletUnitHttpRequest.java,v 1.37 2006/03/24 19:59:12 russgold Exp $
005: *
006: * Copyright (c) 2000-2006, Russell Gold
007: *
008: * Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated
009: * documentation files (the "Software"), to deal in the Software without restriction, including without limitation
010: * the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and
011: * to permit persons to whom the Software is furnished to do so, subject to the following conditions:
012: *
013: * The above copyright notice and this permission notice shall be included in all copies or substantial portions
014: * of the Software.
015: *
016: * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO
017: * THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
018: * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF
019: * CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
020: * DEALINGS IN THE SOFTWARE.
021: *
022: *******************************************************************************************************************/
023: import com.meterware.httpunit.WebRequest;
024: import com.meterware.httpunit.WebClient;
025: import com.meterware.httpunit.Base64;
026: import com.meterware.httpunit.HttpUnitUtils;
027:
028: import java.io.BufferedReader;
029: import java.io.IOException;
030: import java.io.UnsupportedEncodingException;
031: import java.net.MalformedURLException;
032: import java.util.*;
033:
034: import javax.servlet.http.HttpServletRequest;
035: import javax.servlet.http.Cookie;
036: import javax.servlet.http.HttpSession;
037: import javax.servlet.ServletInputStream;
038: import javax.servlet.RequestDispatcher;
039: import javax.servlet.ServletException;
040:
041: /**
042: * This class represents a servlet request created from a WebRequest.
043: **/
044: class ServletUnitHttpRequest implements HttpServletRequest {
045:
046: private ServletInputStreamImpl _inputStream;
047: private String _contentType;
048: private Vector _locales;
049: private boolean _secure;
050: private RequestContext _requestContext;
051: private String _charset;
052:
053: /**
054: * Constructs a ServletUnitHttpRequest from a WebRequest object.
055: **/
056: ServletUnitHttpRequest(ServletMetaData servletRequest,
057: WebRequest request, ServletUnitContext context,
058: Dictionary clientHeaders, byte[] messageBody)
059: throws MalformedURLException {
060: if (context == null)
061: throw new IllegalArgumentException(
062: "Context must not be null");
063:
064: _servletRequest = servletRequest;
065: _request = request;
066: _context = context;
067: _headers = new WebClient.HeaderDictionary();
068: _headers.addEntries(clientHeaders);
069: _headers.addEntries(request.getHeaders());
070: setCookiesFromHeader(_headers);
071: _messageBody = messageBody;
072: _secure = request.getURL().getProtocol().equalsIgnoreCase(
073: "https");
074:
075: _requestContext = new RequestContext(request.getURL());
076: String contentTypeHeader = (String) _headers
077: .get("Content-Type");
078: if (contentTypeHeader != null) {
079: String[] res = HttpUnitUtils
080: .parseContentTypeHeader(contentTypeHeader);
081: _contentType = res[0];
082: _charset = res[1];
083: _requestContext.setMessageEncoding(_charset);
084: }
085: if (_headers.get("Content-Length") == null)
086: _headers.put("Content-Length", Integer
087: .toString(messageBody.length));
088:
089: if (_messageBody != null
090: && (_contentType == null || _contentType
091: .indexOf("x-www-form-urlencoded") >= 0)) {
092: _requestContext.setMessageBody(_messageBody);
093: }
094: }
095:
096: //----------------------------------------- HttpServletRequest methods --------------------------
097:
098: /**
099: * Returns the name of the authentication scheme used to protect the servlet, for example, "BASIC" or "SSL,"
100: * or null if the servlet was not protected.
101: **/
102: public String getAuthType() {
103: return null;
104: }
105:
106: /**
107: * Returns the query string that is contained in the request URL after the path.
108: **/
109: public String getQueryString() {
110: return _request.getQueryString();
111: }
112:
113: /**
114: * Returns an array containing all of the Cookie objects the client sent with this request.
115: * This method returns null if no cookies were sent.
116: **/
117: public Cookie[] getCookies() {
118: if (_cookies.size() == 0) {
119: return null;
120: } else {
121: Cookie[] result = new Cookie[_cookies.size()];
122: _cookies.copyInto(result);
123: return result;
124: }
125: }
126:
127: /**
128: * Returns the value of the specified request header as an int. If the request does not have a header
129: * of the specified name, this method returns -1. If the header cannot be converted to an integer,
130: * this method throws a NumberFormatException.
131: **/
132: public int getIntHeader(String name) {
133: return Integer.parseInt(getHeader(name));
134: }
135:
136: /**
137: * Returns the value of the specified request header as a long value that represents a Date object.
138: * Use this method with headers that contain dates, such as If-Modified-Since.
139: * <br>
140: * The date is returned as the number of milliseconds since January 1, 1970 GMT. The header name is case insensitive.
141: *
142: * If the request did not have a header of the specified name, this method returns -1.
143: * If the header can't be converted to a date, the method throws an IllegalArgumentException.
144: **/
145: public long getDateHeader(String name) {
146: return -1;
147: }
148:
149: /**
150: * Returns the value of the specified request header as a String. If the request did not include
151: * a header of the specified name, this method returns null. The header name is case insensitive.
152: * You can use this method with any request header.
153: **/
154: public String getHeader(String name) {
155: return (String) _headers.get(name);
156: }
157:
158: /**
159: * Returns an enumeration of all the header names this request contains. If the request has no headers,
160: * this method returns an empty enumeration.
161: *
162: * Some servlet containers do not allow do not allow servlets to access headers using this method,
163: * in which case this method returns null.
164: **/
165: public Enumeration getHeaderNames() {
166: return _headers.keys();
167: }
168:
169: /**
170: * Returns the part of this request's URL that calls the servlet. This includes either the servlet name
171: * or a path to the servlet, but does not include any extra path information or a query string.
172: **/
173: public String getServletPath() {
174: return _servletRequest.getServletPath();
175: }
176:
177: /**
178: * Returns the name of the HTTP method with which this request was made, for example, GET, POST, or PUT.
179: **/
180: public String getMethod() {
181: return _request.getMethod();
182: }
183:
184: /**
185: * Returns any extra path information associated with the URL the client sent when it made this request.
186: * The extra path information follows the servlet path but precedes the query string.
187: * This method returns null if there was no extra path information.
188: **/
189: public String getPathInfo() {
190: return _servletRequest.getPathInfo();
191: }
192:
193: /**
194: * Returns any extra path information after the servlet name but before the query string,
195: * and translates it to a real path. If the URL does not have any extra path information, this method returns null.
196: **/
197: public String getPathTranslated() {
198: return null;
199: }
200:
201: /**
202: * Checks whether the requested session ID came in as a cookie.
203: **/
204: public boolean isRequestedSessionIdFromCookie() {
205: return _sessionID != null;
206: }
207:
208: /**
209: * Returns the login of the user making this request, if the user has been authenticated,
210: * or null if the user has not been authenticated.
211: * Whether the user name is sent with each subsequent request depends on the browser and type of authentication.
212: **/
213: public String getRemoteUser() {
214: return _userName;
215: }
216:
217: /**
218: * Returns the session ID specified by the client. This may not be the same as the ID of the actual session in use.
219: * For example, if the request specified an old (expired) session ID and the server has started a new session,
220: * this method gets a new session with a new ID. If the request did not specify a session ID, this method returns null.
221: **/
222: public String getRequestedSessionId() {
223: return _sessionID;
224: }
225:
226: /**
227: * Returns the part of this request's URL from the protocol name up to the query string in the first line of the HTTP request.
228: **/
229: public String getRequestURI() {
230: return _requestContext.getRequestURI();
231: }
232:
233: /**
234: * Returns the current HttpSession associated with this request or, if there is no current session
235: * and create is true, returns a new session.
236: * <br>
237: * If create is false and the request has no valid HttpSession, this method returns null.
238: **/
239: public HttpSession getSession(boolean create) {
240: _session = _context.getValidSession(getRequestedSessionId(),
241: _session, create);
242: return _session;
243: }
244:
245: /**
246: * Returns the current session associated with this request, or if the request does not have a session, creates one.
247: **/
248: public HttpSession getSession() {
249: return getSession(true);
250: }
251:
252: /**
253: * Checks whether the requested session ID is still valid.
254: **/
255: public boolean isRequestedSessionIdValid() {
256: return false;
257: }
258:
259: /**
260: * Checks whether the requested session ID came in as part of the request URL.
261: **/
262: public boolean isRequestedSessionIdFromURL() {
263: return false;
264: }
265:
266: /**
267: * @deprecated use #isRequestedSessionIdFromURL
268: **/
269: public boolean isRequestedSessionIdFromUrl() {
270: return isRequestedSessionIdFromURL();
271: }
272:
273: //--------------------------------- ServletRequest methods ----------------------------------------------------
274:
275: /**
276: * Returns the length, in bytes, of the content contained in the
277: * request and sent by way of the input stream or -1 if the
278: * length is not known.
279: **/
280: public int getContentLength() {
281: return getIntHeader("Content-length");
282: }
283:
284: /**
285: *
286: * Returns the value of the named attribute as an <code>Object</code>.
287: * This method allows the servlet engine to give the servlet
288: * custom information about a request. This method returns
289: * <code>null</code> if no attribute of the given name exists.
290: **/
291: public Object getAttribute(String name) {
292: return _attributes.get(name);
293: }
294:
295: /**
296: * Returns an <code>Enumeration</code> containing the
297: * names of the attributes available to this request.
298: * This method returns an empty <code>Enumeration</code>
299: * if the request has no attributes available to it.
300: **/
301: public Enumeration getAttributeNames() {
302: return _attributes.keys();
303: }
304:
305: /**
306: * Retrieves binary data from the body of the request as
307: * a {@link ServletInputStream}, which
308: * gives you the ability to read one line at a time.
309: *
310: * @return a {@link ServletInputStream} object containing
311: * the body of the request
312: *
313: * @exception IllegalStateException if the {@link #getReader} method
314: * has already been called for this request
315: *
316: * @exception IOException if an input or output exception occurred
317: *
318: */
319: public ServletInputStream getInputStream() throws IOException {
320: if (_inputStream == null) {
321: _inputStream = new ServletInputStreamImpl(_messageBody);
322: }
323: return _inputStream;
324: }
325:
326: /**
327: * Returns the name of the character encoding style used in this
328: * request. This method returns <code>null</code> if the request
329: * does not use character encoding.
330: **/
331: public String getCharacterEncoding() {
332: return _charset;
333: }
334:
335: /**
336: *
337: * Returns an <code>Enumeration</code> of <code>String</code>
338: * objects containing the names of the parameters contained
339: * in this request. If the request has
340: * no parameters or if the input stream is empty, returns an
341: * empty <code>Enumeration</code>. The input stream is empty
342: * when all the data returned by {@link #getInputStream} has
343: * been read.
344: **/
345: public Enumeration getParameterNames() {
346: return _requestContext.getParameterNames();
347: }
348:
349: /**
350: * Returns the MIME type of the content of the request, or
351: * <code>null</code> if the type is not known. Same as the value
352: * of the CGI variable CONTENT_TYPE.
353: **/
354: public String getContentType() {
355: return _contentType;
356: }
357:
358: /**
359: * Returns the value of a request parameter as a <code>String</code>,
360: * or <code>null</code> if the parameter does not exist. Request parameters
361: * are extra information sent with the request.
362: **/
363: public String getParameter(String name) {
364: String[] parameters = getParameterValues(name);
365: return parameters == null ? null : parameters[0];
366: }
367:
368: /**
369: * Returns an array of <code>String</code> objects containing
370: * all of the values the
371: * given request parameter has, or <code>null</code> if the
372: * parameter does not exist. For example, in an HTTP servlet,
373: * this method returns an array of <code>String</code> objects
374: * containing the values of a query string or posted form.
375: **/
376: public String[] getParameterValues(String name) {
377: return _requestContext.getParameterValues(name);
378: }
379:
380: /**
381: * Returns the name and version of the protocol the request uses
382: * in the form <i>protocol/majorVersion.minorVersion</i>, for
383: * example, HTTP/1.1.
384: **/
385: public String getProtocol() {
386: return "HTTP/1.1";
387: }
388:
389: /**
390: * Returns the name of the scheme used to make this request,
391: * for example,
392: * <code>http</code>, <code>https</code>, or <code>ftp</code>.
393: * Different schemes have different rules for constructing URLs,
394: * as noted in RFC 1738.
395: **/
396: public String getScheme() {
397: return "http";
398: }
399:
400: /**
401: * Returns the fully qualified name of the client that sent the
402: * request.
403: **/
404: public String getRemoteHost() {
405: return "localhost";
406: }
407:
408: /**
409: * Returns the host name of the server that received the request.
410: **/
411: public String getServerName() {
412: return "localhost";
413: }
414:
415: /**
416: * Returns the port number on which this request was received.
417: **/
418: public int getServerPort() {
419: return 0;
420: }
421:
422: /**
423: *
424: * @deprecated As of Version 2.1 of the Java Servlet API,
425: * use {@link javax.servlet.ServletContext#getRealPath} instead.
426: *
427: */
428: public String getRealPath(String path) {
429: throwNotImplementedYet();
430: return "";
431: }
432:
433: /**
434: * Returns the body of the request as a <code>BufferedReader</code>
435: * that translates character set encodings.
436: **/
437: public BufferedReader getReader() throws IOException {
438: throwNotImplementedYet();
439: return null;
440: }
441:
442: /**
443: * Returns the Internet Protocol (IP) address of the client
444: * that sent the request.
445: **/
446: public String getRemoteAddr() {
447: return LOOPBACK_ADDRESS;
448: }
449:
450: /**
451: *
452: * Stores an attribute in the context of this request.
453: * Attributes are reset between requests.
454: **/
455: public void setAttribute(String key, Object o) {
456: if (o == null)
457: _attributes.remove(key);
458: else
459: _attributes.put(key, o);
460: }
461:
462: //--------------------------------- methods added to ServletRequest in Servlet API 2.2 ------------------------------------------------
463:
464: /**
465: * Returns a boolean indicating whether this request was made using a secure channel, such as HTTPS.
466: **/
467: public boolean isSecure() {
468: return _secure;
469: }
470:
471: /**
472: * Returns the preferred Locale that the client will accept content in, based on the Accept-Language header.
473: * If the client request doesn't provide an Accept-Language header, this method returns the default locale for the server.
474: **/
475: public Locale getLocale() {
476: return (Locale) getPreferredLocales().firstElement();
477: }
478:
479: /**
480: * Returns an Enumeration of Locale objects indicating, in decreasing order starting with the preferred locale,
481: * the locales that are acceptable to the client based on the Accept-Language header.
482: * If the client request doesn't provide an Accept-Language header, this
483: * method returns an Enumeration containing one Locale, the default locale for the server.
484: **/
485: public java.util.Enumeration getLocales() {
486: return getPreferredLocales().elements();
487: }
488:
489: /**
490: * Parses the accept-language header to obtain a vector of preferred locales
491: * @return the preferred locales, sorted by qvalue
492: */
493: private Vector getPreferredLocales() {
494: if (_locales == null) {
495: _locales = new Vector();
496: String languages = getHeader("accept-language");
497: if (languages == null) {
498: _locales.add(Locale.getDefault());
499: } else {
500: StringTokenizer st = new StringTokenizer(languages, ",");
501: ArrayList al = new ArrayList();
502: while (st.hasMoreTokens()) {
503: String token = st.nextToken();
504: al.add(new PrioritizedLocale(token));
505: }
506: Collections.sort(al);
507: for (Iterator iterator = al.iterator(); iterator
508: .hasNext();) {
509: _locales.add(((PrioritizedLocale) iterator.next())
510: .getLocale());
511: }
512: }
513: }
514: return _locales;
515: }
516:
517: /**
518: * Removes an attribute from this request. This method is not generally needed
519: * as attributes only persist as long as the request is being handled.
520: **/
521: public void removeAttribute(String name) {
522: _attributes.remove(name);
523: }
524:
525: /**
526: * Returns a RequestDispatcher object that acts as a wrapper for the resource located at the given path.
527: * A RequestDispatcher object can be used to forward a request to the resource or to include the
528: * resource in a response. The resource can be dynamic or static.
529: *
530: * The pathname specified may be relative, although it cannot extend outside the current servlet
531: * context. If the path begins with a "/" it is interpreted as relative to the current context root.
532: * This method returns null if the servlet container cannot return a RequestDispatcher.
533: *
534: * The difference between this method and ServletContext.getRequestDispatcher(java.lang.String)
535: * is that this method can take a relative path.
536: **/
537: public RequestDispatcher getRequestDispatcher(String path) {
538: try {
539: if (!path.startsWith("/"))
540: path = combinedPath(getServletPath(), path);
541: return _servletRequest.getServlet().getServletConfig()
542: .getServletContext().getRequestDispatcher(path);
543: } catch (ServletException e) {
544: return null;
545: }
546: }
547:
548: private String combinedPath(String basePath, String relativePath) {
549: if (basePath.indexOf('/') < 0)
550: return relativePath;
551: return basePath.substring(0, basePath.lastIndexOf('/')) + '/'
552: + relativePath;
553: }
554:
555: //--------------------------------- methods added to HttpServletRequest in Servlet API 2.2 ------------------------------------------------
556:
557: /**
558: * Returns a java.security.Principal object containing the name of the current authenticated user.
559: * If the user has not been authenticated, the method returns null.
560: **/
561: public java.security.Principal getUserPrincipal() {
562: return null;
563: }
564:
565: /**
566: * Returns a boolean indicating whether the authenticated user is included in the specified
567: * logical "role". Roles and role membership can be defined using deployment descriptors.
568: * If the user has not been authenticated, the method returns false.
569: **/
570: public boolean isUserInRole(String role) {
571: if (_roles == null)
572: return false;
573: for (int i = 0; i < _roles.length; i++) {
574: if (role.equals(_roles[i]))
575: return true;
576: }
577: return false;
578: }
579:
580: /**
581: * Returns all the values of the specified request header as an Enumeration of String objects.
582: **/
583: public java.util.Enumeration getHeaders(String name) {
584: Vector list = new Vector();
585: if (_headers.containsKey(name))
586: list.add(_headers.get(name));
587: return list.elements();
588: }
589:
590: /**
591: * Returns the portion of the request URI that indicates the context of the request.
592: * The context path always comes first in a request URI. The path starts with a "/" character
593: * but does not end with a "/" character. For servlets in the default (root) context,
594: * this method returns "".
595: **/
596: public String getContextPath() {
597: return _context.getContextPath();
598: }
599:
600: //--------------------------------------- methods added to ServletRequest in Servlet API 2.3 ----------------------------
601:
602: /**
603: * Returns a java.util.Map of the parameters of this request.
604: * Request parameters are extra information sent with the request. For HTTP servlets, parameters are contained
605: * in the query string or posted form data.
606: *
607: * @since 1.3
608: **/
609: public Map getParameterMap() {
610: return _requestContext.getParameterMap();
611: }
612:
613: /**
614: * Overrides the name of the character encoding used in the body of this request.
615: * This method must be called prior to reading request parameters or reading input using getReader().
616: *
617: * @since 1.3
618: **/
619: public void setCharacterEncoding(String charset)
620: throws UnsupportedEncodingException {
621: _charset = charset;
622: _requestContext.setMessageEncoding(charset);
623: }
624:
625: //--------------------------------------- methods added to HttpServletRequest in Servlet API 2.3 ----------------------------
626:
627: /**
628: * Reconstructs the URL the client used to make the request.
629: * The returned URL contains a protocol, server name, port number, and server path, but
630: * it does not include query string parameters.
631: *
632: * Because this method returns a StringBuffer, not a string, you can modify the URL easily, for example,
633: * to append query parameters.
634: *
635: * This method is useful for creating redirect messages and for reporting errors.
636: *
637: * @since 1.3
638: */
639: public StringBuffer getRequestURL() {
640: StringBuffer url = new StringBuffer();
641: try {
642: url.append(_request.getURL().getProtocol()).append("://");
643: url.append(_request.getURL().getHost());
644: url.append(_request.getURL().getPath());
645: } catch (MalformedURLException e) {
646: throw new RuntimeException(
647: "unable to read URL from request: " + _request);
648: }
649: return url;
650: }
651:
652: //--------------------------------------- methods added to ServletRequest in Servlet API 2.4 ----------------------------
653:
654: public int getRemotePort() {
655: return 0; //To change body of implemented methods use File | Settings | File Templates.
656: }
657:
658: public String getLocalName() {
659: return "localhost";
660: }
661:
662: public String getLocalAddr() {
663: return "127.0.0.1";
664: }
665:
666: public int getLocalPort() {
667: return 0; //To change body of implemented methods use File | Settings | File Templates.
668: }
669:
670: //--------------------------------------------- package members ----------------------------------------------
671:
672: private void addCookie(Cookie cookie) {
673: _cookies.addElement(cookie);
674: if (cookie.getName().equalsIgnoreCase(
675: ServletUnitHttpSession.SESSION_COOKIE_NAME)) {
676: _sessionID = cookie.getValue();
677: }
678: }
679:
680: private ServletUnitHttpSession getServletSession() {
681: return (ServletUnitHttpSession) getSession();
682: }
683:
684: void readFormAuthentication() {
685: if (getSession( /* create */false) != null) {
686: recordAuthenticationInfo(getServletSession().getUserName(),
687: getServletSession().getRoles());
688: }
689: }
690:
691: void readBasicAuthentication() {
692: String authorizationHeader = (String) _headers
693: .get("Authorization");
694:
695: if (authorizationHeader != null) {
696: String userAndPassword = Base64.decode(authorizationHeader
697: .substring(authorizationHeader.indexOf(' ') + 1));
698: int colonPos = userAndPassword.indexOf(':');
699: recordAuthenticationInfo(userAndPassword.substring(0,
700: colonPos), toArray(userAndPassword
701: .substring(colonPos + 1)));
702: }
703: }
704:
705: static String[] toArray(String roleList) {
706: StringTokenizer st = new StringTokenizer(roleList, ",");
707: String[] result = new String[st.countTokens()];
708: for (int i = 0; i < result.length; i++) {
709: result[i] = st.nextToken();
710: }
711: return result;
712: }
713:
714: void recordAuthenticationInfo(String userName, String[] roles) {
715: _userName = userName;
716: _roles = roles;
717: }
718:
719: //--------------------------------------------- private members ----------------------------------------------
720:
721: final static private String LOOPBACK_ADDRESS = "127.0.0.1";
722:
723: private WebRequest _request;
724: private ServletMetaData _servletRequest;
725: private WebClient.HeaderDictionary _headers;
726: private ServletUnitContext _context;
727: private ServletUnitHttpSession _session;
728: private Hashtable _attributes = new Hashtable();
729: private Vector _cookies = new Vector();
730: private String _sessionID;
731: private byte[] _messageBody;
732:
733: private String _userName;
734: private String[] _roles;
735:
736: private void throwNotImplementedYet() {
737: throw new RuntimeException("Not implemented yet");
738: }
739:
740: private void setCookiesFromHeader(Dictionary clientHeaders) {
741: String cookieHeader = (String) clientHeaders.get("Cookie");
742: if (cookieHeader == null)
743: return;
744:
745: StringTokenizer st = new StringTokenizer(cookieHeader, ",;=",
746: true);
747: String lastToken = st.nextToken();
748: while (st.hasMoreTokens()) {
749: String token = st.nextToken();
750: if (token.equals("=")) {
751: if (st.hasMoreTokens())
752: addCookie(new Cookie(lastToken.trim(), st
753: .nextToken().trim()));
754: }
755: lastToken = token;
756: }
757: }
758:
759: static class PrioritizedLocale implements Comparable {
760:
761: private Locale _locale;
762: private float _priority;
763:
764: PrioritizedLocale(String languageSpec) {
765: int semiIndex = languageSpec.indexOf(';');
766: if (semiIndex < 0) {
767: _priority = 1;
768: _locale = parseLocale(languageSpec);
769: } else {
770: _priority = Float
771: .parseFloat(languageSpec.substring(languageSpec
772: .indexOf('=', semiIndex) + 1));
773: _locale = parseLocale(languageSpec.substring(0,
774: semiIndex));
775: }
776: }
777:
778: private Locale parseLocale(String range) {
779: range = range.trim();
780: int dashIndex = range.indexOf('-');
781: if (dashIndex < 0) {
782: return new Locale(range, "");
783: } else {
784: return new Locale(range.substring(0, dashIndex), range
785: .substring(dashIndex + 1));
786: }
787: }
788:
789: public Locale getLocale() {
790: return _locale;
791: }
792:
793: public int compareTo(Object o) {
794: if (!(o instanceof PrioritizedLocale))
795: throw new IllegalArgumentException(
796: "may only combine with other prioritized locales");
797: PrioritizedLocale other = (PrioritizedLocale) o;
798: return _priority == other._priority ? _locale.getLanguage()
799: .compareTo(other._locale.getLanguage())
800: : (_priority < other._priority ? +1 : -1);
801: }
802:
803: }
804: }
|