Coverage Report - com.sdmetrics.model.ModelElement - www.sdmetrics.com
 
Classes in this File Line Coverage Branch Coverage Complexity
ModelElement
100%
82/82
100%
28/28
1,864
ModelElement$ElementOrderComparator
100%
5/5
100%
4/4
1,864
 
 1  406
 /*
 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.io.Serializable;
 25  
 import java.util.Collection;
 26  
 import java.util.Collections;
 27  
 import java.util.Comparator;
 28  
 import java.util.HashMap;
 29  
 import java.util.HashSet;
 30  
 
 31  
 /**
 32  
  * Represents a model element of a model. A model element stores the values of
 33  
  * its attributes (which includes outgoing references to other model elements),
 34  
  * and keeps track of incoming references from other model elements.
 35  
  */
 36  
 public class ModelElement {
 37  
         /** Initial size of a hash map that probably will not carry many elements. */
 38  
         private static final int INITIAL_FEW_ELEMENTS = 0;
 39  
         /** Separator string used to build fully qualified element names. */
 40  
         private static final String QUALIFIER_SEPARATOR = ".";
 41  
 
 42  
         /** The type of this element. */
 43  
         private MetaModelElement type;
 44  
         /** The values of the attributes of this model element. */
 45  
         private Object[] attributeValues;
 46  
         /**
 47  
          * Model elements have a running ID to preserve the order in which the
 48  
          * elements are defined in the XMI source file. Elements with higher IDs
 49  
          * were defined after elements with lower IDs.
 50  
          */
 51  812
         private int runningID;
 52  
         /**
 53  
          * Map of elements that have cross-reference attributes pointing to this
 54  
          * element. Key is the name of the cross-reference attribute, value is the
 55  
          * set of elements pointing to this element with that cross-reference
 56  
          * attribute.
 57  
          */
 58  
         private HashMap<String, Collection<ModelElement>> relations;
 59  
         /**
 60  
          * Indicates if cross-references to this element should be ignored according
 61  
          * to the element filter settings.
 62  
          */
 63  13715
         private boolean ignoreLinks = false;
 64  
 
 65  
         /**
 66  
          * Creates a new element.
 67  
          * 
 68  
          * @param type The element type of the model element.
 69  
          */
 70  13715
         public ModelElement(MetaModelElement type) {
 71  13715
                 this.type = type;
 72  13715
                 Collection<String> attributeList = type.getAttributeNames();
 73  
                 // Initialize the attribute values of the element to empty strings/sets
 74  13715
                 attributeValues = new Object[attributeList.size()];
 75  96455
                 for (String attrName : attributeList)
 76  69025
                         if (!type.isSetAttribute(attrName))
 77  55220
                                 attributeValues[type.getAttributeIndex(attrName)] = "";
 78  13715
         }
 79  
 
 80  
         /**
 81  
          * Registers a model element that has a cross-reference attribute pointing
 82  
          * to this model element.
 83  
          * 
 84  
          * @param relationName Name of the cross-reference attribute.
 85  
          * @param source The model element pointing to this element.
 86  
          */
 87  
         void addRelation(String relationName, ModelElement source) {
 88  17801
                 if (relations == null) {
 89  7166
                         relations = new HashMap<String, Collection<ModelElement>>(
 90  3583
                                         INITIAL_FEW_ELEMENTS);
 91  
                 }
 92  17801
                 Collection<ModelElement> relset = relations.get(relationName);
 93  17801
                 if (relset == null) {
 94  
                         // no relations of relationName yet, install set
 95  6133
                         relset = new HashSet<ModelElement>(INITIAL_FEW_ELEMENTS);
 96  6133
                         relations.put(relationName, relset);
 97  
                 }
 98  17801
                 relset.add(source);
 99  17801
         }
 100  
 
 101  
         /**
 102  
          * Returns the set of model elements that point to this model element via a
 103  
          * specified cross-reference attribute.
 104  
          * 
 105  
          * @param relationName Name of the cross-reference attribute.
 106  
          * @return The set of model elements that point to this model element with
 107  
          *         the specified cross-reference attribute. May be <code>null</code>
 108  
          *         if there are no such referencing model elements.
 109  
          */
 110  
         public Collection<ModelElement> getRelations(String relationName) {
 111  354
                 if (relations != null)
 112  318
                         return relations.get(relationName);
 113  36
                 return null;
 114  
         }
 115  
 
 116  
         /**
 117  
          * Sets the value of an attribute for this model element. If the attribute
 118  
          * is multi-valued, the string will be added to the set.
 119  
          * 
 120  
          * @param attrName Name of the attribute.
 121  
          * @param value Value of the attribute.
 122  
          */
 123  
         @SuppressWarnings("unchecked")
 124  
         void setAttribute(String attrName, String value) {
 125  53260
                 int index = type.getAttributeIndex(attrName);
 126  53260
                 if (type.isSetAttribute(attrName)) {
 127  
                         @SuppressWarnings("rawtypes")
 128  387
                         Collection set = ((Collection) attributeValues[index]);
 129  387
                         if (set == null) {
 130  335
                                 set = new HashSet<Object>(INITIAL_FEW_ELEMENTS);
 131  335
                                 attributeValues[index] = set;
 132  
                         }
 133  387
                         set.add(value);
 134  387
                 } else {
 135  52873
                         attributeValues[index] = value;
 136  
                 }
 137  53260
         }
 138  
 
 139  
         /**
 140  
          * Sets the target model element of a single-valued cross-reference
 141  
          * attribute.
 142  
          * 
 143  
          * @param attrName Name of the cross-reference attribute.
 144  
          * @param target The referenced model element
 145  
          */
 146  
         void setRefAttribute(String attrName, ModelElement target) {
 147  18206
                 attributeValues[type.getAttributeIndex(attrName)] = target;
 148  18206
         }
 149  
 
 150  
         /**
 151  
          * Sets the value of a multi-valued attribute.
 152  
          * 
 153  
          * @param attrName Name of the multi-valued attribute.
 154  
          * @param set The collection of values for the attribute
 155  
          */
 156  
         void setSetAttribute(String attrName, Collection<?> set) {
 157  336
                 attributeValues[type.getAttributeIndex(attrName)] = set;
 158  336
         }
 159  
 
 160  
         /**
 161  
          * Retrieves the value of a single-valued data attribute for this model
 162  
          * element.
 163  
          * 
 164  
          * @param attrName Name of the attribute.
 165  
          * @return Value of the attribute.
 166  
          */
 167  
         public String getPlainAttribute(String attrName) {
 168  45956
                 return (String) attributeValues[type.getAttributeIndex(attrName)];
 169  
         }
 170  
 
 171  
         /**
 172  
          * Retrieves the model element referenced by a single-valued cross-reference
 173  
          * attribute.
 174  
          * 
 175  
          * @param attrName Name of the cross-reference attribute.
 176  
          * @return the referenced model element, or <code>null</code> if the
 177  
          *         reference is empty or the reference should be ignored as per
 178  
          *         filter settings.
 179  
          */
 180  
         public ModelElement getRefAttribute(String attrName) {
 181  356
                 ModelElement me = (ModelElement) attributeValues[type
 182  178
                                 .getAttributeIndex(attrName)];
 183  178
                 if (me != null && me.ignoreLinks)
 184  1
                         return null;
 185  177
                 return me;
 186  
         }
 187  
 
 188  
         /**
 189  
          * Retrieves the set of values for a multi-valued attribute. For
 190  
          * cross-reference attributes, this is a collection of model elements. For
 191  
          * data attributes, the collection contains strings.
 192  
          * 
 193  
          * @param attrName Name of the multi-valued attribute.
 194  
          * @return Collection of model elements or strings stored by the attribute.
 195  
          */
 196  
         public Collection<?> getSetAttribute(String attrName) {
 197  27562
                 Collection<?> result = (Collection<?>) attributeValues[type
 198  13781
                                 .getAttributeIndex(attrName)];
 199  13781
                 if (result == null)
 200  13438
                         return Collections.EMPTY_SET;
 201  343
                 return result;
 202  
         }
 203  
 
 204  
         /**
 205  
          * Tests whether cross-references to this element should be ignored
 206  
          * according to the element filter settings.
 207  
          * 
 208  
          * @return <code>true</code> if the cross-references to this element should
 209  
          *         be ignored
 210  
          */
 211  
         public boolean getLinksIgnored() {
 212  1405
                 return ignoreLinks;
 213  
         }
 214  
 
 215  
         /**
 216  
          * Marks whether links to this element are to be ignored according to the
 217  
          * filter settings or not.
 218  
          * 
 219  
          * @param ignore <code>true</code> if the cross-references to this element
 220  
          *        are to be ignored, else <code>false</code>.
 221  
          */
 222  
         void setLinksIgnored(boolean ignore) {
 223  203
                 ignoreLinks = ignore;
 224  203
         }
 225  
 
 226  
         /**
 227  
          * Returns the metamodel element type of this model element.
 228  
          * 
 229  
          * @return The type of this element
 230  
          * */
 231  
         public MetaModelElement getType() {
 232  26029
                 return type;
 233  
         }
 234  
 
 235  
         /**
 236  
          * Sets the running ID of this model element.
 237  
          * 
 238  
          * @param id The running ID
 239  
          */
 240  
         void setRunningID(int id) {
 241  13599
                 runningID = id;
 242  13599
         }
 243  
 
 244  
         /**
 245  
          * Gets the fully qualified name of this model element. This is the path to
 246  
          * the model in the containment hierarchy, with the names of the owner
 247  
          * elements separated by dots.
 248  
          * 
 249  
          * @return Fully qualified name of this model element
 250  
          */
 251  
         public String getFullName() {
 252  4
                 StringBuilder sb = new StringBuilder();
 253  4
                 ModelElement currentElement = this;
 254  17
                 while (currentElement != null) {
 255  18
                         String name = currentElement
 256  9
                                         .getPlainAttribute(MetaModelElement.NAME);
 257  9
                         sb.insert(0, name);
 258  9
                         currentElement = currentElement.getOwner();
 259  9
                         if (currentElement != null) {
 260  5
                                 sb.insert(0, QUALIFIER_SEPARATOR);
 261  
                         }
 262  
                 }
 263  
 
 264  4
                 return sb.toString();
 265  
         }
 266  
 
 267  
         /**
 268  
          * Gets the owner of this model element.
 269  
          * 
 270  
          * @return Owner of the model element, <code>null</code> for root model
 271  
          *         elements.
 272  
          */
 273  
         public ModelElement getOwner() {
 274  1594
                 return (ModelElement) attributeValues[type
 275  797
                                 .getAttributeIndex(MetaModelElement.CONTEXT)];
 276  
         }
 277  
 
 278  
         /**
 279  
          * Gets the model elements owned by this element.
 280  
          * 
 281  
          * @return A collection of all that this model element owns.
 282  
          */
 283  
         public Collection<ModelElement> getOwnedElements() {
 284  26
                 return getRelations(MetaModelElement.CONTEXT);
 285  
         }
 286  
 
 287  
         /**
 288  
          * Gets the XMI ID of this model element.
 289  
          * 
 290  
          * @return XMI ID of the model element.
 291  
          */
 292  
         public String getXMIID() {
 293  81598
                 return (String) attributeValues[type
 294  40799
                                 .getAttributeIndex(MetaModelElement.ID)];
 295  
         }
 296  
 
 297  
         /**
 298  
          * Gets the name of this model element.
 299  
          * 
 300  
          * @return The unqualified name of the model element
 301  
          */
 302  
         public String getName() {
 303  5104
                 return (String) attributeValues[type
 304  2552
                                 .getAttributeIndex(MetaModelElement.NAME)];
 305  
         }
 306  
 
 307  
         /** Returns the XMI ID of the model element as its string representation. */
 308  
         @Override
 309  
         public String toString() {
 310  3
                 return String.valueOf(getXMIID());
 311  
         }
 312  
 
 313  
         /**
 314  
          * Returns a comparator to sort model elements by the order in which they
 315  
          * are defined in the XMI file.
 316  
          * 
 317  
          * @return Model element comparator
 318  
          */
 319  
         public static Comparator<ModelElement> getComparator() {
 320  10
                 return new ElementOrderComparator();
 321  
         }
 322  
 
 323  
         /**
 324  
          * Compares running IDs of the model elements.
 325  
          */
 326  20
         private static class ElementOrderComparator implements
 327  
                         Comparator<ModelElement>, Serializable {
 328  
                 private static final long serialVersionUID = -7690366551032834958L;
 329  
 
 330  
                 @Override
 331  
                 public int compare(ModelElement e1, ModelElement e2) {
 332  406
                         int id1 = e1.runningID;
 333  406
                         int id2 = e2.runningID;
 334  406
                         return (id1 < id2) ? -1 : ((id1 == id2) ? 0 : 1);
 335  
                 }
 336  
         }
 337  
 
 338  
         /**
 339  
          * Merges the data from another model element with this one. Copies all
 340  
          * attributes (except "id").
 341  
          * 
 342  
          * @param other The element with which to merge this one.
 343  
          */
 344  
         void merge(ModelElement other) {
 345  3
                 this.ignoreLinks = other.ignoreLinks;
 346  3
                 this.runningID = other.runningID;
 347  
 
 348  
                 // copy all attribute values except "id" from other element
 349  3
                 MetaModelElement otherType = other.getType();
 350  3
                 Collection<String> attributes = otherType.getAttributeNames();
 351  21
                 for (String attr : attributes) {
 352  15
                         if (!MetaModelElement.ID.equals(attr)) {
 353  12
                                 int thisIndex = type.getAttributeIndex(attr);
 354  12
                                 int otherIndex = otherType.getAttributeIndex(attr);
 355  12
                                 attributeValues[thisIndex] = other.attributeValues[otherIndex];
 356  
                         }
 357  
                 }
 358  3
         }
 359  
 }