mim.meta initial commit.

This commit is contained in:
bitwave 2013-05-25 16:18:29 +02:00
parent 1a965a4d2f
commit 8fa4d79ad7
47 changed files with 2477 additions and 0 deletions

4
ch.bitwave.mim.meta/.gitignore vendored Normal file
View File

@ -0,0 +1,4 @@
/.classpath
/.project
/target
/.settings

View File

@ -0,0 +1,16 @@
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<parent>
<groupId>ch.bitwave</groupId>
<artifactId>maven.platform.parent</artifactId>
<version>1.0.0</version>
</parent>
<artifactId>mim.meta</artifactId>
<version>0.0.1-SNAPSHOT</version>
<name>mentor meta model</name>
<description>contains the meta model of the mentor</description>
</project>

View File

@ -0,0 +1,155 @@
package ch.bitwave.mim.m2.core;
import java.util.ArrayList;
import java.util.List;
/**
* <p>
* An association describes a set of tuples whose values refer to typed
* instances. An instance of an association is called a link. A link is a tuple
* with one value for each end of the association, where each value is an
* instance of the type of the end.
* </p>
*
* <p>
* An association specifies a semantic relationship that can occur between typed
* instances. It has at least two ends represented by properties, each of which
* is connected to the type of the end. More than one end of an association may
* have the same type.
* </p>
* <p>
* An end property of an association that is owned by an end class or that is a
* navigable owned end of the association indicates that the association is
* navigable from the opposite ends, otherwise the association is not navigable
* from the opposite ends.
* </p>
*/
public class Association extends Classifier implements Relationship {
private List<Property> ownedEnds;
private List<Property> memberEnds;
public Association() {
this.ownedEnds = new ArrayList<Property>();
this.memberEnds = new ArrayList<Property>();
}
public Namespace getOwningNamespace() {
return getOwnerAs(Namespace.class);
}
public void setOwningNamespace(final Namespace owningNamespace) {
this.setOwner(owningNamespace);
}
/**
* The ends that are owned by the association itself. This is an ordered
* association. Subsets {@link Association#getMemberEnds()},
* {@link Classifier#getFeatures()} and {@link Namespace#getOwnedMembers()}.
*
* @return
*/
public List<Property> getOwnedEnds() {
return this.ownedEnds;
}
/**
* Each end represents participation of instances of the classifier
* connected to the end in links of the association. This is an ordered
* association and a subset of {@link #getMembers()}.
*
* @return
*/
public List<Property> getMemberEnds() {
return this.memberEnds;
}
/**
* References the classifiers that are used as types of the ends of the
* association.
*
* @return
*/
public List<MimType> getEndTypes() {
List<MimType> result = new ArrayList<MimType>();
for (Property element : getMemberEnds()) {
result.add(element.getType());
}
return result;
}
@Override
public List<MimElement> getRelatedElements() {
ArrayList<MimElement> result = new ArrayList<MimElement>(this.ownedEnds);
result.addAll(this.memberEnds);
return result;
}
/**
* The navigable ends that are owned by the association itself. Subsets
* {@link #getOwnedEnds()}.
*
* @return
*/
public List<Property> getNavigableOwnedEnds() {
// TODO: filter by navigability.
return this.ownedEnds;
}
@Override
protected void contributeFeatures(final List<Feature> list) {
super.contributeFeatures(list);
list.addAll(this.ownedEnds);
}
@Override
protected void contributeOwnedMembers(final List<NamedElement> list) {
list.addAll(this.ownedEnds);
}
@Override
public void addOwnedMember(final NamedElement member) {
Property prop = assertProperty(member);
prop.setOwner(this);
prop.setRelationship(this);
this.memberEnds.add(prop);
this.ownedEnds.add(prop);
}
@Override
public void removeOwnedMember(final NamedElement member) {
Property prop = assertProperty(member);
if (prop.getOwner() == this) {
prop.setOwner(null);
}
if (prop.getRelationship() == this) {
prop.setRelationship(null);
}
this.memberEnds.remove(prop);
this.ownedEnds.remove(prop);
}
protected Property assertProperty(final NamedElement member) {
if (!(member instanceof Property)) {
throw new RuntimeException(
String.format(
"An association can only own elements of type Property, but the given element is of type %s.",
member.getClass().getSimpleName()));
}
Property prop = (Property) member;
return prop;
}
public void addMember(final NamedElement member) {
if (!(member instanceof Property)) {
throw new RuntimeException(
String.format(
"An association can only have members of type Property, but the given element is of type %s.",
member.getClass().getSimpleName()));
}
Property prop = (Property) member;
prop.setRelationship(this);
this.memberEnds.add(prop);
}
}

View File

