Coverage Report - org.simpleframework.xml.core.TreeModel
 
Classes in this File Line Coverage Branch Coverage Complexity
TreeModel
92%
145/156
80%
76/94
2.771
TreeModel$OrderList
100%
2/2
N/A
2.771
 
 1  
 /*
 2  
  * TreeModel.java November 2010
 3  
  *
 4  
  * Copyright (C) 2010, 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.core;
 20  
 
 21  
 import java.util.ArrayList;
 22  
 import java.util.Iterator;
 23  
 import java.util.List;
 24  
 import java.util.Set;
 25  
 
 26  
 /**
 27  
  * The <code>TreeModel</code> object is used to build a tree like
 28  
  * structure to represent the XML schema for an annotated class. The
 29  
  * model is responsible  for building, ordering, and validating all
 30  
  * criteria used to represent the class schema. This is immutable
 31  
  * to ensure it can be reused many time, in a concurrent environment.
 32  
  * Each time attribute and element definitions are requested they
 33  
  * are build as new <code>LabelMap</code> objects using a provided
 34  
  * context. This ensures the mappings can be styled as required.
 35  
  * 
 36  
  * @author Niall Gallagher
 37  
  * 
 38  
  * @see org.simpleframework.xml.core.Context
 39  
  */
 40  
 class TreeModel implements Model {
 41  
   
 42  
    /**
 43  
     * This is the XPath expression representing the location.
 44  
     */
 45  
    private Expression expression;
 46  
   
 47  
    /**
 48  
     * This holds the mappings for elements within the model.
 49  
     */
 50  
    private LabelMap attributes;
 51  
    
 52  
    /**
 53  
     * This holds the mappings for elements within the model.
 54  
     */
 55  
    private LabelMap elements;
 56  
    
 57  
    /**
 58  
     * This holds the mappings for the models within this instance.
 59  
     */
 60  
    private ModelMap models;
 61  
    
 62  
    /**
 63  
     * This is used to provide the order of the model elements.
 64  
     */
 65  
    private OrderList order;
 66  
    
 67  
    /**
 68  
     * This is the serialization policy enforced on this model.
 69  
     */
 70  
    private Policy policy;
 71  
    
 72  
    /**
 73  
     * This is the type used for reporting validation errors.
 74  
     */
 75  
    private Detail detail;
 76  
    
 77  
    /**
 78  
     * This must be a valid XML element representing the name.
 79  
     */
 80  
    private String name;
 81  
    
 82  
    /**
 83  
     * This is used to represent the prefix for this model.
 84  
     */
 85  
    private String prefix;
 86  
    
 87  
    /**
 88  
     * This is an optional text label used for this model.
 89  
     */
 90  
    private Label text;
 91  
    
 92  
    /**
 93  
     * This is an optional text label used for this model.
 94  
     */
 95  
    private Label list;
 96  
    
 97  
    /**
 98  
     * This is the index used to sort similarly named models.
 99  
     */
 100  
    private int index;
 101  
    
 102  
    /**
 103  
     * Constructor for the <code>TreeModel</code> object. This can be
 104  
     * used to register the attributes and elements associated with
 105  
     * an annotated class. Also, if there are any path references, 
 106  
     * this can contain a tree of models mirroring the XML structure.
 107  
     * 
 108  
     * @param policy this is the serialization policy enforced
 109  
     * @param detail this is the detail associated with this model
 110  
     */
 111  
    public TreeModel(Policy policy, Detail detail) {
 112  2379
       this(policy, detail, null, null, 1);
 113  2379
    }
 114  
    
 115  
    /**
 116  
     * Constructor for the <code>TreeModel</code> object. This can be
 117  
     * used to register the attributes and elements associated with
 118  
     * an annotated class. Also, if there are any path references, 
 119  
     * this can contain a tree of models mirroring the XML structure.
 120  
     * 
 121  
     * @param policy this is the serialization policy enforced
 122  
     * @param detail this is the detail associated with this model
 123  
     * @param name this is the XML element name for this model
 124  
     * @param prefix this is the prefix used for this model object
 125  
     * @param index this is the index used to order the model
 126  
     */
 127  2741
    public TreeModel(Policy policy, Detail detail, String name, String prefix, int index) {
 128  2741
       this.attributes = new LabelMap(policy);
 129  2741
       this.elements = new LabelMap(policy);
 130  2741
       this.models = new ModelMap(detail);
 131  2741
       this.order = new OrderList();
 132  2741
       this.detail = detail;
 133  2741
       this.policy = policy;
 134  2741
       this.prefix = prefix;
 135  2741
       this.index = index;
 136  2741
       this.name = name;
 137  2741
    }
 138  
    
 139  
    /**
 140  
     * This method is used to look for a <code>Model</code> that
 141  
     * matches the specified expression. If no such model exists
 142  
     * then this will return null. Using an XPath expression allows
 143  
     * a tree like structure to be navigated with ease.
 144  
     * 
 145  
     * @param path an XPath expression used to locate a model
 146  
     * 
 147  
     * @return this returns the model located by the expression
 148  
     */
 149  
    public Model lookup(Expression path) {
 150  810
       String name = path.getFirst();
 151  810
       int index = path.getIndex();
 152  810
       Model model = lookup(name, index);
 153  
       
 154  810
       if(path.isPath()) {
 155  362
          path = path.getPath(1, 0);
 156  
          
 157  362
          if(model != null) {     
 158  304
             return model.lookup(path);
 159  
          }
 160  
       }
 161  506
       return model;   
 162  
    }   
 163  
    
 164  
    /**
 165  
     * This is used to register an XML entity within the model. The
 166  
     * registration process has the affect of telling the model that
 167  
     * it will contain a specific, named, XML entity. It also has 
 168  
     * the affect of ordering them within the model, such that the
 169  
     * first registered entity is the first iterated over.
 170  
     * 
 171  
     * @param name this is the name of the element to register
 172  
     */   
 173  
    public void registerElement(String name) throws Exception {
 174  0
       if(!order.contains(name)) {
 175  0
          order.add(name);
 176  
       }
 177  0
       elements.put(name, null);
 178  0
    }   
 179  
    
 180  
    /**
 181  
     * This is used to register an XML entity within the model. The
 182  
     * registration process has the affect of telling the model that
 183  
     * it will contain a specific, named, XML entity. It also has 
 184  
     * the affect of ordering them within the model, such that the
 185  
     * first registered entity is the first iterated over.
 186  
     * 
 187  
     * @param name this is the name of the element to register
 188  
     */
 189  
    public void registerAttribute(String name) throws Exception {
 190  67
       attributes.put(name, null);
 191  67
    }
 192  
    
 193  
    /**
 194  
     * This is used to register an XML entity within the model. The
 195  
     * registration process has the affect of telling the model that
 196  
     * it will contain a specific, named, XML entity. It also has 
 197  
     * the affect of ordering them within the model, such that the
 198  
     * first registered entity is the first iterated over.
 199  
     * 
 200  
     * @param label this is the label to register with the model
 201  
     */   
 202  
    public void registerText(Label label) throws Exception {
 203  122
       if(text != null) {
 204  0
          throw new TextException("Duplicate text annotation on %s", label);
 205  
       }
 206  122
       text = label;
 207  122
    }
 208  
    
 209  
    /**
 210  
     * This is used to register an XML entity within the model. The
 211  
     * registration process has the affect of telling the model that
 212  
     * it will contain a specific, named, XML entity. It also has 
 213  
     * the affect of ordering them within the model, such that the
 214  
     * first registered entity is the first iterated over.
 215  
     * 
 216  
     * @param label this is the label to register with the model
 217  
     */   
 218  
    public void registerAttribute(Label label) throws Exception {
 219  882
       String name = label.getName();
 220  
       
 221  882
       if(attributes.get(name) != null) {
 222  0
          throw new AttributeException("Duplicate annotation of name '%s' on %s", name, label);
 223  
       }
 224  882
       attributes.put(name, label);
 225  882
    }   
 226  
    
 227  
    /**
 228  
     * This is used to register an XML entity within the model. The
 229  
     * registration process has the affect of telling the model that
 230  
     * it will contain a specific, named, XML entity. It also has 
 231  
     * the affect of ordering them within the model, such that the
 232  
     * first registered entity is the first iterated over.
 233  
     * 
 234  
     * @param label this is the label to register with the model
 235  
     */   
 236  
    public void registerElement(Label label) throws Exception {
 237  2951
       String name = label.getName();
 238  
       
 239  2951
       if(elements.get(name) != null) {
 240  0
          throw new ElementException("Duplicate annotation of name '%s' on %s", name, label);
 241  
       }
 242  2951
       if(!order.contains(name)) {
 243  2876
          order.add(name);
 244  
       }
 245  2951
       if(label.isTextList()) {
 246  36
          list = label;
 247  
       }
 248  2951
       elements.put(name, label);
 249  2951
    }
 250  
    
 251  
    /**
 252  
     * This is used to build a map from a <code>Context</code> object.
 253  
     * Building a map in this way ensures that any style specified by
 254  
     * the context can be used to create the XML element and attribute
 255  
     * names in the styled format. It also ensures that the model
 256  
     * remains immutable as it only provides copies of its data.
 257  
     * 
 258  
     * @return this returns a map built from the specified context
 259  
     */   
 260  
    public ModelMap getModels() throws Exception {
 261  930837
       return models.getModels();
 262  
    }
 263  
 
 264  
    /**
 265  
     * This is used to build a map from a <code>Context</code> object.
 266  
     * Building a map in this way ensures that any style specified by
 267  
     * the context can be used to create the XML element and attribute
 268  
     * names in the styled format. It also ensures that the model
 269  
     * remains immutable as it only provides copies of its data.
 270  
     * 
 271  
     * @return this returns a map built from the specified context
 272  
     */   
 273  
    public LabelMap getAttributes() throws Exception {
 274  932930
       return attributes.getLabels();
 275  
    }
 276  
 
 277  
    /**
 278  
     * This is used to build a map from a <code>Context</code> object.
 279  
     * Building a map in this way ensures that any style specified by
 280  
     * the context can be used to create the XML element and attribute
 281  
     * names in the styled format. It also ensures that the model
 282  
     * remains immutable as it only provides copies of its data.
 283  
     * 
 284  
     * @return this returns a map built from the specified context
 285  
     */
 286  
    public LabelMap getElements() throws Exception{
 287  931420
       return elements.getLabels();
 288  
    }
 289  
    
 290  
    /**
 291  
     * This is used to determine if the provided name represents
 292  
     * a model. This is useful when validating the model as it
 293  
     * allows determination of a named model, which is an element. 
 294  
     * 
 295  
     * @param name this is the name of the section to determine
 296  
     * 
 297  
     * @return this returns true if the model is registered
 298  
     */
 299  
    public boolean isModel(String name) {
 300  13
       return models.containsKey(name);
 301  
    }
 302  
 
 303  
    /**
 304  
     * This is used to determine if the provided name represents
 305  
     * an element. This is useful when validating the model as 
 306  
     * it allows determination of a named XML element. 
 307  
     * 
 308  
     * @param name this is the name of the section to determine
 309  
     * 
 310  
     * @return this returns true if the element is registered
 311  
     */
 312  
    public boolean isElement(String name) {
 313  87
       return elements.containsKey(name);
 314  
    }
 315  
    
 316  
    /**
 317  
     * This is used to determine if the provided name represents
 318  
     * an attribute. This is useful when validating the model as 
 319  
     * it allows determination of a named XML attribute
 320  
     * 
 321  
     * @param name this is the name of the attribute to determine
 322  
     * 
 323  
     * @return this returns true if the attribute is registered
 324  
     */
 325  
    public boolean isAttribute(String name) {
 326  67
       return attributes.containsKey(name);
 327  
    }
 328  
    
 329  
    /**
 330  
     * This will return the names of all elements contained within
 331  
     * the model. This includes the names of all XML elements that
 332  
     * have been registered as well as any other models that have
 333  
     * been added. Iteration is done in an ordered manner, according
 334  
     * to the registration of elements and models.
 335  
     * 
 336  
     * @return an order list of the elements and models registered
 337  
     */
 338  
    public Iterator<String> iterator() {
 339  217742
       List<String> list = new ArrayList<String>();
 340  
       
 341  217742
       for(String name : order) {
 342  421394
          list.add(name);        
 343  
       }
 344  217742
       return list.iterator();      
 345  
    }
 346  
    
 347  
    /**
 348  
     * This is used to validate the model to ensure all elements and
 349  
     * attributes are valid. Validation also ensures that any order
 350  
     * specified by an annotated class did not contain invalid XPath
 351  
     * values, or redundant elements and attributes.
 352  
     * 
 353  
     * @param type this is the object type representing the schema
 354  
     * 
 355  
     * @throws Exception if text and element annotations are present
 356  
     */
 357  
    public void validate(Class type) throws Exception {
 358  1825
       validateExpressions(type);
 359  1825
       validateAttributes(type);
 360  1824
       validateElements(type);
 361  1823
       validateModels(type);
 362  1819
       validateText(type);
 363  1813
    }
 364  
    
 365  
    /**
 366  
     * This method is used to validate the model based on whether it 
 367  
     * has a text annotation. If this model has a text annotation then
 368  
     * it is checked to see if it is a composite model or has any
 369  
     * elements. If it has either then the model is considered invalid.
 370  
     *
 371  
     * @param type this is the object type representing the schema
 372  
     */
 373  
    private void validateText(Class type) throws Exception {
 374  1819
       if(text != null) {
 375  120
          if(!elements.isEmpty()) {
 376  4
             throw new TextException("Text annotation %s used with elements in %s", text, type);
 377  
          }
 378  116
          if(isComposite()) {
 379  2
             throw new TextException("Text annotation %s can not be used with paths in %s", text, type);
 380  
          }
 381  
       }
 382  1813
    }
 383  
    
 384  
    /**
 385  
     * This is used to validate the expressions used for each label that
 386  
     * this model represents. Each label within a model must have an
 387  
     * XPath expression, if the expressions do not match then this will
 388  
     * throw an exception. If the model contains no labels then it is
 389  
     * considered empty and does not need validation.
 390  
     * 
 391  
     * @param type this is the object type representing the schema
 392  
     */
 393  
    private void validateExpressions(Class type) throws Exception {
 394  1825
       for(Label label : elements) {
 395  2914
          if(label != null) {
 396  2914
             validateExpression(label);
 397  
          }
 398  
       }
 399  1825
       for(Label label : attributes) {
 400  873
          if(label != null) {
 401  872
             validateExpression(label);
 402  
          }
 403  
       }
 404  1825
       if(text != null) {
 405  120
          validateExpression(text);
 406  
       } 
 407  1825
    }
 408  
    
 409  
    /**
 410  
     * This is used to validate the expressions used for a label that
 411  
     * this model represents. Each label within a model must have an
 412  
     * XPath expression, if the expressions do not match then this will
 413  
     * throw an exception. If the model contains no labels then it is
 414  
     * considered empty and does not need validation.
 415  
     * 
 416  
     * @param label this is the object type representing the schema
 417  
     */
 418  
    private void validateExpression(Label label) throws Exception {
 419  3906
       Expression location = label.getExpression();
 420  
       
 421  3906
       if(expression != null) {
 422  2313
          String path = expression.getPath();
 423  2313
          String expect = location.getPath();
 424  
          
 425  2313
          if(!path.equals(expect)) {
 426  0
             throw new PathException("Path '%s' does not match '%s' in %s", path, expect, detail);
 427  
          }
 428  2313
       } else {
 429  1593
          expression = location;
 430  
       }
 431  3906
    }
 432  
    
 433  
    /**
 434  
     * This is used to validate the models within the instance. This
 435  
     * will basically result in validation of the entire tree. Once
 436  
     * finished all models contained within the tree will be valid.
 437  
     * If any model is invalid an exception will be thrown.
 438  
     * <p>
 439  
     * To ensure that all ordering and registration of the models
 440  
     * is consistent this will check to ensure the indexes of each
 441  
     * registered model are in sequence. If they are out of sequence
 442  
     * then this will throw an exception.
 443  
     * 
 444  
     * @param type this is the type this model is created for
 445  
     */
 446  
    private void validateModels(Class type) throws Exception {
 447  1823
       for(ModelList list : models) {
 448  315
          int count = 1;
 449  
          
 450  315
          for(Model model : list) {
 451  348
             if(model != null) {        
 452  348
                String name = model.getName();
 453  348
                int index = model.getIndex();
 454  
             
 455  348
                if(index != count++) {
 456  0
                   throw new ElementException("Path section '%s[%s]' is out of sequence in %s", name, index, type);
 457  
                }
 458  348
                model.validate(type);
 459  344
             }
 460  
          }
 461  311
       }
 462  1819
    }
 463  
    
 464  
    /**
 465  
     * This is used to validate the individual attributes within the
 466  
     * model. Validation is done be acquiring all the attributes and
 467  
     * determining if they are null. If they are null this means that
 468  
     * an ordering has been imposed on a non-existing attribute.
 469  
     * 
 470  
     * @param type this is the type this model is created for   
 471  
     */
 472  
    private void validateAttributes(Class type) throws Exception {
 473  1825
       Set<String> keys = attributes.keySet();
 474  
       
 475  1825
       for(String name : keys) {
 476  873
          Label label = attributes.get(name);
 477  
          
 478  873
          if(label == null) {
 479  1
             throw new AttributeException("Ordered attribute '%s' does not exist in %s", name, type);
 480  
          }
 481  872
          if(expression != null) {
 482  872
             expression.getAttribute(name); // prime cache
 483  
          }
 484  872
       }
 485  1824
    }
 486  
    
 487  
    /**
 488  
     * This is used to validate the individual elements within the
 489  
     * model. Validation is done be acquiring all the elements and
 490  
     * determining if they are null. If they are null this means that
 491  
     * an ordering has been imposed on a non-existing element.
 492  
     * 
 493  
     * @param type this is the type this model is created for   
 494  
     */
 495  
    private void validateElements(Class type) throws Exception {
 496  1824
       Set<String> keys = elements.keySet();
 497  
       
 498  1824
       for(String name : keys) {
 499  2914
          ModelList list = models.get(name);
 500  2914
          Label label = elements.get(name);
 501  
          
 502  2914
          if(list == null && label == null) {
 503  0
             throw new ElementException("Ordered element '%s' does not exist in %s", name, type);
 504  
          }
 505  2914
          if(list != null && label != null) {
 506  73
             if(!list.isEmpty()) {
 507  1
                throw new ElementException("Element '%s' is also a path name in %s", name, type);
 508  
             }
 509  
          }
 510  2913
          if(expression != null) {
 511  2913
             expression.getElement(name); // prime cache
 512  
          }
 513  2913
       }
 514  1823
    }
 515  
    
 516  
    /**
 517  
     * This is used to register an XML entity within the model. The
 518  
     * registration process has the affect of telling the model that
 519  
     * it will contain a specific, named, XML entity. It also has 
 520  
     * the affect of ordering them within the model, such that the
 521  
     * first registered entity is the first iterated over.
 522  
     * 
 523  
     * @param label this is the label to register with the model
 524  
     */
 525  
    public void register(Label label) throws Exception {
 526  3955
       if(label.isAttribute()) {
 527  882
          registerAttribute(label);
 528  3073
       } else if(label.isText()) {
 529  122
          registerText(label);
 530  
       } else {
 531  2951
          registerElement(label);
 532  
       }
 533  3955
    }   
 534  
 
 535  
    /**
 536  
     * This method is used to look for a <code>Model</code> that
 537  
     * matches the specified element name. If no such model exists
 538  
     * then this will return null. This is used as an alternative
 539  
     * to providing an XPath expression to navigate the tree.
 540  
     * 
 541  
     * @param name this is the name of the model to be acquired
 542  
     * 
 543  
     * @return this returns the model located by the expression
 544  
     */
 545  
    public Model lookup(String name, int index) {
 546  827
       return models.lookup(name, index);
 547  
    }
 548  
 
 549  
    /**
 550  
     * This is used to register a <code>Model</code> within this
 551  
     * model. Registration of a model creates a tree of models that
 552  
     * can be used to represent an XML structure. Each model can
 553  
     * contain elements and attributes associated with a type.
 554  
     * 
 555  
     * @param name this is the name of the model to be registered
 556  
     * @param prefix this is the prefix used for this model
 557  
     * @param index this is the index used to order the model
 558  
     * 
 559  
     * @return this returns the model that was registered
 560  
     */
 561  
    public Model register(String name, String prefix, int index) throws Exception {
 562  708
       Model model = models.lookup(name, index);
 563  
       
 564  708
       if (model == null) {
 565  362
          return create(name, prefix, index);
 566  
       }
 567  346
       return model;
 568  
    }
 569  
    
 570  
    /**
 571  
     * This is used to register a <code>Model</code> within this
 572  
     * model. Registration of a model creates a tree of models that
 573  
     * can be used to represent an XML structure. Each model can
 574  
     * contain elements and attributes associated with a type.
 575  
     * 
 576  
     * @param name this is the name of the model to be registered
 577  
     * @param prefix this is the prefix used for this model
 578  
     * @param index this is the index used to order the model
 579  
     * 
 580  
     * @return this returns the model that was registered
 581  
     */
 582  
    private Model create(String name, String prefix, int index) throws Exception {
 583  362
       Model model = new TreeModel(policy, detail, name, prefix, index);
 584  
       
 585  362
       if(name != null) {
 586  362
          models.register(name, model);
 587  362
          order.add(name);
 588  
       }
 589  362
       return model;
 590  
    }
 591  
    
 592  
    /**
 593  
     * This is used to perform a recursive search of the models that
 594  
     * have been registered, if a model has elements or attributes
 595  
     * then this returns true. If however no other model contains 
 596  
     * any attributes or elements then this will return false.
 597  
     * 
 598  
     * @return true if any model has elements or attributes
 599  
     */
 600  
    public boolean isComposite() {
 601  3025
       for(ModelList list : models) {
 602  830
          for(Model model : list) {
 603  830
             if(model != null) {
 604  830
                if(!model.isEmpty()) {
 605  830
                   return true;
 606  
                }
 607  
             }
 608  
          }
 609  
       }
 610  2195
       return !models.isEmpty();
 611  
    }
 612  
    
 613  
    /**
 614  
     * Used to determine if a model is empty. A model is considered
 615  
     * empty if that model does not contain any registered elements
 616  
     * or attributes. However, if the model contains other models
 617  
     * that have registered elements or attributes it is not empty.
 618  
     * 
 619  
     * @return true if the model does not contain registrations
 620  
     */
 621  
    public boolean isEmpty() {
 622  6009
       if(text != null) {
 623  182
          return false;
 624  
       }
 625  5827
       if(!elements.isEmpty()) {
 626  2721
          return false;
 627  
       }
 628  3106
       if(!attributes.isEmpty()) {
 629  309
          return false;
 630  
       }
 631  2797
       return !isComposite();
 632  
    }
 633  
    
 634  
    /**
 635  
     * This returns a text label if one is associated with the model.
 636  
     * If the model does not contain a text label then this method
 637  
     * will return null. Any model with a text label should not be
 638  
     * composite and should not contain any elements.
 639  
     * 
 640  
     * @return this is the optional text label for this model
 641  
     */
 642  
    public Label getText() {
 643  935644
       if(list != null) {
 644  67
          return list;
 645  
       }
 646  935577
       return text;
 647  
    }
 648  
    
 649  
    /**
 650  
     * This returns an <code>Expression</code> representing the path
 651  
     * this model exists at within the class schema. This should 
 652  
     * never be null for any model that is not empty.
 653  
     * 
 654  
     * @return this returns the expression associated with this
 655  
     */
 656  
    public Expression getExpression() {
 657  2494566
       return expression;
 658  
    }
 659  
    
 660  
    /**
 661  
     * This is used to acquire the path prefix for the model. The
 662  
     * path prefix is used when the model is transformed in to an
 663  
     * XML structure. This ensures that the XML element created to
 664  
     * represent the model contains the optional prefix.
 665  
     * 
 666  
     * @return this returns the prefix for this model
 667  
     */
 668  
    public String getPrefix() {
 669  217738
       return prefix;
 670  
    }
 671  
    
 672  
    /**
 673  
     * This is used to return the name of the model. The name is 
 674  
     * must be a valid XML element name. It is used when a style
 675  
     * is applied to a section as the model name must be styled.
 676  
     * 
 677  
     * @return this returns the name of this model instance
 678  
     */
 679  
    public String getName() {
 680  348
       return name;
 681  
    }
 682  
    
 683  
    /**
 684  
     * This method is used to return the index of the model. The
 685  
     * index is the order that this model appears within the XML
 686  
     * document. Having an index allows multiple models of the
 687  
     * same name to be inserted in to a sorted collection.
 688  
     * 
 689  
     * @return this is the index of this model instance
 690  
     */
 691  
    public int getIndex() {
 692  1737
       return index;
 693  
    }
 694  
    
 695  
    /**
 696  
     * For the purposes of debugging we provide a representation
 697  
     * of the model in a string format. This will basically show
 698  
     * the name of the model and the index it exists at.
 699  
     * 
 700  
     * @return this returns some details for the model
 701  
     */
 702  
    public String toString() {
 703  0
       return String.format("model '%s[%s]'", name, index);
 704  
    }
 705  
    
 706  
    /**
 707  
     * The <code>OrderList</code> object is used to maintain the order
 708  
     * of the XML elements within the model. Elements are either 
 709  
     * other models or element <code>Label</code> objects that are
 710  
     * annotated fields or methods. Maintaining order is important     
 711  
     * 
 712  
     * @author Niall Gallagher
 713  
     */
 714  
    private static class OrderList extends ArrayList<String> {
 715  
       
 716  
       /**
 717  
        * Constructor for the <code>OrderList</code> object. This is
 718  
        * basically a typedef of sorts that hides the ugly generic
 719  
        * details from the class definition.        
 720  
        */
 721  
       public OrderList() {
 722  2741
          super();
 723  2741
       }
 724  
    }
 725  
 }