Source Code Cross Referenced for Reference.java in  » Web-Services » restlet-1.0.8 » org » restlet » data » Java Source Code / Java DocumentationJava Source Code and Java Documentation

Java Source Code / Java Documentation
1. 6.0 JDK Core
2. 6.0 JDK Modules
3. 6.0 JDK Modules com.sun
4. 6.0 JDK Modules com.sun.java
5. 6.0 JDK Modules sun
6. 6.0 JDK Platform
7. Ajax
8. Apache Harmony Java SE
9. Aspect oriented
10. Authentication Authorization
11. Blogger System
12. Build
13. Byte Code
14. Cache
15. Chart
16. Chat
17. Code Analyzer
18. Collaboration
19. Content Management System
20. Database Client
21. Database DBMS
22. Database JDBC Connection Pool
23. Database ORM
24. Development
25. EJB Server geronimo
26. EJB Server GlassFish
27. EJB Server JBoss 4.2.1
28. EJB Server resin 3.1.5
29. ERP CRM Financial
30. ESB
31. Forum
32. GIS
33. Graphic Library
34. Groupware
35. HTML Parser
36. IDE
37. IDE Eclipse
38. IDE Netbeans
39. Installer
40. Internationalization Localization
41. Inversion of Control
42. Issue Tracking
43. J2EE
44. JBoss
45. JMS
46. JMX
47. Library
48. Mail Clients
49. Net
50. Parser
51. PDF
52. Portal
53. Profiler
54. Project Management
55. Report
56. RSS RDF
57. Rule Engine
58. Science
59. Scripting
60. Search Engine
61. Security
62. Sevlet Container
63. Source Control
64. Swing Library
65. Template Engine
66. Test Coverage
67. Testing
68. UML
69. Web Crawler
70. Web Framework
71. Web Mail
72. Web Server
73. Web Services
74. Web Services apache cxf 2.0.1
75. Web Services AXIS2
76. Wiki Engine
77. Workflow Engines
78. XML
79. XML UI
Java
Java Tutorial
Java Open Source
Jar File Download
Java Articles
Java Products
Java by API
Photoshop Tutorials
Maya Tutorials
Flash Tutorials
3ds-Max Tutorials
Illustrator Tutorials
GIMP Tutorials
C# / C Sharp
C# / CSharp Tutorial
C# / CSharp Open Source
ASP.Net
ASP.NET Tutorial
JavaScript DHTML
JavaScript Tutorial
JavaScript Reference
HTML / CSS
HTML CSS Reference
C / ANSI-C
C Tutorial
C++
C++ Tutorial
Ruby
PHP
Python
Python Tutorial
Python Open Source
SQL Server / T-SQL
SQL Server / T-SQL Tutorial
Oracle PL / SQL
Oracle PL/SQL Tutorial
PostgreSQL
SQL / MySQL
MySQL Tutorial
VB.Net
VB.Net Tutorial
Flash / Flex / ActionScript
VBA / Excel / Access / Word
XML
XML Tutorial
Microsoft Office PowerPoint 2007 Tutorial
Microsoft Office Excel 2007 Tutorial
Microsoft Office Word 2007 Tutorial
Java Source Code / Java Documentation » Web Services » restlet 1.0.8 » org.restlet.data 
Source Cross Referenced  Class Diagram Java Document (Java Doc) 