@ -0,0 +1,275 @@
package ch.bitwave.mim.m2.core;
import java.util.ArrayList;
import java.util.List;
import java.util.regex.Matcher;
import javax.annotation.Nonnull;
/**
* A classifier is a classification of instances it describes a set of
* instances that have features in common.
*/
public abstract class Classifier extends Namespace {
private List<GeneralizationEnd> generals;
private List<GeneralizationEnd> specifics;
private boolean abstractClassifier;
private List<Feature> nonOwnedFeatures;
public Classifier() {
super();
this.nonOwnedFeatures = new ArrayList<Feature>();
this.generals = new ArrayList<GeneralizationEnd>();
this.specifics = new ArrayList<GeneralizationEnd>();
}
public boolean isAbstract() {
return this.abstractClassifier;
}
public void setAbstract(final boolean value) {
this.abstractClassifier = value;
}
public void addGeneral(final GeneralizationEnd genEnd) {
this.generals.add(genEnd);
}
public void removeGeneral(final GeneralizationEnd genEnd) {
this.generals.remove(genEnd);
}
public void addSpecific(final GeneralizationEnd genEnd) {
this.specifics.add(genEnd);
}
public void removeSpecific(final GeneralizationEnd genEnd) {
this.specifics.remove(genEnd);
}
/**
* Returns the list of features directly introduced by this classifier.
*
* @return the list of features.
*/
public List<Feature> getFeatures() {
List<Feature> result = new ArrayList<Feature>();
contributeFeatures(result);
return result;
}
protected void contributeFeatures(final List<Feature> list) {
list.addAll(this.nonOwnedFeatures);
}
/**
* The query allFeatures() gives all of the features in the namespace of the
* classifier. In general, through mechanisms such as inheritance, this will
* be a larger set than feature.
*
* @return the complete list of features attributed to this classifier.
*/
public List<Feature> getAllFeatures() {
List<Feature> result = getFeatures();
for (Classifier parent : getAllParents()) {
parent.contributeFeatures(result);
}
return result;
}
public List<Generalization> getGeneralizations() {
List<Generalization> result = new ArrayList<Generalization>();
for (GeneralizationEnd general : this.generals) {
result.add(general.getGeneralization());
}
return result;
}
public List<Generalization> getSpecializations() {
List<Generalization> result = new ArrayList<Generalization>();
for (GeneralizationEnd general : this.specifics) {
result.add(general.getGeneralization());
}
return result;
}
/**
* Specifies the more general classifiers in the generalization hierarchy
* for this Classifier.
*
* @return the list of generals.
*/
public List<Classifier> getGenerals() {
List<Classifier> result = new ArrayList<Classifier>();
for (GeneralizationEnd genend : this.generals) {
result.add(genend.getGeneralization().getGeneral());
}
return result;
}
/**
* Specifies the more general classifiers in the generalization hierarchy
* for this Classifier.
*
* @return the list of generals.
*/
public List<Classifier> getSpecifics() {
List<Classifier> result = new ArrayList<Classifier>();
for (GeneralizationEnd genend : this.specifics) {
result.add(genend.getGeneralization().getSpecific());
}
return result;
}
/**
* Returns all of the immediate ancestors of this Classifier. Synonymous for
* {@link #getGenerals()}.
*
* @return the list of direct parents.
*/
public List<Classifier> getParents() {
return getGenerals();
}
/**
* Returns all of the direct and indirect ancestors of this Classifier.
*
* @return the list of all parents, including indirect ones.
*/
public List<Classifier> getAllParents() {
List<Classifier> result = new ArrayList<Classifier>();
this.contributeParents(result);
return result;
}
protected void contributeParents(final List<Classifier> list) {
list.add(this);
for (Classifier parent : getParents()) {
parent.contributeParents(list);
}
}
@Override
protected void contributeOwnedElements(final List<MimElement> result) {
super.contributeOwnedElements(result);
result.addAll(getFeatures());
}
/**
* Specifies all elements inherited by this classifier from the general
* classifiers. Subsets the namespace members.
*
* @return
*/
public List<NamedElement> getInheritedMembers() {
List<NamedElement> result = new ArrayList<NamedElement>();
List<Classifier> generals = getGenerals();
for (Classifier general : generals) {
result.addAll(general.getAllFeatures());
}
return result;
}
public boolean isStereotype(final Stereotype stereotype) {
List<Property> properties = getOwnedMembersOfType(Property.class);
for (Property property : properties) {
Relationship rel = property.getRelationship();
if (rel instanceof Extension) {
Extension ext = (Extension) rel;
if (stereotype == ext.getMetaClass()) {
return true;
}
}
}
return false;
}
@SuppressWarnings("unchecked")
public <T> List<T> getFeaturesOfType(final java.lang.Class<T> featureType) {
List<T> result = new ArrayList<T>();
for (Feature feature : getFeatures()) {
if (featureType.isAssignableFrom(feature.getClass())) {
result.add((T) feature);
}
}
return result;
}
public void addNonOwnedFeature(@Nonnull final Feature feature) {
this.nonOwnedFeatures.add(feature);
}
/**
* Checks whether this classifier is a specialization of the given
* classifier.
*
* @param general
* the classifier to test as a general of this classifier.
* @return true if general is an ancestor of this classifier.
*/
public boolean isSpecializationOf(final Classifier general) {
for (GeneralizationEnd genend : this.generals) {
if (genend.getGeneralization().getGeneral() == general) {
return true;
}
}
return false;
}
/**
* Checks whether this classifier is a generalization of the given
* classifier.
*
* @param specific
* the classifier to test as a specific of this classifier.
* @return true if general derives from this classifier.
*/
public boolean isGeneralizationOf(final Classifier specific) {
for (GeneralizationEnd genend : this.specifics) {
if (genend.getGeneralization().getSpecific() == specific) {
return true;
}
}
return false;
}
/**
* Tells whether this classifier has a feature (including inherited
* features) whose (unqualified) name matches the given matcher.
*
* @param matcher
* the matcher to judge the names by.
* @return true if the classifier has a matching feature.
*/
public boolean hasFeatureMatching(@Nonnull final Matcher matcher) {
for (Feature feature : getAllFeatures()) {
String name = feature.getName();
if (name != null) {
matcher.reset(name);
if (matcher.matches())
return true;
}
}
return false;
}
/**
* Tells whether this classifier introduces a feature whose (unqualified)
* name matches the given matcher.
*
* @param matcher
* the matcher to judge the names by.
* @return true if the classifier introduces a matching feature.
*/
public boolean introducesFeatureMatching(@Nonnull final Matcher matcher) {
for (Feature feature : getFeatures()) {
String name = feature.getName();
if (name != null) {
matcher.reset(name);
if (matcher.matches())
return true;
}
}
return false;
}
}

View File

@ -0,0 +1,22 @@
package ch.bitwave.mim.m2.core;
public class Comment extends MimElement {
private String body;
public String getBody() {
return this.body;
}
public void setBody(final String body) {
this.body = body;
}
public MimElement getAnnotatedElement() {
return getOwner();
}
public void setAnnotatedElement(final MimElement annotatedElement) {
this.setOwner(annotatedElement);
}
}

View File

@ -0,0 +1,9 @@
package ch.bitwave.mim.m2.core;
/**
* DataType is an abstract class that acts as a common superclass for different
* kinds of data types.
*/
public interface DataType extends MimType {
}

View File

@ -0,0 +1,33 @@
package ch.bitwave.mim.m2.core;
import java.util.HashSet;
import java.util.Set;
public class Dependencies implements Dependent {
private Set<String> identifierDependencies;
public Dependencies() {
this.identifierDependencies = new HashSet<String>();
}
@Override
public boolean depdendsOnIdentifier(final String name) {
if (this.identifierDependencies == null) {
return false;
}
return this.identifierDependencies.contains(name);
}
@Override
public void addIdentifierDependency(final String name) {
if (this.identifierDependencies == null) {
this.identifierDependencies = new HashSet<String>();
}
this.identifierDependencies.add(name);
}
public Set<String> getIdentifierDependencies() {
return this.identifierDependencies;
}
}

View File

@ -0,0 +1,13 @@
package ch.bitwave.mim.m2.core;
/**
* Interface to an element which is depending on some other elements. Provides a
* list of elements the element depends on and a means of extending the list.
*/
public interface Dependent {
boolean depdendsOnIdentifier(final String name);
void addIdentifierDependency(final String name);
}

View File

@ -0,0 +1,15 @@
package ch.bitwave.mim.m2.core;
import java.util.List;
/**
* A directed relationship references one or more source elements and one or
* more target elements. DirectedRelationship is an abstract metaclass.
*/
public interface DirectedRelationship extends Relationship {
List<MimElement> getSourceElements();
List<MimElement> getTargetElements();
}

View File

@ -0,0 +1,54 @@
package ch.bitwave.mim.m2.core;
import java.util.ArrayList;
import java.util.List;
/**
* <p>
* An enumeration defines a set of literals that can be used as its values.
* </p>
*
* <p>
* An enumeration defines a finite ordered set of values, such as {red, green,
* blue}. The values denoted by typed elements whose type is an enumeration must
* be taken from this set.
* </p>
*/
public class Enumeration extends NamedElement implements DataType {
private Namespace owner;
private List<EnumerationLiteral> ownedLiterals;
public Enumeration() {
this.ownedLiterals = new ArrayList<EnumerationLiteral>();
}
public List<EnumerationLiteral> getOwnedLiterals() {
return this.ownedLiterals;
}
public void setOwner(final Namespace owner) {
this.owner = owner;
}
@Override
public boolean conformsTo(final MimType other) {
return false;
}
@Override
public MimElement getOwner() {
return this.owner;
}
@Override
public MimPackage getPackage() {
return getOwnerAs(MimPackage.class);
}
@Override
public void setPackage(final MimPackage owner) {
this.setOwner(owner);
}
}

View File

@ -0,0 +1,23 @@
package ch.bitwave.mim.m2.core;
/**
* An enumeration literal is a value of an enumeration.
*/
public class EnumerationLiteral extends NamedElement {
private Enumeration enumeration;
public Enumeration getEnumeration() {
return this.enumeration;
}
public void setEnumeration(final Enumeration enumeration) {
this.enumeration = enumeration;
}
@Override
public MimElement getOwner() {
return this.enumeration;
}
}

View File

@ -0,0 +1,21 @@
package ch.bitwave.mim.m2.core;
import org.apache.commons.lang.StringUtils;
/**
* A naming strategy which compares names exactly.
*/
public class ExactNamingStrategy implements NamingStrategy {
private static final ExactNamingStrategy INSTANCE = new ExactNamingStrategy();
@Override
public boolean isSameName(final String firstName, final String secondName) {
return StringUtils.equals(firstName, secondName);
}
public static NamingStrategy getInstance() {
return INSTANCE;
}
}

