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