0001:        /*
0002:         * Copyright 2005-2007 Noelios Consulting.
0003:         * 
0004:         * The contents of this file are subject to the terms of the Common Development
0005:         * and Distribution License (the "License"). You may not use this file except in
0006:         * compliance with the License.
0007:         * 
0008:         * You can obtain a copy of the license at
0009:         * http://www.opensource.org/licenses/cddl1.txt See the License for the specific
0010:         * language governing permissions and limitations under the License.
0011:         * 
0012:         * When distributing Covered Code, include this CDDL HEADER in each file and
0013:         * include the License file at http://www.opensource.org/licenses/cddl1.txt If
0014:         * applicable, add the following below this CDDL HEADER, with the fields
0015:         * enclosed by brackets "[]" replaced with your own identifying information:
0016:         * Portions Copyright [yyyy] [name of copyright owner]
0017:         */
0018:
0019:        package org.restlet.data;
0020:
0021:        import java.io.IOException;
0022:        import java.io.UnsupportedEncodingException;
0023:        import java.net.URLDecoder;
0024:        import java.net.URLEncoder;
0025:        import java.util.ArrayList;
0026:        import java.util.List;
0027:        import java.util.logging.Level;
0028:        import java.util.logging.Logger;
0029:
0030:        /**
0031:         * Reference to a Uniform Resource Identifier (URI). Contrary to the
0032:         * java.net.URI class, this interface represents mutable references. It strictly
0033:         * conforms to the RFC 3986 specifying URIs and follow its naming conventions.<br/>
0034:         * 
0035:         * <pre>
0036:         * URI reference        = absolute-reference | relative-reference
0037:         * 
0038:         * absolute-reference   = scheme &quot;:&quot; scheme-specific-part [ &quot;#&quot; fragment ]
0039:         * scheme-specific-part = ( hierarchical-part [ &quot;?&quot; query ] ) | opaque-part
0040:         * hierarchical-part    = ( &quot;//&quot; authority path-abempty ) | path-absolute | path-rootless | path-empty
0041:         * authority            = [ user-info &quot;@&quot; ] host-domain [ &quot;:&quot; host-port ]
0042:         * 
0043:         * relative-reference   = relative-part [ &quot;?&quot; query ] [ &quot;#&quot; fragment ]
0044:         * relative-part        = ( &quot;//&quot; authority path-abempty ) | path-absolute | path-noscheme | path-empty
0045:         * 
0046:         * path-abempty         = begins with &quot;/&quot; or is empty
0047:         * path-absolute        = begins with &quot;/&quot; but not &quot;//&quot;
0048:         * path-noscheme        = begins with a non-colon segment
0049:         * path-rootless        = begins with a segment
0050:         * path-empty           = zero characters
0051:         * </pre>
0052:         * 
0053:         * <p>
0054:         * Note that this class doesn't encode or decode the reserved characters. It
0055:         * assumes that the URIs or the URI parts passed in are properly encoded using
0056:         * the standard URI encoding mechanism. You can use the static "encode()" and
0057:         * "decode()" methods for this purpose.
0058:         * </p>
0059:         * <p>
0060:         * The fundamental point to underline is the difference between an URI
0061:         * "reference" and an URI. Contrary to an URI (the target identifier of a REST
0062:         * resource), an URI reference can be relative (with or without query and
0063:         * fragment part). This relative URI reference can then be resolved against a
0064:         * base reference via the getTargetRef() method which will return a new resolved
0065:         * Reference instance, an absolute URI reference with no base reference and with
0066:         * no dot-segments (the path segments "." and "..").
0067:         * </p>
0068:         * <p>
0069:         * You can also apply the getTargetRef() method on absolute references in order
0070:         * to solve the dot-segments. Note that applying the getRelativeRef() method on
0071:         * an absolute reference returns the current reference relatively to a base
0072:         * reference, if any, and solves the dot-segments.
0073:         * </p>
0074:         * <p>
0075:         * The Reference stores its data as a single string, the one passed to the
0076:         * constructor. This string can always be obtained using the toString() method.
0077:         * A couple of integer indexes are maintained to improve the extraction time of
0078:         * various reference properties (URI components).
0079:         * </p>
0080:         * <p>
0081:         * When you modify a specific component of the URI reference, via the setPath()
0082:         * method for example, the internal string is simply regenerated by updating
0083:         * only the relevant part. We try as much as possible to protect the bytes given
0084:         * to the Reference class instead of transparently parsing and normalizing the
0085:         * URI data. Our idea is to protect encodings and special characters in all case
0086:         * and reduce the memory size taken by this class while making Reference
0087:         * instances mutable.
0088:         * </p>
0089:         * <p>
0090:         * Because the base reference is only a property of the Reference ("baseRef").
0091:         * When you use the "Reference(base, path)" constructor, it is equivalent to
0092:         * doing:<br>
0093:         * ref = new Reference(path);<br>
0094:         * ref.setBaseRef(base);
0095:         * </p>
0096:         * <p>
0097:         * The base ref is not automatically resolved or "merged" with the rest of the
0098:         * reference information (the path here). For example, this let's you reuse a
0099:         * single reference as the base of several relative references. If you modify
0100:         * the base reference, all relative references are still accurate.
0101:         * </p>
0102:         * 
0103:         * @author Jerome Louvel (contact@noelios.com)
0104:         * @see <a href="http://www.faqs.org/rfcs/rfc3986.html">RFC 3986</a>
0105:         */
0106:        public class Reference {
0107:
0108:            /**
0109:             * Decodes a given string using the standard URI encoding mechanism and the
0110:             * UTF-8 character set.
0111:             * 
0112:             * @param toDecode
0113:             *            The string to decode.
0114:             * @return The decoded string.
0115:             */
0116:            public static String decode(String toDecode) {
0117:                String result = null;
0118:
0119:                try {
0120:                    result = URLDecoder.decode(toDecode, "UTF-8");
0121:                } catch (UnsupportedEncodingException uee) {
0122:                    Logger
0123:                            .getLogger(Reference.class.getCanonicalName())
0124:                            .log(
0125:                                    Level.WARNING,
0126:                                    "Unable to decode the string with the UTF-8 character set.",
0127:                                    uee);
0128:                }
0129:
0130:                return result;
0131:            }
0132:
0133:            /**
0134:             * Encodes a given string using the standard URI encoding mechanism and the
0135:             * UTF-8 character set.
0136:             * 
0137:             * @param toEncode
0138:             *            The string to encode.
0139:             * @return The encoded string.
0140:             */
0141:            public static String encode(String toEncode) {
0142:                String result = null;
0143:
0144:                try {
0145:                    result = URLEncoder.encode(toEncode, "UTF-8");
0146:                } catch (UnsupportedEncodingException uee) {
0147:                    Logger
0148:                            .getLogger(Reference.class.getCanonicalName())
0149:                            .log(
0150:                                    Level.WARNING,
0151:                                    "Unable to encode the string with the UTF-8 character set.",
0152:                                    uee);
0153:                }
0154:
0155:                return result;
0156:            }
0157:
0158:            /**
0159:             * Encodes a given string using the standard URI encoding mechanism. If the
0160:             * provided character set is null, the string is returned but not encoded.
0161:             * 
0162:             * <em><strong>Note:</strong> The <a
0163:             * href="http://www.w3.org/TR/html40/appendix/notes.html#non-ascii-chars">
0164:             * World Wide Web Consortium Recommendation</a> states that UTF-8 should be
0165:             * used. Not doing so may introduce incompatibilites.</em>
0166:             * 
0167:             * @param toEncode
0168:             *            The string to encode.
0169:             * @param characterSet
0170:             *            The supported character encoding.
0171:             * @return The encoded string or null if the named character encoding is not
0172:             *         supported.
0173:             */
0174:            public static String encode(String toEncode,
0175:                    CharacterSet characterSet) {
0176:                String result = null;
0177:
0178:                try {
0179:                    result = (characterSet == null) ? toEncode : URLEncoder
0180:                            .encode(toEncode, characterSet.getName());
0181:                } catch (UnsupportedEncodingException uee) {
0182:                    Logger
0183:                            .getLogger(Reference.class.getCanonicalName())
0184:                            .log(
0185:                                    Level.WARNING,
0186:                                    "Unable to encode the string with the UTF-8 character set.",
0187:                                    uee);
0188:                }
0189:
0190:                return result;
0191:            }
0192:
0193:            /**
0194:             * Decodes a given string using the standard URI encoding mechanism. If the
0195:             * provided character set is null, the string is returned but not decoded.
0196:             * <em><strong>Note:</strong> The <a
0197:             * href="http://www.w3.org/TR/html40/appendix/notes.html#non-ascii-chars">
0198:             * World Wide Web Consortium Recommendation</a> states that UTF-8 should be
0199:             * used. Not doing so may introduce incompatibilites.</em>
0200:             * 
0201:             * @param toDecode
0202:             *            The string to decode.
0203:             * @param characterSet
0204:             *            The name of a supported character encoding.
0205:             * @return The decoded string or null if the named character encoding is not
0206:             *         supported.
0207:             */
0208:            public static String decode(String toDecode,
0209:                    CharacterSet characterSet) {
0210:                String result = null;
0211:
0212:                try {
0213:                    result = (characterSet == null) ? toDecode : URLDecoder
0214:                            .decode(toDecode, characterSet.getName());
0215:                } catch (UnsupportedEncodingException uee) {
0216:                    Logger
0217:                            .getLogger(Reference.class.getCanonicalName())
0218:                            .log(
0219:                                    Level.WARNING,
0220:                                    "Unable to decode the string with the UTF-8 character set.",
0221:                                    uee);
0222:                }
0223:
0224:                return result;
0225:            }
0226:
0227:            /**
0228:             * Creates a reference string from its parts.
0229:             * 
0230:             * @param scheme
0231:             *            The scheme ("http", "https" or "ftp").
0232:             * @param hostName
0233:             *            The host name or IP address.
0234:             * @param hostPort
0235:             *            The host port (default ports are correctly ignored).
0236:             * @param path
0237:             *            The path component for hierarchical identifiers.
0238:             * @param query
0239:             *            The optional query component for hierarchical identifiers.
0240:             * @param fragment
0241:             *            The optional fragment identifier.
0242:             */
0243:            public static String toString(String scheme, String hostName,
0244:                    Integer hostPort, String path, String query, String fragment) {
0245:                String host = hostName;
0246:
0247:                // Appends the host port number
0248:                if (hostPort != null) {
0249:                    int defaultPort = Protocol.valueOf(scheme).getDefaultPort();
0250:                    if (hostPort != defaultPort) {
0251:                        host = hostName + ':' + hostPort;
0252:                    }
0253:                }
0254:
0255:                return toString(scheme, host, path, query, fragment);
0256:            }
0257:
0258:            /**
0259:             * Creates a relative reference string from its parts.
0260:             * 
0261:             * @param relativePart
0262:             *            The relative part component.
0263:             * @param query
0264:             *            The optional query component for hierarchical identifiers.
0265:             * @param fragment
0266:             *            The optional fragment identifier.
0267:             */
0268:            public static String toString(String relativePart, String query,
0269:                    String fragment) {
0270:                StringBuilder sb = new StringBuilder();
0271:
0272:                // Append the path
0273:                if (relativePart != null) {
0274:                    sb.append(relativePart);
0275:                }
0276:
0277:                // Append the query string
0278:                if (query != null) {
0279:                    sb.append('?').append(query);
0280:                }
0281:
0282:                // Append the fragment identifier
0283:                if (fragment != null) {
0284:                    sb.append('#').append(fragment);
0285:                }
0286:
0287:                // Actually construct the reference
0288:                return sb.toString();
0289:            }
0290:
0291:            /**
0292:             * Creates a reference string from its parts.
0293:             * 
0294:             * @param scheme
0295:             *            The scheme ("http", "https" or "ftp").
0296:             * @param host
0297:             *            The host name or IP address plus the optional port number.
0298:             * @param path
0299:             *            The path component for hierarchical identifiers.
0300:             * @param query
0301:             *            The optional query component for hierarchical identifiers.
0302:             * @param fragment
0303:             *            The optional fragment identifier.
0304:             */
0305:            public static String toString(String scheme, String host,
0306:                    String path, String query, String fragment) {
0307:                StringBuilder sb = new StringBuilder();
0308:
0309:                if (scheme != null) {
0310:                    // Append the scheme and host name
0311:                    sb.append(scheme.toLowerCase()).append("://").append(host);
0312:                }
0313:
0314:                // Append the path
0315:                if (path != null) {
0316:                    sb.append(path);
0317:                }
0318:
0319:                // Append the query string
0320:                if (query != null) {
0321:                    sb.append('?').append(query);
0322:                }
0323:
0324:                // Append the fragment identifier
0325:                if (fragment != null) {
0326:                    sb.append('#').append(fragment);
0327:                }
0328:
0329:                // Actually construct the reference
0330:                return sb.toString();
0331:            }
0332:
0333:            /** The base reference for relative references. */
0334:            private Reference baseRef;
0335:
0336:            /** The internal reference. */
0337:            private String internalRef;
0338:
0339:            /** The fragment separator index. */
0340:            private int fragmentIndex;
0341:
0342:            /** The query separator index. */
0343:            private int queryIndex;
0344:
0345:            /** The scheme separator index. */
0346:            private int schemeIndex;
0347:
0348:            /**
0349:             * Empty constructor.
0350:             */
0351:            public Reference() {
0352:                this ((Reference) null, (String) null);
0353:            }
0354:
0355:            /**
0356:             * Clone constructor.
0357:             * 
0358:             * @param ref
0359:             *            The reference to clone.
0360:             */
0361:            public Reference(Reference ref) {
0362:                this (ref.baseRef, ref.internalRef);
0363:            }
0364:
0365:            /**
0366:             * Constructor from an URI reference (most likely relative).
0367:             * 
0368:             * @param baseRef
0369:             *            The base reference.
0370:             * @param uriReference
0371:             *            The URI reference, either absolute or relative.
0372:             */
0373:            public Reference(Reference baseRef, String uriReference) {
0374:                this .baseRef = baseRef;
0375:                this .internalRef = uriReference;
0376:                updateIndexes();
0377:            }
0378:
0379:            /**
0380:             * Constructor of relative reference from its parts.
0381:             * 
0382:             * @param baseRef
0383:             *            The base reference.
0384:             * @param relativePart
0385:             *            The relative part component (most of the time it is the path
0386:             *            component).
0387:             * @param query
0388:             *            The optional query component for hierarchical identifiers.
0389:             * @param fragment
0390:             *            The optional fragment identifier.
0391:             */
0392:            public Reference(Reference baseRef, String relativePart,
0393:                    String query, String fragment) {
0394:                this (baseRef, toString(relativePart, query, fragment));
0395:            }
0396:
0397:            /**
0398:             * Constructor from an URI reference.
0399:             * 
0400:             * @param uriReference
0401:             *            The URI reference, either absolute or relative.
0402:             */
0403:            public Reference(String uriReference) {
0404:                this ((Reference) null, uriReference);
0405:            }
0406:
0407:            /**
0408:             * Constructor from an identifier and a fragment.
0409:             * 
0410:             * @param identifier
0411:             *            The resource identifier.
0412:             * @param fragment
0413:             *            The fragment identifier.
0414:             */
0415:            public Reference(String identifier, String fragment) {
0416:                this ((fragment == null) ? identifier : identifier + '#'
0417:                        + fragment);
0418:            }
0419:
0420:            /**
0421:             * Constructor of absolute reference from its parts.
0422:             * 
0423:             * @param scheme
0424:             *            The scheme ("http", "https" or "ftp").
0425:             * @param hostName
0426:             *            The host name or IP address.
0427:             * @param hostPort
0428:             *            The host port (default ports are correctly ignored).
0429:             * @param path
0430:             *            The path component for hierarchical identifiers.
0431:             * @param query
0432:             *            The optional query component for hierarchical identifiers.
0433:             * @param fragment
0434:             *            The optional fragment identifier.
0435:             */
0436:            public Reference(String scheme, String hostName, int hostPort,
0437:                    String path, String query, String fragment) {
0438:                this (
0439:                        toString(scheme, hostName, hostPort, path, query,
0440:                                fragment));
0441:            }
0442:
0443:            /**
0444:             * Indicates whether some other object is "equal to" this one.
0445:             * 
0446:             * @param object
0447:             *            The object to compare to.
0448:             * @return True if this object is the same as the obj argument.
0449:             */
0450:            @Override
0451:            public boolean equals(Object object) {
0452:                if (object instanceof  Reference) {
0453:                    Reference ref = (Reference) object;
0454:                    if (this .internalRef == null) {
0455:                        return ref.internalRef == null;
0456:                    } else {
0457:                        return this .internalRef.equals(ref.internalRef);
0458:                    }
0459:                } else {
0460:                    return false;
0461:                }
0462:            }
0463:
0464:            /**
0465:             * Returns the authority component for hierarchical identifiers. Includes
0466:             * the user info, host name and the host port number.
0467:             * 
0468:             * @return The authority component for hierarchical identifiers.
0469:             */
0470:            public String getAuthority() {
0471:                String part = isRelative() ? getRelativePart()
0472:                        : getSchemeSpecificPart();
0473:
0474:                if (part.startsWith("//")) {
0475:                    int index = part.indexOf('/', 2);
0476:
0477:                    if (index != -1) {
0478:                        return part.substring(2, index);
0479:                    } else {
0480:                        index = part.indexOf('?');
0481:                        if (index != -1) {
0482:                            return part.substring(2, index);
0483:                        } else {
0484:                            return part.substring(2);
0485:                        }
0486:                    }
0487:                } else {
0488:                    return null;
0489:                }
0490:            }
0491:
0492:            /**
0493:             * Returns the base reference for relative references.
0494:             * 
0495:             * @return The base reference for relative references.
0496:             */
0497:            public Reference getBaseRef() {
0498:                return this .baseRef;
0499:            }
0500:
0501:            /**
0502:             * Returns the fragment identifier.
0503:             * 
0504:             * @return The fragment identifier.
0505:             */
0506:            public String getFragment() {
0507:                if (fragmentIndex != -1) {
0508:                    return this .internalRef.substring(fragmentIndex + 1);
0509:                } else {
0510:                    return null;
0511:                }
0512:            }
0513:
0514:            /**
0515:             * Returns the hierarchical part which is equivalent to the scheme specific
0516:             * part less the query component.
0517:             * 
0518:             * @return The hierarchical part .
0519:             */
0520:            public String getHierarchicalPart() {
0521:                if (schemeIndex != -1) {
0522:                    // Scheme found
0523:                    if (queryIndex != -1) {
0524:                        // Query found
0525:                        return this .internalRef.substring(schemeIndex + 1,
0526:                                queryIndex);
0527:                    } else {
0528:                        // No query found
0529:                        if (fragmentIndex != -1) {
0530:                            // Fragment found
0531:                            return this .internalRef.substring(schemeIndex + 1,
0532:                                    fragmentIndex);
0533:                        } else {
0534:                            // No fragment found
0535:                            return this .internalRef.substring(schemeIndex + 1);
0536:                        }
0537:                    }
0538:                } else {
0539:                    // No scheme found
0540:                    if (queryIndex != -1) {
0541:                        // Query found
0542:                        return this .internalRef.substring(0, queryIndex);
0543:                    } else {
0544:                        if (fragmentIndex != -1) {
0545:                            // Fragment found
0546:                            return this .internalRef.substring(0, fragmentIndex);
0547:                        } else {
0548:                            // No fragment found
0549:                            return this .internalRef;
0550:                        }
0551:                    }
0552:                }
0553:            }
0554:
0555:            /**
0556:             * Returns the host domain name component for server based hierarchical
0557:             * identifiers. It can also be replaced by an IP address when no domain name
0558:             * was registered.
0559:             * 
0560:             * @return The host domain name component for server based hierarchical
0561:             *         identifiers.
0562:             */
0563:            public String getHostDomain() {
0564:                String result = null;
0565:                String authority = getAuthority();
0566:
0567:                if (authority != null) {
0568:                    int index1 = authority.indexOf('@');
0569:                    int index2 = authority.indexOf(':');
0570:
0571:                    if (index1 != -1) {
0572:                        // User info found
0573:                        if (index2 != -1) {
0574:                            // Port found
0575:                            result = authority.substring(index1 + 1, index2);
0576:                        } else {
0577:                            // No port found
0578:                            result = authority.substring(index1 + 1);
0579:                        }
0580:                    } else {
0581:                        // No user info found
0582:                        if (index2 != -1) {
0583:                            // Port found
0584:                            result = authority.substring(0, index2);
0585:                        } else {
0586:                            // No port found
0587:                            result = authority;
0588:                        }
0589:                    }
0590:                }
0591:
0592:                return result;
0593:            }
0594:
0595:            /**
0596:             * Returns the host identifier. Includes the scheme, the host name and the
0597:             * host port number.
0598:             * 
0599:             * @return The host identifier.
0600:             */
0601:            public String getHostIdentifier() {
0602:                StringBuilder result = new StringBuilder();
0603:                result.append(getScheme()).append("://").append(getAuthority());
0604:                return result.toString();
0605:            }
0606:
0607:            /**
0608:             * Returns the optional port number for server based hierarchical
0609:             * identifiers.
0610:             * 
0611:             * @return The optional port number for server based hierarchical
0612:             *         identifiers or -1 if the port number does not exist.
0613:             */
0614:            public int getHostPort() {
0615:                int result = -1;
0616:                String authority = getAuthority();
0617:
0618:                if (authority != null) {
0619:                    int index = authority.indexOf(':');
0620:
0621:                    if (index != -1) {
0622:                        try {
0623:                            result = Integer.parseInt(authority
0624:                                    .substring(index + 1));
0625:                        } catch (NumberFormatException nfe) {
0626:                            Logger
0627:                                    .getLogger(
0628:                                            Reference.class.getCanonicalName())
0629:                                    .log(
0630:                                            Level.WARNING,
0631:                                            "Can't parse hostPort : [hostRef,requestUri]=["
0632:                                                    + getBaseRef() + ","
0633:                                                    + internalRef + "]");
0634:                        }
0635:                    }
0636:                }
0637:
0638:                return result;
0639:            }
0640:
0641:            /**
0642:             * Returns the absolute resource identifier, without the fragment.
0643:             * 
0644:             * @return The absolute resource identifier, without the fragment.
0645:             */
0646:            public String getIdentifier() {
0647:                if (fragmentIndex != -1) {
0648:                    // Fragment found
0649:                    return this .internalRef.substring(0, fragmentIndex);
0650:                } else {
0651:                    // No fragment found
0652:                    return this .internalRef;
0653:                }
0654:            }
0655:
0656:            /**
0657:             * Returns the last segment of a hierarchical path.<br/> For example the
0658:             * "/a/b/c" and "/a/b/c/" paths have the same segments: "a", "b", "c.
0659:             * 
0660:             * @return The last segment of a hierarchical path.
0661:             */
0662:            public String getLastSegment() {
0663:                String result = null;
0664:                int lastSlash = getPath().lastIndexOf('/');
0665:
0666:                if (lastSlash != -1) {
0667:                    result = getPath().substring(lastSlash + 1);
0668:                }
0669:
0670:                return result;
0671:            }
0672:
0673:            /**
0674:             * Returns the parent reference of a hierarchical reference. The last slash
0675:             * of the path will be considered as the end of the parent path.
0676:             * 
0677:             * @return The parent reference of a hierarchical reference.
0678:             */
0679:            public Reference getParentRef() {
0680:                Reference result = null;
0681:
0682:                if (isHierarchical()) {
0683:                    String parentRef = null;
0684:                    String path = getPath();
0685:                    if (!path.equals("/") && !path.equals("")) {
0686:                        if (path.endsWith("/")) {
0687:                            path = path.substring(0, path.length() - 1);
0688:                        }
0689:
0690:                        parentRef = getHostIdentifier()
0691:                                + path.substring(0, path.lastIndexOf('/') + 1);
0692:                    } else {
0693:                        parentRef = this .internalRef;
0694:                    }
0695:
0696:                    result = new Reference(parentRef);
0697:                }
0698:
0699:                return result;
0700:            }
0701:
0702:            /**
0703:             * Returns the path component for hierarchical identifiers.
0704:             * 
0705:             * @return The path component for hierarchical identifiers.
0706:             */
0707:            public String getPath() {
0708:                String result = null;
0709:                String part = isRelative() ? getRelativePart()
0710:                        : getSchemeSpecificPart();
0711:
0712:                if (part != null) {
0713:                    if (part.startsWith("//")) {
0714:                        // Authority found
0715:                        int index1 = part.indexOf('/', 2);
0716:
0717:                        if (index1 != -1) {
0718:                            // Path found
0719:                            int index2 = part.indexOf('?');
0720:                            if (index2 != -1) {
0721:                                // Query found
0722:                                result = part.substring(index1, index2);
0723:                            } else {
0724:                                // No query found
0725:                                result = part.substring(index1);
0726:                            }
0727:                        } else {
0728:                            // Path must be empty in this case
0729:                        }
0730:                    } else {
0731:                        // No authority found
0732:                        int index = part.indexOf('?');
0733:                        if (index != -1) {
0734:                            // Query found
0735:                            result = part.substring(0, index);
0736:                        } else {
0737:                            // No query found
0738:                            result = part;
0739:                        }
0740:                    }
0741:                }
0742:
0743:                return result;
0744:            }
0745:
0746:            /**
0747:             * Returns the optional query component for hierarchical identifiers.
0748:             * 
0749:             * @return The optional query component for hierarchical identifiers.
0750:             */
0751:            public String getQuery() {
0752:                if (queryIndex != -1) {
0753:                    // Query found
0754:                    if (fragmentIndex != -1) {
0755:                        if (queryIndex < fragmentIndex) {
0756:                            // Fragment found and query sign not inside fragment
0757:                            return this .internalRef.substring(queryIndex + 1,
0758:                                    fragmentIndex);
0759:                        } else {
0760:                            return null;
0761:                        }
0762:                    } else {
0763:                        // No fragment found
0764:                        return this .internalRef.substring(queryIndex + 1);
0765:                    }
0766:                } else {
0767:                    // No query found
0768:                    return null;
0769:                }
0770:            }
0771:
0772:            /**
0773:             * Returns the optional query component as a form submission.
0774:             * 
0775:             * @return The optional query component as a form submission.
0776:             * @throws IOException
0777:             */
0778:            public Form getQueryAsForm() {
0779:                return new Form(getQuery());
0780:            }
0781:
0782:            /**
0783:             * Returns the optional query component as a form submission.
0784:             * 
0785:             * @param characterSet
0786:             *            The supported character encoding.
0787:             * @return The optional query component as a form submission.
0788:             * @throws IOException
0789:             */
0790:            public Form getQueryAsForm(CharacterSet characterSet) {
0791:                return new Form(getQuery(), characterSet);
0792:            }
0793:
0794:            /**
0795:             * Returns the relative part of relative references, without the query and
0796:             * fragment. If the reference is absolute, then null is returned.
0797:             * 
0798:             * @return The relative part.
0799:             */
0800:            public String getRelativePart() {
0801:                return isRelative() ? toString(false, false) : null;
0802:            }
0803:
0804:            /**
0805:             * Returns the part of the resource identifier remaining after the base
0806:             * reference. Note that the optional fragment is not returned by this
0807:             * method. Must be used with the following prerequisites:
0808:             * <ul>
0809:             * <li>the reference is absolute</li>
0810:             * <li>the reference identifier starts with the resource baseRef</li>
0811:             * </ul>
0812:             * 
0813:             * @return The remaining resource part or null if the prerequisites are not
0814:             *         satisfied.
0815:             */
0816:            public String getRemainingPart() {
0817:                String result = null;
0818:                String all = toString(true, false);
0819:
0820:                if (getBaseRef() != null) {
0821:                    String base = getBaseRef().toString(true, false);
0822:
0823:                    if ((base != null) && all.startsWith(base)) {
0824:                        result = all.substring(base.length());
0825:                    }
0826:                } else {
0827:                    result = all;
0828:                }
0829:
0830:                return result;
0831:            }
0832:
0833:            /**
0834:             * Returns the current reference as a relative reference to the current base
0835:             * reference. This method should only be invoked for absolute references,
0836:             * otherwise an IllegalArgumentException will be raised.
0837:             * 
0838:             * @return The current reference as a relative reference to the current base
0839:             *         reference.
0840:             * @see #getRelativeRef(Reference)
0841:             */
0842:            public Reference getRelativeRef() {
0843:                return getRelativeRef(getBaseRef());
0844:            }
0845:
0846:            /**
0847:             * Returns the current reference relatively to a base reference. This method
0848:             * should only be invoked for absolute references, otherwise an
0849:             * IllegalArgumentException will be raised.
0850:             * 
0851:             * @throws IllegalArgumentException
0852:             *             If the relative reference is computed although the reference
0853:             *             or the base reference are not absolute or not hierarchical.
0854:             * @param base
0855:             *            The base reference to use.
0856:             * @return The current reference relatively to a base reference.
0857:             */
0858:            public Reference getRelativeRef(Reference base) {
0859:                Reference result = null;
0860:
0861:                if (base == null) {
0862:                    result = this ;
0863:                } else if (!isAbsolute() || !isHierarchical()) {
0864:                    throw new IllegalArgumentException(
0865:                            "The reference must have an absolute hierarchical path component");
0866:                } else if (!base.isAbsolute() || !base.isHierarchical()) {
0867:                    throw new IllegalArgumentException(
0868:                            "The base reference must have an absolute hierarchical path component");
0869:                } else if (!getHostIdentifier()
0870:                        .equals(base.getHostIdentifier())) {
0871:                    result = this ;
0872:                } else {
0873:                    String localPath = getPath();
0874:                    String basePath = base.getPath();
0875:                    String relativePath = null;
0876:
0877:                    if ((basePath == null) || (localPath == null)) {
0878:                        relativePath = localPath;
0879:                    } else {
0880:                        // Find the junction point
0881:                        boolean diffFound = false;
0882:                        int lastSlashIndex = -1;
0883:                        int i = 0;
0884:                        char current;
0885:                        while (!diffFound && (i < localPath.length())
0886:                                && (i < basePath.length())) {
0887:                            current = localPath.charAt(i);
0888:
0889:                            if (current != basePath.charAt(i)) {
0890:                                diffFound = true;
0891:                            } else {
0892:                                if (current == '/')
0893:                                    lastSlashIndex = i;
0894:                                i++;
0895:                            }
0896:                        }
0897:
0898:                        if (!diffFound) {
0899:                            if (localPath.length() == basePath.length()) {
0900:                                // Both paths are strictely equivalent
0901:                                relativePath = ".";
0902:                            } else if (i == localPath.length()) {
0903:                                // End of local path reached
0904:                                if (basePath.charAt(i) == '/') {
0905:                                    if ((i + 1) == basePath.length()) {
0906:                                        // Both paths are strictely equivalent
0907:                                        relativePath = ".";
0908:                                    } else {
0909:                                        // The local path is a direct parent of the base
0910:                                        // path
0911:                                        // We need to add enough ".." in the relative
0912:                                        // path
0913:                                        StringBuilder sb = new StringBuilder();
0914:                                        sb.append("..");
0915:                                        boolean canAdd = false;
0916:
0917:                                        for (int j = i + 1; j < basePath
0918:                                                .length(); j++) {
0919:                                            if (basePath.charAt(j) == '/') {
0920:                                                canAdd = true;
0921:                                            } else if (canAdd) {
0922:                                                sb.append("/..");
0923:                                                canAdd = false;
0924:                                            }
0925:                                        }
0926:
0927:                                        relativePath = sb.toString();
0928:                                    }
0929:                                } else {
0930:                                    // The base path has a segment that starts like
0931:                                    // the last local path segment
0932:                                    // But that is longer. Situation similar to a
0933:                                    // junction
0934:                                    StringBuilder sb = new StringBuilder();
0935:                                    boolean firstAdd = true;
0936:                                    boolean canAdd = false;
0937:
0938:                                    for (int j = i; j < basePath.length(); j++) {
0939:                                        if (basePath.charAt(j) == '/') {
0940:                                            canAdd = true;
0941:                                        } else if (canAdd) {
0942:                                            if (firstAdd) {
0943:                                                firstAdd = false;
0944:                                            } else {
0945:                                                sb.append("/");
0946:                                            }
0947:
0948:                                            sb.append("..");
0949:                                            canAdd = false;
0950:                                        }
0951:                                    }
0952:
0953:                                    if (lastSlashIndex + 1 < localPath.length()) {
0954:                                        if (!firstAdd)
0955:                                            sb.append('/');
0956:                                        sb.append(localPath
0957:                                                .substring(lastSlashIndex + 1));
0958:                                    }
0959:
0960:                                    relativePath = sb.toString();
0961:
0962:                                    if (relativePath.equals(""))
0963:                                        relativePath = ".";
0964:                                }
0965:                            } else if (i == basePath.length()) {
0966:                                if (localPath.charAt(i) == '/') {
0967:                                    if ((i + 1) == localPath.length()) {
0968:                                        // Both paths are strictely equivalent
0969:                                        relativePath = ".";
0970:                                    } else {
0971:                                        // The local path is a direct child of the base
0972:                                        // path
0973:                                        relativePath = localPath
0974:                                                .substring(i + 1);
0975:                                    }
0976:                                } else {
0977:                                    if (lastSlashIndex == (i - 1)) {
0978:                                        // The local path is a direct subpath of the
0979:                                        // base path
0980:                                        relativePath = localPath.substring(i);
0981:                                    } else {
0982:                                        relativePath = ".."
0983:                                                + localPath
0984:                                                        .substring(lastSlashIndex);
0985:                                    }
0986:                                }
0987:                            }
0988:                        } else {
0989:                            // We found a junction point, we need to add enough ".." in
0990:                            // the relative path and append the rest of the local path
0991:                            // the local path is a direct subpath of the base path
0992:                            StringBuilder sb = new StringBuilder();
0993:                            boolean canAdd = false;
0994:                            boolean firstAdd = true;
0995:
0996:                            for (int j = i; j < basePath.length(); j++) {
0997:                                if (basePath.charAt(j) == '/') {
0998:                                    canAdd = true;
0999:                                } else if (canAdd) {
1000:                                    if (firstAdd) {
1001:                                        firstAdd = false;
1002:                                    } else {
1003:                                        sb.append("/");
1004:                                    }
1005:
1006:                                    sb.append("..");
1007:                                    canAdd = false;
1008:                                }
1009:                            }
1010:
1011:                            if (!firstAdd)
1012:                                sb.append('/');
1013:                            sb.append(localPath.substring(lastSlashIndex + 1));
1014:                            relativePath = sb.toString();
1015:                        }
1016:                    }
1017:
1018:                    // Builde the result reference
1019:                    result = new Reference();
1020:                    String query = getQuery();
1021:                    String fragment = getFragment();
1022:                    boolean modified = false;
1023:
1024:                    if ((query != null) && (!query.equals(base.getQuery()))) {
1025:                        result.setQuery(query);
1026:                        modified = true;
1027:                    }
1028:
1029:                    if ((fragment != null)
1030:                            && (!fragment.equals(base.getFragment()))) {
1031:                        result.setFragment(fragment);
1032:                        modified = true;
1033:                    }
1034:
1035:                    if (!modified || !relativePath.equals(".")) {
1036:                        result.setPath(relativePath);
1037:                    }
1038:                }
1039:
1040:                return result;
1041:            }
1042:
1043:            /**
1044:             * Returns the scheme component.
1045:             * 
1046:             * @return The scheme component.
1047:             */
1048:            public String getScheme() {
1049:                if (schemeIndex != -1) {
1050:                    // Scheme found
1051:                    return this .internalRef.substring(0, schemeIndex);
1052:                } else {
1053:                    // No scheme found
1054:                    return null;
1055:                }
1056:            }
1057:
1058:            /**
1059:             * Returns the protocol associated with the scheme component.
1060:             * 
1061:             * @return The protocol associated with the scheme component.
1062:             */
1063:            public Protocol getSchemeProtocol() {
1064:                return Protocol.valueOf(getScheme());
1065:            }
1066:
1067:            /**
1068:             * Returns the scheme specific part.
1069:             * 
1070:             * @return The scheme specific part.
1071:             */
1072:            public String getSchemeSpecificPart() {
1073:                String result = null;
1074:
1075:                if (schemeIndex != -1) {
1076:                    // Scheme found
1077:                    if (fragmentIndex != -1) {
1078:                        // Fragment found
1079:                        result = this .internalRef.substring(schemeIndex + 1,
1080:                                fragmentIndex);
1081:                    } else {
1082:                        // No fragment found
1083:                        result = this .internalRef.substring(schemeIndex + 1);
1084:                    }
1085:                }
1086:
1087:                return result;
1088:            }
1089:
1090:            /**
1091:             * Returns the segments of a hierarchical path.<br/> A new list is created
1092:             * for each call.
1093:             * 
1094:             * @return The segments of a hierarchical path.
1095:             */
1096:            public List<String> getSegments() {
1097:                List<String> result = new ArrayList<String>();
1098:                ;
1099:                String path = getPath();
1100:                int start = -2; // The index of the slash starting the segment
1101:                char current;
1102:
1103:                if (path != null) {
1104:                    for (int i = 0; i < path.length(); i++) {
1105:                        current = path.charAt(i);
1106:
1107:                        if (current == '/') {
1108:                            if (start == -2) {
1109:                                // Beginning of an absolute path or sequence of two
1110:                                // separators
1111:                                start = i;
1112:                            } else {
1113:                                // End of a segment
1114:                                result.add(path.substring(start + 1, i));
1115:                                start = i;
1116:                            }
1117:                        } else {
1118:                            if (start == -2) {
1119:                                // Starting a new segment for a relative path
1120:                                start = -1;
1121:                            } else {
1122:                                // Looking for the next character
1123:                            }
1124:                        }
1125:                    }
1126:
1127:                    if (start != -2) {
1128:                        // Add the last segment
1129:                        result.add(path.substring(start + 1));
1130:                    }
1131:                }
1132:
1133:                return result;
1134:            }
1135:
1136:            /**
1137:             * Returns the target reference. This method resolves relative references
1138:             * against the base reference then normalize them.
1139:             * 
1140:             * @throws IllegalArgumentException
1141:             *             If the base reference (after resolution) is not absolute.
1142:             * @throws IllegalArgumentException
1143:             *             If the reference is relative and not base reference has been
1144:             *             provided.
1145:             * 
1146:             * @return The target reference.
1147:             */
1148:            public Reference getTargetRef() {
1149:                Reference result = null;
1150:
1151:                // Step 1 - Resolve relative reference against their base reference
1152:                if (isRelative() && (this .baseRef != null)) {
1153:                    Reference baseReference = null;
1154:                    if (this .baseRef.isAbsolute()) {
1155:                        baseReference = this .baseRef;
1156:                    } else {
1157:                        baseReference = this .baseRef.getTargetRef();
1158:                    }
1159:                    if (baseReference.isRelative()) {
1160:                        throw new IllegalArgumentException(
1161:                                "The base reference must have an absolute hierarchical path component");
1162:                    }
1163:
1164:                    // Relative URI detected
1165:                    String authority = getAuthority();
1166:                    String path = getPath();
1167:                    String query = getQuery();
1168:                    String fragment = getFragment();
1169:
1170:                    // Create an empty reference
1171:                    result = new Reference();
1172:                    result.setScheme(baseReference.getScheme());
1173:
1174:                    if (authority != null) {
1175:                        result.setAuthority(authority);
1176:                        result.setPath(path);
1177:                        result.setQuery(query);
1178:                    } else {
1179:                        result.setAuthority(baseReference.getAuthority());
1180:
1181:                        if ((path == null) || (path.equals(""))) {
1182:                            result.setPath(baseReference.getPath());
1183:
1184:                            if (query != null) {
1185:                                result.setQuery(query);
1186:                            } else {
1187:                                result.setQuery(baseReference.getQuery());
1188:                            }
1189:                        } else {
1190:                            if (path.startsWith("/")) {
1191:                                result.setPath(path);
1192:                            } else {
1193:                                String basePath = baseReference.getPath();
1194:                                String mergedPath = null;
1195:
1196:                                if ((baseReference.getAuthority() != null)
1197:                                        && ((basePath == null) || (basePath
1198:                                                .equals("")))) {
1199:                                    mergedPath = "/" + path;
1200:                                } else {
1201:                                    // Remove the last segment which may be empty if
1202:                                    // the path is ending with a slash
1203:                                    int lastSlash = basePath.lastIndexOf('/');
1204:                                    if (lastSlash == -1) {
1205:                                        mergedPath = path;
1206:                                    } else {
1207:                                        mergedPath = basePath.substring(0,
1208:                                                lastSlash + 1)
1209:                                                + path;
1210:                                    }
1211:                                }
1212:
1213:                                result.setPath(mergedPath);
1214:                            }
1215:
1216:                            result.setQuery(query);
1217:                        }
1218:                    }
1219:
1220:                    result.setFragment(fragment);
1221:                } else if (isRelative()) {
1222:                    // Relative reference with no baseRef detected
1223:                    throw new IllegalArgumentException(
1224:                            "Relative references are only usable when a base reference is set.");
1225:                } else {
1226:                    // Absolute URI detected
1227:                    result = new Reference(this );
1228:                }
1229:
1230:                // Step 2 - Normalize the target reference
1231:                result.normalize();
1232:
1233:                return result;
1234:            }
1235:
1236:            /**
1237:             * Returns the user info component for server based hierarchical
1238:             * identifiers.
1239:             * 
1240:             * @return The user info component for server based hierarchical
1241:             *         identifiers.
1242:             */
1243:            public String getUserInfo() {
1244:                String result = null;
1245:                String authority = getAuthority();
1246:
1247:                if (authority != null) {
1248:                    int index = authority.indexOf('@');
1249:
1250:                    if (index != -1) {
1251:                        result = authority.substring(0, index);
1252:                    }
1253:                }
1254:
1255:                return result;
1256:            }
1257:
1258:            /**
1259:             * Returns a hash code value for the object.
1260:             * 
1261:             * @return A hash code value for the object.
1262:             */
1263:            @Override
1264:            public int hashCode() {
1265:                return (this .internalRef == null) ? 0 : this .internalRef
1266:                        .hashCode();
1267:            }
1268:
1269:            /**
1270:             * Indicates if the reference is absolute.
1271:             * 
1272:             * @return True if the reference is absolute.
1273:             */
1274:            public boolean isAbsolute() {
1275:                return (getScheme() != null);
1276:            }
1277:
1278:            /**
1279:             * Returns true if both reference are equivalent, meaning that they resolve
1280:             * to the same target reference.
1281:             * 
1282:             * @param ref
1283:             *            The reference to compare.
1284:             * @return True if both reference are equivalent.
1285:             */
1286:            public boolean isEquivalentTo(Reference ref) {
1287:                return getTargetRef().equals(ref.getTargetRef());
1288:            }
1289:
1290:            /**
1291:             * Indicates if the identifier is hierarchical.
1292:             * 
1293:             * @return True if the identifier is hierarchical, false if it is opaque.
1294:             */
1295:            public boolean isHierarchical() {
1296:                return isRelative()
1297:                        || (getSchemeSpecificPart().charAt(0) == '/');
1298:            }
1299:
1300:            /**
1301:             * Indicates if the identifier is opaque.
1302:             * 
1303:             * @return True if the identifier is opaque, false if it is hierarchical.
1304:             */
1305:            public boolean isOpaque() {
1306:                return isAbsolute()
1307:                        && (getSchemeSpecificPart().charAt(0) != '/');
1308:            }
1309:
1310:            /**
1311:             * Indicates if the reference is a parent of the hierarchical child
1312:             * reference.
1313:             * 
1314:             * @param childRef
1315:             *            The hierarchical reference.
1316:             * @return True if the reference is a parent of the hierarchical child
1317:             *         reference.
1318:             */
1319:            public boolean isParent(Reference childRef) {
1320:                boolean result = false;
1321:
1322:                if ((childRef != null) && (childRef.isHierarchical())) {
1323:                    result = childRef.toString(false, false).startsWith(
1324:                            toString(false, false));
1325:                }
1326:
1327:                return result;
1328:            }
1329:
1330:            /**
1331:             * Indicates if the reference is relative.
1332:             * 
1333:             * @return True if the reference is relative.
1334:             */
1335:            public boolean isRelative() {
1336:                return (getScheme() == null);
1337:            }
1338:
1339:            /**
1340:             * Normalizes the reference. Useful before comparison between references or
1341:             * when building a target reference from a base and a relative references.
1342:             * 
1343:             * @return The current reference.
1344:             */
1345:            public Reference normalize() {
1346:                // 1. The input buffer is initialized with the now-appended path
1347:                // components and the output buffer is initialized to the empty string.
1348:                StringBuilder output = new StringBuilder();
1349:                StringBuilder input = new StringBuilder();
1350:                String path = getPath();
1351:                if (path != null)
1352:                    input.append(path);
1353:
1354:                // 2. While the input buffer is not empty, loop as follows:
1355:                while (input.length() > 0) {
1356:                    // A. If the input buffer begins with a prefix of "../" or "./",
1357:                    // then remove that prefix from the input buffer; otherwise,
1358:                    if ((input.length() >= 3)
1359:                            && input.substring(0, 3).equals("../")) {
1360:                        input.delete(0, 3);
1361:                    } else if ((input.length() >= 2)
1362:                            && input.substring(0, 2).equals("./")) {
1363:                        input.delete(0, 2);
1364:                    }
1365:
1366:                    // B. if the input buffer begins with a prefix of "/./" or "/.",
1367:                    // where "." is a complete path segment, then replace that
1368:                    // prefix with "/" in the input buffer; otherwise,
1369:                    else if ((input.length() >= 3)
1370:                            && input.substring(0, 3).equals("/./")) {
1371:                        input.delete(0, 2);
1372:                    } else if ((input.length() == 2)
1373:                            && input.substring(0, 2).equals("/.")) {
1374:                        input.delete(1, 2);
1375:                    }
1376:
1377:                    // C. if the input buffer begins with a prefix of "/../" or "/..",
1378:                    // where ".." is a complete path segment, then replace that prefix
1379:                    // with "/" in the input buffer and remove the last segment and its
1380:                    // preceding "/" (if any) from the output buffer; otherwise,
1381:                    else if ((input.length() >= 4)
1382:                            && input.substring(0, 4).equals("/../")) {
1383:                        input.delete(0, 3);
1384:                        removeLastSegment(output);
1385:                    } else if ((input.length() == 3)
1386:                            && input.substring(0, 3).equals("/..")) {
1387:                        input.delete(1, 3);
1388:                        removeLastSegment(output);
1389:                    }
1390:
1391:                    // D. if the input buffer consists only of "." or "..", then remove
1392:                    // that from the input buffer; otherwise,
1393:                    else if ((input.length() == 1)
1394:                            && input.substring(0, 1).equals(".")) {
1395:                        input.delete(0, 1);
1396:                    } else if ((input.length() == 2)
1397:                            && input.substring(0, 2).equals("..")) {
1398:                        input.delete(0, 2);
1399:                    }
1400:
1401:                    // E. move the first path segment in the input buffer to the end of
1402:                    // the output buffer, including the initial "/" character (if any)
1403:                    // and any subsequent characters up to, but not including, the next
1404:                    // "/" character or the end of the input buffer.
1405:                    else {
1406:                        int max = -1;
1407:                        for (int i = 1; (max == -1) && (i < input.length()); i++) {
1408:                            if (input.charAt(i) == '/')
1409:                                max = i;
1410:                        }
1411:
1412:                        if (max != -1) {
1413:                            // We found the next "/" character.
1414:                            output.append(input.substring(0, max));
1415:                            input.delete(0, max);
1416:                        } else {
1417:                            // End of input buffer reached
1418:                            output.append(input);
1419:                            input.delete(0, input.length());
1420:                        }
1421:                    }
1422:                }
1423:
1424:                // Finally, the output buffer is returned as the result
1425:                setPath(output.toString());
1426:
1427:                // Ensure that the scheme and host names are reset in lower case
1428:                setScheme(getScheme());
1429:                setHostDomain(getHostDomain());
1430:
1431:                // Remove the port if it is equal to the default port of the reference's
1432:                // Protocol.
1433:                int hostPort = getHostPort();
1434:                if (hostPort != -1) {
1435:                    int defaultPort = Protocol.valueOf(getScheme())
1436:                            .getDefaultPort();
1437:                    if (hostPort == defaultPort) {
1438:                        setHostPort(null);
1439:                    }
1440:                }
1441:                return this ;
1442:            }
1443:
1444:            /**
1445:             * Removes the last segement from the output builder.
1446:             * 
1447:             * @param output
1448:             *            The output builder to update.
1449:             */
1450:            private void removeLastSegment(StringBuilder output) {
1451:                int min = -1;
1452:                for (int i = output.length() - 1; (min == -1) && (i >= 0); i--) {
1453:                    if (output.charAt(i) == '/')
1454:                        min = i;
1455:                }
1456:
1457:                if (min != -1) {
1458:                    // We found the previous "/" character.
1459:                    output.delete(min, output.length());
1460:                } else {
1461:                    // End of output buffer reached
1462:                    output.delete(0, output.length());
1463:                }
1464:
1465:            }
1466:
1467:            /**
1468:             * Sets the authority component for hierarchical identifiers.
1469:             * 
1470:             * @param authority
1471:             *            The authority component for hierarchical identifiers.
1472:             */
1473:            public void setAuthority(String authority) {
1474:                String oldPart = isRelative() ? getRelativePart()
1475:                        : getSchemeSpecificPart();
1476:                String newPart;
1477:                String newAuthority = (authority == null) ? "" : "//"
1478:                        + authority;
1479:
1480:                if (oldPart.startsWith("//")) {
1481:                    int index = oldPart.indexOf('/', 2);
1482:
1483:                    if (index != -1) {
1484:                        newPart = newAuthority + oldPart.substring(index);
1485:                    } else {
1486:                        index = oldPart.indexOf('?');
1487:                        if (index != -1) {
1488:                            newPart = newAuthority + oldPart.substring(index);
1489:                        } else {
1490:                            newPart = newAuthority;
1491:                        }
1492:                    }
1493:                } else {
1494:                    newPart = newAuthority + oldPart;
1495:                }
1496:
1497:                if (isAbsolute()) {
1498:                    setSchemeSpecificPart(newPart);
1499:                } else {
1500:                    setRelativePart(newPart);
1501:                }
1502:            }
1503:
1504:            /**
1505:             * Sets the base reference for relative references.
1506:             * 
1507:             * @param baseUri
1508:             *            The base URI for relative references.
1509:             */
1510:            public void setBaseRef(String baseUri) {
1511:                setBaseRef(new Reference(baseUri));
1512:            }
1513:
1514:            /**
1515:             * Sets the base reference for relative references.
1516:             * 
1517:             * @param baseRef
1518:             *            The base reference for relative references.
1519:             */
1520:            public void setBaseRef(Reference baseRef) {
1521:                this .baseRef = baseRef;
1522:            }
1523:
1524:            /**
1525:             * Sets the fragment identifier.
1526:             * 
1527:             * @throws IllegalArgumentException
1528:             *             if the fragment parameter contains the fragment delimiter
1529:             *             ('#').
1530:             * 
1531:             * @param fragment
1532:             *            The fragment identifier.
1533:             */
1534:            public void setFragment(String fragment) {
1535:                if ((fragment != null) && (fragment.indexOf('#') != -1)) {
1536:                    throw new IllegalArgumentException(
1537:                            "Illegal '#' character detected in parameter");
1538:                } else {
1539:                    if (fragmentIndex != -1) {
1540:                        // Existing fragment
1541:                        if (fragment != null) {
1542:                            this .internalRef = this .internalRef.substring(0,
1543:                                    fragmentIndex + 1)
1544:                                    + fragment;
1545:                        } else {
1546:                            this .internalRef = this .internalRef.substring(0,
1547:                                    fragmentIndex);
1548:                        }
1549:                    } else {
1550:                        // No existing fragment
1551:                        if (fragment != null) {
1552:                            if (this .internalRef != null) {
1553:                                this .internalRef = this .internalRef + '#'
1554:                                        + fragment;
1555:                            } else {
1556:                                this .internalRef = '#' + fragment;
1557:                            }
1558:                        } else {
1559:                            // Do nothing
1560:                        }
1561:                    }
1562:                }
1563:
1564:                updateIndexes();
1565:            }
1566:
1567:            /**
1568:             * Sets the host domain component for server based hierarchical identifiers.
1569:             * 
1570:             * @param domain
1571:             *            The host component for server based hierarchical identifiers.
1572:             */
1573:            public void setHostDomain(String domain) {
1574:                String authority = getAuthority();
1575:
1576:                if (authority != null) {
1577:                    if (domain == null) {
1578:                        domain = "";
1579:                    } else {
1580:                        // URI specification indicates that host names should be
1581:                        // produced in lower case
1582:                        domain = domain.toLowerCase();
1583:                    }
1584:
1585:                    int index1 = authority.indexOf('@');
1586:                    int index2 = authority.indexOf(':');
1587:
1588:                    if (index1 != -1) {
1589:                        // User info found
1590:                        if (index2 != -1) {
1591:                            // Port found
1592:                            setAuthority(authority.substring(0, index1 + 1)
1593:                                    + domain + authority.substring(index2));
1594:                        } else {
1595:                            // No port found
1596:                            setAuthority(authority.substring(0, index1 + 1)
1597:                                    + domain);
1598:                        }
1599:                    } else {
1600:                        // No user info found
1601:                        if (index2 != -1) {
1602:                            // Port found
1603:                            setAuthority(domain + authority.substring(index2));
1604:                        } else {
1605:                            // No port found
1606:                            setAuthority(domain);
1607:                        }
1608:                    }
1609:                }
1610:            }
1611:
1612:            /**
1613:             * Sets the optional port number for server based hierarchical identifiers.
1614:             * 
1615:             * @throws IllegalArgumentException
1616:             *             If the autority has not been defined.
1617:             * @param port
1618:             *            The optional port number for server based hierarchical
1619:             *            identifiers.
1620:             */
1621:            public void setHostPort(Integer port) {
1622:                String authority = getAuthority();
1623:
1624:                if (authority != null) {
1625:                    int index = authority.indexOf(':');
1626:                    String newPort = (port == null) ? "" : ":" + port;
1627:
1628:                    if (index != -1) {
1629:                        setAuthority(authority.substring(0, index) + newPort);
1630:                    } else {
1631:                        setAuthority(authority + newPort);
1632:                    }
1633:                } else {
1634:                    throw new IllegalArgumentException(
1635:                            "No authority defined, please define a host name first");
1636:                }
1637:            }
1638:
1639:            /**
1640:             * Sets the absolute resource identifier.
1641:             * 
1642:             * @throws IllegalArgumentException
1643:             *             If the identifier parameter contains the fragment delimiter
1644:             *             ('#').
1645:             * 
1646:             * @param identifier
1647:             *            The absolute resource identifier.
1648:             */
1649:            public void setIdentifier(String identifier) {
1650:                if (identifier == null)
1651:                    identifier = "";
1652:                if (identifier.indexOf('#') != -1) {
1653:                    throw new IllegalArgumentException(
1654:                            "Illegal '#' character detected in parameter");
1655:                } else {
1656:                    if (fragmentIndex != -1) {
1657:                        // Fragment found
1658:                        this .internalRef = identifier
1659:                                + this .internalRef.substring(fragmentIndex);
1660:                    } else {
1661:                        // No fragment found
1662:                        this .internalRef = identifier;
1663:                    }
1664:
1665:                    updateIndexes();
1666:                }
1667:            }
1668:
1669:            /**
1670:             * Sets the path component for hierarchical identifiers.
1671:             * 
1672:             * @param path
1673:             *            The path component for hierarchical identifiers.
1674:             */
1675:            public void setPath(String path) {
1676:                String oldPart = isRelative() ? getRelativePart()
1677:                        : getSchemeSpecificPart();
1678:                String newPart = null;
1679:
1680:                if (oldPart != null) {
1681:                    if (path == null)
1682:                        path = "";
1683:
1684:                    if (oldPart.startsWith("//")) {
1685:                        // Authority found
1686:                        int index1 = oldPart.indexOf('/', 2);
1687:
1688:                        if (index1 != -1) {
1689:                            // Path found
1690:                            int index2 = oldPart.indexOf('?');
1691:                            if (index2 != -1) {
1692:                                // Query found
1693:                                newPart = oldPart.substring(0, index1) + path
1694:                                        + oldPart.substring(index2);
1695:                            } else {
1696:                                // No query found
1697:                                newPart = oldPart.substring(0, index1) + path;
1698:                            }
1699:                        } else {
1700:                            // No path found
1701:                            int index2 = oldPart.indexOf('?');
1702:                            if (index2 != -1) {
1703:                                // Query found
1704:                                newPart = oldPart.substring(0, index2) + path
1705:                                        + oldPart.substring(index2);
1706:                            } else {
1707:                                // No query found
1708:                                newPart = oldPart + path;
1709:                            }
1710:                        }
1711:                    } else {
1712:                        // No authority found
1713:                        int index = oldPart.indexOf('?');
1714:                        if (index != -1) {
1715:                            // Query found
1716:                            newPart = path + oldPart.substring(index);
1717:                        } else {
1718:                            // No query found
1719:                            newPart = path;
1720:                        }
1721:                    }
1722:                } else {
1723:                    newPart = path;
1724:                }
1725:
1726:                if (isAbsolute()) {
1727:                    setSchemeSpecificPart(newPart);
1728:                } else {
1729:                    setRelativePart(newPart);
1730:                }
1731:            }
1732:
1733:            /**
1734:             * Sets the scheme component based on this protocol.
1735:             * 
1736:             * @param protocol
1737:             *            The protocol of the scheme component.
1738:             */
1739:            public void setProtocol(Protocol protocol) {
1740:                setScheme(protocol.getSchemeName());
1741:            }
1742:
1743:            /**
1744:             * Sets the query component for hierarchical identifiers.
1745:             * 
1746:             * @param query
1747:             *            The query component for hierarchical identifiers.
1748:             */
1749:            public void setQuery(String query) {
1750:                if (queryIndex != -1) {
1751:                    // Query found
1752:                    if (fragmentIndex != -1) {
1753:                        // Fragment found
1754:                        if (query != null) {
1755:                            this .internalRef = this .internalRef.substring(0,
1756:                                    queryIndex + 1)
1757:                                    + query
1758:                                    + this .internalRef.substring(fragmentIndex);
1759:                        } else {
1760:                            this .internalRef = this .internalRef.substring(0,
1761:                                    queryIndex)
1762:                                    + this .internalRef.substring(fragmentIndex);
1763:                        }
1764:                    } else {
1765:                        // No fragment found
1766:                        if (query != null) {
1767:                            this .internalRef = this .internalRef.substring(0,
1768:                                    queryIndex + 1)
1769:                                    + query;
1770:                        } else {
1771:                            this .internalRef = this .internalRef.substring(0,
1772:                                    queryIndex);
1773:                        }
1774:                    }
1775:                } else {
1776:                    // No query found
1777:                    if (fragmentIndex != -1) {
1778:                        // Fragment found
1779:                        if (query != null) {
1780:                            this .internalRef = this .internalRef.substring(0,
1781:                                    fragmentIndex)
1782:                                    + '?'
1783:                                    + query
1784:                                    + this .internalRef.substring(fragmentIndex);
1785:                        } else {
1786:                            // Do nothing;
1787:                        }
1788:                    } else {
1789:                        // No fragment found
1790:                        if (query != null) {
1791:                            if (this .internalRef != null) {
1792:                                this .internalRef = this .internalRef + '?'
1793:                                        + query;
1794:                            } else {
1795:                                this .internalRef = '?' + query;
1796:                            }
1797:                        } else {
1798:                            // Do nothing;
1799:                        }
1800:                    }
1801:                }
1802:
1803:                updateIndexes();
1804:            }
1805:
1806:            /**
1807:             * Sets the relative part for relative references only.
1808:             * 
1809:             * @param relativePart
1810:             *            The relative part to set.
1811:             */
1812:            public void setRelativePart(String relativePart) {
1813:                if (relativePart == null)
1814:                    relativePart = "";
1815:                if (schemeIndex == -1) {
1816:                    // This is a relative reference, no scheme found
1817:                    if (queryIndex != -1) {
1818:                        // Query found
1819:                        this .internalRef = relativePart
1820:                                + this .internalRef.substring(queryIndex);
1821:                    } else if (fragmentIndex != -1) {
1822:                        // Fragment found
1823:                        this .internalRef = relativePart
1824:                                + this .internalRef.substring(fragmentIndex);
1825:                    } else {
1826:                        // No fragment found
1827:                        this .internalRef = relativePart;
1828:                    }
1829:                }
1830:
1831:                updateIndexes();
1832:            }
1833:
1834:            /**
1835:             * Sets the scheme component.
1836:             * 
1837:             * @param scheme
1838:             *            The scheme component.
1839:             */
1840:            public void setScheme(String scheme) {
1841:                if (scheme != null) {
1842:                    // URI specification indicates that scheme names should be
1843:                    // produced in lower case
1844:                    scheme = scheme.toLowerCase();
1845:                }
1846:
1847:                if (schemeIndex != -1) {
1848:                    // Scheme found
1849:                    if (scheme != null) {
1850:                        this .internalRef = scheme
1851:                                + this .internalRef.substring(schemeIndex);
1852:                    } else {
1853:                        this .internalRef = this .internalRef
1854:                                .substring(schemeIndex + 1);
1855:                    }
1856:                } else {
1857:                    // No scheme found
1858:                    if (scheme != null) {
1859:                        if (this .internalRef == null) {
1860:                            this .internalRef = scheme + ':';
1861:                        } else {
1862:                            this .internalRef = scheme + ':' + this .internalRef;
1863:                        }
1864:                    }
1865:                }
1866:
1867:                updateIndexes();
1868:            }
1869:
1870:            /**
1871:             * Sets the scheme specific part.
1872:             * 
1873:             * @param schemeSpecificPart
1874:             *            The scheme specific part.
1875:             */
1876:            public void setSchemeSpecificPart(String schemeSpecificPart) {
1877:                if (schemeSpecificPart == null)
1878:                    schemeSpecificPart = "";
1879:                if (schemeIndex != -1) {
1880:                    // Scheme found
1881:                    if (fragmentIndex != -1) {
1882:                        // Fragment found
1883:                        this .internalRef = this .internalRef.substring(0,
1884:                                schemeIndex + 1)
1885:                                + schemeSpecificPart
1886:                                + this .internalRef.substring(fragmentIndex);
1887:                    } else {
1888:                        // No fragment found
1889:                        this .internalRef = this .internalRef.substring(0,
1890:                                schemeIndex + 1)
1891:                                + schemeSpecificPart;
1892:                    }
1893:                } else {
1894:                    // No scheme found
1895:                    if (fragmentIndex != -1) {
1896:                        // Fragment found
1897:                        this .internalRef = schemeSpecificPart
1898:                                + this .internalRef.substring(fragmentIndex);
1899:                    } else {
1900:                        // No fragment found
1901:                        this .internalRef = schemeSpecificPart;
1902:                    }
1903:                }
1904:
1905:                updateIndexes();
1906:            }
1907:
1908:            /**
1909:             * Sets the segments of a hierarchical path.<br/> A new absolute path will
1910:             * replace any existing one.
1911:             * 
1912:             * @param segments
1913:             *            The segments of the hierarchical path.
1914:             */
1915:            public void setSegments(List<String> segments) {
1916:                StringBuilder sb = new StringBuilder();
1917:                for (String segment : segments) {
1918:                    sb.append('/').append(segment);
1919:                }
1920:                setPath(sb.toString());
1921:            }
1922:
1923:            /**
1924:             * Sets the user info component for server based hierarchical identifiers.
1925:             * 
1926:             * @throws IllegalArgumentException
1927:             *             If the autority part has not been defined.
1928:             * 
1929:             * @param userInfo
1930:             *            The user info component for server based hierarchical
1931:             *            identifiers.
1932:             */
1933:            public void setUserInfo(String userInfo) {
1934:                String authority = getAuthority();
1935:
1936:                if (authority != null) {
1937:                    int index = authority.indexOf('@');
1938:                    String newUserInfo = (userInfo == null) ? ""
1939:                            : userInfo + '@';
1940:
1941:                    if (index != -1) {
1942:                        setAuthority(newUserInfo
1943:                                + authority.substring(index + 1));
1944:                    } else {
1945:                        setAuthority(newUserInfo + authority);
1946:                    }
1947:                } else {
1948:                    throw new IllegalArgumentException(
1949:                            "No authority defined, please define a host name first");
1950:                }
1951:            }
1952:
1953:            /**
1954:             * Returns the reference as an URI string.
1955:             * 
1956:             * @return The reference as an URI string.
1957:             */
1958:            @Override
1959:            public String toString() {
1960:                return this .internalRef;
1961:            }
1962:
1963:            /**
1964:             * Returns the URI reference string.
1965:             * 
1966:             * @param query
1967:             *            Indicates if the query should be included;
1968:             * @param fragment
1969:             *            Indicates if the fragment should be included;
1970:             * @return The URI reference string.
1971:             */
1972:            public String toString(boolean query, boolean fragment) {
1973:                if (query) {
1974:                    if (fragment) {
1975:                        return this .internalRef;
1976:                    } else {
1977:                        if (fragmentIndex != -1) {
1978:                            return this .internalRef.substring(0, fragmentIndex);
1979:                        } else {
1980:                            return this .internalRef;
1981:                        }
1982:                    }
1983:                } else {
1984:                    if (fragment) {
1985:                        if (queryIndex != -1) {
1986:                            if (fragmentIndex != -1) {
1987:                                return this .internalRef
1988:                                        .substring(0, queryIndex)
1989:                                        + "#" + getFragment();
1990:                            } else {
1991:                                return this .internalRef
1992:                                        .substring(0, queryIndex);
1993:                            }
1994:                        } else {
1995:                            return this .internalRef;
1996:                        }
1997:                    } else {
1998:                        if (queryIndex != -1) {
1999:                            return this .internalRef.substring(0, queryIndex);
2000:                        } else {
2001:                            if (fragmentIndex != -1) {
2002:                                return this .internalRef.substring(0,
2003:                                        fragmentIndex);
2004:                            } else {
2005:                                return this .internalRef;
2006:                            }
2007:                        }
2008:                    }
2009:                }
2010:            }
2011:
2012:            /**
2013:             * Update internal indexes.
2014:             */
2015:            private void updateIndexes() {
2016:                if (internalRef != null) {
2017:                    int firstSlashIndex = this .internalRef.indexOf('/');
2018:                    this .schemeIndex = this .internalRef.indexOf(':');
2019:
2020:                    if ((firstSlashIndex != -1)
2021:                            && (this .schemeIndex > firstSlashIndex)) {
2022:                        // We are in the rare case of a relative reference where one of
2023:                        // the path segments contains a colon character. In this case,
2024:                        // we ignore the colon as a valid scheme index.
2025:                        // Note that this colon can't be in the first segment as it is
2026:                        // forbidden by the URI RFC.
2027:                        this .schemeIndex = -1;
2028:                    }
2029:
2030:                    this .queryIndex = this .internalRef.indexOf('?');
2031:                    this .fragmentIndex = this .internalRef.indexOf('#');
2032:                    if ((this .queryIndex != -1) && (this .fragmentIndex != -1)
2033:                            && (this .queryIndex > this .fragmentIndex)) {
2034:                        // Query sign inside fragment
2035:                        this .queryIndex = -1;
2036:                    }
2037:                } else {
2038:                    this .schemeIndex = -1;
2039:                    this .queryIndex = -1;
2040:                    this .fragmentIndex = -1;
2041:                }
2042:            }
2043:        }
www.java2java.com | Contact Us
Copyright 2009 - 12 Demo Source and Support. All rights reserved.
All other trademarks are property of their respective owners.