View File

@ -0,0 +1,33 @@
package ch.bitwave.mim.m2.core;
/**
* <p>
* An extension is used to indicate that the properties of a metaclass are
* extended through a stereotype, and gives the ability to flexibly add (and
* later remove) stereotypes to classes.
* </p>
*
* <p>
* Extension is a kind of Association. One end of the Extension is an ordinary
* Property and the other end is an ExtensionEnd. The former ties the Extension
* to a Class, while the latter ties the Extension to a Stereotype that extends
* the Class.
* </p>
*/
public class Extension extends Association {
public MimClass getMetaClass() {
return (MimClass) getFirstNonOwnedEnd().getType();
}
private Property getFirstNonOwnedEnd() {
for (Property prop : getMemberEnds()) {
if (!prop.isOwnedBy(this)) {
return prop;
}
}
throw new MetaModelRuntimeException(String.format(
"%s does not contain a non-owned member end.", getName()));
}
}

View File

@ -0,0 +1,14 @@
package ch.bitwave.mim.m2.core;
public class ExtensionEnd extends Property {
@Override
public Stereotype getType() {
return (Stereotype) super.getType();
}
public void setType(final Stereotype type) {
super.setType(type);
}
}

View File

@ -0,0 +1,18 @@
package ch.bitwave.mim.m2.core;
/**
* A feature declares a behavioral or structural characteristic of instances of
* classifiers.
*/
public abstract class Feature extends NamedElement {
private Classifier featuringClassifier;
public Classifier getFeaturingClassifier() {
return this.featuringClassifier;
}
public void setFeaturingClassifier(final Classifier featuringClassifier) {
this.featuringClassifier = featuringClassifier;
}
}

View File

@ -0,0 +1,97 @@
package ch.bitwave.mim.m2.core;
import java.util.ArrayList;
import java.util.List;
/**
* <p>
* A generalization is a taxonomic relationship between a more general
* classifier and a more specific classifier. Each instance of the specific
* classifier is also an instance of the general classifier. Thus, the specific
* classifier indirectly has features of the more general classifier.
* </p>
*
* <p>
* A generalization relates a specific classifier to a more general classifier,
* and is owned by the specific classifier.
* </p>
*/
public class Generalization extends MimElement implements DirectedRelationship {
private GeneralizationEnd generalEnd;
private GeneralizationEnd specificEnd;
public Classifier getSpecific() {
return this.specificEnd.getClassifier();
}
public void setSpecific(final Classifier specific) {
if (this.specificEnd == null) {
this.specificEnd = new GeneralizationEnd();
this.specificEnd.setGeneralization(this);
}
if (this.specificEnd.getClassifier() != null) {
this.specificEnd.getClassifier().removeGeneral(this.specificEnd);
}
this.specificEnd.setClassifier(specific);
specific.addGeneral(this.specificEnd);
}
public Classifier getGeneral() {
return this.generalEnd.getClassifier();
}
public void setGeneral(final Classifier general) {
if (this.generalEnd == null) {
this.generalEnd = new GeneralizationEnd();
this.generalEnd.setGeneralization(this);
}
if (this.generalEnd.getClassifier() != null) {
this.generalEnd.getClassifier().removeSpecific(this.generalEnd);
}
this.generalEnd.setClassifier(general);
general.addSpecific(this.generalEnd);
}
public GeneralizationEnd getGeneralEnd() {
return this.generalEnd;
}
public void setGeneralEnd(final GeneralizationEnd generalEnd) {
this.generalEnd = generalEnd;
}
public GeneralizationEnd getSpecificEnd() {
return this.specificEnd;
}
public void setSpecificEnd(final GeneralizationEnd specificEnd) {
this.specificEnd = specificEnd;
}
@Override
public List<MimElement> getRelatedElements() {
List<MimElement> result = new ArrayList<MimElement>();
result.add(getSpecific());
result.add(getGeneral());
return result;
}
@Override
public List<MimElement> getSourceElements() {
List<MimElement> result = new ArrayList<MimElement>();
result.add(getSpecific());
return result;
}
@Override
public List<MimElement> getTargetElements() {
List<MimElement> result = new ArrayList<MimElement>();
result.add(getGeneral());
return result;
}
@Override
public String toString() {
return "Generalization";
}
}

View File

@ -0,0 +1,31 @@
package ch.bitwave.mim.m2.core;
public class GeneralizationEnd extends MimElement {
private Classifier classifier;
private Generalization generalization;
public void setGeneralization(final Generalization generalization) {
this.generalization = generalization;
}
public Classifier getClassifier() {
return this.classifier;
}
public void setClassifier(final Classifier classifier) {
this.classifier = classifier;
}
public Generalization getGeneralization() {
return this.generalization;
}
@Override
public String toString() {
StringBuilder builder = new StringBuilder();
builder.append("GeneralizationEnd [classifier=").append(this.classifier).append("]");
return builder.toString();
}
}

View File

@ -0,0 +1,11 @@
package ch.bitwave.mim.m2.core;
public class MetaModelException extends Exception {
private static final long serialVersionUID = 1L;
public MetaModelException(final String message) {
super(message);
}
}

View File

@ -0,0 +1,23 @@
package ch.bitwave.mim.m2.core;
public class MetaModelRuntimeException extends RuntimeException {
private static final long serialVersionUID = 1L;
public MetaModelRuntimeException() {
super();
}
public MetaModelRuntimeException(final String message, final Throwable cause) {
super(message, cause);
}
public MetaModelRuntimeException(final String message) {
super(message);
}
public MetaModelRuntimeException(final Throwable cause) {
super(cause);
}
}

View File

