Coverage Report - com.damnhandy.uri.template.impl.UriTemplateParser
 
Classes in this File Line Coverage Branch Coverage Complexity
UriTemplateParser
92%
60/65
80%
32/40
4.5
 
 1  
 /*
 2  
  * Copyright 2012, Ryan J. McDonough
 3  
  *
 4  
  * Licensed under the Apache License, Version 2.0 (the "License");
 5  
  * you may not use this file except in compliance with the License.
 6  
  * You may obtain a copy of the License at
 7  
  *
 8  
  *     http://www.apache.org/licenses/LICENSE-2.0
 9  
  *
 10  
  * Unless required by applicable law or agreed to in writing, software
 11  
  * distributed under the License is distributed on an "AS IS" BASIS,
 12  
  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 13  
  * See the License for the specific language governing permissions and
 14  
  * limitations under the License.
 15  
  */
 16  
 package com.damnhandy.uri.template.impl;
 17  
 
 18  
 import com.damnhandy.uri.template.Expression;
 19  
 import com.damnhandy.uri.template.Literal;
 20  
 import com.damnhandy.uri.template.MalformedUriTemplateException;
 21  
 import com.damnhandy.uri.template.UriTemplateComponent;
 22  
 
 23  
 import java.util.LinkedList;
 24  
 
 25  
 /**
 26  
  * Utility class used to parse the URI template string into a series of components
 27  
  *
 28  
  * @author <a href="ryan@damnhandy.com">Ryan J. McDonough</a>
 29  
  * @version $Revision: 1.1 $
 30  
  * @since 2.0
 31  
  */
 32  1032
 public final class UriTemplateParser
 33  
 {
 34  
 
 35  
     private static final char EXPR_START = '{';
 36  
 
 37  
     private static final char EXPR_END = '}';
 38  
 
 39  1032
     private boolean startedTemplate = false;
 40  
 
 41  1032
     private boolean expressionCaptureOn = false;
 42  
 
 43  1032
     private boolean literalCaptureOn = false;
 44  
 
 45  1032
     private LinkedList<UriTemplateComponent> components = new LinkedList<UriTemplateComponent>();
 46  
 
 47  
     private StringBuilder buffer;
 48  
 
 49  
     private int startPosition;
 50  
 
 51  
 
 52  
     /**
 53  
      * Scans the URI template looking for literal string components and expressions.
 54  
      *
 55  
      * @param templateString the URI template string to scan
 56  
      * @since 2.0
 57  
      */
 58  
     public LinkedList<UriTemplateComponent> scan(String templateString) throws MalformedUriTemplateException
 59  
     {
 60  1032
         char[] template = templateString.toCharArray();
 61  1032
         startTemplate();
 62  
         int i;
 63  14808
         for (i = 0; i < template.length; i++)
 64  
         {
 65  13834
             char c = template[i];
 66  
 
 67  13834
             if (c == EXPR_START)
 68  
             {
 69  1066
                 if (literalCaptureOn)
 70  
                 {
 71  374
                     endLiteral(i);
 72  
                 }
 73  1066
                 startExpression(i);
 74  
             }
 75  
 
 76  13828
             if (c != EXPR_START || c != EXPR_END)
 77  
             {
 78  13828
                 startLiteral(i);
 79  
             }
 80  
 
 81  
 
 82  13828
             if (expressionCaptureOn || literalCaptureOn)
 83  
             {
 84  13828
                 capture(c);
 85  
             }
 86  
 
 87  13828
             if (c == EXPR_END)
 88  
             {
 89  1054
                 endExpression(i);
 90  1002
                 startLiteral(i);
 91  
             }
 92  
         }
 93  974
         if (literalCaptureOn)
 94  
         {
 95  974
             endLiteral(i);
 96  
         }
 97  974
         endTemplate(i);
 98  970
         return components;
 99  
     }
 100  
 
 101  
     /**
 102  
      * If capture is active, collect the characters into the buffer
 103  
      *
 104  
      * @param currentChar
 105  
      */
 106  
     private void capture(char currentChar)
 107  
     {
 108  13828
         if (buffer == null)
 109  
         {
 110  1482
             buffer = new StringBuilder();
 111  
         }
 112  13828
         buffer.append(currentChar);
 113  13828
     }
 114  
 
 115  
     /**
 116  
      * Called when the {@link UriTemplateParser} has started on the template.
 117  
      */
 118  
     private void startTemplate()
 119  
     {
 120  1032
         startedTemplate = true;
 121  1032
     }
 122  
 
 123  
     /**
 124  
      * Called when the end of the template is reached. If an expression has
 125  
      * not been closed, an exception will be raised.
 126  
      */
 127  
     private void endTemplate(int position) throws MalformedUriTemplateException
 128  
     {
 129  974
         startedTemplate = false;
 130  974
         if (expressionCaptureOn)
 131  
         {
 132  4
             throw new MalformedUriTemplateException("The expression at position " + startPosition + " was never terminated", startPosition);
 133  
         }
 134  
 
 135  970
     }
 136  
 
 137  
     /**
 138  
      * Marks the start of
 139  
      *
 140  
      * @param position
 141  
      */
 142  
     private void startLiteral(int position) throws MalformedUriTemplateException
 143  
     {
 144  
 
 145  14830
         if (startedTemplate)
 146  
         {
 147  14830
             if (!literalCaptureOn)
 148  
             {
 149  
                 //throw new IllegalStateException("Literal capture already started at character "+template[position]);
 150  1400
                 literalCaptureOn = true;
 151  1400
                 startPosition = position;
 152  
             }
 153  
         }
 154  
         else
 155  
         {
 156  0
             throw new IllegalStateException("Cannot start a literal without beginning the template");
 157  
         }
 158  14830
     }
 159  
 
 160  
     private void endLiteral(int position) throws MalformedUriTemplateException
 161  
     {
 162  1348
         if (startedTemplate)
 163  
         {
 164  1348
             if (!literalCaptureOn)
 165  
             {
 166  0
                 throw new IllegalStateException("Can't end a literal without starting it first");
 167  
             }
 168  
             // in the case that we have back to back expressions ({foo}{?bar}), we can get into a state
 169  
             // we started capturing a literal but never actually collected anything yet.
 170  1348
             if (buffer != null)
 171  
             {
 172  428
                 components.add(new Literal(buffer.toString(), this.startPosition));
 173  428
                 literalCaptureOn = false;
 174  428
                 buffer = null;
 175  
             }
 176  
 
 177  
         }
 178  
         else
 179  
         {
 180  0
             throw new IllegalStateException("Cannot end a literal without beginning the template");
 181  
         }
 182  1348
     }
 183  
 
 184  
 
 185  
     /**
 186  
      * Called when the start of an expression has been encountered.
 187  
      */
 188  
     private void startExpression(int position) throws MalformedUriTemplateException
 189  
     {
 190  
 
 191  1066
         if (startedTemplate)
 192  
         {
 193  1066
             if (expressionCaptureOn)
 194  
 
 195  
             {
 196  6
                 throw new MalformedUriTemplateException("A new expression start brace found at " + position
 197  
                 + " but another unclosed expression was found at " + startPosition, position);
 198  
             }
 199  1060
             literalCaptureOn = false;
 200  1060
             expressionCaptureOn = true;
 201  1060
             startPosition = position;
 202  
         }
 203  
         else
 204  
         {
 205  0
             throw new IllegalStateException("Cannot start an expression without beginning the template");
 206  
         }
 207  1060
     }
 208  
 
 209  
     /**
 210  
      * Called when the end of an expression has been encountered.
 211  
      */
 212  
     private void endExpression(int position) throws MalformedUriTemplateException
 213  
     {
 214  
 
 215  
         // an expression close brace is found without a start
 216  1054
         if (startedTemplate)
 217  
         {
 218  1054
             if (!expressionCaptureOn)
 219  
 
 220  
             {
 221  4
                 throw new MalformedUriTemplateException("Expression close brace was found at position " + position
 222  
                 + " yet there was no start brace.", position);
 223  
             }
 224  1050
             expressionCaptureOn = false;
 225  1050
             components.add(new Expression(buffer.toString(), this.startPosition));
 226  1002
             buffer = null;
 227  
         }
 228  
         else
 229  
         {
 230  0
             throw new IllegalStateException("Cannot end an expression without beginning the template");
 231  
         }
 232  1002
     }
 233  
 }