/** * This is supposed to find out, whether the given category 'cat' applied in 'this' class complies * to the categories of all its base classes. If at least one base class does not comply, 'false' * is returned. Overloaded from supertype, because we here have more comfortable data structures * available. */ @Override public boolean checkSupertypes(int cat) { // Prepare set of base classes TreeSet<ClassInfoEA> bcis = new TreeSet<ClassInfoEA>(); if (baseclassInfo != null) bcis.add(baseclassInfo); else if (baseclassInfoSet != null) bcis = baseclassInfoSet; // Consider all baseclasses in turn, break as soon as a first non- // compliancy is detected. boolean res = true; for (ClassInfoEA bci : bcis) { // Get category of base class int bcicat = bci.category(); // Find out about category compliance if (bcicat == Options.UNKNOWN) { // If base class category unknown, obtain from its base classes res = bci.checkSupertypes(cat); } else if (bcicat == Options.MIXIN) { // Ignore mixin base class continue; } else if (bcicat != cat) { // Not compliant: Reject res = false; } // We no longer need to look, if the result is non-compliant ... if (!res) break; } // Trace for debugging if (res) document.result.addDebug(null, 10003, name(), "" + cat, "TRUE"); else document.result.addDebug(null, 10003, name(), "" + cat, "FALSE"); // Return, what we found out return res; } // checkSupertypes()
/** * This determines the particular base class of a class in the sense of ISO19136 annex D+E. Only * classes of categories resulting from the acknowledged stereotypes are considered. A base class * is selected if it has the same category as this class or category unknown. However mixin * classes are always ignored. */ public ClassInfo baseClass() { // Initialize int stsize = 0; // # of proper base candidates ClassInfo cir = null; // the base result int cat = category(); // category of this class // Check if the class has one of the acknowledged categories. If not // no bases classes will be reported. if (cat == Options.FEATURE || cat == Options.OBJECT || cat == Options.DATATYPE || cat == Options.MIXIN || cat == Options.UNION) { // Get hold of the available base classes TreeSet<ClassInfoEA> baseCIs = null; if (baseclassInfoSet != null) baseCIs = baseclassInfoSet; else if (baseclassInfo != null) { baseCIs = new TreeSet<ClassInfoEA>(); baseCIs.add(baseclassInfo); } // Loop over base classes and select the GML-relevant one if (baseCIs != null) { for (ClassInfoEA baseCI : baseCIs) { // Get base class category int bcat = baseCI.category(); // Needs to compatible and not a mixin. If not so, // we have an error if ((cat == bcat || bcat == Options.UNKNOWN) && bcat != Options.MIXIN) { // Compatible select and count stsize++; cir = baseCI; } else if (bcat != Options.MIXIN) { // Ignore, if we accept supertypes that are not mixins and we are a mixin if (cat == Options.MIXIN && matches("rule-xsd-cls-mixin-classes-non-mixin-supertypes")) { // do nothing and ignore } else if (this.model().isInSelectedSchemas(this)) { // Not compatible and not mixin: An error MessageContext mc = document.result.addError(null, 108, name()); if (mc != null) mc.addDetail(null, 400, "Package", pkg().fullName()); document.result.addDebug(null, 10003, name(), "" + cat, "!FALSE"); document.result.addDebug(null, 10003, name(), "" + bcat, "!TRUE"); } else { /* * 2015-07-17 JE: So this is a class that violates * multiple inheritance rules. However, it is * outside the selected schemas. We could log a * debug, info, or even warning message. However, we * should not raise an error because creation of a * complete GenericModel that also copies ISO * classes would raise an error which would cause a * unit test to fail. */ } } } } // Did we find more than one suitable base class? Which is // an error. if (stsize > 1) { if (this.model().isInSelectedSchemas(this)) { MessageContext mc = document.result.addError(null, 109, name()); if (mc != null) mc.addDetail(null, 400, "Package", pkg().fullName()); } else { /* * 2015-07-17 JE: So this is a class that violates multiple * inheritance rules. However, it is outside the selected * schemas. We could log a debug, info, or even warning * message. However, we should not raise an error because * creation of a complete GenericModel that also copies ISO * classes would raise an error which would cause a unit * test to fail. */ } } } // Return, what we found return cir; } // baseClass()
// Establish class derivation hierarchy. This auxiliary initializing // method sets the base class relation ship obtained from the model and // also enters this class as subclass of all its base classes. // Note that invocation of this method requires that all classes in // the model are already cached. // Note: ISO19107 makes use of realization instead of generalization in some // cases to inherit from interfaces. Therefore realization of interfaces is // also considered a base class relationship as a default unless overruled // by // a parameter. public void establishClassDerivationHierarchy() { // Find out about all connectors attached to the class // Only do this once; cache the results for subsequent use if (!connectorsAccessed) { conns = eaClassElement.GetConnectors(); connectorsAccessed = true; } // check that this class has connectors if (conns != null) { // Enumerate connectors selecting those where this class is the // client, // from these select "Generalization" and "Realisation". Retrieve // the // supplier class wrappers. For "Realisation" type suppliers also // make // sure the class is an interface. The classes found are registered // as // base classes. In the base classes register this class as // subclass. int nbcl = 0; int clientid, bclid, cat; String conntype; boolean gen, rea; for (Connector conn : conns) { // Skip all other connector types conntype = conn.GetType(); gen = conntype.equals("Generalization"); rea = conntype.equals("Realisation"); // this.realization is determined from configuration parameters // if it is not null then it is false if (this.realization != null && !this.realization.booleanValue()) rea = false; if (!gen && !rea) continue; // Make sure we are the client of this connector clientid = conn.GetClientID(); if (clientid != this.eaClassId) continue; // Find out about the id of the base class (=supplier) bclid = conn.GetSupplierID(); // From this determine the ClassInfo wrapper object ClassInfoEA baseCI = document.fClassById.get(String.valueOf(bclid)); // If such an object exists establish it as base class. if (baseCI != null) { // If we know this via a Realization we additionally check // we are seeing an interface. if (rea) { cat = baseCI.category(); if (cat != Options.MIXIN) continue; } // Establish as base class. Since most classes indeed // possess // at most one base class, this case will be treated // somewhat // storage-optimized. if (++nbcl == 1) { baseclassInfo = baseCI; } else { if (baseclassInfoSet == null) { baseclassInfoSet = new TreeSet<ClassInfoEA>(); baseclassInfoSet.add(baseclassInfo); baseclassInfo = null; } baseclassInfoSet.add(baseCI); } // Register with the subclasses of the base class. baseCI.subclassInfoSet.add(this); } } } } // establishClassDerivationHierarchy()