@ -0,0 +1,195 @@
package ch.bitwave.mim.m2.core;
import java.util.ArrayList;
import java.util.HashSet;
import java.util.List;
import java.util.Set;
/**
* <p>
* A class is a type that has objects as its instances.
* </p>
*
* <p>
* Classes have attributes and operations and participate in inheritance
* hierarchies. Multiple inheritance is allowed. The instances of a class are
* objects. When a class is abstract it cannot have any direct instances. Any
* direct instance of a concrete (i.e., non-abstract) class is also an indirect
* instance of its class's superclasses. An object has a slot for each of its
* class's direct and inherited attributes. An object permits the invocation of
* operations defined in its class and its class's superclasses. The context of
* such an invocation is the invoked object.
* </p>
*
* <p>
* A class cannot access private features of another class, or protected
* features on another class that is not its supertype. When creating and
* deleting associations, at least one end must allow access to the class.
* </p>
*
* <p>
* The purpose of a class is to specify a classification of objects and to
* specify the features that characterize the structure and behavior of those
* objects.
* </p>
* <p>
* Objects of a class must contain values for each attribute that is a member of
* that class, in accordance with the characteristics of the attribute, for
* example its type and multiplicity. When an object is instantiated in a class,
* for every attribute of the class that has a specified default, if an initial
* value of the attribute is not specified explicitly for the instantiation,
* then the default value specification is evaluated to set the initial value of
* the attribute for the object.
* </p>
* <p>
* Operations of a class can be invoked on an object, given a particular set of
* substitutions for the parameters of the operation. An operation invocation
* may cause changes to the values of the attributes of that object. It may also
* return a value as a result, where a result type for the operation has been
* defined. Operation invocations may also cause changes in value to the
* attributes of other objects that can be navigated to, directly or indirectly,
* from the object on which the operation is invoked, to its output parameters,
* to objects navigable from its parameters, or to other objects in the scope of
* the operations execution. Operation invocations may also cause the creation
* and deletion of objects.
* </p>
*/
public class MimClass extends Classifier implements MimType, Dependent {
private List<Property> ownedAttributes;
private List<Operation> ownedOperations;
private boolean abstractFlag;
private Dependencies dependencies;
public MimClass() {
this.ownedAttributes = new ArrayList<Property>();
this.ownedOperations = new ArrayList<Operation>();
}
@Override
public boolean isAbstract() {
return this.abstractFlag;
}
@Override
public void setAbstract(final boolean value) {
this.abstractFlag = value;
}
public MimPackage getOwningPackage() {
return getOwnerAs(MimPackage.class);
}
public void setOwningPackage(final MimPackage owningPackage) {
this.setOwner(owningPackage);
}
public List<Property> getOwnedAttributes() {
return this.ownedAttributes;
}
public List<Operation> getOwnedOperations() {
return this.ownedOperations;
}
@Override
public boolean conformsTo(final MimType other) {
return false;
}
public List<MimClass> getSuperClasses() {
List<MimClass> result = new ArrayList<MimClass>();
List<Classifier> generals = getGenerals();
for (Classifier general : generals) {
if (general instanceof MimClass) {
result.add((MimClass) general);
}
}
return result;
}
@Override
protected void contributeFeatures(final List<Feature> list) {
super.contributeFeatures(list);
list.addAll(this.ownedAttributes);
list.addAll(this.ownedOperations);
}
@Override
protected void contributeOwnedMembers(final List<NamedElement> list) {
list.addAll(this.ownedAttributes);
list.addAll(this.ownedOperations);
}
@Override
public MimPackage getPackage() {
return getOwningPackage();
}
@Override
public void setPackage(final MimPackage owner) {
this.setOwner(owner);
}
@Override
public void addOwnedMember(final NamedElement member) {
if (member instanceof Property) {
this.ownedAttributes.add((Property) member);
} else if (member instanceof Operation) {
this.ownedOperations.add((Operation) member);
} else {
throw new RuntimeException(
String.format(
"A class can only own elements of type Property or Operation, but the given element is of type %s.",
member.getClass().getSimpleName()));
}
}
@Override
public void removeOwnedMember(final NamedElement member) {
this.ownedAttributes.remove(member);
this.ownedOperations.remove(member);
}
/**
* Adds the given stereotype as a new stereotype of this class.
*
* @param stereotype
* the stereotype to add.
*/
public void addStereotype(final Stereotype stereotype) {
Extension ext = new Extension();
ExtensionEnd ee = new ExtensionEnd();
ee.setType(stereotype);
Property prop = new Property();
prop.setType(this);
ext.addMember(ee);
ext.addOwnedMember(prop);
addOwnedMember(prop);
stereotype.addNonOwnedFeature(ee);
getOwnerAs(Namespace.class).addOwnedMember(ext);
}
@Override
public boolean depdendsOnIdentifier(final String name) {
if (this.dependencies == null) {
return false;
}
return this.dependencies.depdendsOnIdentifier(name);
}
@Override
public void addIdentifierDependency(final String name) {
if (this.dependencies == null) {
this.dependencies = new Dependencies();
}
this.dependencies.addIdentifierDependency(name);
}
public Set<String> getIdentifierDependencies() {
if (this.dependencies == null) {
return new HashSet<String>();
}
return this.dependencies.getIdentifierDependencies();
}
}

View File

@ -0,0 +1,51 @@
package ch.bitwave.mim.m2.core;
import java.util.ArrayList;
import java.util.List;
/**
* Element is an abstract metaclass with no superclass. It is used as the common
* superclass for all metaclasses in the infrastructure library. Element has a
* derived composition association to itself to support the general capability
* for elements to own other elements.
*/
public abstract class MimElement {
private List<Comment> ownedComments;
private MimElement owner;
public MimElement getOwner() {
return this.owner;
}
public void setOwner(final MimElement owner) {
this.owner = owner;
}
@SuppressWarnings("unchecked")
public <T> T getOwnerAs(final java.lang.Class<T> elementType) {
if (this.owner == null)
return null;
if (!elementType.isAssignableFrom(this.owner.getClass())) {
throw new RuntimeException(String.format(
"The owner of %s is not of the desired type \"%s\".", toString(), elementType
.getClass().getSimpleName()));
}
return (T) this.owner;
}
public final List<MimElement> getOwnedElements() {
List<MimElement> result = new ArrayList<MimElement>();
contributeOwnedElements(result);
return result;
}
protected void contributeOwnedElements(final List<MimElement> result) {
result.addAll(this.ownedComments);
}
public boolean isStub() {
return false;
}
}

View File

@ -0,0 +1,192 @@
package ch.bitwave.mim.m2.core;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.LinkedHashSet;
import java.util.List;
import java.util.Map;
import java.util.Set;
import java.util.logging.Logger;
import javax.annotation.CheckForNull;
/**
* Packages provide a way of grouping types and packages together, which can be
* useful for understanding and managing a model. A package cannot contain
* itself.
*/
public class MimPackage extends Namespace {
private static final Logger LOGGER = Logger.getLogger(MimPackage.class.getName());
private List<NamedElement> ownedTypes;
public MimPackage() {
this.ownedTypes = new ArrayList<NamedElement>();
}
public List<MimType> getOwnedTypes() {
List<MimType> result = new ArrayList<MimType>();
for (NamedElement element : getOwnedMembers()) {
if (element instanceof MimType) {
result.add((MimType) element);
}
}
return result;
}
public List<MimType> getOwnedStereotypes() {
List<MimType> result = new ArrayList<MimType>();
for (NamedElement element : getOwnedMembers()) {
if (element instanceof Stereotype) {
result.add((Stereotype) element);
}
}
return result;
}
public List<MimPackage> getNestedPackages() {
List<MimPackage> result = new ArrayList<MimPackage>();
for (NamedElement element : getOwnedMembers()) {
if (element instanceof MimPackage) {
result.add((MimPackage) element);
}
}
return result;
}
public MimPackage getNestingPackage() {
return getOwnerAs(MimPackage.class);
}
@Override
protected void contributeOwnedMembers(final List<NamedElement> list) {
list.addAll(this.ownedTypes);
}
@Override
protected void contributeOwnedElements(final List<MimElement> result) {
result.addAll(this.ownedTypes);
}
@Override
protected void contributeAllMembers(final List<NamedElement> list) {
super.contributeAllMembers(list);
for (MimPackage nested : getNestedPackages()) {
nested.contributeAllMembers(list);
}
}
@Override
public void addOwnedMember(final NamedElement member) {
this.ownedTypes.add(member);
member.setOwner(this);
}
@Override
public void removeOwnedMember(final NamedElement member) {
this.ownedTypes.remove(member);
if (member.getOwner() == this) {
member.setOwner(null);
}
}
/**
* Adds a package import for the given package name, which makes the names
* of that package available within this package.
*
* @param name
*/
public void addPackageImportStub(final String name) {
PackageImport imp = new PackageImport();
imp.setImportingNamespace(this);
StubPackage target = new StubPackage(imp);
target.setName(name);
imp.setImportedPackage(target);
addPackageImport(imp);
target.addImportingPackage(imp);
}
/**
* Locates any package nested in this package by name.
*
* @param name
* the package name.
* @return a reference to the package with this name, or null.
*/
@CheckForNull
public MimPackage findContainedPackage(final String name) {
if (name.equalsIgnoreCase(getName())) {
return this;
}
for (MimPackage detail : getOwnedMembersOfType(MimPackage.class)) {
MimPackage found = detail.findContainedPackage(name);
if (found != null) {
return found;
}
}
return null;
}
protected void collectOwnedClasses(final Set<MimClass> elementSet) {
{
List<MimClass> elements = getOwnedMembersOfType(MimClass.class);
for (MimClass mimClass : elements) {
elementSet.add(mimClass);
}
}
for (MimPackage detail : getNestedPackages()) {
detail.collectOwnedClasses(elementSet);
}
}
public Set<MimClass> getAllOwnedClasses() {
Set<MimClass> result = new LinkedHashSet<MimClass>();
collectOwnedClasses(result);
return result;
}
protected void collectPackages(final List<MimPackage> elementSet) {
{
List<MimPackage> elements = getOwnedMembersOfType(MimPackage.class);
for (MimPackage mimClass : elements) {
elementSet.add(mimClass);
}
}
for (MimPackage detail : getNestedPackages()) {
detail.collectPackages(elementSet);
}
}
public List<MimPackage> getAllOwnedPackages() {
List<MimPackage> result = new ArrayList<MimPackage>();
collectPackages(result);
return result;
}
public Map<String, MimPackage> getAllOwnedNonStubPackages(final boolean lowercaseKeys) {
List<MimPackage> allPackages = getAllOwnedPackages();
return removeStubs(allPackages, lowercaseKeys);
}
public Map<String, MimClass> getAllNonStubClasses(final boolean lowercaseKeys) {
List<MimClass> allClasses = getAllMembersOfType(MimClass.class);
return removeStubs(allClasses, lowercaseKeys);
}
protected <T extends NamedElement> Map<String, T> removeStubs(final List<T> elements,
final boolean lowercaseKeys) {
Map<String, T> result = new HashMap<String, T>();
for (T element : elements) {
if (!element.isStub()) {
String key = element.getName();
if (lowercaseKeys)
key = key.toLowerCase();
result.put(key, element);
} else {
LOGGER.info(String.format("Stub %s was filtered out.", element.getName()));
}
}
return result;
}
}

