package org.modeldriven.fuml.repository.model; import java.util.List; import org.apache.commons.logging.Log; import org.apache.commons.logging.LogFactory; import org.modeldriven.fuml.assembly.AssemblyException; import org.modeldriven.fuml.environment.Environment; import org.modeldriven.fuml.io.ArtifactLoader; import org.modeldriven.fuml.repository.Element; import org.modeldriven.fuml.repository.Class_; import org.modeldriven.fuml.repository.Classifier; import org.modeldriven.fuml.repository.Repository; import org.modeldriven.fuml.repository.RepositoryArtifact; import org.modeldriven.fuml.repository.RepositorylException; import org.modeldriven.fuml.xmi.InvalidReferenceException; import UMLPrimitiveTypes.UnlimitedNatural; import fUML.Syntax.Classes.Kernel.Association; import fUML.Syntax.Classes.Kernel.EnumerationLiteral; import fUML.Syntax.Classes.Kernel.InstanceValue; import fUML.Syntax.Classes.Kernel.LiteralBoolean; import fUML.Syntax.Classes.Kernel.LiteralInteger; import fUML.Syntax.Classes.Kernel.LiteralNull; import fUML.Syntax.Classes.Kernel.LiteralString; import fUML.Syntax.Classes.Kernel.LiteralUnlimitedNatural; import fUML.Syntax.Classes.Kernel.ValueSpecification; public class Property extends NamedElement implements org.modeldriven.fuml.repository.Property{ private static Log log = LogFactory.getLog(Property.class); private fUML.Syntax.Classes.Kernel.Property property; public Property(fUML.Syntax.Classes.Kernel.Property property, RepositoryArtifact artifact) { super(property, artifact); this.property = property; } public Class_ getClass_() { return (Class_)Repository.INSTANCE.getElementById(this.property.class_.getXmiId()); } public ValueSpecification getDefaultValue() { return this.property.defaultValue; } public void setDefaultValue(ValueSpecification defaultValue) { this.property.defaultValue = defaultValue; } public org.modeldriven.fuml.repository.Property getOpposite() { if (this.property.opposite != null) { org.modeldriven.fuml.repository.Property result = (org.modeldriven.fuml.repository.Property)Repository.INSTANCE.getElementById(this.property.opposite.getXmiId()); return result; } if (property.owningAssociation == null) { fUML.Syntax.Classes.Kernel.Property otherEnd = getOtherEnd(this); if (otherEnd != null && otherEnd.owningAssociation == null) { this.property.opposite = otherEnd; org.modeldriven.fuml.repository.Property result = (org.modeldriven.fuml.repository.Property)Repository.INSTANCE.getElementById(this.property.opposite.getXmiId()); return result; } } return null; } public fUML.Syntax.Classes.Kernel.Property getDelegate() { return this.property; } public Classifier getType() { return this.findType(false); } public Classifier findType() { return this.findType(true); } private Classifier findType(boolean supressErrors) { Classifier result = null; if (this.property.typedElement != null && this.property.typedElement.type != null) { String typeXmiId = this.property.typedElement.type.getXmiId(); if (typeXmiId != null) { Element elementResult = Repository.INSTANCE.getElementById(typeXmiId); try { result = (Classifier)elementResult; } catch (ClassCastException e) { throw new RuntimeException(e); } //if (Classifier.class.isAssignableFrom(Element.class)) // result = Classifier.class.cast(elementResult); //else // throw new IllegalStateException(Classifier.class.getName() // + " cannot be assigned from " + Element.class.getName()); if (result == null && !supressErrors) throw new InvalidReferenceException(typeXmiId); } } if (result == null && !supressErrors) throw new RepositorylException("no type found for property, " + this.property.class_.name + "." + this.property.name); return result; } public boolean isDataType() { return getType().isDataType(); } public Association getAssociation() { return this.property.association; } public void setAssociation(Association assoc) { this.property.association = assoc; } public boolean isDerived() { return this.property.isDerived; } public boolean isRequired() { return this.getLowerValue() > 0; } public boolean isSingular() { return "1".equals(this.getUpperValue()); } public String getPropertyDefault() { return getPropertyDefaultValue(false); } public String findPropertyDefault() { return getPropertyDefaultValue(true); } public boolean hasPropertyDefaultValue() { String value = getPropertyDefaultValue(true); return value != null && value.trim().length() > 0; } private String getPropertyDefaultValue(boolean supressErrors) { ValueSpecification valueSpec = findDefaultValueSpecification(); if (valueSpec != null) return getValue(valueSpec); else return null; } private ValueSpecification findDefaultValueSpecification() { return property.defaultValue; } public String getUpperValue() { return getValue(this.property.multiplicityElement.upperValue); } public int getLowerValue() { String value = getValue(this.property.multiplicityElement.lowerValue); if (value == null || "null".equalsIgnoreCase(value)) value = "0"; return Integer.valueOf(value); } private String getValue(ValueSpecification valueSpec) { if (LiteralString.class.isAssignableFrom(valueSpec.getClass())) { return ((LiteralString)valueSpec).value; } else if (LiteralInteger.class.isAssignableFrom(valueSpec.getClass())) { return String.valueOf(((LiteralInteger)valueSpec).value); // use specifically typed value in subclass } else if (LiteralBoolean.class.isAssignableFrom(valueSpec.getClass())) { return String.valueOf(((LiteralBoolean)valueSpec).value); // use specifically typed value in subclass } else if (LiteralNull.class.isAssignableFrom(valueSpec.getClass())) { return null; } else if (LiteralUnlimitedNatural.class.isAssignableFrom(valueSpec.getClass())) { return String.valueOf(((LiteralUnlimitedNatural)valueSpec).value.naturalValue); } else if (InstanceValue.class.isAssignableFrom(valueSpec.getClass())) { InstanceValue instanceValue = (InstanceValue)valueSpec; if (EnumerationLiteral.class.isAssignableFrom(instanceValue.instance.getClass())) { EnumerationLiteral enumerationLiteral = (EnumerationLiteral)instanceValue.instance; return enumerationLiteral.name; } else throw new RepositorylException("unknown instance type, " + instanceValue.instance.getClass().getName()); } else { // return ((OpaqueExpression)valueSpec).getBody(); throw new IllegalArgumentException("expected literal or instance value"); } } private void setValue(ValueSpecification valueSpec, String value) { if (LiteralString.class.isAssignableFrom(valueSpec.getClass())) ((LiteralString)valueSpec).value = value; else if (LiteralInteger.class.isAssignableFrom(valueSpec.getClass())) ((LiteralInteger)valueSpec).value = Integer.parseInt(value); else if (LiteralBoolean.class.isAssignableFrom(valueSpec.getClass())) ((LiteralBoolean)valueSpec).value = Boolean.parseBoolean(value); //else if (LiteralNull.class.isAssignableFrom(valueSpec.getClass())) else if (LiteralUnlimitedNatural.class.isAssignableFrom(valueSpec.getClass())) { UnlimitedNatural un = new UnlimitedNatural(); un.naturalValue = Integer.parseInt(value); ((LiteralUnlimitedNatural)valueSpec).value = un; } else if (InstanceValue.class.isAssignableFrom(valueSpec.getClass())) { valueSpec.setName(value); } else { // ((OpaqueExpression)valueSpec).setBody(value); throw new IllegalArgumentException("expected literal or instance value"); } } private static fUML.Syntax.Classes.Kernel.Property getOtherEnd(org.modeldriven.fuml.repository.Property property) { Association association = property.getAssociation(); if (association != null) { List<?> memberEnds = association.memberEnd; if (memberEnds.size() == 2) { int index = memberEnds.indexOf(property.getDelegate()); if (index != -1) { return (fUML.Syntax.Classes.Kernel.Property) memberEnds.get(Math.abs(index - 1)); } } else if (log.isDebugEnabled()) log.debug("expected exactly 2 (not " + memberEnds.size() + ") member-end elements for association (" + association.getXmiId() + ") linking property " + property.getClass_().getQualifiedName() + "." + property.getName() + " - ignoring any association owned-end property as not applicable as property opposite"); // Note where one end (Property) of an association is linked to a read-only class, tools (MagicDraw) // will necessarily create an association owned-end as it cannot modify the target read-only class. This // can be the case when imported read-only modules are used. } return null; } } // Property