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