View File

@ -0,0 +1,9 @@
package ch.bitwave.mim.m2.core;
public interface MimType {
public abstract boolean conformsTo(MimType other);
public MimPackage getPackage();
public void setPackage(MimPackage owner);
}

View File

@ -0,0 +1,42 @@
package ch.bitwave.mim.m2.core;
public class Multiplicity {
// isOrdered
// isUnique
private int lower;
private int upper;
public Multiplicity() {
this.lower = 1;
this.upper = 1;
}
public int getLower() {
return this.lower;
}
public void setLower(final int lower) {
this.lower = lower;
}
public int getUpper() {
return this.upper;
}
public void setUpper(final int upper) {
this.upper = upper;
}
public boolean isMultiValued() {
return this.upper == 0 || this.upper > 1;
}
public boolean includesCardinality(final int value) {
boolean lowerMet = value >= this.lower;
if (this.upper == 0) {
return lowerMet;
}
return lowerMet && value <= this.upper;
}
}

View File

@ -0,0 +1,8 @@
package ch.bitwave.mim.m2.core;
public interface MultiplicityElement {
Multiplicity getMultiplicity();
}

View File

@ -0,0 +1,63 @@
package ch.bitwave.mim.m2.core;
/**
* A named element represents elements that may have a name. The name is used
* for identification of the named element within the namespace in which it is
* defined. A named element also has a qualified name that allows it to be
* unambiguously identified within a hierarchy of nested namespaces.
* NamedElement is an abstract metaclass.
*
* The name for a named element is optional. If specified, then any valid
* string, including the empty string, may be used.
*/
public abstract class NamedElement extends MimElement {
private String name;
private VisibilityKind visibility;
public VisibilityKind getVisibility() {
return this.visibility;
}
public void setVisibility(final VisibilityKind visibility) {
this.visibility = visibility;
}
public String getName() {
return this.name;
}
public void setName(final String name) {
this.name = name;
}
public Namespace getNamespace() {
MimElement owner = getOwner();
if (owner instanceof Namespace)
return (Namespace) owner;
return null;
}
/**
* A name which allows the NamedElement to be identified within a hierarchy
* of nested Namespaces. It is constructed from the names of the containing
* namespaces starting at the root of the hierarchy and ending with the name
* of the NamedElement itself. This is a derived attribute.
*
* @return the qualified name.
*/
public String getQualifiedName() {
Namespace ns = getNamespace();
if (ns == null) {
return this.name;
}
return ns.getQualifiedName() + '.' + this.name;
}
@Override
public String toString() {
StringBuilder builder = new StringBuilder();
builder.append(getClass().getSimpleName()).append(" ").append(getQualifiedName());
return builder.toString();
}
}

View File

