Coverage Report - org.simpleframework.xml.stream.Indenter
 
Classes in this File Line Coverage Branch Coverage Complexity
Indenter
93%
30/32
100%
14/14
2.077
Indenter$Cache
61%
11/18
50%
4/8
2.077
 
 1  
 /*
 2  
  * Indenter.java July 2006
 3  
  *
 4  
  * Copyright (C) 2006, Niall Gallagher <niallg@users.sf.net>
 5  
  *
 6  
  * Licensed under the Apache License, Version 2.0 (the "License");
 7  
  * you may not use this file except in compliance with the License.
 8  
  * You may obtain a copy of the License at
 9  
  *
 10  
  *     http://www.apache.org/licenses/LICENSE-2.0
 11  
  *
 12  
  * Unless required by applicable law or agreed to in writing, software
 13  
  * distributed under the License is distributed on an "AS IS" BASIS,
 14  
  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or 
 15  
  * implied. See the License for the specific language governing 
 16  
  * permissions and limitations under the License.
 17  
  */
 18  
 
 19  
 package org.simpleframework.xml.stream;
 20  
 
 21  
 /**
 22  
  * The <code>Indenter</code> is used create indent strings using the
 23  
  * stack paradigm. This allows XML documents to be generated by 
 24  
  * pushing and popping indents onto the stack. This indenter caches
 25  
  * all indent strings created so that when the same position on the
 26  
  * stack is encountered the indent can be acquired quickly.
 27  
  * <p>
 28  
  * The indents created by this are all prefixed with the line feed
 29  
  * character, which allows XML tags to span exclusive lines. If the
 30  
  * indent size specified is zero or less then no spaces, or line 
 31  
  * feed will be added to the generated indent string.
 32  
  *
 33  
  * @author Niall Gallagher
 34  
  */ 
 35  
 class Indenter {
 36  
 
 37  
    /**
 38  
     * Provides a quick string cache that caches using by index.
 39  
     */         
 40  
    private Cache cache;
 41  
        
 42  
    /**
 43  
     * Number of spaces that is used for each of the indents.
 44  
     */ 
 45  
    private int indent;
 46  
    
 47  
    /**
 48  
     * Represents the current number of spaces in the indent text.
 49  
     */ 
 50  
    private int count;
 51  
 
 52  
    /**
 53  
     * Represents the index within the cache to get the indent.
 54  
     */ 
 55  
    private int index;
 56  
   
 57  
    /**
 58  
     * Constructor for the <code>Indenter</code> object. This will
 59  
     * create an indent that uses three spaces for each indent that
 60  
     * is pushed on to the stack. This also uses a default cache 
 61  
     * size of sixteen, which should be sufficient for most files.
 62  
     */ 
 63  
    public Indenter() {
 64  0
       this(new Format());
 65  0
    }
 66  
 
 67  
    /**
 68  
     * Constructor for the <code>Indenter</code> object. This will
 69  
     * create an indent that uses the specified number of spaces to
 70  
     * create each entry pushed on to the stack. This uses a cache
 71  
     * size of sixteen, which should be sufficient for most files.
 72  
     *
 73  
     * @param format determines the number of spaces per indent
 74  
     */ 
 75  
    public Indenter(Format format) {
 76  24420
       this(format, 16);           
 77  24420
    }
 78  
    
 79  
    /**
 80  
     * Constructor for the <code>Indenter</code> object. This will
 81  
     * create an indent that uses the specified number of spaces to
 82  
     * create each entry pushed on to the stack. This uses a cache
 83  
     * of the specified size, which is used to optimize the object.
 84  
     *
 85  
     * @param format determines the number of spaces per indent
 86  
     * @param size this is the initial size of the indent cache
 87  
     */ 
 88  24420
    private Indenter(Format format, int size) {
 89  24420
       this.indent = format.getIndent();           
 90  24420
       this.cache = new Cache(size);
 91  24420
    }  
 92  
    
 93  
    /**
 94  
     * This returns the current indent for this indenter. This should
 95  
     * be used to write elements or comments that should be at the
 96  
     * same indentation level as the XML element that will follow. 
 97  
     * 
 98  
     * @return this returns the current indentation level for this
 99  
     */
 100  
    public String top() {
 101  25450
       return indent(index);
 102  
    }
 103  
 
 104  
    /**
 105  
     * This is used to push an indent on to the cache. The first
 106  
     * indent created by this is an empty string, this is because an
 107  
     * indent is not required for the start of an XML file. If there
 108  
     * are multiple roots written to the same writer then the start
 109  
     * and end tags of a root element will exist on the same line.
 110  
     * 
 111  
     * @return this is used to push an indent on to the stack
 112  
     */ 
 113  
    public String push() {
 114  561691
       String text = indent(index++);
 115  
    
 116  561691
       if(indent > 0) {
 117  561674
          count += indent;
 118  
       }         
 119  561691
       return text;
 120  
    }                  
 121  
 
 122  
    /**
 123  
     * This is used to pop an indent from the cache. This reduces
 124  
     * the length of the current indent and is typically used when
 125  
     * an end tag is added to an XML document. If the number of pop
 126  
     * requests exceeds the number of push requests then an empty
 127  
     * string is returned from this method.
 128  
     *
 129  
     * @return this is used to pop an indent from the stack
 130  
     */ 
 131  
    public String pop() {
 132  561685
       String text = indent(--index);
 133  
 
 134  561685
       if(indent > 0) {
 135  561668
          count -= indent;
 136  
       }      
 137  561685
       return text;
 138  
    }
 139  
 
 140  
    /**
 141  
     * This is used to acquire the indent at the specified index. If
 142  
     * the indent does not exist at the specified index then on is
 143  
     * created using the current value of the indent. The very first
 144  
     * indent taken from this will be an empty string value.
 145  
     *
 146  
     * @param index this is the index to acquire the indent from
 147  
     *
 148  
     * @return this returns the indent from the specified index
 149  
     */ 
 150  
    private String indent(int index) {
 151  1148826
       if(indent > 0) {
 152  1148792
          String text = cache.get(index);
 153  
 
 154  1148792
          if(text == null){
 155  112447
             text = create();
 156  112447
             cache.set(index, text);         
 157  
          }
 158  1148792
          if(cache.size() >0) {
 159  1124314
             return text;
 160  
          }            
 161  
       }         
 162  24512
       return "";  
 163  
    }
 164  
 
 165  
    /**
 166  
     * This is used to create an indent which can later be pushed on
 167  
     * to the stack. If the number of spaces to be added is zero then
 168  
     * this will return a single character string with a line feed.
 169  
     *
 170  
     * @return this will create an indent to be added to the stack
 171  
     */ 
 172  
    private String create() {
 173  112447
       char[] text = new char[count+1];
 174  
 
 175  112447
       if(count > 0) {
 176  88058
          text[0] = '\n';
 177  
 
 178  729832
          for(int i = 1; i <= count; i++){
 179  641774
             text[i] = ' ';                 
 180  
          }         
 181  88058
          return new String(text);
 182  
       }
 183  24389
       return "\n";
 184  
    }
 185  
 
 186  
    /**
 187  
     * The <code>Cache</code> object is used create an indexable list
 188  
     * which allows the indenter to quickly acquire an indent using
 189  
     * a stack position. This ensures that the indenter need only 
 190  
     * create an index once for a given stack position. The number of
 191  
     * indents held within this cache can also be tracked.
 192  
     */ 
 193  
    private static class Cache {
 194  
 
 195  
       /**
 196  
        * This is used to track indent strings within the cache.
 197  
        */            
 198  
       private String[] list;
 199  
 
 200  
       /**
 201  
        * Represents the number of indent strings held by the cache.
 202  
        */ 
 203  
       private int count;
 204  
       
 205  
       /**
 206  
        * Constructor for the <code>Cache</code> object. This creates
 207  
        * a cache of the specified size, the specified size acts as
 208  
        * an initial size and the cache can be expanded on demand.
 209  
        *
 210  
        * @param size the initial number of entries in the cache
 211  
        */ 
 212  24420
       public Cache(int size) {
 213  24420
          this.list = new String[size];              
 214  24420
       }
 215  
 
 216  
       /**
 217  
        * This method is used to retrieve the number of indents that
 218  
        * have been added to the cache. This is used to determine if
 219  
        * an indent request is the first.
 220  
        *
 221  
        * @return this returns the number of indents in the cache
 222  
        */ 
 223  
       public int size() {
 224  1148792
          return count;              
 225  
       }      
 226  
 
 227  
       /**
 228  
        * This method is used to add the specified indent on to the
 229  
        * cache. The index allows the cache to act as a stack, when
 230  
        * the index is specified it can be used to retrieve the same
 231  
        * indent using that index.
 232  
        * 
 233  
        * @param index this is the position to add the index to
 234  
        * @param text this is the indent to add to the position
 235  
        */ 
 236  
       public void set(int index, String text) {
 237  112447
          if(index >= list.length) {
 238  0
             resize(index * 2);                             
 239  
          }
 240  112447
          if(index > count) {
 241  88058
             count = index;                 
 242  
          }
 243  112447
          list[index] = text;         
 244  112447
       }
 245  
 
 246  
       /**
 247  
        * This method is used to retrieve an indent from the given
 248  
        * position. This allows the indenter to use the cache as a
 249  
        * stack, by increasing and decreasing the index as required.
 250  
        * 
 251  
        * @param index the position to retrieve the indent from
 252  
        *
 253  
        * @return this is the indent retrieve from the given index
 254  
        */ 
 255  
       public String get(int index) {
 256  1148792
          if(index < list.length) {
 257  1148792
             return list[index];
 258  
          }              
 259  0
          return null;
 260  
       }
 261  
 
 262  
       /**
 263  
        * Should the number of indents to be cache grows larger than
 264  
        * the default initial size then this will increase the size
 265  
        * of the cache. This ensures that the indenter can handle an
 266  
        * arbitrary number of indents for a given output.
 267  
        *
 268  
        * @param size this is the size to expand the cache to
 269  
        */ 
 270  
       private void resize(int size) {
 271  0
          String[] temp = new String[size];
 272  
 
 273  0
          for(int i = 0; i < list.length; i++){
 274  0
             temp[i] = list[i];                 
 275  
          }
 276  0
          list = temp;
 277  0
       }
 278  
    }
 279  
 }