Source Code Cross Referenced for Template.java in  » Web-Services » restlet-1.0.8 » org » restlet » util » 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.util 
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.util;
0020:
0021:        import java.util.List;
0022:        import java.util.Map;
0023:        import java.util.concurrent.ConcurrentHashMap;
0024:        import java.util.concurrent.CopyOnWriteArrayList;
0025:        import java.util.logging.Logger;
0026:        import java.util.regex.Matcher;
0027:        import java.util.regex.Pattern;
0028:
0029:        import org.restlet.data.Reference;
0030:        import org.restlet.data.Request;
0031:        import org.restlet.data.Response;
0032:
0033:        /**
0034:         * String template with a model is based on a request. Supports both formatting
0035:         * and parsing. The template variables can be inserted using the "{name}" syntax
0036:         * and described using the modifiable map of variable descriptors. When no
0037:         * descriptor is found for a given variable, the template logic uses its default
0038:         * variable property initialized using the default {@link Variable} constructor.
0039:         * 
0040:         * <table>
0041:         * <tr>
0042:         * <th>Model property</th>
0043:         * <th>Variable name</th>
0044:         * <th>Content type</th>
0045:         * </tr>
0046:         * <tr>
0047:         * <td>request.confidential</td>
0048:         * <td>c</td>
0049:         * <td>boolean (true|false)</td>
0050:         * </tr>
0051:         * <tr>
0052:         * <td>request.clientInfo.address</td>
0053:         * <td>cia</td>
0054:         * <td>String</td>
0055:         * </tr>
0056:         * <tr>
0057:         * <td>request.clientInfo.agent</td>
0058:         * <td>cig</td>
0059:         * <td>String</td>
0060:         * </tr>
0061:         * <tr>
0062:         * <td>request.challengeResponse.identifier</td>
0063:         * <td>cri</td>
0064:         * <td>String</td>
0065:         * </tr>
0066:         * <tr>
0067:         * <td>request.challengeResponse.scheme</td>
0068:         * <td>crs</td>
0069:         * <td>String</td>
0070:         * </tr>
0071:         * <tr>
0072:         * <td>request.entity.characterSet</td>
0073:         * <td>ecs</td>
0074:         * <td>String</td>
0075:         * </tr>
0076:         * <tr>
0077:         * <td>response.entity.characterSet</td>
0078:         * <td>ECS</td>
0079:         * <td>String</td>
0080:         * </tr>
0081:         * <tr>
0082:         * <td>request.entity.encoding</td>
0083:         * <td>ee</td>
0084:         * <td>String</td>
0085:         * </tr>
0086:         * <tr>
0087:         * <td>response.entity.encoding</td>
0088:         * <td>EE</td>
0089:         * <td>String</td>
0090:         * </tr>
0091:         * <tr>
0092:         * <td>request.entity.expirationDate</td>
0093:         * <td>eed</td>
0094:         * <td>Date (HTTP format)</td>
0095:         * </tr>
0096:         * <tr>
0097:         * <td>response.entity.expirationDate</td>
0098:         * <td>EED</td>
0099:         * <td>Date (HTTP format)</td>
0100:         * </tr>
0101:         * <tr>
0102:         * <td>request.entity.language</td>
0103:         * <td>el</td>
0104:         * <td>String</td>
0105:         * </tr>
0106:         * <tr>
0107:         * <td>response.entity.language</td>
0108:         * <td>EL</td>
0109:         * <td>String</td>
0110:         * </tr>
0111:         * <tr>
0112:         * <td>request.entity.modificationDate</td>
0113:         * <td>emd</td>
0114:         * <td>Date (HTTP format)</td>
0115:         * </tr>
0116:         * <tr>
0117:         * <td>response.entity.modificationDate</td>
0118:         * <td>EMD</td>
0119:         * <td>Date (HTTP format)</td>
0120:         * </tr>
0121:         * <tr>
0122:         * <td>request.entity.mediaType</td>
0123:         * <td>emt</td>
0124:         * <td>String</td>
0125:         * </tr>
0126:         * <tr>
0127:         * <td>response.entity.mediaType</td>
0128:         * <td>EMT</td>
0129:         * <td>String</td>
0130:         * </tr>
0131:         * <tr>
0132:         * <td>request.entity.size</td>
0133:         * <td>es</td>
0134:         * <td>Integer</td>
0135:         * </tr>
0136:         * <tr>
0137:         * <td>response.entity.size</td>
0138:         * <td>ES</td>
0139:         * <td>Integer</td>
0140:         * </tr>
0141:         * <tr>
0142:         * <td>request.entity.tag</td>
0143:         * <td>et</td>
0144:         * <td>String</td>
0145:         * </tr>
0146:         * <tr>
0147:         * <td>response.entity.tag</td>
0148:         * <td>ET</td>
0149:         * <td>String</td>
0150:         * </tr>
0151:         * <tr>
0152:         * <td>request.referrerRef</td>
0153:         * <td>f*</td>
0154:         * <td>Reference (see table below variable name sub-parts)</td>
0155:         * </tr>
0156:         * <tr>
0157:         * <td>request.hostRef</td>
0158:         * <td>h*</td>
0159:         * <td>Reference (see table below variable name sub-parts)</td>
0160:         * </tr>
0161:         * <tr>
0162:         * <td>request.method</td>
0163:         * <td>m</td>
0164:         * <td>String</td>
0165:         * </tr>
0166:         * <tr>
0167:         * <td>request.rootRef</td>
0168:         * <td>o*</td>
0169:         * <td>Reference (see table below variable name sub-parts)</td>
0170:         * </tr>
0171:         * <tr>
0172:         * <td>request.protocol</td>
0173:         * <td>p</td>
0174:         * <td>String</td>
0175:         * </tr>
0176:         * <tr>
0177:         * <td>request.resourceRef</td>
0178:         * <td>r*</td>
0179:         * <td>Reference (see table below variable name sub-parts)</td>
0180:         * </tr>
0181:         * <tr>
0182:         * <td>response.redirectRef</td>
0183:         * <td>R*</td>
0184:         * <td>Reference (see table below variable name sub-parts)</td>
0185:         * </tr>
0186:         * <tr>
0187:         * <td>response.status</td>
0188:         * <td>S</td>
0189:         * <td>Integer</td>
0190:         * </tr>
0191:         * <tr>
0192:         * <td>response.serverInfo.address</td>
0193:         * <td>SIA</td>
0194:         * <td>String</td>
0195:         * </tr>
0196:         * <tr>
0197:         * <td>response.serverInfo.agent</td>
0198:         * <td>SIG</td>
0199:         * <td>String</td>
0200:         * </tr>
0201:         * <tr>
0202:         * <td>response.serverInfo.port</td>
0203:         * <td>SIP</td>
0204:         * <td>Integer</td>
0205:         * </tr>
0206:         * </table> <br/>
0207:         * 
0208:         * Below is the list of name sub-parts, for Reference variables, that can
0209:         * replace the asterix in the variable names above:<br/><br/>
0210:         * 
0211:         * <table>
0212:         * <tr>
0213:         * <th>Reference property</th>
0214:         * <th>Sub-part name</th>
0215:         * <th>Content type</th>
0216:         * </tr>
0217:         * <tr>
0218:         * <td>authority</td>
0219:         * <td>a</td>
0220:         * <td>String</td>
0221:         * </tr>
0222:         * <tr>
0223:         * <td>baseRef</td>
0224:         * <td>b*</td>
0225:         * <td>Reference</td>
0226:         * </tr>
0227:         * <tr>
0228:         * <td>relativePart</td>
0229:         * <td>e</td>
0230:         * <td>String</td>
0231:         * </tr>
0232:         * <tr>
0233:         * <td>fragment</td>
0234:         * <td>f</td>
0235:         * <td>String</td>
0236:         * </tr>
0237:         * <tr>
0238:         * <td>hostIdentifier</td>
0239:         * <td>h</td>
0240:         * <td>String</td>
0241:         * </tr>
0242:         * <tr>
0243:         * <td>identifier</td>
0244:         * <td>i</td>
0245:         * <td>String</td>
0246:         * </tr>
0247:         * <tr>
0248:         * <td>path</td>
0249:         * <td>p</td>
0250:         * <td>String</td>
0251:         * </tr>
0252:         * <tr>
0253:         * <td>query</td>
0254:         * <td>q</td>
0255:         * <td>String</td>
0256:         * </tr>
0257:         * <tr>
0258:         * <td>remainingPart</td>
0259:         * <td>r</td>
0260:         * <td>String</td>
0261:         * </tr>
0262:         * </table>
0263:         * 
0264:         * @see <a href="http://bitworking.org/projects/URI-Templates/">URI Template
0265:         *      specification</a>
0266:         * @author Jerome Louvel (contact@noelios.com)
0267:         */
0268:        public class Template {
0269:            public static final int MODE_STARTS_WITH = 1;
0270:
0271:            public static final int MODE_EQUALS = 2;
0272:
0273:            /**
0274:             * Indicates if the given character is alphabetical (a-z or A-Z).
0275:             * 
0276:             * @param character
0277:             *                The character to test.
0278:             * @return True if the given character is alphabetical (a-z or A-Z).
0279:             */
0280:            private static boolean isAlpha(int character) {
0281:                return isUpperCase(character) || isLowerCase(character);
0282:            }
0283:
0284:            /**
0285:             * Indicates if the given character is a digit (0-9).
0286:             * 
0287:             * @param character
0288:             *                The character to test.
0289:             * @return True if the given character is a digit (0-9).
0290:             */
0291:            private static boolean isDigit(int character) {
0292:                return (character >= '0') && (character <= '9');
0293:            }
0294:
0295:            /**
0296:             * Indicates if the given character is lower case (a-z).
0297:             * 
0298:             * @param character
0299:             *                The character to test.
0300:             * @return True if the given character is lower case (a-z).
0301:             */
0302:            private static boolean isLowerCase(int character) {
0303:                return (character >= 'a') && (character <= 'z');
0304:            }
0305:
0306:            /**
0307:             * Indicates if the given character is an unreserved URI character.
0308:             * 
0309:             * @param character
0310:             *                The character to test.
0311:             * @return True if the given character is an unreserved URI character.
0312:             */
0313:            private static boolean isUnreserved(int character) {
0314:                return isAlpha(character) || isDigit(character)
0315:                        || (character == '-') || (character == '.')
0316:                        || (character == '_') || (character == '~');
0317:            }
0318:
0319:            /**
0320:             * Indicates if the given character is upper case (A-Z).
0321:             * 
0322:             * @param character
0323:             *                The character to test.
0324:             * @return True if the given character is upper case (A-Z).
0325:             */
0326:            private static boolean isUpperCase(int character) {
0327:                return (character >= 'A') && (character <= 'Z');
0328:            }
0329:
0330:            /** The pattern to use for formatting or parsing. */
0331:            private volatile String pattern;
0332:
0333:            /** The default variable to use when no matching variable descriptor exists. */
0334:            private volatile Variable defaultVariable;
0335:
0336:            /** The logger to use. */
0337:            private volatile Logger logger;
0338:
0339:            /** The matching mode to use when parsing a formatted reference. */
0340:            private volatile int matchingMode;
0341:
0342:            /** The map of variables associated to the route's template. */
0343:            private final Map<String, Variable> variables;
0344:
0345:            /** The internal Regex pattern. */
0346:            private volatile Pattern regexPattern;
0347:
0348:            /** The sequence of Regex variable names as found in the pattern string. */
0349:            private final List<String> regexVariables;
0350:
0351:            /**
0352:             * Default constructor. Each variable matches any sequence of characters by
0353:             * default. When parsing, the template will attempt to match the whole
0354:             * template. When formatting, the variable are replaced by an empty string
0355:             * if they don't exist in the model.
0356:             * 
0357:             * @param logger
0358:             *                The logger to use.
0359:             * @param pattern
0360:             *                The pattern to use for formatting or parsing.
0361:             */
0362:            public Template(Logger logger, String pattern) {
0363:                this (logger, pattern, MODE_EQUALS, Variable.TYPE_ALL, "", true,
0364:                        false);
0365:            }
0366:
0367:            /**
0368:             * Constructor.
0369:             * 
0370:             * @param logger
0371:             *                The logger to use.
0372:             * @param pattern
0373:             *                The pattern to use for formatting or parsing.
0374:             * @param matchingMode
0375:             *                The matching mode to use when parsing a formatted
0376:             *                reference.
0377:             */
0378:            public Template(Logger logger, String pattern, int matchingMode) {
0379:                this (logger, pattern, matchingMode, Variable.TYPE_ALL, "",
0380:                        true, false);
0381:            }
0382:
0383:            /**
0384:             * Constructor.
0385:             * 
0386:             * @param logger
0387:             *                The logger to use.
0388:             * @param pattern
0389:             *                The pattern to use for formatting or parsing.
0390:             * @param matchingMode
0391:             *                The matching mode to use when parsing a formatted
0392:             *                reference.
0393:             * @param defaultType
0394:             *                The default type of variables with no descriptor.
0395:             * @param defaultDefaultValue
0396:             *                The default value for null variables with no descriptor.
0397:             * @param defaultRequired
0398:             *                The default required flag for variables with no
0399:             *                descriptor.
0400:             * @param defaultFixed
0401:             *                The default fixed value for variables with no descriptor.
0402:             */
0403:            public Template(Logger logger, String pattern, int matchingMode,
0404:                    int defaultType, String defaultDefaultValue,
0405:                    boolean defaultRequired, boolean defaultFixed) {
0406:                this .logger = logger;
0407:                this .pattern = pattern;
0408:                this .defaultVariable = new Variable(defaultType,
0409:                        defaultDefaultValue, defaultRequired, defaultFixed);
0410:                this .matchingMode = matchingMode;
0411:                this .variables = new ConcurrentHashMap<String, Variable>();
0412:                this .regexPattern = null;
0413:                this .regexVariables = new CopyOnWriteArrayList<String>();
0414:            }
0415:
0416:            /**
0417:             * Creates a formatted string based on the given request.
0418:             * 
0419:             * @param request
0420:             *                The request to use as a model.
0421:             * @param response
0422:             *                The response to use as a model.
0423:             * @return The formatted string.
0424:             */
0425:            public String format(Request request, Response response) {
0426:                return format(new CallVariableResolver(request, response));
0427:            }
0428:
0429:            /**
0430:             * Creates a formatted string based on the given request.
0431:             * 
0432:             * @param variables
0433:             *                The variables to use when formatting.
0434:             * @return The formatted string.
0435:             */
0436:            public String format(Map<String, Object> variables) {
0437:                return format(new MapVariableResolver(variables));
0438:            }
0439:
0440:            /**
0441:             * Creates a formatted string based on the given variable resolver.
0442:             * 
0443:             * @param resolver
0444:             *                The variable resolver to use.
0445:             * @return The formatted string.
0446:             */
0447:            private String format(VariableResolver resolver) {
0448:                StringBuilder result = new StringBuilder();
0449:                StringBuilder varBuffer = null;
0450:                char next;
0451:                boolean inVariable = false;
0452:                for (int i = 0; i < getPattern().length(); i++) {
0453:                    next = getPattern().charAt(i);
0454:
0455:                    if (inVariable) {
0456:                        if (isUnreserved(next)) {
0457:                            // Append to the variable name
0458:                            varBuffer.append(next);
0459:                        } else if (next == '}') {
0460:                            // End of variable detected
0461:                            if (varBuffer.length() == 0) {
0462:                                getLogger().warning(
0463:                                        "Empty pattern variables are not allowed : "
0464:                                                + this .regexPattern);
0465:                            } else {
0466:                                String varName = varBuffer.toString();
0467:                                result.append(resolver.resolve(varName));
0468:
0469:                                // Reset the variable name buffer
0470:                                varBuffer = new StringBuilder();
0471:                            }
0472:                            inVariable = false;
0473:                        } else {
0474:                            getLogger().warning(
0475:                                    "An invalid character was detected inside a pattern variable : "
0476:                                            + this .regexPattern);
0477:                        }
0478:                    } else {
0479:                        if (next == '{') {
0480:                            inVariable = true;
0481:                            varBuffer = new StringBuilder();
0482:                        } else if (next == '}') {
0483:                            getLogger().warning(
0484:                                    "An invalid character was detected inside a pattern variable : "
0485:                                            + this .regexPattern);
0486:                        } else {
0487:                            result.append(next);
0488:                        }
0489:                    }
0490:                }
0491:
0492:                return result.toString();
0493:            }
0494:
0495:            /**
0496:             * Returns the default variable.
0497:             * 
0498:             * @return The default variable.
0499:             */
0500:            public Variable getDefaultVariable() {
0501:                return this .defaultVariable;
0502:            }
0503:
0504:            /**
0505:             * Returns the logger to use.
0506:             * 
0507:             * @return The logger to use.
0508:             */
0509:            public Logger getLogger() {
0510:                return this .logger;
0511:            }
0512:
0513:            /**
0514:             * Returns the matching mode to use when parsing a formatted reference.
0515:             * 
0516:             * @return The matching mode to use when parsing a formatted reference.
0517:             */
0518:            public int getMatchingMode() {
0519:                return this .matchingMode;
0520:            }
0521:
0522:            /**
0523:             * Returns the pattern to use for formatting or parsing.
0524:             * 
0525:             * @return The pattern to use for formatting or parsing.
0526:             */
0527:            public String getPattern() {
0528:                return this .pattern;
0529:            }
0530:
0531:            /**
0532:             * Compiles the URI pattern into a Regex pattern.
0533:             * 
0534:             * @param uriPattern
0535:             *                The URI pattern.
0536:             * @return The Regex pattern.
0537:             */
0538:            private synchronized Pattern getRegexPattern() {
0539:                if (this .regexPattern == null) {
0540:                    StringBuilder patternBuffer = new StringBuilder();
0541:                    StringBuilder varBuffer = null;
0542:                    char next;
0543:                    boolean inVariable = false;
0544:                    for (int i = 0; i < getPattern().length(); i++) {
0545:                        next = getPattern().charAt(i);
0546:
0547:                        if (inVariable) {
0548:                            if (isUnreserved(next)) {
0549:                                // Append to the variable name
0550:                                varBuffer.append(next);
0551:                            } else if (next == '}') {
0552:                                // End of variable detected
0553:                                if (varBuffer.length() == 0) {
0554:                                    getLogger().warning(
0555:                                            "Empty pattern variables are not allowed : "
0556:                                                    + this .regexPattern);
0557:                                } else {
0558:                                    String varName = varBuffer.toString();
0559:                                    int varIndex = getRegexVariables().indexOf(
0560:                                            varName);
0561:
0562:                                    if (varIndex != -1) {
0563:                                        // The variable is used several times in the
0564:                                        // pattern, ensure that this constraint is
0565:                                        // enforced when parsing.
0566:                                        patternBuffer.append("\\"
0567:                                                + (varIndex + 1));
0568:                                    } else {
0569:                                        // New variable detected. Insert a capturing
0570:                                        // group.
0571:                                        getRegexVariables().add(varName);
0572:                                        Variable var = getVariables().get(
0573:                                                varName);
0574:                                        if (var == null)
0575:                                            var = getDefaultVariable();
0576:                                        patternBuffer
0577:                                                .append(getVariableRegex(var));
0578:                                    }
0579:
0580:                                    // Reset the variable name buffer
0581:                                    varBuffer = new StringBuilder();
0582:                                }
0583:                                inVariable = false;
0584:
0585:                            } else {
0586:                                getLogger().warning(
0587:                                        "An invalid character was detected inside a pattern variable : "
0588:                                                + this .regexPattern);
0589:                            }
0590:                        } else {
0591:                            if (next == '{') {
0592:                                inVariable = true;
0593:                                varBuffer = new StringBuilder();
0594:                            } else if (next == '}') {
0595:                                getLogger().warning(
0596:                                        "An invalid character was detected inside a pattern variable : "
0597:                                                + this .regexPattern);
0598:                            } else {
0599:                                patternBuffer.append(quote(next));
0600:                            }
0601:                        }
0602:                    }
0603:
0604:                    this .regexPattern = Pattern.compile(patternBuffer
0605:                            .toString());
0606:                }
0607:
0608:                return this .regexPattern;
0609:            }
0610:
0611:            /**
0612:             * Quotes special characters that could be taken for special Regex
0613:             * characters.
0614:             * 
0615:             * @param character
0616:             *                The character to quote if necessary.
0617:             * @return The quoted character.
0618:             */
0619:            private static String quote(char character) {
0620:                switch (character) {
0621:                case '[':
0622:                    return "\\[";
0623:                case ']':
0624:                    return "\\]";
0625:                case '.':
0626:                    return "\\.";
0627:                case '\\':
0628:                    return "\\\\";
0629:                case '$':
0630:                    return "\\$";
0631:                case '^':
0632:                    return "\\^";
0633:                case '?':
0634:                    return "\\?";
0635:                case '*':
0636:                    return "\\*";
0637:                case '|':
0638:                    return "\\|";
0639:                case '(':
0640:                    return "\\(";
0641:                case ')':
0642:                    return "\\)";
0643:                case ':':
0644:                    return "\\:";
0645:                case '-':
0646:                    return "\\-";
0647:                case '!':
0648:                    return "\\!";
0649:                case '<':
0650:                    return "\\<";
0651:                case '>':
0652:                    return "\\>";
0653:                default:
0654:                    return Character.toString(character);
0655:                }
0656:            }
0657:
0658:            /**
0659:             * Returns the sequence of Regex variable names as found in the pattern
0660:             * string.
0661:             * 
0662:             * @return The sequence of Regex variable names as found in the pattern
0663:             *         string.
0664:             */
0665:            private List<String> getRegexVariables() {
0666:                return this .regexVariables;
0667:            }
0668:
0669:            /**
0670:             * Returns the content corresponding to a reference property.
0671:             * 
0672:             * @param partName
0673:             *                The variable sub-part name.
0674:             * @param reference
0675:             *                The reference to use as a model.
0676:             * @return The content corresponding to a reference property.
0677:             */
0678:            private static String getReferenceContent(String partName,
0679:                    Reference reference) {
0680:                String result = null;
0681:
0682:                if (reference != null) {
0683:                    if (partName.equals("a")) {
0684:                        result = reference.getAuthority();
0685:                    } else if (partName.startsWith("b")) {
0686:                        result = getReferenceContent(partName.substring(1),
0687:                                reference.getBaseRef());
0688:                    } else if (partName.equals("e")) {
0689:                        result = reference.getRelativePart();
0690:                    } else if (partName.equals("f")) {
0691:                        result = reference.getFragment();
0692:                    } else if (partName.equals("h")) {
0693:                        result = reference.getHostIdentifier();
0694:                    } else if (partName.equals("i")) {
0695:                        result = reference.getIdentifier();
0696:                    } else if (partName.equals("p")) {
0697:                        result = reference.getPath();
0698:                    } else if (partName.equals("q")) {
0699:                        result = reference.getQuery();
0700:                    } else if (partName.equals("r")) {
0701:                        result = reference.getRemainingPart();
0702:                    }
0703:                }
0704:
0705:                return result;
0706:            }
0707:
0708:            /**
0709:             * Returns the Regex pattern string corresponding to a variable.
0710:             * 
0711:             * @param variable
0712:             *                The variable.
0713:             * @return The Regex pattern string corresponding to a variable.
0714:             */
0715:            private static String getVariableRegex(Variable variable) {
0716:                String result = null;
0717:
0718:                if (variable.isFixed()) {
0719:                    result = Pattern.quote(variable.getDefaultValue());
0720:                } else {
0721:                    // Expressions to create character classes
0722:                    final String ALL = ".";
0723:                    final String ALPHA = "a-zA-Z";
0724:                    final String DIGIT = "0-9";
0725:                    final String ALPHA_DIGIT = ALPHA + DIGIT;
0726:                    final String HEXA = DIGIT + "ABCDEFabcdef";
0727:                    final String URI_UNRESERVED = ALPHA_DIGIT + "\\-\\.\\_\\~";
0728:                    final String URI_GEN_DELIMS = "\\:\\/\\?\\#\\[\\]\\@";
0729:                    final String URI_SUB_DELIMS = "\\!\\$\\&\\'\\(\\)\\*\\+\\,\\;\\=";
0730:                    final String URI_RESERVED = URI_GEN_DELIMS + URI_SUB_DELIMS;
0731:                    final String URI_ALL = URI_RESERVED + URI_UNRESERVED;
0732:                    final String WORD = "\\w";
0733:
0734:                    // Expressions to create non-capturing groups
0735:                    final String PCT_ENCODED = "\\%[" + HEXA + "][" + HEXA
0736:                            + "]";
0737:                    // final String PCHAR = "[" + URI_UNRESERVED + "]|(?:" + PCT_ENCODED
0738:                    // + ")|[" + URI_SUB_DELIMS + "]|\\:|\\@";
0739:                    final String PCHAR = "[" + URI_UNRESERVED + URI_SUB_DELIMS
0740:                            + "\\:\\@]|(?:" + PCT_ENCODED + ")";
0741:                    final String QUERY = PCHAR + "|\\/|\\?";
0742:                    final String FRAGMENT = QUERY;
0743:
0744:                    StringBuilder coreRegex = new StringBuilder();
0745:
0746:                    switch (variable.getType()) {
0747:                    case Variable.TYPE_ALL:
0748:                        appendClass(coreRegex, ALL, variable.isRequired());
0749:                        break;
0750:                    case Variable.TYPE_ALPHA:
0751:                        appendClass(coreRegex, ALPHA, variable.isRequired());
0752:                        break;
0753:                    case Variable.TYPE_DIGIT:
0754:                        appendClass(coreRegex, DIGIT, variable.isRequired());
0755:                        break;
0756:                    case Variable.TYPE_ALPHA_DIGIT:
0757:                        appendClass(coreRegex, ALPHA_DIGIT, variable
0758:                                .isRequired());
0759:                        break;
0760:                    case Variable.TYPE_URI_ALL:
0761:                        appendClass(coreRegex, URI_ALL, variable.isRequired());
0762:                        break;
0763:                    case Variable.TYPE_URI_UNRESERVED:
0764:                        appendClass(coreRegex, URI_UNRESERVED, variable
0765:                                .isRequired());
0766:                        break;
0767:                    case Variable.TYPE_WORD:
0768:                        appendClass(coreRegex, WORD, variable.isRequired());
0769:                        break;
0770:
0771:                    case Variable.TYPE_URI_FRAGMENT:
0772:                        appendGroup(coreRegex, FRAGMENT, variable.isRequired());
0773:                        break;
0774:                    case Variable.TYPE_URI_QUERY:
0775:                        appendGroup(coreRegex, QUERY, variable.isRequired());
0776:                        break;
0777:                    case Variable.TYPE_URI_SEGMENT:
0778:                        appendGroup(coreRegex, PCHAR, variable.isRequired());
0779:                        break;
0780:                    }
0781:
0782:                    result = coreRegex.toString();
0783:                }
0784:
0785:                return result;
0786:            }
0787:
0788:            /**
0789:             * Appends to a pattern a repeating group of a given content based on a
0790:             * class of characters.
0791:             * 
0792:             * @param pattern
0793:             *                The pattern to append to.
0794:             * @param content
0795:             *                The content of the group.
0796:             * @param required
0797:             *                Indicates if the group is required.
0798:             */
0799:            private static void appendClass(StringBuilder pattern,
0800:                    String content, boolean required) {
0801:
0802:                pattern.append("(");
0803:
0804:                if (content.equals(".")) {
0805:                    // Special case for the TYPE_ALL variable type because the
0806:                    // dot looses its meaning inside a character class
0807:                    pattern.append(content);
0808:                } else {
0809:                    pattern.append("[").append(content).append(']');
0810:
0811:                }
0812:
0813:                if (required) {
0814:                    pattern.append("+");
0815:                } else {
0816:                    pattern.append("*");
0817:                }
0818:
0819:                pattern.append(")");
0820:            }
0821:
0822:            /**
0823:             * Appends to a pattern a repeating group of a given content based on a
0824:             * non-capturing group.
0825:             * 
0826:             * @param pattern
0827:             *                The pattern to append to.
0828:             * @param content
0829:             *                The content of the group.
0830:             * @param required
0831:             *                Indicates if the group is required.
0832:             */
0833:            private static void appendGroup(StringBuilder pattern,
0834:                    String content, boolean required) {
0835:                pattern.append("((?:").append(content).append(')');
0836:
0837:                if (required) {
0838:                    pattern.append("+");
0839:                } else {
0840:                    pattern.append("*");
0841:                }
0842:
0843:                pattern.append(")");
0844:            }
0845:
0846:            /**
0847:             * Returns the modifiable map of variables.
0848:             * 
0849:             * @return The modifiable map of variables.
0850:             */
0851:            public Map<String, Variable> getVariables() {
0852:                return this .variables;
0853:            }
0854:
0855:            /**
0856:             * Indicates if the current pattern matches the given formatted string.
0857:             * 
0858:             * @param formattedString
0859:             *                The formatted string to match.
0860:             * @return The number of matched characters or -1 if the match failed.
0861:             */
0862:            public int match(String formattedString) {
0863:                int result = -1;
0864:
0865:                try {
0866:                    if (formattedString != null) {
0867:                        Matcher matcher = getRegexPattern().matcher(
0868:                                formattedString);
0869:
0870:                        if ((getMatchingMode() == MODE_EQUALS)
0871:                                && matcher.matches()) {
0872:                            result = matcher.end();
0873:                        } else if ((getMatchingMode() == MODE_STARTS_WITH)
0874:                                && matcher.lookingAt()) {
0875:                            result = matcher.end();
0876:                        }
0877:                    }
0878:                } catch (StackOverflowError soe) {
0879:                    getLogger().warning(
0880:                            "StackOverflowError exception encountered while matching this string : "
0881:                                    + formattedString);
0882:                }
0883:
0884:                return result;
0885:            }
0886:
0887:            /**
0888:             * Attempts to parse a formatted reference. If the parsing succeeds, the
0889:             * given request's attributes are updated.<br>
0890:             * Note that the values parsed are directly extracted from the formatted
0891:             * reference and are therefore not percent-decoded.
0892:             * 
0893:             * @see Reference#decode(String)
0894:             * 
0895:             * @param formattedString
0896:             *                The string to parse.
0897:             * @param request
0898:             *                The request to update.
0899:             * @return The number of matched characters or -1 if no character matched.
0900:             */
0901:            public int parse(String formattedString, Request request) {
0902:                return parse(formattedString, request.getAttributes());
0903:            }
0904:
0905:            /**
0906:             * Attempts to parse a formatted reference. If the parsing succeeds, the
0907:             * given request's attributes are updated.<br>
0908:             * Note that the values parsed are directly extracted from the formatted
0909:             * reference and are therefore not percent-decoded.
0910:             * 
0911:             * @see Reference#decode(String)
0912:             * 
0913:             * @param formattedString
0914:             *                The string to parse.
0915:             * @param variables
0916:             *                The map of variables to update.
0917:             * @return The number of matched characters or -1 if no character matched.
0918:             */
0919:            public int parse(String formattedString,
0920:                    Map<String, Object> variables) {
0921:                int result = -1;
0922:                try {
0923:
0924:                    Matcher matcher = getRegexPattern()
0925:                            .matcher(formattedString);
0926:                    boolean matched = ((getMatchingMode() == MODE_EQUALS) && matcher
0927:                            .matches())
0928:                            || ((getMatchingMode() == MODE_STARTS_WITH) && matcher
0929:                                    .lookingAt());
0930:
0931:                    if (matched) {
0932:                        // Update the number of matched characters
0933:                        result = matcher.end();
0934:
0935:                        // Update the attributes with the variables value
0936:                        String attributeName = null;
0937:                        String attributeValue = null;
0938:                        for (int i = 0; i < getRegexVariables().size(); i++) {
0939:                            attributeName = getRegexVariables().get(i);
0940:                            attributeValue = matcher.group(i + 1);
0941:                            variables.put(attributeName, attributeValue);
0942:                        }
0943:                    }
0944:                } catch (StackOverflowError soe) {
0945:                    getLogger().warning(
0946:                            "StackOverflowError exception encountered while matching this string : "
0947:                                    + formattedString);
0948:                }
0949:
0950:                return result;
0951:            }
0952:
0953:            /**
0954:             * Sets the pattern to use for formatting or parsing.
0955:             * 
0956:             * @param pattern
0957:             *                The pattern to use for formatting or parsing.
0958:             */
0959:            public void setPattern(String pattern) {
0960:                this .pattern = pattern;
0961:            }
0962:
0963:            /**
0964:             * Sets the matching mode to use when parsing a formatted reference.
0965:             * 
0966:             * @param matchingMode
0967:             *                The matching mode to use when parsing a formatted
0968:             *                reference.
0969:             */
0970:            public void setMatchingMode(int matchingMode) {
0971:                this .matchingMode = matchingMode;
0972:            }
0973:
0974:            /**
0975:             * Resolves variable values.
0976:             * 
0977:             * @author Jerome Louvel (contact@noelios.com)
0978:             */
0979:            private abstract class VariableResolver {
0980:                public abstract String resolve(String variableName);
0981:            }
0982:
0983:            /**
0984:             * Resolves variable values based on a request and a response.
0985:             * 
0986:             * @author Jerome Louvel (contact@noelios.com)
0987:             */
0988:            private class CallVariableResolver extends VariableResolver {
0989:                /** The request to use as a model. */
0990:                private Request request;
0991:
0992:                /** The response to use as a model. */
0993:                private Response response;
0994:
0995:                /**
0996:                 * Constructor.
0997:                 * 
0998:                 * @param request
0999:                 *                The request to use as a model.
1000:                 * @param response
1001:                 *                The response to use as a model.
1002:                 */
1003:                public CallVariableResolver(Request request, Response response) {
1004:                    this .request = request;
1005:                    this .response = response;
1006:                }
1007:
1008:                @Override
1009:                public String resolve(String variableName) {
1010:                    String result = null;
1011:
1012:                    Variable var = getVariables().get(variableName);
1013:                    if (var == null)
1014:                        var = getDefaultVariable();
1015:
1016:                    // Check for a matching request attribute
1017:                    if (request != null) {
1018:                        Object variable = request.getAttributes().get(
1019:                                variableName);
1020:                        if (variable != null) {
1021:                            result = variable.toString();
1022:                        }
1023:                    }
1024:
1025:                    // Check for a matching response attribute
1026:                    if ((result == null)
1027:                            && (response != null)
1028:                            && response.getAttributes().containsKey(
1029:                                    variableName)) {
1030:                        result = response.getAttributes().get(variableName)
1031:                                .toString();
1032:                    }
1033:
1034:                    // Check for a matching request or response property
1035:                    if (result == null) {
1036:                        if (request != null) {
1037:                            if (variableName.equals("c")) {
1038:                                result = Boolean.toString(request
1039:                                        .isConfidential());
1040:                            } else if (variableName.equals("cia")) {
1041:                                result = request.getClientInfo().getAddress();
1042:                            } else if (variableName.equals("cig")) {
1043:                                result = request.getClientInfo().getAgent();
1044:                            } else if (variableName.equals("cri")) {
1045:                                result = request.getChallengeResponse()
1046:                                        .getIdentifier();
1047:                            } else if (variableName.equals("crs")) {
1048:                                if (request.getChallengeResponse().getScheme() != null) {
1049:                                    result = request.getChallengeResponse()
1050:                                            .getScheme().getTechnicalName();
1051:                                }
1052:                            } else if (variableName.equals("ecs")) {
1053:                                if ((request.getEntity() != null)
1054:                                        && (request.getEntity()
1055:                                                .getCharacterSet() != null)) {
1056:                                    result = request.getEntity()
1057:                                            .getCharacterSet().getName();
1058:                                }
1059:                            } else if (variableName.equals("ee")) {
1060:                                if ((request.getEntity() != null)
1061:                                        && (!request.getEntity().getEncodings()
1062:                                                .isEmpty())) {
1063:                                    StringBuilder value = new StringBuilder();
1064:                                    for (int i = 0; i < request.getEntity()
1065:                                            .getEncodings().size(); i++) {
1066:                                        if (i > 0)
1067:                                            value.append(", ");
1068:                                        value.append(request.getEntity()
1069:                                                .getEncodings().get(i)
1070:                                                .getName());
1071:                                    }
1072:                                    result = value.toString();
1073:                                }
1074:                            } else if (variableName.equals("eed")) {
1075:                                if ((request.getEntity() != null)
1076:                                        && (request.getEntity()
1077:                                                .getExpirationDate() != null)) {
1078:                                    result = DateUtils.format(request
1079:                                            .getEntity().getExpirationDate(),
1080:                                            DateUtils.FORMAT_RFC_1123.get(0));
1081:                                }
1082:                            } else if (variableName.equals("el")) {
1083:                                if ((request.getEntity() != null)
1084:                                        && (!request.getEntity().getLanguages()
1085:                                                .isEmpty())) {
1086:                                    StringBuilder value = new StringBuilder();
1087:                                    for (int i = 0; i < request.getEntity()
1088:                                            .getLanguages().size(); i++) {
1089:                                        if (i > 0)
1090:                                            value.append(", ");
1091:                                        value.append(request.getEntity()
1092:                                                .getLanguages().get(i)
1093:                                                .getName());
1094:                                    }
1095:                                    result = value.toString();
1096:                                }
1097:                            } else if (variableName.equals("emd")) {
1098:                                if ((request.getEntity() != null)
1099:                                        && (request.getEntity()
1100:                                                .getModificationDate() != null)) {
1101:                                    result = DateUtils.format(request
1102:                                            .getEntity().getModificationDate(),
1103:                                            DateUtils.FORMAT_RFC_1123.get(0));
1104:                                }
1105:                            } else if (variableName.equals("emt")) {
1106:                                if ((request.getEntity() != null)
1107:                                        && (request.getEntity().getMediaType() != null)) {
1108:                                    result = request.getEntity().getMediaType()
1109:                                            .getName();
1110:                                }
1111:                            } else if (variableName.equals("es")) {
1112:                                if ((request.getEntity() != null)
1113:                                        && (request.getEntity().getSize() != -1)) {
1114:                                    result = Long.toString(request.getEntity()
1115:                                            .getSize());
1116:                                }
1117:                            } else if (variableName.equals("et")) {
1118:                                if ((request.getEntity() != null)
1119:                                        && (request.getEntity().getTag() != null)) {
1120:                                    result = request.getEntity().getTag()
1121:                                            .getName();
1122:                                }
1123:                            } else if (variableName.startsWith("f")) {
1124:                                result = getReferenceContent(variableName
1125:                                        .substring(1), request.getReferrerRef());
1126:                            } else if (variableName.startsWith("h")) {
1127:                                result = getReferenceContent(variableName
1128:                                        .substring(1), request.getHostRef());
1129:                            } else if (variableName.equals("m")) {
1130:                                if (request.getMethod() != null) {
1131:                                    result = request.getMethod().getName();
1132:                                }
1133:                            } else if (variableName.startsWith("o")) {
1134:                                result = getReferenceContent(variableName
1135:                                        .substring(1), request.getRootRef());
1136:                            } else if (variableName.equals("p")) {
1137:                                if (request.getProtocol() != null) {
1138:                                    result = request.getProtocol().getName();
1139:                                }
1140:                            } else if (variableName.startsWith("r")) {
1141:                                result = getReferenceContent(variableName
1142:                                        .substring(1), request.getResourceRef());
1143:                            }
1144:                        }
1145:
1146:                        if ((result == null) && (response != null)) {
1147:                            if (variableName.equals("ECS")) {
1148:                                if ((response.getEntity() != null)
1149:                                        && (response.getEntity()
1150:                                                .getCharacterSet() != null)) {
1151:                                    result = response.getEntity()
1152:                                            .getCharacterSet().getName();
1153:                                }
1154:                            } else if (variableName.equals("EE")) {
1155:                                if ((response.getEntity() != null)
1156:                                        && (!response.getEntity()
1157:                                                .getEncodings().isEmpty())) {
1158:                                    StringBuilder value = new StringBuilder();
1159:                                    for (int i = 0; i < response.getEntity()
1160:                                            .getEncodings().size(); i++) {
1161:                                        if (i > 0)
1162:                                            value.append(", ");
1163:                                        value.append(response.getEntity()
1164:                                                .getEncodings().get(i)
1165:                                                .getName());
1166:                                    }
1167:                                    result = value.toString();
1168:                                }
1169:                            } else if (variableName.equals("EED")) {
1170:                                if ((response.getEntity() != null)
1171:                                        && (response.getEntity()
1172:                                                .getExpirationDate() != null)) {
1173:                                    result = DateUtils.format(response
1174:                                            .getEntity().getExpirationDate(),
1175:                                            DateUtils.FORMAT_RFC_1123.get(0));
1176:                                }
1177:                            } else if (variableName.equals("EL")) {
1178:                                if ((response.getEntity() != null)
1179:                                        && (!response.getEntity()
1180:                                                .getLanguages().isEmpty())) {
1181:                                    StringBuilder value = new StringBuilder();
1182:                                    for (int i = 0; i < response.getEntity()
1183:                                            .getLanguages().size(); i++) {
1184:                                        if (i > 0)
1185:                                            value.append(", ");
1186:                                        value.append(response.getEntity()
1187:                                                .getLanguages().get(i)
1188:                                                .getName());
1189:                                    }
1190:                                    result = value.toString();
1191:                                }
1192:                            } else if (variableName.equals("EMD")) {
1193:                                if ((response.getEntity() != null)
1194:                                        && (response.getEntity()
1195:                                                .getModificationDate() != null)) {
1196:                                    result = DateUtils.format(response
1197:                                            .getEntity().getModificationDate(),
1198:                                            DateUtils.FORMAT_RFC_1123.get(0));
1199:                                }
1200:                            } else if (variableName.equals("EMT")) {
1201:                                if ((response.getEntity() != null)
1202:                                        && (response.getEntity().getMediaType() != null)) {
1203:                                    result = response.getEntity()
1204:                                            .getMediaType().getName();
1205:                                }
1206:                            } else if (variableName.equals("ES")) {
1207:                                if ((response.getEntity() != null)
1208:                                        && (response.getEntity().getSize() != -1)) {
1209:                                    result = Long.toString(response.getEntity()
1210:                                            .getSize());
1211:                                }
1212:                            } else if (variableName.equals("ET")) {
1213:                                if ((response.getEntity() != null)
1214:                                        && (response.getEntity().getTag() != null)) {
1215:                                    result = response.getEntity().getTag()
1216:                                            .getName();
1217:                                }
1218:                            } else if (variableName.startsWith("R")) {
1219:                                result = getReferenceContent(variableName
1220:                                        .substring(1), response
1221:                                        .getRedirectRef());
1222:                            } else if (variableName.equals("S")) {
1223:                                if (response.getStatus() != null) {
1224:                                    result = Integer.toString(response
1225:                                            .getStatus().getCode());
1226:                                }
1227:                            } else if (variableName.equals("SIA")) {
1228:                                result = response.getServerInfo().getAddress();
1229:                            } else if (variableName.equals("SIG")) {
1230:                                result = response.getServerInfo().getAgent();
1231:                            } else if (variableName.equals("SIP")) {
1232:                                if (response.getServerInfo().getPort() != -1) {
1233:                                    result = Integer.toString(response
1234:                                            .getServerInfo().getPort());
1235:                                }
1236:                            }
1237:                        }
1238:                    }
1239:
1240:                    if (result == null) {
1241:                        // Use the default value instead
1242:                        result = var.getDefaultValue();
1243:                    }
1244:
1245:                    return result;
1246:                }
1247:            }
1248:
1249:            /**
1250:             * Resolves variable values based on a map.
1251:             * 
1252:             * @author Jerome Louvel (contact@noelios.com)
1253:             */
1254:            private class MapVariableResolver extends VariableResolver {
1255:                /** The variables to use when formatting. */
1256:                private Map<String, Object> map;
1257:
1258:                /**
1259:                 * Constructor.
1260:                 * 
1261:                 * @param map
1262:                 *                The variables to use when formatting.
1263:                 */
1264:                public MapVariableResolver(Map<String, Object> map) {
1265:                    this .map = map;
1266:                }
1267:
1268:                @Override
1269:                public String resolve(String variableName) {
1270:                    Object value = this.map.get(variableName);
1271:                    return (value == null) ? null : value.toString();
1272:                }
1273:            }
1274:
1275:        }
www.java2java.com | Contact Us
Copyright 2009 - 12 Demo Source and Support. All rights reserved.
All other trademarks are property of their respective owners.