@ -0,0 +1,242 @@
package ch.bitwave.mim.m2.core;
import java.util.ArrayList;
import java.util.List;
import javax.annotation.Nonnull;
/**
* A namespace is a named element that can own other named elements. Each named
* element may be owned by at most one namespace. A namespace provides a means
* for identifying named elements by name. Named elements can be identified by
* name in a namespace either by being directly owned by the namespace or by
* being introduced into the namespace by other means (e.g., importing or
* inheriting). Namespace is an abstract metaclass.
*/
public abstract class Namespace extends NamedElement {
private List<PackageImport> packageImports;
private List<PackageImport> importingPackages;
private NamingStrategy namingStrategy;
public Namespace() {
super();
this.packageImports = new ArrayList<PackageImport>();
this.importingPackages = new ArrayList<PackageImport>();
this.namingStrategy = ExactNamingStrategy.getInstance();
}
public NamingStrategy getNamingStrategy() {
return this.namingStrategy;
}
public void setNamingStrategy(final NamingStrategy namingStrategy) {
this.namingStrategy = namingStrategy;
}
public List<PackageImport> getPackageImports() {
return this.packageImports;
}
public List<PackageImport> getImportingPackages() {
return this.importingPackages;
}
public void addPackageImport(@Nonnull final PackageImport imp) {
this.packageImports.add(imp);
}
public void removePackageImport(@Nonnull final PackageImport imp) {
this.packageImports.remove(imp);
}
public void addImportingPackage(@Nonnull final PackageImport imp) {
this.importingPackages.add(imp);
}
public void removeImportingPackage(@Nonnull final PackageImport imp) {
this.importingPackages.remove(imp);
}
/**
* Returns the elements directly owned by this namespace.
*
* @return the list of owned elements.
*/
public List<NamedElement> getOwnedMembers() {
List<NamedElement> result = new ArrayList<NamedElement>();
contributeOwnedMembers(result);
return result;
}
protected abstract void contributeOwnedMembers(final List<NamedElement> list);
/**
* A collection of NamedElements identifiable within the Namespace, either
* by being owned or by being introduced by importing or inheritance. This
* is a derived union.
*
* @return the complete list of members contained in this namespace.
*/
public List<NamedElement> getMembers() {
List<NamedElement> result = new ArrayList<NamedElement>();
contributeMembers(result);
return result;
}
protected List<NamedElement> getAllMembers() {
List<NamedElement> result = new ArrayList<NamedElement>();
contributeAllMembers(result);
return result;
}
public List<MimPackage> getImportedPackages() {
List<MimPackage> result = new ArrayList<MimPackage>();
for (PackageImport imp : this.packageImports) {
if (imp.getImportedPackage() == null) {
throw new MetaModelRuntimeException(
"Invalid package import: Imported package is null.");
}
result.add(imp.getImportedPackage());
}
return result;
}
protected void contributeMembers(final List<NamedElement> list) {
list.addAll(getOwnedMembers());
for (MimPackage importedPackage : getImportedPackages()) {
list.addAll(importedPackage.getOwnedMembers());
}
}
protected void contributeAllMembers(final List<NamedElement> list) {
contributeMembers(list);
}
public NamedElement getMemberByName(final String name) throws UnknownMemberException {
NamedElement member = findMember(name);
if (member == null) {
throw new UnknownMemberException(String.format(
"Element \"%s\" does not have a member element with name \"%s\".", getName(),
name));
}
return member;
}
public <T extends NamedElement> T getMemberOfTypeByName(final java.lang.Class<T> type,
final String name) throws UnknownMemberException {
T member = findMemberOfType(type, name);
if (member == null) {
throw new UnknownMemberException(String.format(
"Element \"%s\" does not have a member element with name \"%s\".", getName(),
name));
}
return member;
}
public NamedElement getOwnedMemberByName(final String name) throws UnknownMemberException {
NamedElement member = findOwnedMember(name);
if (member == null) {
throw new UnknownMemberException(String.format(
"Element \"%s\" does not own an element with name \"%s\".", getName(), name));
}
return member;
}
public NamedElement findMember(final String name) {
return findByName(getMembers(), name);
}
public <T extends NamedElement> T findMemberOfType(final java.lang.Class<T> type,
final String name) {
List<T> elements = getMembersOfType(type);
return findByName(elements, name);
}
public <T extends NamedElement> List<T> getMembersOfType(final java.lang.Class<T> type) {
@SuppressWarnings("unchecked")
List<T> elements = (List<T>) getMembers();
return filterByElementType(elements, type);
}
public <T extends NamedElement> List<T> getAllMembersOfType(final java.lang.Class<T> type) {
@SuppressWarnings("unchecked")
List<T> elements = (List<T>) getAllMembers();
return filterByElementType(elements, type);
}
protected <T extends NamedElement> T findByName(final List<T> elements, final String name) {
for (T element : elements) {
if (this.namingStrategy.isSameName(name, element.getName())) {
return element;
}
}
return null;
}
public NamedElement findOwnedMember(final String name) {
for (NamedElement element : getOwnedMembers()) {
if (this.namingStrategy.isSameName(name, element.getName())) {
return element;
}
}
return null;
}
@SuppressWarnings("unchecked")
public <T> T findOwnedMemberAs(final String name, final java.lang.Class<T> elementType) {
NamedElement detailMember = findOwnedMember(name);
if (detailMember != null) {
if (!elementType.isAssignableFrom(detailMember.getClass())) {
throw new RuntimeException(String.format(
"Element \"%s\" contained in \"%s\" is not of type %s.", name, getName(),
elementType.getClass().getSimpleName()));
}
return (T) detailMember;
}
return null;
}
@SuppressWarnings("unchecked")
public <T extends NamedElement> List<T> getOwnedMembersOfType(
final java.lang.Class<T> memberClass) {
List<T> members = (List<T>) getOwnedMembers();
return filterByElementType(members, memberClass);
}
@SuppressWarnings("unchecked")
protected <T extends NamedElement> List<T> filterByElementType(final List<T> elements,
final java.lang.Class<T> memberClass) {
List<T> result = new ArrayList<T>();
for (NamedElement element : elements) {
if (memberClass.isAssignableFrom(element.getClass())) {
result.add((T) element);
}
}
return result;
}
@SuppressWarnings("unchecked")
protected <T extends MimType> List<T> filterByType(final List<NamedElement> elements,
final java.lang.Class<T> typeClass) {
List<T> result = new ArrayList<T>();
for (NamedElement element : elements) {
if (typeClass.isAssignableFrom(element.getClass())) {
result.add((T) element);
}
}
return result;
}
public abstract void addOwnedMember(NamedElement member);
public abstract void removeOwnedMember(NamedElement member);
public MimType findType(final String typeName) {
NamedElement elem = findMember(typeName);
if (elem instanceof MimType) {
return (MimType) elem;
}
return null;
}
}

View File

@ -0,0 +1,8 @@
package ch.bitwave.mim.m2.core;
/**
* Defines how names are compared with each other.
*/
public interface NamingStrategy {
boolean isSameName(String firstName, String secondName);
}

View File

@ -0,0 +1,86 @@
package ch.bitwave.mim.m2.core;
import java.util.HashSet;
import java.util.List;
import java.util.Set;
/**
* <p>
* An operation is owned by a class and may be invoked in the context of objects
* that are instances of that class. It is a typed element and a multiplicity
* element.
* </p>
*
* <p>
* An operation belongs to a class. It is possible to invoke an operation on any
* object that is directly or indirectly an instance of the class. Within such
* an invocation the execution context includes this object and the values of
* the parameters. The type of the operation, if any, is the type of the result
* returned by the operation, and the multiplicity is the multiplicity of the
* result. An operation can be associated with a set of types that represent
* possible exceptions that the operation may raise.
* </p>
*/
public class Operation extends Feature implements TypedElement, MultiplicityElement, Dependent {
private MimClass owningClass;
private Multiplicity multiplicity;
private List<Parameter> ownedParameters;
private List<MimType> raisedExceptions;
private Dependencies dependencies;
public Operation() {
}
public List<Parameter> getOwnedParameters() {
return this.ownedParameters;
}
public List<MimType> getRaisedExceptions() {
return this.raisedExceptions;
}
@Override
public MimElement getOwner() {
return this.owningClass;
}
@Override
public MimType getType() {
return null;
}
@Override
public void setType(final MimType type) {
}
@Override
public Multiplicity getMultiplicity() {
return this.multiplicity;
}
@Override
public boolean depdendsOnIdentifier(final String name) {
if (this.dependencies == null) {
return false;
}
return this.dependencies.depdendsOnIdentifier(name);
}
@Override
public void addIdentifierDependency(final String name) {
if (this.dependencies == null) {
this.dependencies = new Dependencies();
}
this.dependencies.addIdentifierDependency(name);
}
public Set<String> getIdentifierDependencies() {
if (this.dependencies == null) {
return new HashSet<String>();
}
return this.dependencies.getIdentifierDependencies();
}
}

View File

@ -0,0 +1,81 @@
package ch.bitwave.mim.m2.core;
import java.util.ArrayList;
import java.util.List;
/**
* <p>
* A package import is a relationship that allows the use of unqualified names
* to refer to package members from other namespaces.
* </p>
*
* <p>
* A package import is a relationship between an importing namespace and a
* package, indicating that the importing namespace adds the names of the
* members of the package to its own namespace. Conceptually, a package import
* is equivalent to having an element import to each individual member of the
* imported namespace, unless there is already a separately-defined element
* import.
* </p>
*/
public class PackageImport extends MimElement implements DirectedRelationship {
private MimPackage importedPackage;
/**
* Specifies the Package whose members are imported into a Namespace.
* Subsets {@link DirectedRelationship#getTargetElements()}.
*
* @return
*/
public MimPackage getImportedPackage() {
return this.importedPackage;
}
public void setImportedPackage(final MimPackage importedPackage) {
this.importedPackage = importedPackage;
}
/**
* Specifies the Namespace that imports the members from a Package. Subsets
* {@link DirectedRelationship#getSourceElements()} and Element::owner.
*
* @return
*/
public Namespace getImportingNamespace() {
return this.getOwnerAs(Namespace.class);
}
public void setImportingNamespace(final Namespace importingNamespace) {
this.setOwner(importingNamespace);
}
@Override
public List<MimElement> getRelatedElements() {
List<MimElement> result = new ArrayList<MimElement>();
result.add(getImportingNamespace());
result.add(getImportedPackage());
return result;
}
@Override
public List<MimElement> getSourceElements() {
List<MimElement> result = new ArrayList<MimElement>();
result.add(getImportingNamespace());
return result;
}
@Override
public List<MimElement> getTargetElements() {
List<MimElement> result = new ArrayList<MimElement>();
result.add(getImportedPackage());
return result;
}
@Override
public String toString() {
StringBuilder builder = new StringBuilder();
builder.append("PackageImport [importingNamespace=").append(getImportingNamespace())
.append(", importedPackage=").append(getImportedPackage()).append("]");
return builder.toString();
}
}

View File

