/** * 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()
/** * Find the operation identified by its name and the types of its parameters in this class or (if * not present there) recursively in its base classes. */ public OperationInfo operation(String name, String[] types) { // Make sure operations are loaded validateOperationsCache(); // Search in the class itself search_operation: for (OperationInfo oi : operationsCache.values()) { if (oi.name().equals(name)) { // Success if types shall not be compared if (types == null) return oi; // Check number of parameters if (types.length != oi.parameterCount()) continue; // Check type strings SortedMap<Integer, String> ptypes = oi.parameterTypes(); for (int i = 0; i < types.length; i++) { if (types[i].equals("*")) continue; if (!ptypes.get(i + 1).equals(types[i])) continue search_operation; } // All types found matching return oi; } } // Go and search in base classes TreeSet<ClassInfoEA> bcis = new TreeSet<ClassInfoEA>(); if (baseclassInfo != null) bcis.add(baseclassInfo); else if (baseclassInfoSet != null) bcis = baseclassInfoSet; for (ClassInfoEA bci : bcis) { OperationInfo oi = bci.operation(name, types); if (oi != null) return oi; } return null; }
/** @see de.interactive_instruments.ShapeChange.Model.ClassInfo#supertypes() */ public SortedSet<String> supertypes() { // Convert base class object set to base class id set. SortedSet<String> baseids = new TreeSet<String>(); if (baseclassInfo != null) baseids.add(baseclassInfo.id()); else if (baseclassInfoSet != null) for (ClassInfoEA bci : baseclassInfoSet) baseids.add(bci.id()); return baseids; } // supertypes()
/** @return set of ids of classes this class depends on */ protected TreeSet<String> supplierIds() { // Only retrieve/compute supplierIds once // Cache the results for subsequent use if (supplierIds == null) { // Prepare set to return supplierIds = new TreeSet<String>(); // Ask EA for the connectors attached to the package object and loop // over the connectors returned // Only compute them once for the whole class if (!connectorsAccessed) { conns = eaClassElement.GetConnectors(); connectorsAccessed = true; } // Ensure that there are connectors before continuing if (conns != null) { for (Connector conn : conns) { // Single out dependency connectors String type = conn.GetType(); if (type.equals("Dependency")) { // From the dependency grab the id of the supplier int suppId = conn.GetSupplierID(); String suppIdS = Integer.toString(suppId); // Since all connectors are delivered from both objects // at the // connector ends, we have to make sure it is not // accidently us, // which we found. if (suppId == eaClassId) continue; // Now, this is an element id, not a package id. So we // have to // identify the package, which owns the element // addressed. ClassInfoEA suppClass = (ClassInfoEA) document.fClassById.get(suppIdS); if (suppClass != null) { // From this only the id is required String suppPackId = suppClass.id(); if (suppPackId != null) supplierIds.add(suppPackId); } else { // package of supplier class has not been loaded, // dismiss the supplier } } } } } return supplierIds; } // supplierIds()
/** @see de.interactive_instruments.ShapeChange.Model.ClassInfo#property(java.lang.String) */ public PropertyInfo property(String name) { // Search in own properties validatePropertiesCache(); for (PropertyInfo pi : propertiesCache.values()) { if (pi.name().equals(name)) return pi; } // Go and search in base classes TreeSet<ClassInfoEA> bcis = new TreeSet<ClassInfoEA>(); if (baseclassInfo != null) bcis.add(baseclassInfo); else if (baseclassInfoSet != null) bcis = baseclassInfoSet; for (ClassInfoEA bci : bcis) { PropertyInfo pi = bci.property(name); if (pi != null) return pi; } return null; } // property()
/** * Return the documentation attached to the property object. This is fetched from tagged values * and - if this is absent - from the 'notes' specific to the EA objects model. */ @Override public String documentation() { // Retrieve/compute the documentation only once // Cache the result for subsequent use if (!documentationAccessed) { documentationAccessed = true; // Try default first String s = super.documentation(); // Try EA notes, if both tagged values fail and ea:notes is the source if ((s == null || s.length() == 0) && descriptorSource(Options.Descriptor.DOCUMENTATION.toString()).equals("ea:notes")) { s = eaClassElement.GetNotes(); // Fix for EA7.5 bug if (s != null) { s = EADocument.removeSpuriousEA75EntitiesFromStrings(s); super.documentation = options().internalize(s); } } // If result is empty, check if we can get the documentation from a // dependency if (s == null || s.isEmpty()) { for (Iterator<String> i = this.supplierIds().iterator(); i.hasNext(); ) { String cid = i.next(); ClassInfoEA cix = document.fClassById.get(cid); if (cix != null) { if (cix.name().equalsIgnoreCase(this.name()) && cix.stereotype("featureconcept")) { s = cix.documentation(); break; } } } } // If result is empty, check if we can get the documentation from a // supertype with the same name (added for ELF/INSPIRE) if (s == null || s.isEmpty()) { HashSet<ClassInfoEA> sts = supertypesAsClassInfoEA(); if (sts != null) { for (ClassInfoEA stci : sts) { if (stci.name().equals(this.name())) { s = stci.documentation(); break; } } } } // Assign what we got or "" ... super.documentation = options().internalize(s != null ? s : ""); } return super.documentation; } // documentation()
// Validate constraints cache. This makes sure the constraints cache // contains all constraints ordered by their appearance in the class. // If constraints are disabled the cache is empty. private void validateConstraintsCache() { if (constraintsCache == null) { // Allocate cache constraintsCache = new Vector<Constraint>(); // Constraints disabled? String check = document.options.parameter("checkingConstraints"); if (check != null && check.equalsIgnoreCase("disabled")) return; // Constraints for this class category irrelevant? if (!document.options.isClassTypeToCreateConstraintsFor(category())) return; // Constraints from selected schemas only? if (document.options.isLoadConstraintsForSelectedSchemasOnly() && !document.isInSelectedSchemas(this)) { return; } // Filter map for inheritance and overriding by name HashMap<String, Constraint> namefilter = new HashMap<String, Constraint>(); // Access EA constraints data Collection<org.sparx.Constraint> constrs = eaClassElement.GetConstraints(); // Determine constraint types to be parsed as OCL String oclTypes = document.options.parameter("oclConstraintTypeRegex"); // Determine constraint types to be parsed as FOL String folTypes = document.options.parameter("folConstraintTypeRegex"); // Enumerate all constraints found // Ensure that there are constraints before continuing if (constrs != null) { for (org.sparx.Constraint constr : constrs) { // Wrap into constraint object String type = constr.GetType(); Constraint oc; if (oclTypes.length() > 0 && type.matches(oclTypes)) { // 100422/re removed: && // !encodingRule("xsd").equals(Options.ISO19136_2007_INSPIRE) OclConstraintEA ocl = new OclConstraintEA(document, this, constr); if (ocl.syntaxTree() == null) // Text constraint is a fallback in case of parsing // issues oc = new TextConstraintEA(document, this, constr); else oc = ocl; } else if (folTypes != null && folTypes.length() > 0 && type.matches(folTypes)) { /* * only sets up the textual information; parsing is done * during model postprocessing - see * ModelImpl.postprocessFolConstraints() */ oc = new FolConstraintEA(document, this, constr); } else { oc = new TextConstraintEA(document, this, constr); } // Collect in cache constraintsCache.add(oc); // If the constraint has a name, add it to the filter which // blocks inheritance of constraints String conam = oc.name(); if (conam != null && conam.length() > 0) namefilter.put(conam, oc); } } /* * Fetch constraints from super-classes. Override by name. */ /* * JE: replaced this code with code (see below) that directly * accesses the supertype objects, instead of first getting all * their IDs and then looking the objects up in the model. */ // HashSet<String> stids = supertypes(); // if (stids != null) { // for (String stid : stids) { // ClassInfo stci = model().classById(stid); // Vector<Constraint> stcos = null; // if (stci != null) // stcos = stci.constraints(); // if (stcos != null) { // for (Constraint stco : stcos) { // String nam = stco == null ? null : stco.name(); // if(nam!=null && nam.length()>0 && namefilter.containsKey(nam)) // continue; // constraintsCache.add(stco); // } // } // } // } HashSet<ClassInfoEA> sts = supertypesAsClassInfoEA(); if (sts != null) { for (ClassInfoEA stci : sts) { Vector<Constraint> stcos = null; if (stci != null) stcos = stci.constraints(); if (stcos != null) { for (Constraint stco : stcos) { String nam = stco == null ? null : stco.name(); if (nam != null && nam.length() > 0 && namefilter.containsKey(nam)) continue; // Is the context of stco still the supertype, or // should it not be this (ClassInfoEA)? constraintsCache.add(stco); } } } } } }
/** Provide the ids of all subclasses of this class. */ public SortedSet<String> subtypes() { // Convert subclass object set to subclass id set. SortedSet<String> subids = new TreeSet<String>(); for (ClassInfoEA sci : subclassInfoSet) subids.add(sci.id()); return subids; } // subtypes()
/** * 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()