Coverage Report - com.sdmetrics.model.MetaModel - www.sdmetrics.com
 
Classes in this File Line Coverage Branch Coverage Complexity
MetaModel
100%
6/6
N/A
2,7
MetaModel$MetaModelParser
100%
61/61
100%
34/34
2,7
 
 1  
 /*
 2  
  * SDMetrics Open Core for UML design measurement
 3  
  * Copyright (c) Juergen Wuest
 4  
  * To contact the author, see <http://www.sdmetrics.com/Contact.html>.
 5  
  * 
 6  
  * This file is part of the SDMetrics Open Core.
 7  
  * 
 8  
  * SDMetrics Open Core is free software: you can redistribute it and/or modify
 9  
  * it under the terms of the GNU Affero General Public License as
 10  
  * published by the Free Software Foundation, either version 3 of the
 11  
  * License, or (at your option) any later version.
 12  
     
 13  
  * SDMetrics Open Core is distributed in the hope that it will be useful,
 14  
  * but WITHOUT ANY WARRANTY; without even the implied warranty of
 15  
  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 16  
  * GNU Affero General Public License for more details.
 17  
  *
 18  
  * You should have received a copy of the GNU Affero General Public License
 19  
  * along with SDMetrics Open Core.  If not, see <http://www.gnu.org/licenses/>.
 20  
  *
 21  
  */
 22  
 package com.sdmetrics.model;
 23  
 
 24  
 import java.util.Iterator;
 25  
 import java.util.LinkedHashMap;
 26  
 import java.util.Map;
 27  
 
 28  
 import org.xml.sax.Attributes;
 29  
 import org.xml.sax.SAXException;
 30  
 import org.xml.sax.helpers.DefaultHandler;
 31  
 
 32  
 import com.sdmetrics.util.SAXHandler;
 33  
 
 34  
 /**
 35  
  * Represents an SDMetrics metamodel. The metamodel defines the available model
 36  
  * element types and their attributes.
 37  
  * <p>
 38  
  * The class parses the metamodel definition file, manages the set of
 39  
  * {@link MetaModelElement} instances that constitute the metamodel, and
 40  
  * provides access to them.
 41  
  */
 42  434
 public class MetaModel implements Iterable<MetaModelElement> {
 43  
 
 44  
         /** The name of the top level XML element in the metamodel definition file. */
 45  
         public final static String TL_ELEMENT = "sdmetricsmetamodel";
 46  
         /** The name of the base element type. */
 47  
         public final static String BASE_ELEMENT = "sdmetricsbase";
 48  
 
 49  
         /**
 50  
          * Directory of the element types that constitute this metamodel. Allows
 51  
          * lookup of the element types by their name.
 52  
          */
 53  5352
         private final Map<String, MetaModelElement> elementMap = new LinkedHashMap<String, MetaModelElement>();
 54  
 
 55  
         /**
 56  
          * Retrieves an iterator over the element types in this metamodel. Types are
 57  
          * returned in the order in which they were added/defined in the metamodel
 58  
          * definition file.
 59  
          * 
 60  
          * @return Metamodel element iterator
 61  
          */
 62  
         @Override
 63  
         public Iterator<MetaModelElement> iterator() {
 64  769
                 return elementMap.values().iterator();
 65  
         }
 66  
 
 67  
         /**
 68  
          * Gets a SAX handler to populate this metamodel with the contents of a
 69  
          * metamodel definition file.
 70  
          * 
 71  
          * @return SAX handler to parse the metamodel definition file
 72  
          */
 73  
         public DefaultHandler getSAXParserHandler() {
 74  217
                 return new MetaModelParser();
 75  
         }
 76  
 
 77  
         /**
 78  
          * Retrieves a metamodel element by its type name.
 79  
          * 
 80  
          * @param typeName The type name of the metamodel element.
 81  
          * @return The metamodel element with that name or <code>null</code> if
 82  
          *         there is no element of that name.
 83  
          */
 84  
         public MetaModelElement getType(String typeName) {
 85  12569
                 return elementMap.get(typeName);
 86  
         }
 87  
 
 88  
         /**
 89  
          * Gets the number of element types defined by this metamodel.
 90  
          * 
 91  
          * @return The number of types in this metamodel.
 92  
          */
 93  
         int getNumberOfTypes() {
 94  159
                 return elementMap.size();
 95  
         }
 96  
 
 97  
         /**
 98  
          * SAX handler to parse a metamodel definition file.
 99  
          */
 100  434
         private class MetaModelParser extends SAXHandler {
 101  
                 // XML element and attribute names of the metamodel definition
 102  
                 private final static String ELEM_MODELELEMENT = "modelelement";
 103  
                 private final static String ATTR_NAME = "name";
 104  
                 private final static String ATTR_PARENT = "parent";
 105  
                 private final static String ELEM_ATTRIBUTE = "attribute";
 106  
                 private final static String ATTR_TYPE = "type";
 107  
                 private final static String ATTR_MULTIPLICITY = "multiplicity";
 108  
 
 109  217
                 private MetaModelElement currentMME = null;
 110  217
                 private String currentAttributeName = null;
 111  
 
 112  
                 /** Clear the metamodel at the beginning of the XML document. */
 113  
                 @Override
 114  
                 public void startDocument() {
 115  217
                         elementMap.clear();
 116  217
                 }
 117  
 
 118  
                 /**
 119  
                  * Process an XML element in the metamodel definition file. Extracts and
 120  
                  * stores the metamodel element or attribute information.
 121  
                  * 
 122  
                  * @throws SAXException The XML file contains something other than model
 123  
                  *         element and attribute definitions.
 124  
                  */
 125  
                 @Override
 126  
                 public void startElement(String uri, String local, String raw,
 127  
                                 Attributes attrs) throws SAXException {
 128  5423
                         if (TL_ELEMENT.equals(raw)) {
 129  217
                                 checkVersion(attrs, null);
 130  216
                         } else if (ELEM_MODELELEMENT.equals(raw)) {
 131  2461
                                 handleMetaModelElement(attrs);
 132  2458
                         } else if (ELEM_ATTRIBUTE.equals(raw)) {
 133  2744
                                 handleAttributeDefinition(attrs);
 134  2740
                         } else {
 135  1
                                 reportError("Unexpected XML element <" + raw + ">.");
 136  
                         }
 137  5414
                 }
 138  
 
 139  
                 /**
 140  
                  * Handles a metamodel element definition.
 141  
                  * 
 142  
                  * @param attrs XML attributes of the element
 143  
                  * @throws SAXException metamodel element definition is invalid
 144  
                  */
 145  
                 private void handleMetaModelElement(Attributes attrs)
 146  
                                 throws SAXException {
 147  2461
                         String typeName = attrs.getValue(ATTR_NAME);
 148  2461
                         if (typeName == null)
 149  1
                                 reportError("Model element is missing \"" + ATTR_NAME
 150  
                                                 + "\" attribute.");
 151  2460
                         String parentName = attrs.getValue(ATTR_PARENT);
 152  2460
                         if (parentName == null)
 153  2107
                                 parentName = BASE_ELEMENT;
 154  2460
                         MetaModelElement parentElement = elementMap.get(parentName);
 155  2460
                         if (parentElement == null && !BASE_ELEMENT.equals(typeName)) {
 156  2
                                 if (BASE_ELEMENT.equals(parentName))
 157  1
                                         reportError("The first metamodel element to be defined must be named \""
 158  
                                                         + BASE_ELEMENT + "\".");
 159  2
                                 reportError("Unknown parent type \"" + parentName
 160  1
                                                 + "\" for model element \"" + typeName + "\".");
 161  
                         }
 162  
 
 163  2458
                         currentMME = new MetaModelElement(typeName, parentElement);
 164  2458
                         elementMap.put(typeName, currentMME);
 165  2458
                         currentAttributeName = null;
 166  2458
                 }
 167  
 
 168  
                 /**
 169  
                  * Handles a metamodel attribute definition.
 170  
                  * 
 171  
                  * @param attrs XML attributes of the metamodel attribute
 172  
                  * @throws SAXException metamodel attribute definition is invalid
 173  
                  */
 174  
                 private void handleAttributeDefinition(Attributes attrs)
 175  
                                 throws SAXException {
 176  2744
                         if (currentMME == null)
 177  1
                                 reportError("Attribute definition outside model element definition.");
 178  
 
 179  2743
                         currentAttributeName = attrs.getValue(ATTR_NAME);
 180  2743
                         if (currentAttributeName == null)
 181  2
                                 reportError("Attribute without a name for model element \""
 182  1
                                                 + currentMME.getName() + "\".");
 183  
 
 184  2742
                         boolean isRefAttribute = "ref".equals(attrs.getValue(ATTR_TYPE));
 185  5484
                         boolean isSetAttribute = "many".equals(attrs
 186  2742
                                         .getValue(ATTR_MULTIPLICITY));
 187  
 
 188  2742
                         if ("extref".equals(attrs.getValue(ATTR_TYPE))) {
 189  101
                                 if (currentMME.getExtensionReference() != null)
 190  2
                                         reportError("Duplicate extension reference attribute '"
 191  1
                                                         + currentAttributeName + "'.");
 192  100
                                 if (isSetAttribute)
 193  2
                                         reportError("Extension reference attribute '"
 194  1
                                                         + currentAttributeName
 195  1
                                                         + "' cannot be multi-valued.");
 196  99
                                 isRefAttribute = true;
 197  99
                                 currentMME.setExtensionReference(currentAttributeName);
 198  
                         }
 199  
 
 200  5480
                         currentMME.addAttribute(currentAttributeName, isRefAttribute,
 201  2740
                                         isSetAttribute);
 202  2740
                 }
 203  
 
 204  
                 /** Registers end of metamodel element/attribute definitions. */
 205  
                 @Override
 206  
                 public void endElement(String uri, String local, String raw) {
 207  5402
                         if (ELEM_MODELELEMENT.equals(raw))
 208  2454
                                 currentMME = null;
 209  2948
                         else if (ELEM_ATTRIBUTE.equals(raw))
 210  2740
                                 currentAttributeName = null;
 211  5402
                 }
 212  
 
 213  
                 /**
 214  
                  * Adds description text to the current attribute of the current element
 215  
                  * type.
 216  
                  */
 217  
                 @Override
 218  
                 public void characters(char ch[], int start, int length) {
 219  9460
                         if (currentMME != null && currentAttributeName != null) {
 220  4594
                                 currentMME.addAttributeDescription(currentAttributeName,
 221  2297
                                                 new String(ch, start, length));
 222  
                         }
 223  9460
                 }
 224  
         }
 225  
 }