@ -0,0 +1,57 @@
package ch.bitwave.mim.m2.core;
/**
* <p>
* A parameter is a typed element that represents a parameter of an operation.
* </p>
*
* <p>
* When an operation is invoked, an argument may be passed to it for each
* parameter. Each parameter has a type and a multiplicity. Every Parameter is
* associated with an operation, although subclasses of Parameter elsewhere in
* the UML model do not have to be associated with an operation, hence the 0..1
* multiplicity.
* </p>
*/
public class Parameter extends NamedElement implements TypedElement, MultiplicityElement {
private Operation operation;
private Multiplicity multiplicity;
private ParameterDirectionKind direction;
public ParameterDirectionKind getDirection() {
return this.direction;
}
public void setDirection(final ParameterDirectionKind direction) {
this.direction = direction;
}
public Operation getOperation() {
return this.operation;
}
public void setOperation(final Operation operation) {
this.operation = operation;
}
@Override
public Multiplicity getMultiplicity() {
return this.multiplicity;
}
@Override
public MimType getType() {
return null;
}
@Override
public void setType(final MimType type) {
}
@Override
public MimElement getOwner() {
return this.operation;
}
}

View File

@ -0,0 +1,5 @@
package ch.bitwave.mim.m2.core;
public enum ParameterDirectionKind {
IN, IN_OUT, OUT, RETURN
}

View File

@ -0,0 +1,23 @@
package ch.bitwave.mim.m2.core;
/**
* A primitive type is a data type implemented by the underlying infrastructure
* and made available for modeling.
*/
public class PrimitiveType extends NamedElement implements DataType {
@Override
public boolean conformsTo(final MimType other) {
return this == other;
}
@Override
public MimPackage getPackage() {
return getOwnerAs(MimPackage.class);
}
@Override
public void setPackage(final MimPackage owner) {
setOwner(owner);
}
}

View File

@ -0,0 +1,12 @@
package ch.bitwave.mim.m2.core;
import org.apache.commons.lang.StringUtils;
public class Profile extends MimPackage implements NamingStrategy {
@Override
public boolean isSameName(final String firstName, final String secondName) {
return StringUtils.equals(firstName, secondName);
}
}

View File

@ -0,0 +1,171 @@
package ch.bitwave.mim.m2.core;
import javax.annotation.CheckForNull;
/**
* <p>
* A property represents an attribute of a class. A property has a type and a
* multiplicity. When a property is paired with an opposite they represent two
* mutually constrained attributes. The semantics of two properties that are
* mutual opposites are the same as for bidirectionally navigable associations
* in Constructs, with the exception that the association has no explicit links
* as instances, and has no name.
* </p>
*/
public class Property extends StructuralFeature implements TypedElement, MultiplicityElement {
private Relationship owningRelationship;
private Relationship relationship;
private Multiplicity multiplicity;
private String defaultValue;
private boolean composite;
private boolean derived;
private boolean readOnly;
private Property opposite;
private MimType type;
public Property() {
this.multiplicity = new Multiplicity();
}
/**
* References the owning relationship of this property, if any.
*
* @return
*/
public Relationship getOwningRelationship() {
return this.owningRelationship;
}
/**
* References the Class that owns the Property. Subsets
* {@link NamedElement#getNamespace()},
* {@link Feature#getFeaturingClassifier()}.
*
* @return
*/
public MimClass getOwningClass() {
MimElement owner = this.getOwner();
if (owner == null)
return null;
if (!(owner instanceof MimClass))
throw new MetaModelRuntimeException(String.format("%s is not owned by a class.",
toString()));
return (MimClass) owner;
}
public void setOwningClass(final MimClass owningClass) {
this.setOwner(owningClass);
}
/**
* References the relationship of which this property is a member, if any.
*
* @return
*/
@CheckForNull
public Relationship getRelationship() {
return this.relationship;
}
public void setAssociation(final Association association) {
this.relationship = association;
}
/**
* Two attributes attr1 and attr2 of two objects o1 and o2 (which may be the
* same object) may be paired with each other so that o1.attr1 refers to o2
* if and only if o2.attr2 refers to o1. In such a case attr1 is the
* opposite of attr2 and attr2 is the opposite of attr1.
*
* @return
*/
public Property getOpposite() {
return this.opposite;
}
public void setOpposite(final Property opposite) {
this.opposite = opposite;
}
/**
* If isReadOnly is true, the attribute may not be written to after
* initialization. The default value is false.
*
* @return
*/
public boolean isReadOnly() {
return this.readOnly;
}
public void setReadOnly(final boolean readOnly) {
this.readOnly = readOnly;
}
/**
* If isComposite is true, the object containing the attribute is a
* container for the object or value contained in the attribute. The default
* value is false.
*
* @return
*/
public boolean isComposite() {
return this.composite;
}
public void setComposite(final boolean composite) {
this.composite = composite;
}
/**
* If isDerived is true, the value of the attribute is derived from
* information elsewhere. The default value is false.
*
* @return
*/
public boolean isDerived() {
return this.derived;
}
public void setDerived(final boolean derived) {
this.derived = derived;
}
/**
* A string that is evaluated to give a default value for the attribute when
* an object of the owning class is instantiated.
*
* @return
*/
public String getDefaultValue() {
return this.defaultValue;
}
public void setDefaultValue(final String defaultValue) {
this.defaultValue = defaultValue;
}
@Override
public Multiplicity getMultiplicity() {
return this.multiplicity;
}
@Override
public MimType getType() {
return this.type;
}
@Override
public void setType(final MimType type) {
this.type = type;
}
public boolean isOwnedBy(final Classifier classifier) {
return getOwner() == classifier;
}
public void setRelationship(final Relationship relationship) {
this.relationship = relationship;
}
}

View File

@ -0,0 +1,13 @@
package ch.bitwave.mim.m2.core;
import java.util.List;
/**
* Relationship is an abstract concept that specifies some kind of relationship
* between elements.
*/
public interface Relationship {
List<MimElement> getRelatedElements();
}

View File

@ -0,0 +1,13 @@
package ch.bitwave.mim.m2.core;
public class Stereotype extends MimClass {
public Profile getProfile() {
return getOwnerAs(Profile.class);
}
public void setProfile(final Profile profile) {
setOwner(profile);
}
}

View File

@ -0,0 +1,9 @@
package ch.bitwave.mim.m2.core;
/**
* A structural feature is a typed feature of a classifier that specifies the
* structure of instances of the classifier.
*/
public abstract class StructuralFeature extends Feature implements TypedElement {
}

View File

@ -0,0 +1,61 @@
package ch.bitwave.mim.m2.core;
import java.util.ArrayList;
import java.util.List;
public class StubClass extends MimClass {
private String stubReason;
private List<MimElement> referers;
public StubClass() {
this.referers = new ArrayList<MimElement>();
}
public String getStubReason() {
return this.stubReason;
}
public void setStubReason(final String stubReason) {
this.stubReason = stubReason;
}
@Override
public String toString() {
StringBuilder builder = new StringBuilder();
builder.append("StubClass ").append(getName()).append(": ").append(this.stubReason);
return builder.toString();
}
/**
* Makes all relationship ends pointing at this stub point at the given
* class instead.
*
* @param resolved
*/
public void replaceWith(final MimClass replacement) {
if (replacement.isStub())
throw new MetaModelRuntimeException(String.format(
"Cannot replace stub %s with stub %s.", this, replacement));
for (MimElement element : this.referers) {
if (element instanceof Generalization) {
((Generalization) element).setGeneral(replacement);
}
}
MimPackage owner = getOwnerAs(MimPackage.class);
owner.removeOwnedMember(this);
}
@Override
protected void contributeOwnedMembers(final List<NamedElement> list) {
}
public void addReferer(final MimElement element) {
this.referers.add(element);
}
@Override
public boolean isStub() {
return true;
}
}

View File

@ -0,0 +1,27 @@
package ch.bitwave.mim.m2.core;
public class StubPackage extends MimPackage {
private PackageImport owningImport;
public StubPackage(final PackageImport owningImport) {
super();
this.owningImport = owningImport;
}
public PackageImport getOwningImport() {
return this.owningImport;
}
public void replaceWith(final MimPackage resolved) {
this.owningImport.setImportedPackage(resolved);
removeImportingPackage(this.owningImport);
resolved.addImportingPackage(this.owningImport);
}
@Override
public boolean isStub() {
return true;
}
}

View File

@ -0,0 +1,31 @@
package ch.bitwave.mim.m2.core;
public class StubType extends NamedElement implements DataType {
private String message;
public String getMessage() {
return this.message;
}
@Override
public String toString() {
StringBuilder builder = new StringBuilder();
builder.append("StubType ").append(getName()).append(": ").append(this.message);
return builder.toString();
}
@Override
public boolean conformsTo(final MimType other) {
return false;
}
@Override
public MimPackage getPackage() {
return getOwnerAs(MimPackage.class);
}
@Override
public void setPackage(final MimPackage owner) {
setOwner(owner);
}
}

View File

@ -0,0 +1,7 @@
package ch.bitwave.mim.m2.core;
public interface TypedElement {
MimType getType();
void setType(MimType type);
}

View File

@ -0,0 +1,11 @@
package ch.bitwave.mim.m2.core;
public class UnknownMemberException extends MetaModelException {
private static final long serialVersionUID = 1L;
public UnknownMemberException(final String message) {
super(message);
}
}

View File

@ -0,0 +1,48 @@
package ch.bitwave.mim.m2.core;
import java.util.Set;
/**
* VisibilityKind is intended for use in the specification of visibility in
* conjunction with, for example, the Imports, Generalizations, Packages, and
* Classifiers packages. Detailed semantics are specified with those mechanisms.
* If the Visibility package is used without those packages, these literals will
* have different meanings, or no meanings.
* <ol>
* <li>A public element is visible to all elements that can access the contents
* of the namespace that owns it.</li>
* <li>A private element is only visible inside the namespace that owns it.</li>
* <li>A protected element is visible to elements that have a generalization
* relationship to the namespace that owns it.</li>
* <li>A package element is owned by a namespace that is not a package, and is
* visible to elements that are in the same package as its owning namespace.
* Only named elements that are not owned by packages can be marked as having
* package visibility. Any element marked as having package visibility is
* visible to all elements within the nearest enclosing package (given that
* other owning elements have proper visibility). Outside the nearest enclosing
* package, an element marked as having package visibility is not visible.</li>
* </ol>
* In circumstances where a named element ends up with multiple visibilities,
* for example by being imported multiple times, public visibility overrides
* private visibility, i.e., if an element is imported twice into the same
* namespace, once using public import and once using private import, it will be
* public.
*/
public enum VisibilityKind {
PRIVATE, PROTECTED, PACKAGE, PUBLIC;
/**
* Examines a set of VisibilityKinds, and returns PUBLIC as the preferred
* visibility. If PUBLIC is not in the set, PRIVATE is returned.
*
* @param set
* the set to examine.
* @return the best visibility.
*/
public static VisibilityKind getBestVisibility(final Set<VisibilityKind> set) {
if (set.contains(VisibilityKind.PUBLIC)) {
return VisibilityKind.PUBLIC;
}
return VisibilityKind.PRIVATE;
}
}

View File

@ -0,0 +1,99 @@
package ch.bitwave.mim.m2.profiles;
import java.util.HashMap;
import java.util.Map;
import javax.annotation.Nonnull;
import org.apache.commons.lang.StringUtils;
import ch.bitwave.mim.m2.core.MetaModelRuntimeException;
import ch.bitwave.mim.m2.core.MimClass;
import ch.bitwave.mim.m2.core.MimPackage;
import ch.bitwave.mim.m2.core.MimType;
import ch.bitwave.mim.m2.core.PrimitiveType;
import ch.bitwave.mim.m2.core.Profile;
import ch.bitwave.mim.m2.core.Stereotype;
public class DelphiProfile extends Profile {
private final Stereotype interfaceStereotype;
private final MimType stringType;
private final MimType integerType;
private final MimType booleanType;
Map<String, MimType> typesByName;
public DelphiProfile() {
this.typesByName = new HashMap<String, MimType>();
this.interfaceStereotype = createStereotype("interface");
this.stringType = createPrimitiveType("string");
this.integerType = createPrimitiveType("integer");
this.booleanType = createPrimitiveType("boolean");
}
private MimType createPrimitiveType(final String name) {
PrimitiveType result = new PrimitiveType();
result.setName(name);
this.typesByName.put(name, result);
return result;
}
private Stereotype createStereotype(final String name) {
Stereotype result = new Stereotype();
result.setName(name);
addOwnedMember(result);
this.typesByName.put(name, result);
return result;
}
public Stereotype getInterfaceStereotype() {
return this.interfaceStereotype;
}
public MimType getStringType() {
return this.stringType;
}
public MimType getIntegerType() {
return this.integerType;
}
public MimType getBooleanType() {
return this.booleanType;
}
public MimType getType(@Nonnull final String typeName) {
MimType result = findType(typeName);
if (result == null) {
throw new MetaModelRuntimeException(String.format(
"The Delphi profile does not provide type \"%s\".", typeName));
}
return result;
}
@Override
public MimType findType(final String typeName) {
return this.typesByName.get(typeName.toLowerCase());
}
public MimPackage createPackage(final String name) {
MimPackage result = new MimPackage();
result.setNamingStrategy(this);
result.setName(name);
return result;
}
public MimClass createClass(final String name) {
MimClass result = new MimClass();
result.setName(name);
result.setNamingStrategy(this);
return result;
}
@Override
public boolean isSameName(final String firstName, final String secondName) {
return StringUtils.equalsIgnoreCase(firstName, secondName);
}
}

View File

@ -0,0 +1,27 @@
package ch.bitwave.mim.m2.core;
import static org.junit.Assert.assertFalse;
import static org.junit.Assert.assertTrue;
import org.junit.Test;
public class ClassifierTest {
@Test
public void shouldGeneralize() {
// Set up two classes with a specialization. A Car is a Vehicle.
MimClass vehicleClass = new MimClass();
vehicleClass.setName("Vehicle");
MimClass carClass = new MimClass();
carClass.setName("Car");
Generalization gen = new Generalization();
gen.setGeneral(vehicleClass);
gen.setSpecific(carClass);
// Now check the various methods related to generalizations.
assertTrue(carClass.isSpecializationOf(vehicleClass));
assertTrue(vehicleClass.isGeneralizationOf(carClass));
assertFalse(carClass.isGeneralizationOf(vehicleClass));
assertFalse(vehicleClass.isSpecializationOf(carClass));
assertFalse(carClass.getSpecifics().contains(vehicleClass));
assertFalse(vehicleClass.getGenerals().contains(carClass));
}
}

View File

@ -0,0 +1,19 @@
package ch.bitwave.mim.m2.profiles;
import static org.junit.Assert.assertSame;
import org.junit.Test;
import ch.bitwave.mim.m2.core.MimClass;
import ch.bitwave.mim.m2.core.MimPackage;
public class DelphiProfileTest {
@Test
public void shouldThreadIdentifiersCaseInsensitively() {
DelphiProfile profile = new DelphiProfile();
MimPackage toolbox = profile.createPackage("toolbox");
MimClass utils = profile.createClass("utils");
toolbox.addOwnedMember(utils);
assertSame(utils, toolbox.findMember("Utils"));
}
}