Permalink
Fetching contributors…
Cannot retrieve contributors at this time
executable file 4959 lines (4438 sloc) 133 KB
/*
Copyright: All contributers to the Umple Project
This file is made available subject to the open source license found at:
http://umple.org/license
Methods for the metamodel found in Umple.ump. Most of these are mixins.
*/
namespace cruise.umple.compiler;
/**
* In Umple_Code.ump: Methods for manipulating the Model
*/
class UmpleModel
{
//ParsingTime represents Parsing end time
//gTime1 represents code generation start time
//gTime2 represents code generation end time
Double parsingTime = 0.0;
internal Double gTime1 = 0.0;
internal Double gTime2 = 0.0;
Map<String, String> hashMap = new HashMap<String, String>();
public static String[] findValidLanguages()
{
final String NONTERMINAL = "generate";
final String START_TOKEN = "[=language:";
final String END_TOKEN = "]";
final String DELIMITER = "\\|";
String[] result = new String[0];
boolean lineFound = false;
try
{
InputStream in = null;
BufferedReader reader = null;
try
{
in = UmpleModel.class.getResourceAsStream("/umple_core.grammar");
reader = new BufferedReader(new InputStreamReader(in));
String line;
while (((line = reader.readLine()) != null) && !lineFound )
{
if( line.startsWith(NONTERMINAL) && line.contains(START_TOKEN))
{
int start_index = line.indexOf(START_TOKEN) + START_TOKEN.length();
int end_index = line.indexOf(END_TOKEN);
String languages = line.substring( start_index, end_index );
result = languages.split(DELIMITER);
lineFound = true;
}
}
}finally
{
in.close();
reader.close();
}
}catch( IOException e ){
throw new RuntimeException("Error opening '/umple_core.grammar' resource", e);
}
Arrays.sort(result);
return result;
}
after constructor{
if(aUmpleFile!=null){
String[] linkedFilenames = aUmpleFile.getLinkedFiles().split("use");
for( String filename : linkedFilenames ){
// Remove blankspace and newlines
filename = filename.trim();
// Create a file from the name, removing the last ';' from the string
if( filename.length()>1 ){
this.linkedFiles.add(new File(filename.substring(0,filename.length()-1)));
}
}
}
}
public UmpleModel(UmpleFile umpleFile, List<File> linkedFiles ){
this(umpleFile);
this.linkedFiles = linkedFiles;
}
public List<UmpleElement> getUmpleElements()
{
List<UmpleElement> all = new ArrayList<UmpleElement>();
all.addAll(getUmpleClasses());
all.addAll(getUmpleInterfaces());
return all;
}
public UmpleInterface addUmpleInterface(String name)
{
UmpleInterface newInterface = getUmpleInterface(name);
if (newInterface == null)
{
newInterface = new UmpleInterface(name, this);
addUmpleInterface(newInterface);
}
return newInterface;
}
public UmpleClass addUmpleClass(String name)
{
UmpleClass newClass = getUmpleClass(name);
if (newClass == null)
{
newClass = new UmpleClass(name, this);
addUmpleClass(newClass);
}
return newClass;
}
public Association getAssociation(String name)
{
for (Association a : associations)
{
if (a.getName().equals(name))
{
return a;
}
}
return null;
}
public AssociationClass addAssociationClass(String className)
{
AssociationClass newClass = (AssociationClass) getUmpleClass(className);
if (newClass == null)
{
newClass = new AssociationClass(className);
addUmpleClass(newClass);
}
return newClass;
}
public void addGenerate(String lang)
{
addGenerate(new GenerateTarget(lang, null));
}
public void addGenerate(Collection <?extends GenerateTarget> c)
{
generates.addAll(c);
}
public String getDefaultGenerate()
{
// Note that this method should be getDefaultGenerateLanguage
// To avoid rippling changes throughout the code, the name is left as is
if (numberOfGenerates() == 0)
{
return null;
}
else
{
return getGenerate(0).getLanguage();
}
}
public String getDefaultGeneratePath()
{
if (numberOfGenerates() == 0)
{
return null;
}
else
{
return getGenerate(0).getPath() == null ? "./" : getGenerate(0).getPath();
}
}
public void clearGenerates()
{
generates.clear();
}
public UmpleClass getUmpleClass(String name)
{
for (UmpleClass aClass : getUmpleClasses())
{
if (aClass.getName().equals(name))
{
return aClass;
}
}
return null;
}
public UmpleInterface getUmpleInterface(String name)
{
for (UmpleInterface aInterface : getUmpleInterfaces())
{
if (aInterface.getName().equals(name))
{
return aInterface;
}
}
return null;
}
public StateMachine getStateMachineDefinition(String name)
{
for (StateMachine aStateMachine : getStateMachineDefinitions())
{
if (aStateMachine.getName().equals(name))
{
return aStateMachine;
}
}
return null;
}
public boolean hasAnalyzer(String name)
{
return analyzers.containsKey(name);
}
public Analyzer getAnalyzer(String name)
{
return analyzers.get(name);
}
/*
* Creates a new parser, loads the input, parses, then analyses; analyser generates
*/
public void run()
{
boolean failed = false;
String input;
RuleBasedParser parser = new RuleBasedParser();
UmpleInternalParser analyzer = new UmpleInternalParser("UmpleInternalParser",this,parser);
ParseResult result = null;
try {
result = parser.parse(
new File(umpleFile.getPath() + File.separator + umpleFile.getFileName()),
this.linkedFiles.toArray(new File[0]));
}
catch (Exception ex)
{
result = parser.parse("classDefinition",""); // Fake to ensure can proceed
lastResult = result;
result.addErrorMessage(new ErrorMessage(9000,new Position("",0,0,0),
"Could not parse Umple model. Please report an issue with this entire message and your input code to Umple developers. \nStack dump follows\n"+cruise.umple.util.ExceptionDumper.dumpCompilerError(ex)
));
throw new UmpleCompilerException(result.toString(),null);
}
catch (StackOverflowError ex)
{
result = parser.parse("classDefinition",""); // Fake to ensure can proceed
lastResult = result;
result.addErrorMessage(new ErrorMessage(9000,new Position("",0,0,0),
"Could not parse Umple model. Please report an issue with this entire message and your input code to Umple developers. \nStack Overflow in Parsing.\n"+cruise.umple.util.ExceptionDumper.dumpCompilerError(ex)
));
throw new UmpleCompilerException(result.toString(),null);
}
this.extractAnalyzersFromParser(parser);
failed = failed || !result.getWasSuccess();
lastResult = result;
if(!failed)
result = analyzer.analyze(getShouldGenerate());
failed |= !result.getWasSuccess();
if(failed || result.getHasWarnings())
throw new UmpleCompilerException(result.toString(),null);
}
/*
* Creates a generator for you based on the provided Language
*/
public CodeGenerator newGenerator(String language)
{
String realLanguage = language;
// Ensure the target is specified in the proper case.
VALIDATE_GENERATE:
for( String lang : UmpleModel.validLanguages ){
if(lang.equalsIgnoreCase(language)){
realLanguage = lang;
break VALIDATE_GENERATE;
}
}
if (language.equals("Cpp")) realLanguage="RTCpp";
else if (language.equals("SimpleCpp")) realLanguage="RTCpp";
String className = StringFormatter.format("cruise.umple.compiler.{0}Generator",realLanguage);
Class<?> classDefinition = null;
try {
classDefinition = Class.forName(className);
CodeGenerator generator = (CodeGenerator) classDefinition.newInstance();
generator.setModel(this);
return generator;
}
catch (ClassNotFoundException cnf) {
System.err.println("Code generator "+realLanguage+ " not found. Check spelling. Specify --help.");
System.exit(-1);
throw new RuntimeException(cnf);
}
catch (Exception ex2) {
System.err.println("Code generator "+realLanguage+ " not found. Check spelling. Specify --help.");
System.exit(-1);
throw new RuntimeException("Unable to instantiate "+realLanguage+ ".",ex2);
}
}
/*
* Generates the actual code for each generation target
*/
public String generate()
{
String lang="Unknown";
applyFilter(null);
boolean foundGenerator;
parsingTime = System.currentTimeMillis()/1000.0;
try
{
for (GenerateTarget target : getGenerates())
{
lang=target.getLanguage();
CodeGenerator generator = newGenerator(lang);
generator.setOutput(target.getPath());
CodeBlock.languageUsed = lang;
for (String subopt : target.getSuboptions()) {
generator.setSuboption(subopt);
}
gTime1 = System.currentTimeMillis()/1000.0;
generator.generate();
gTime2 = System.currentTimeMillis()/1000.0;
Double gTime = gTime2 - gTime1;
hashMap.put(lang,(String.valueOf(gTime)));
}
return null; // generators all worked
}
catch (Exception ex)
{
return("Could not generate "+lang+"\nPlease report an issue with this entire message and your input code to Umple developers.\nStack Trace Follows.\n"+
cruise.umple.util.ExceptionDumper.dumpCompilerError(ex));
}
}
public Coordinate getDefaultClassPosition(int numDefaults)
{
int xIndex = 0;
int yIndex = 0;
int yOffset = 0;
int xOffset = 0;
xIndex = (numDefaults-1) / (maxYLevels);
yIndex = (numDefaults-1) % (maxYLevels);
yOffset = (yIndex * levelOffset.getY()) + initialOffset.getY();
xOffset = (xIndex * levelOffset.getX()) + initialOffset.getX();
return new Coordinate(xOffset,yOffset,classSize.getWidth(),classSize.getHeight());
}
public Coordinate getDefaultInterfacePosition(int numDefaults)
{
int xIndex = 0;
int yIndex = 0;
int yOffset = 0;
int xOffset = 0;
xIndex = (numDefaults-1) / (maxYLevels);
yIndex = (numDefaults-1) % (maxYLevels);
yOffset = (yIndex * levelOffset.getY()) + initialOffset.getY();
xOffset = (xIndex * levelOffset.getX()) + initialOffset.getX() + 2*classSize.getWidth();
return new Coordinate(xOffset,yOffset,classSize.getWidth(),classSize.getHeight());
}
public Coordinate[] getDefaultAssociationPosition(Association a)
{
Coordinate[] defaults = new Coordinate[2];
int offsetY = offsetFromEdge.getX();
int offsetX = offsetFromEdge.getY();
String classOne = a.getEnd(0).getClassName();
String classTwo = a.getEnd(1).getClassName();
if(getUmpleTraitTypeParameter(classOne) || getUmpleTrait(classOne)!=null) return null;
if(getUmpleTraitTypeParameter(classTwo) || getUmpleTrait(classTwo)!=null) return null;
Coordinate classOnePos = getUmpleClass(classOne).getCoordinates();
Coordinate classTwoPos = getUmpleClass(classTwo).getCoordinates();
if (classOne.equals(classTwo))
{
return getDefaultReflexiveAssociationPosition(a);
}
int num = 1;
String tempClass1 = "";
String tempClass2 = "";
for (Association temp : getAssociations())
{
tempClass1 = temp.getEnd(0).getClassName();
tempClass2 = temp.getEnd(1).getClassName();
if (temp.getName().equals(a.getName()) &&
tempClass1.equals(classOne) &&
tempClass2.equals(classTwo))
{
break;
}
if (tempClass1.equals(classOne) && tempClass2.equals(classTwo)){ ++num; break; }
else if (tempClass1.equals(classTwo) && tempClass2.equals(classOne)){ ++num; break; }
}
Coordinate classOneNoX = new Coordinate(classOnePos.getX(),classOnePos.getY(),classOnePos.getWidth(),classOnePos.getHeight());
Coordinate classTwoNoX = new Coordinate(classTwoPos.getX(),classTwoPos.getY(),classTwoPos.getWidth(),classTwoPos.getHeight());
Coordinate classOneNoY = new Coordinate(classOnePos.getX(),classOnePos.getY(),classOnePos.getWidth(),classOnePos.getHeight());
Coordinate classTwoNoY = new Coordinate(classTwoPos.getX(),classTwoPos.getY(),classTwoPos.getWidth(),classTwoPos.getHeight());
classOneNoX.setX(0);
classTwoNoX.setX(0);
classOneNoY.setY(0);
classTwoNoY.setY(0);
String whereVert = classOneNoX.whereIs(classTwoNoX);
String whereHorz = classOneNoY.whereIs(classTwoNoY);
// alternative 1: left/right wall of class one to left/right wall of class two
int offsetOneX = whereHorz.equals("right")? classOnePos.getWidth() : 0;
int offsetTwoX = whereHorz.equals("right")? 0 : classTwoPos.getWidth();
int offsetOneY = num > 1 ? (num+1)*offsetY : offsetY;
int offsetTwoY = num > 1 ? (num+1)*offsetY : offsetY;
Coordinate offsetOne = new Coordinate(offsetOneX, offsetOneY, 0, 0);
Coordinate offsetTwo = new Coordinate(offsetTwoX, offsetTwoY, 0, 0);
Coordinate start = new Coordinate(classOnePos.getX() + offsetOne.getX(),
classOnePos.getY() + offsetOne.getY(),
0,0);
Coordinate end = new Coordinate( classTwoPos.getX() + offsetTwo.getX(),
classTwoPos.getY() + offsetTwo.getY(),
0,0);
int distance = start.distanceTo(end);
// alternative 2: top/bottom wall of class one to top/bottom wall of class two
int altXOne = num*offsetX;
int altXTwo = num*offsetX;
int altYOne = whereVert.equals("top")? 0 : classOnePos.getHeight();
int altYTwo = whereVert.equals("top")? classTwoPos.getHeight() : 0;
Coordinate altOffsetOne = new Coordinate(altXOne, altYOne, 0, 0);
Coordinate altOffsetTwo = new Coordinate(altXTwo, altYTwo, 0, 0);
Coordinate altStart = new Coordinate(classOnePos.getX() + altOffsetOne.getX(),
classOnePos.getY() + altOffsetOne.getY(),
0,0);
Coordinate altEnd = new Coordinate( classTwoPos.getX() + altOffsetTwo.getX(),
classTwoPos.getY() + altOffsetTwo.getY(),
0,0);
int altDistance = altStart.distanceTo(altEnd);
// choose alternative that generates the shortest line
if (altDistance < distance)
{
defaults[0] = altOffsetOne;
defaults[1] = altOffsetTwo;
}
else
{
defaults[0] = offsetOne;
defaults[1] = offsetTwo;
}
return defaults;
}
private Coordinate[] getDefaultReflexiveAssociationPosition(Association a)
{
Coordinate[] defaults = new Coordinate[2];
String name = a.getEnd(0).getClassName();
Coordinate position = getUmpleClass(name).getCoordinates();
// determine which corner the association should be positioned at
int index = 0;
for (int i=0; i < numberOfAssociations(); i++)
{
Association current = getAssociation(i);
if (current.getEnd(0).getClassName().equals(name) && current.getEnd(1).getClassName().equals(name))
{
if (current.numberOfPositions() > 0)
{
if (current.getPosition(0).getStatus().equals(Coordinate.Status.Defaulted))
{
index += 1;
}
}
}
}
Coordinate offsetOne = new Coordinate(0,0,0,0);
Coordinate offsetTwo = new Coordinate(0,0,0,0);
if (index % 4 == 0)
{
offsetOne.setX(reflexiveSegmentLength);
offsetOne.setY(position.getHeight());
offsetTwo.setX(0);
offsetTwo.setY(position.getHeight() - reflexiveSegmentLength);
}
else if (index % 4 == 1)
{
offsetOne.setX(position.getWidth() - reflexiveSegmentLength);
offsetOne.setY(position.getHeight());
offsetTwo.setX(position.getWidth());
offsetTwo.setY(position.getHeight() - reflexiveSegmentLength);
}
else if (index % 4 == 2)
{
offsetOne.setX(position.getWidth() - reflexiveSegmentLength);
offsetOne.setY(0);
offsetTwo.setX(position.getWidth());
offsetTwo.setY(reflexiveSegmentLength);
}
else
{
offsetOne.setX(reflexiveSegmentLength);
offsetOne.setY(0);
offsetTwo.setX(0);
offsetTwo.setY(reflexiveSegmentLength);
}
defaults[0] = offsetOne;
defaults[1] = offsetTwo;
return defaults;
}
public Map<String, CodeTranslator> getAllTranslators() {
Map<String, CodeTranslator> allTranslators = new HashMap<String, CodeTranslator>();
CodeGenerator tempCodeGen = null;
for(GenerateTarget t : getGenerates())
{
if((tempCodeGen = newGenerator(t.getLanguage())) instanceof CodeTranslator) {
allTranslators.put(t.getLanguage(), (CodeTranslator)tempCodeGen);
}
}
return allTranslators;
}
public void applyFilter(String fname)
{
Filter f = getFilter(fname);
if (f == null)
{
return;
}
if(!f.hasNestedFilter() && f.isEmpty())
{
return;
}
if(f.hasNestedFilter())
{
for(String fn : f.getFilterValues())
{
markIncludedClasses(getFilter(fn));
}
}
markIncludedClasses(f);
filterOutClasses();
}
private void markIncludedClasses(Filter f)
{
if (f == null || f.isEmpty())
{
return;
}
for(UmpleClass clazz : umpleClasses)
{
if(f.isIncluded(clazz))
{
clazz.setFilteredin(true);
if(f.hasSub())
{
addSubClasses(f.getSubCount(),clazz);
}
if(f.hasSuper())
{
addSuperClasses(f.getSuperCount(), clazz);
}
}
}
if(f.hasAssociation())
{
markRelatedClass(f.getAssociationCount());
}
if(!f.hasSuper())
{
for(UmpleClass clazz : umpleClasses)
{
if(clazz.getFilteredin())
{
addSuperClasses(clazz);
}
}
}
}
private void filterOutClasses()
{
List<UmpleInterface> interfacesToKeep = new ArrayList<UmpleInterface>();
int maxIndex = umpleClasses.size() - 1;
for(int i=maxIndex; i>=0; i--)
{
UmpleClass clazz = umpleClasses.get(i);
if (!clazz.getFilteredin())
{
// Chop out it and its associations
for(Association a : clazz.getAssociations())
{
clazz.removeAssociation(a); // Remove from this end
// Find the other end(s) and remove references too
for (AssociationEnd ae : a.getEnds())
{
String endClassName = ae.getClassName();
if(!endClassName.equals(clazz.getName()))
{
UmpleClass otherClass = getUmpleClass(endClassName);
if(otherClass != null) {
otherClass.removeAssociation(a);
}
}
}
removeAssociation(a); // from model
a.delete();
}
Object[] avs = clazz.getAssociationVariables().toArray();
for(Object avo: avs)
{
AssociationVariable av = (AssociationVariable)avo;
AssociationVariable otherAv = av.getRelatedAssociation();
if(otherAv != null) {
otherAv.delete();
}
av.delete();
}
removeUmpleClass(clazz);
clazz.delete();
}
else {
// Flag its interfaces to keep
List<UmpleInterface> interfacesOfClass;
interfacesOfClass=clazz.getParentInterface();
for(UmpleInterface ui : interfacesOfClass)
{
addInterfacesRecursively(interfacesToKeep, ui);
}
}
}
// Delete all other Umple interfaces
maxIndex = umpleInterfaces.size() - 1;
for(int i=maxIndex; i>=0; i--)
{
UmpleInterface theInterface = umpleInterfaces.get(i);
removeUmpleInterface(theInterface);
theInterface.delete();
}
}
private void addInterfacesRecursively(List interfacesToKeep, UmpleInterface anInterface) {
interfacesToKeep.add(anInterface);
for(UmpleInterface pi : anInterface.getExtendsInterface())
{
addInterfacesRecursively(interfacesToKeep, pi);
}
}
private void markRelatedClass(int asso)
{
ArrayList<String> names = new ArrayList<String>();
for(int i = 0; i<asso; i++)
{
for(UmpleClass clazz : umpleClasses)
{
if(clazz.getFilteredin())
{
addRelatedClassName(clazz,names);
}
}
markClassByName(names);
names = new ArrayList<String>();
}
}
private void addRelatedClassName(UmpleClass c, ArrayList<String> names)
{
for(AssociationVariable a : c.getAssociationVariables())
{
names.add(a.getType());
}
}
private void markClassByName(ArrayList<String> names)
{
for(UmpleClass c : umpleClasses)
{
if(names.indexOf(c.getName())>=0)
{
c.setFilteredin(true);
}
}
}
private void addSuperClasses(int sup, UmpleClass c)
{
if(sup==0 || c.getExtendsClass()==null)
{
return;
}
else
{
c.getExtendsClass().setFilteredin(true);
addSuperClasses(sup-1, c.getExtendsClass());
}
}
private void addSuperClasses(UmpleClass c)
{
if(c.getExtendsClass()==null)
{
return;
}
else
{
c.getExtendsClass().setFilteredin(true);
addSuperClasses(c.getExtendsClass());
}
}
private void addSubClasses(int sub, UmpleClass c)
{
if(sub==0)
{
return;
}
else
{
for(UmpleClass s : c.getSubclasses())
{
s.setFilteredin(true);
addSubClasses(sub-1,s);
}
}
}
public Filter getFilter(String name)
{
for (Filter aFilter : getFilters())
{
if(aFilter.getName() != null)
{
if (aFilter.getName().equals(name))
return aFilter;
}
else if(name==null)
{
return aFilter;
}
}
return null;
}
/*
* Extracts Analyzers from a <code>RuleBasedParser</code>, assigning the
* analyzers to this model
*
* @param parser the <code>RuleBasedParser</code> to extract parsers from.
*/
public void extractAnalyzersFromParser( RuleBasedParser parser ){
setAnalyzers(parser.getAnalyzer().getAnalyzerMap());
}
// Issue 1008 - Helper function to determine if the Umple Model has a particular enumeration
public boolean hasEnum(String enumName) {
for (UmpleEnumeration uEnum : getEnums()) {
if (uEnum.getName().equals(enumName)) {
return true;
}
}
return false;
}
}
/*
*/
class Key
{
public boolean isProvided()
{
return isDefault || members.size() > 0;
}
public boolean isMember(String name)
{
return (name == null) ? false : indexOfMember(name) != -1;
}
public boolean isMember(UmpleVariable av)
{
return (av == null) ? false : isMember(av.getName());
}
}
/*
*/
class Depend
{
public String getPackageName()
{
if (name == null || "".equals(name))
{
return "";
}
int dotIndex = name.lastIndexOf(".");
return dotIndex >= 0 ? name.substring(0,dotIndex) : name;
}
}
/**
* This is for cloning
* Note: This code doesn't cover deep cloning. It's a combination of shallow and deep cloning
*/
class Method
{
/**
* This is for cloning
* Note: This code doesn't cover deep cloning. It's a combination of shallow and deep cloning
*/
public Method(Method another) {
this.isAbstract = another.getIsAbstract();
this.modifier = another.getModifier();
this.name = another.getName() ;
this.position = another.getPosition();
this.codePosition = another.getCodePosition();
this.endPosition = another.getEndPosition();
this.type = another.getType();
this.isImplemented = another.getIsImplemented();
this.methodParameters = new ArrayList<MethodParameter>();
this.exceptions = new ArrayList<String>();
for (MethodParameter mParameter : another.getMethodParameters()) {
this.methodParameters.add(new MethodParameter(mParameter));
}
for (String exception:exceptions)
{
this.addException(exception);
}
if (another.getMethodBody()!=null){
this.methodBody = new MethodBody(another.getMethodBody());
} else{
this.methodBody = another.getMethodBody();
}
this. comments = another.getComments();
}
public boolean getExistsInLanguage(String lang)
{
if (!hasMethodBody()){
return false;
}
CodeBlock codeBlock = getMethodBody().getCodeblock();
// Check if another language other than 'lang' is associated with the codeblock
if (codeBlock.hasAnAssociatedLanguage() && !codeBlock.hasCode(lang)){
return false;
}
return true;
}
public String toString()
{
StringBuffer methodBuffer = new StringBuffer();
methodBuffer.append(" " + this.getType()+ " " + this.getName());
methodBuffer.append("(");
String paramName="";
String paramType="";
String aSingleParameter="";
String isList="";
String parameters = "";
String finalParams= "";
if (this.hasMethodParameters()){
for (MethodParameter aMethodParam : this.getMethodParameters())
{
paramName = aMethodParam.getName();
paramType = aMethodParam.getType();
isList = aMethodParam.getIsList() ? " [] " : " ";
aSingleParameter = paramType + isList + paramName;
parameters += aSingleParameter + ",";
}
finalParams = parameters.substring(0, parameters.length()-1);
methodBuffer.append(finalParams);
}
methodBuffer.append(")");
methodBuffer.append(" {");
methodBuffer.append(System.getProperty("line.separator"));
methodBuffer.append( this.getMethodBody().getExtraCode());
methodBuffer.append(System.getProperty("line.separator"));
methodBuffer.append(" }");
return methodBuffer.toString();
}
public boolean equals(Object o)
{
if (o == this) return true;
if (!(o instanceof Method)) return false;
Method comparedMethod = (Method) o;
String methodName = comparedMethod.getName();
String methodType = comparedMethod.getType();
int numberOfParams = comparedMethod.getMethodParameters().size();
if (comparedMethod.isIsConstructor()) return comparedMethod == this;
if (this.getName().equals(methodName))
{
if (numberOfParams == this.getMethodParameters().size())
{
boolean allSame = true;
for (int i = 0; i < numberOfParams; i++)
{
if(!this.getMethodParameter(i).getType().equals(comparedMethod.getMethodParameter(i).getType()))
{
allSame = false;
//break;
}
}
if(allSame) return true;
}
}
return false;
}
}
/*
*/
class MethodBody
{
public MethodBody(MethodBody another) {
codeblock = new CodeBlock(another.getCodeblock());
}
public MethodBody(String aValue)
{
this(new CodeBlock(aValue!=null ? aValue : ""));
}
public String getExtraCode(String lang)
{
return codeblock.getCode(lang);
}
public void setExtraCode(String lang, String code)
{
codeblock.setCode(lang,code);
}
}
class MethodParameter
{
/**
* This is for cloning
* Note: This code doesn't cover deep cloning. It's a combination of shallow and deep cloning
*/
public MethodParameter(MethodParameter another){
super(another.getName(), another.getType(), another.getModifier(), another.getValue());
this.isAutounique = another.getIsAutounique();
this.isList = another.getIsList();
this.isDerived = another.getIsDerived();
this.isLazy = another.getIsLazy();
}
public String getFullType()
{
return this.getType() + (this.getIsList() ? "[]" : "");
}
}
/*
*
*/
class CodeBlock
{
/*
* @author Vahdat
* @param another a CodeBlock that we would like to make a clone of.
* Please maintain this method if you're going to add new attributes to the class CodeBlock.
* This code manually creates a clone of a state machine.
*
*/
public CodeBlock(CodeBlock another){
this.name = another.getName();
this.codes = new HashMap<String,String>();
this.codes.putAll(another.codes);
}
/*
* @author Vahdat
*/
public void ApplyTypeParameters(GeneralTPApplied inGeneralTPApplied, UmpleTrait inTrait){
if (inGeneralTPApplied == null && inTrait.numberOfGeneralTemplateParameters()==0) return;
Integer start=0,end=0;
boolean inProcess = false;
String internalCode = "";
for (String language : codes.keySet()) {
String code = codes.get(language);
start=0;
end=0;
inProcess = false;
internalCode = "";
for (int i=0;i<code.length();i++) {
if (code.charAt(i)=='#' &&!inProcess){
inProcess=true;
start = i;
continue;
}
if (code.charAt(i)=='#' && inProcess){
inProcess=false;
end=i;
String strTemp = code.substring(start+1, end);
Boolean replaced = false;
for(GeneralTemplateParameter gtp : inTrait.getGeneralTemplateParameters()){
if (strTemp.equals(gtp.getName())){
String newName = (inGeneralTPApplied!=null && inGeneralTPApplied.getParameterMapping().containsKey(gtp.getName())) ? inGeneralTPApplied.getParameterMapping().get(gtp.getName()) : gtp.getDefaultValue();
internalCode = internalCode+newName;
replaced = true;
break;
}
}
if (!replaced) {
internalCode = internalCode+"#"+strTemp;
} else{
continue;
}
}
if (!inProcess){
internalCode = internalCode+code.charAt(i);
}
}
codes.put(language, internalCode);
}
}
/*
* @author Vahdat
* The following part of code may not generate proper code-style code generation.
* Currently, we deal with code style at the code generation level (UmpleTemplate Language);
*/
public void findKeywordAndReplace(String keyword, CodeBlock cBlock, StateMachine inStateMachine){
if(keyword==null || keyword=="") return;
for (String language : codes.keySet()) {
String replacement=System.lineSeparator()+"\t\t//This part of code comes from the trait '"+inStateMachine.getRootStateMachine().getUmpleTrait().getName()+"' -> begins"+System.lineSeparator()+"\t\t";
replacement = replacement+cBlock.codes.get(language).replace(keyword, "");
replacement=replacement+System.lineSeparator()+"\t\t//The code coming from trait '"+inStateMachine.getRootStateMachine().getUmpleTrait().getName()+"' ends here"+System.lineSeparator()+"\t\t";
codes.put(language,codes.get(language).replace(keyword,replacement+keyword)) ;
}
}
/*
* @author Vahdat
*/
public void removeKeyword(String keyword){
if(keyword==null || keyword=="") return;
for (String language : codes.keySet()) {
codes.put(language, codes.get(language).replace(keyword,"")) ;
}
}
/*
* @author Vahdat
*/
public void addKeyword(String keyword){
if(keyword==null || keyword=="") return;
// if (codes.isEmpty()) {
// setCode(keyword);
// return;
// }
for (String language : codes.keySet()) {
codes.put(language, codes.get(language)+keyword) ;
}
}
/*
* @author Vahdat
* This function searches for a specific keyword in all langauges in the code blocks.
*/
public boolean hasKeyword(String keyword){
if(keyword==null || keyword=="") return false;
for (String language : codes.keySet()) {
if (codes.get(language).contains(keyword)) return true;
}
return false;
}
public CodeBlock(String add)
{
this();
codes.put("",add);
}
public CodeBlock(String lang, String add)
{
this();
codes.put(lang,add);
}
public void setCode(String add)
{
if(add!=null)
codes.put("",add);
else
codes.put("","");
}
public void setCode(String lang, String add)
{
if(add!=null)
codes.put(lang,add);
else
codes.put(lang,"");
}
public String getCode()
{
return !codes.containsKey(languageUsed) ? "".equals(languageUsed) ? null : codes.get("") : codes.get(languageUsed);
}
public String getCode(String lang)
{
return codes.containsKey(lang)? codes.get(lang) : "";
}
public boolean hasCode(String lang)
{
return codes.containsKey(lang)? true : false;
}
// Will return true if any language has been associated with this code block
public boolean hasAnAssociatedLanguage()
{
for (String codeLang : codes.keySet())
{
if (codeLang != "")
{
return true;
}
}
return false;
}
public String toString(){
String out = "";
for(String next:codes.values())
{
out += next;
}
return out;
}
}
/*
*/
class CodeInjection
{
public CodeInjection(String a, String b, String c, UmpleClassifier d)
{
this(a,b,new CodeBlock(c), d);
}
public void setCode(String str)
{
snippet.setCode(str);
}
public String getCode()
{
return snippet.getCode();
}
public String getConstraintCode(CodeTranslator gen)
{
return StringFormatter.format(gen.translate("Closed",constraintTree),getCode());
}
public void setCode(String lang, String code)
{
snippet.setCode(lang, code);
}
public String getCode(String lang)
{
return snippet.getCode(lang);
}
}
class ExtraCode
{
public void appendExtraCode(String newCode)
{
code.add(new CodeBlock(newCode));
}
public void appendExtraCode(CodeBlock cb)
{
code.add(cb);
}
public String getExtraCode()
{
String returnCode = "";
if(getHasCode())
{
for(CodeBlock cb : code)
{
String temp = cb.getCode();
returnCode += (temp == null ? "" : temp);
}
}
return returnCode;
}
public boolean getHasCode()
{
return code.size() > 0;
}
}
/*
*/
class UmpleElement
{
public void appendExtraCode(String newCode)
{
appendExtraCode(newCode,true);
}
public void resetExtraCode()
{
extraCode = new ExtraCode();
}
public void appendExtraCode(String newCode, boolean addNewline)
{
if (newCode == null)
{
return;
}
if (extraCode.getHasCode() && addNewline)
{
newCode = System.getProperty("line.separator") + newCode;
}
extraCode.appendExtraCode(newCode);
}
public void appendExtraCode(boolean flag, CodeBlock cb)
{
extraCode.appendExtraCode(cb);
}
public boolean hasExtraCode()
{
return extraCode.getHasCode();
}
public String getExtraCode()
{
return extraCode.getExtraCode();
}
}
/*
*/
class AssociationClass
{
public AssociationClass(String name)
{
this(name, null);
}
public void addMissingKeyIfNeeded()
{
Key key = getKey();
if (!key.isProvided())
{
key = new Key();
for(Association associatedTo: getAssociatedTo())
{
key.addMember(associatedTo.getEnd(1).getRoleName());
}
key.setIsInternal(true);
setKey(key);
}
}
}
class UmpleClassifier{
depend java.nio.file.*;
depend cruise.umple.compiler.*;
/*
Counts the number of occurrences of the character <code>needle</code> in the
supplied string <code>haystack</code>.
@param haystack the string to search for
@param needle the character to find
@return the number of occurrences of that character
*/
private static int countOccurrences(String haystack, char needle)
{
int count = 0;
for (int i = 0; i < haystack.length(); ++i)
{
if (haystack.charAt(i) == needle)
{
++count;
}
}
return count;
}
/*
Replaces all instances of '\' with '/' in path strings
@param str a string path to change
@return the new string
*/
private static String deWindowsify(String str)
{
return str.replace('\\','/');
}
/*
Obtains the relative path between the source file for the UmpleClassifier and
and the package name given the target language
@param filename the file name to get the relative path from
@param language The language target to compare
@return The string relative path between the parent and position
*/
public String getRelativePath(String filename, String language)
{
String p = getPackageName();
if (filename == null)
{
return "";
}
//Find path relative to namespace folders
String packageName = getPackageName();
if (packageName == null || packageName.equals(""))
{ //No package, file is output in current directory
return Paths.get(filename).getFileName().toString();
}
else
{ //Has a package, add appropriate number of ..
int pathCount = countOccurrences(packageName, '.') + 1;
StringBuilder build = new StringBuilder();
for (int i = 0; i < pathCount; i++)
{
build.append("../");
}
//Add on relative path from generator location
if (getSourceModel() == null)
{
build.append(Paths.get(filename).getFileName());
return deWindowsify(build.toString());
}
Path currentPath = Paths.get(getSourceModel().getUmpleFile().getPath()).toAbsolutePath();
Path generatesPath = null;
GenerateTarget [] generates = getSourceModel().getGenerates();
for (int i = 0; i < generates.length; i++)
{
if (generates[i].getLanguage().equals(language))
{
generatesPath = currentPath.resolve(Paths.get(generates[i].getPath())).normalize();
}
}
if (generatesPath != null)
{
Path result = generatesPath.relativize(currentPath);
if (!result.equals(Paths.get("")))
{
result = result.normalize();
build.append(result.toString() + '/');
}
}
build.append(Paths.get(filename).getFileName());
return deWindowsify(build.toString());
}
}
public boolean hasMethod(Method comparedMethod){
String methodName = comparedMethod.getName();
String methodType = comparedMethod.getType();
int numberOfParams = comparedMethod.getMethodParameters().size();
for (Method aMethod : this.getMethods()){
// Compare method names
if (aMethod.getName().equals(methodName)){
// Now compare parameters
if (numberOfParams == aMethod.getMethodParameters().size())
{
boolean allSame = true;
for (int i = 0; i < numberOfParams; i++)
{
if(!aMethod.getMethodParameter(i).getType().equals(comparedMethod.getMethodParameter(i).getType()))
{
allSame = false;
break;
}
}
if(allSame)
{
if (aMethod.getSource()==Method.Source.fAuto){
this.removeMethod(aMethod);
return false;
}
return true;
}
}
}
}
return false;
}
}
/*
* In Umple_Code.ump: Methods for computing complex properties
*/
class UmpleClass
{
public Method getAutoGeneratedConstructor()
{
for (Method aMethod : this.getMethods())
{
if (aMethod.getIsConstructor())
{
return aMethod;
}
}
return null;
}
public boolean hasMethodInTraits (Method aMethod) {
for (UmpleTrait uTrait : getExtendsTraits()) {
if (uTrait.hasCascadeMethod(aMethod,true) || uTrait.hasCascadeMethod(aMethod,false)) {
return true;
}
}
return false;
}
after setExtendsClass {
if(aExtendsClass!=null&&aExtendsClass.getMethods()!=null)
for(Method method:aExtendsClass.getMethods())
{
if(this.hasMethod(method))
{
Method aMethod = this.getMethod(method);
if(aMethod.getMethodBody().getExtraCode("")==null||"".equals(aMethod.getMethodBody().getExtraCode("")))
{
aMethod.getMethodBody().setExtraCode("",method.getMethodBody().getExtraCode(""));
while(aMethod.hasMethodParameters())
{
aMethod.removeMethodParameter(aMethod.getMethodParameter(0));
}
for(MethodParameter mp:method.getMethodParameters())
{
aMethod.addMethodParameter(mp);
}
if(!"".equals(aMethod.getMethodBody().getExtraCode("")))
{
aMethod.setIsImplemented(false);
}
}
}
}
}
public UmpleClass(String name)
{
this(name, null);
}
public List<StateMachine> getAllStateMachines()
{
ArrayList<StateMachine> all = new ArrayList<StateMachine>();
all.addAll(getStateMachines());
for (StateMachine sm : getStateMachines())
{
all.addAll(sm.getNestedStateMachines());
}
return all;
}
public List<TraceDirective> getAllTraceDirectives(){
ArrayList<TraceDirective> all = new ArrayList<TraceDirective>();
all.addAll(getTraceDirectives());
for(TraceCase tc : getTraceCases())
if( tc.getActivation() == true )
for(TraceDirective td : tc.getTraceDirectives())
all.add(td);
return all;
}
public ArrayList<String> getMethodNames()
{
ArrayList<String> methodNames = new ArrayList<String>();
for(Attribute attr : this.getAttributes())
{
methodNames.addAll(attr.getMethodNames());
}
for(AssociationVariable av : this.getAssociationVariables())
{
methodNames.addAll(av.getMethodNames());
}
for(StateMachine sm : this.getStateMachines())
{
String stateMachineName = sm.getName().substring(0, 1).toUpperCase() + sm.getName().substring(1);
methodNames.add("set" + stateMachineName);
methodNames.add("get" + stateMachineName);
for(Event ev : sm.getEvents())
{
methodNames.add(ev.getName());
}
}
for (Method m: this.getMethods()) {
if (!isGetterSetter(m) && !m.isIsConstructor()) {
methodNames.add(m.getName());
}
}
methodNames.add("constructor");
methodNames.add("delete");
methodNames.add("toString");
return methodNames;
}
// line 1869 "../../../../src/UmpleInternalParser_CodeClass.ump"
private boolean isGetterSetter(Method method){
if (method.getName().length() <= 2)
return false;
String accessorName = method.getName().substring(0,3);
return ((accessorName.equals("get")) || (accessorName.equals("set"))) && method.getSource() == Method.Source.fAutoAPI && !method.getIsConstructor();
}
public Boolean matchOperationMethod(String fullOperation, String method) {
String formattedMethod = method;
TriState isMatch = new TriState(false);
TriState isMatchOnExclude = new TriState(true);
String[] allOperations = fullOperation.split(",");
for (String operation : allOperations)
{
boolean isNot = false;
if (operation.startsWith("!"))
{
isNot = true;
operation = operation.substring(1);
}
String regexOperation = operation;
regexOperation = regexOperation.replace("_*", "*");
regexOperation = regexOperation.replace("*", ".*");
boolean isCurrentMatch = formattedMethod.matches(regexOperation);
if (isNot && isCurrentMatch)
{
isMatch.setStatus(false);
isMatchOnExclude.setStatus(false);
}
else if (!isNot && isCurrentMatch)
{
isMatch.setStatus(true);
}
}
return isMatchOnExclude.isTrue() || isMatch.isTrue();
}
// Gets applicable code injectiosn for generated methods
public List<CodeInjection> getApplicableCodeInjections(String type, String method)
{
ArrayList<CodeInjection> all = new ArrayList<CodeInjection>();
if (type == null || method == null)
{
return all;
}
String formattedMethod = method;
for (CodeInjection code : getCodeInjections())
{
if (code.getOperation() == null || !type.equals(code.getType()) || !("all".equals(code.getOperationSource()) || "generated".equals(code.getOperationSource())))
{
continue;
}
boolean isAllExcludes = true;
TriState isMatch = new TriState(false);
TriState isMatchOnExclude = new TriState(true);
String[] allOperations = code.getOperation().split(",");
for (String operation : allOperations)
{
boolean isNot = false;
if (operation.startsWith("!"))
{
isNot = true;
operation = operation.substring(1);
}
else
{
isAllExcludes = false;
}
isMatchOnExclude.setIsSet(true);
String regexOperation = operation;
regexOperation = regexOperation.replace("_*", "*");
regexOperation = regexOperation.replace("*", ".*");
boolean isCurrentMatch = formattedMethod.matches(regexOperation);
if (isNot && isCurrentMatch)
{
isMatch.setStatus(false);
isMatchOnExclude.setStatus(false);
}
else if (!isNot && isCurrentMatch)
{
isMatch.setStatus(true);
}
}
if ((isAllExcludes && isMatchOnExclude.isTrue()) || isMatch.isTrue())
{
all.add(code);
}
}
return all;
}
// Gets applicable code injectiosn for custom defined methods
public List<CodeInjection> getApplicableCodeInjectionsCustomMethod(String type, String method, List<MethodParameter> parameters)
{
ArrayList<CodeInjection> all = new ArrayList<CodeInjection>();
if (type == null || method == null)
{
return all;
}
String formattedMethod = method;
for (CodeInjection code : getCodeInjections())
{
if (code.getOperation() == null || !type.equals(code.getType()) || !("all".equals(code.getOperationSource()) || "custom".equals(code.getOperationSource())))
{
continue;
}
boolean isAllExcludes = true;
TriState isMatch = new TriState(false);
TriState isMatchOnExclude = new TriState(true);
String[] allOperations = code.getOperation().split(",");
for (int opInd = 0; opInd < allOperations.length; opInd++)
{
String operation = allOperations[opInd];
boolean isNot = false;
if (operation.startsWith("!"))
{
isNot = true;
operation = operation.substring(1);
}
else
{
isAllExcludes = false;
}
isMatchOnExclude.setIsSet(true);
String regexOperation = operation;
regexOperation = regexOperation.replace("_*", "*");
regexOperation = regexOperation.replace("*", ".*");
regexOperation = regexOperation.replace("_~", "");
boolean isCurrentMatch = formattedMethod.matches(regexOperation);
boolean isParameterMatch = true;
String currentParameters = code.getParameters()[opInd];
if((parameters.size() == 0 && "".equals(currentParameters)) || "...".equals(currentParameters)) {
isParameterMatch = true;
}
else if(parameters.size() != currentParameters.split(",").length)
{
isParameterMatch = false;
}
else {
int indx = 0;
for(String parameterType : currentParameters.split(",")) {
if(!parameterType.equals(parameters.get(indx).getType())) {
isParameterMatch = false;
}
indx++;
}
}
isCurrentMatch &= isParameterMatch;
if (isNot && isCurrentMatch)
{
isMatch.setStatus(false);
isMatchOnExclude.setStatus(false);
}
else if (!isNot && isCurrentMatch)
{
isMatch.setStatus(true);
}
}
if ((isAllExcludes && isMatchOnExclude.isTrue()) || isMatch.isTrue())
{
all.add(code);
}
}
return all;
}
public List<StateMachine> getStateMachines(Event e)
{
List<StateMachine> allStateMachines = new ArrayList<StateMachine>();
for (StateMachine sm : getAllStateMachines())
{
List<Event> allEvents = sm.getEvents();
if (allEvents.contains(e))
{
allStateMachines.add(sm);
}
}
return allStateMachines;
}
public List<Event> getEvents()
{
List<Event> allEvents = new ArrayList<Event>();
for (StateMachine sm : getAllStateMachines())
{
allEvents.addAll(sm.getEvents());
}
List<Event> allUniqueEvents = new ArrayList<Event>();
for (Event e : allEvents)
{
if (!allUniqueEvents.contains(e))
{
allUniqueEvents.add(e);
}
}
return allUniqueEvents;
}
public Event findOrCreateEvent(String aName)
{
if (aName == null)
{
return null;
}
for (StateMachine sm : getStateMachines())
{
for (Event aEvent : sm.getAllEvents())
{
if (aName.equals(aEvent.getName()))
{
return aEvent;
}
}
}
return new Event(aName);
}
public StateMachine getStateMachine(String name)
{
for (StateMachine sm : stateMachines)
{
if (sm.getName().equals(name))
{
return sm;
}
}
return null;
}
public void addReferencedPackage(String aNamespace)
{
if (indexOfNamespace(aNamespace) == -1 && !aNamespace.equals(getPackageName()))
{
addNamespace(aNamespace);
}
}
// It can happen that one class has multiple association variables with the same name
public AssociationVariable getAssociationVariable(String className, String roleName)
{
for (AssociationVariable av : associationVariables)
{
if (av.getName().equals(roleName) && av.getType().equals(className))
{
return av;
}
}
return null;
}
public AssociationVariable getAssociationVariable(String name)
{
for (AssociationVariable av : associationVariables)
{
if (av.getName().equals(name))
{
return av;
}
}
return null;
}
public AssociationVariable getAssociationVariableFor(UmpleClass uClass)
{
for (AssociationVariable av : associationVariables)
{
if (av.getType().equals(uClass.getName()))
{
return av;
}
}
return null;
}
public boolean hasImplementedMethodIncludingWithinParentClasses(Method comparedMethod) {
Method aMethod = getMethod(comparedMethod);
if(aMethod!=null&&!aMethod.isIsAbstract()){
return true;
}
if (numberOfStateMachines()>0){
for(StateMachine sm : getStateMachines()){
if (sm.getEventByMethod(comparedMethod)!=null){
return true;
}
}
}
if(getExtendsClass()!=null&&getExtendsClass().hasImplementedMethodIncludingWithinParentClasses(comparedMethod)){
return true;
}
return false;
}
//Issue 771
public boolean hasSameType(Method comparedMethod){
String methodType = comparedMethod.getType();
for (Method aMethod : this.getMethods()){
if(aMethod.getType().equals(methodType)){
return true;
}
}
return false;
}
public Method getMethod(Method comparedMethod){
String methodName = comparedMethod.getName();
int numberOfParams = comparedMethod.getMethodParameters().size();
for (Method aMethod : this.getMethods()){
// Compare method names
if (aMethod.getName().equals(methodName)){
// Now compare parameters
if (numberOfParams == aMethod.getMethodParameters().size())
{
boolean allSame = true;
for (int i = 0; i < numberOfParams; i++)
{
if(!aMethod.getMethodParameter(i).getType().equals(comparedMethod.getMethodParameter(i).getType()))
{
allSame = false;
break;
}
}
if(allSame)
{
return aMethod;
}
}
}
}
return null;
}
public boolean hasAllAttributes()
{
return getAllAttributes().size() > 0;
}
public List<Attribute> getAllAttributes()
{
List<Attribute> all = new ArrayList<Attribute>();
// Get all it's inherited attributes
if (this.hasExtendsClass()) {
UmpleClass parent = this.getExtendsClass();
List<Attribute> allParent = parent.getAllAttributes();
all.addAll(allParent);
}
all.addAll(getAttributes());
return all;
}
public Attribute getAttribute(String name)
{
for (Attribute av : getAllAttributes())
{
if (av.getName().equals(name))
{
return av;
}
}
return null;
}
public boolean isRoot()
{
return extendsClass == null;
}
protected GeneratedClass gClass = null;
public GeneratedClass getGeneratedClass()
{
return gClass;
}
public GeneratedClass createGeneratedClass(UmpleModel model)
{
gClass = new GeneratedClass(model, this);
if (getExtendsClass() != null)
{
gClass.setParentClass(getExtendsClass().getGeneratedClass());
}
return getGeneratedClass();
}
public boolean isAttributeClass()
{
for (AssociationVariable association : getAssociationVariables())
{
if (association.getIsNavigable())
{
return false;
}
}
return true;
}
/* @return true if this class is immutable, either because it has the "immutable" modifier or
* because an ancestor class is immutable; false if this class neither has the "immutable" modifier
* nor an immutable ancestor.
*/
public boolean isImmutable()
{
return (iAmImmutable || ancestorIsImmutable);
}
public boolean setImmutable()
{
boolean wasSet = false;
if (extendsClass != null && !ancestorIsImmutable) { return wasSet; }
if (propagateImmutabilityToAllRelationships(true))
{
iAmImmutable = true;
wasSet = true;
}
return wasSet;
}
internal const Integer CounterLimit = 25; //Arbitary Limit
Integer propagateCounter = CounterLimit;
private boolean propagateImmutabilityToAllRelationships(boolean isImmutable)
{
setPropagateCounter(getPropagateCounter() - 1); //Reduce by 1 for each call
if (isImmutable)
{
if (this.hasStateMachines()) { return false; }
for (AssociationVariable av : associationVariables)
{
if (!immutabilityAssociationRulesSatisfied(av, true)) { return false; }
}
}
if( getPropagateCounter() == 0 ) {
setPropagateCounter(CounterLimit);
return true;
}
else{
return notifySubclassesAncestorImmutable(isImmutable);
}
}
private boolean notifySubclassesAncestorImmutable(boolean isImmutable)
{
boolean notified = true;
List<UmpleClass> wereSet = new ArrayList<UmpleClass>();
for (UmpleClass subclass : getSubclasses())
{
notified = subclass.setAncestorIsImmutable(isImmutable);
if (!notified)
{
for (UmpleClass wasSet : wereSet)
{
wasSet.setAncestorIsImmutable(!isImmutable);
}
return notified;
}
}
return notified;
}
protected boolean setAncestorIsImmutable(boolean isImmutable)
{
if (iAmImmutable)
{
ancestorIsImmutable = isImmutable;
return true;
}
else
{
boolean success = propagateImmutabilityToAllRelationships(isImmutable);
if (success) { ancestorIsImmutable = isImmutable; }
return success;
}
}
private boolean enforceImmutabilityInheritanceRules(UmpleClass newSuperClass)
{
// A subclass may not be immutable if the superclass is not immutable
if (iAmImmutable && newSuperClass != null && !newSuperClass.isImmutable()) { return false; }
boolean ancestorImmutable = (newSuperClass == null) ? false : newSuperClass.isImmutable();
return setAncestorIsImmutable(ancestorImmutable);
}
protected static boolean immutabilityAssociationRulesSatisfied(AssociationVariable myAV, UmpleClass myClass, boolean myClassImmutable,
AssociationVariable yourAV, UmpleClass yourClass, boolean yourClassImmutable)
{
boolean satisfied = false;
if (myAV == null || yourAV == null)
{
satisfied = true;
}
else if (!myClassImmutable && !yourClassImmutable && !"immutable".equals(myAV.getModifier()) && !"immutable".equals(yourAV.getModifier()))
{
satisfied = true;
}
else if (myAV.getIsNavigable() && yourAV.getIsNavigable())
{
//satisfied = false;
}
else if (myClass == null && yourClass == null)
{
satisfied = true;
}
else if (!yourAV.getIsNavigable() && (yourClass == null || yourClassImmutable))
{
if (yourClass != null && yourClass == myClass && myAV.isMandatory())
{
// reflexive associations may not be mandatory:
//satisfied = false
}
else
{
satisfied = true;
}
}
else if (!myAV.getIsNavigable() && (myClass == null || myClassImmutable))
{
if (myClass != null && yourClass == myClass && yourAV.isMandatory())
{
// reflexive associations may not be mandatory:
//satisfied = false
}
else
{
satisfied = true;
}
}
return satisfied;
}
protected boolean immutabilityAssociationRulesSatisfied(AssociationVariable myAV, boolean myClassImmutable)
{
AssociationVariable relatedAV = myAV.getRelatedAssociation();
UmpleClass relatedClass = (relatedAV == null) ? null : relatedAV.getUmpleClass();
boolean relatedClassImmutable = (relatedClass == null) ? false : ((relatedClass == this) ? myClassImmutable : relatedClass.isImmutable());
return immutabilityAssociationRulesSatisfied(myAV, this, myClassImmutable, relatedAV, relatedClass, relatedClassImmutable);
}
public boolean deleteAttribute(Attribute aAttribute)
{
boolean wasRemoved = false;
//Unable to remove aAttribute, as it must always have a umpleClass
if (this.equals(aAttribute.getUmpleClass()))
{
attributes.remove(aAttribute);
wasRemoved = true;
}
return wasRemoved;
}
public void removeAllAutoGeneratedMethods()
{
List<Method> methodsCopy = new ArrayList<Method>(this.getMethods());
for (Method m: methodsCopy)
{
if (m.getSource() == Method.Source.fAutoAPI)
removeMethod(m);
}
}
public void removeAutoGenerateMethodsForAttribute(Attribute attribute)
{
String attributeName = attribute.getName();
String firstLetter = attributeName.substring(0,1).toUpperCase();
String rest = "";
if (attributeName.length() > 1)
{
rest = attributeName.substring(1);
}
String getName = "get" + firstLetter + rest;
String setName = "set" + firstLetter + rest;
List<Method> methodsCopy = new ArrayList<Method>(this.getMethods());
for (Method m : methodsCopy)
{
if (m.getName().equals(getName) && m.getMethodParameters().size() == 0)
removeMethod(m);
else if (m.getName().equals(setName) && m.getMethodParameters().size() == 1
&& m.getMethodParameter(0).getType().equals(attribute.getType()))
removeMethod(m);
}
}
public void removeAttributeFromAutogeneratedConstructor(Attribute aAttribute)
{
Method constructor = this.getAutoGeneratedConstructor();
if (constructor != null)
{
String attributeName = aAttribute.getName();
String parameterName = "a" + attributeName.substring(0,1).toUpperCase();
if (attributeName.length() > 1)
{
parameterName += attributeName.substring(1);
}
MethodParameter toRemove = null;
for (MethodParameter mp : constructor.getMethodParameters())
{
if (mp.getName().equals(parameterName) && mp.getFullType().equals(aAttribute.getType()))
{
toRemove = mp;
break;
}
}
if (toRemove != null)
{
constructor.removeMethodParameter(toRemove);
}
}
}
after removeAttribute {
if (wasRemoved)
{
this.removeAttributeFromAutogeneratedConstructor(aAttribute);
}
}
// Issue 1008 - Helper function to determine if the Umple Class has a particular enumeration
public boolean hasEnum(String enumName) {
for (UmpleEnumeration uEnum : getEnums()) {
if (uEnum.getName().equals(enumName)) {
return true;
}
}
return false;
}
}
/*
*/
class UmpleVariable
{
public String getUpperCaseName()
{
if (name == null || name.length() == 0)
{
return name;
}
else if (name.length() == 1)
{
return name.toUpperCase();
}
else
{
return name.toUpperCase().charAt(0) + name.substring(1);
}
}
public boolean isImmutable()
{
return "immutable".equals(modifier);
}
public String normalizeValue(String aType, String aValue)
{
if (aType == null || aValue == null || aValue.length() == 0)
{
return aValue;
}
else if (("Float".equals(aType)) && ("f".equals(aValue.substring(aValue.length()-1))))
{
return aValue.substring(0, aValue.length()-1);
}
else
{
return aValue;
}
}
}
/*
*/
class Attribute
{
public Attribute(Attribute another){
super(another.getName(), another.getType(), another.getModifier(), another.getValue());
isAutounique = another.getIsAutounique() ;
isUnique = another.getIsUnique();
isList = another.getIsList();
isDerived = another.getIsDerived();
codeblock = another.getCodeblock();
isLazy = another.getIsLazy();
//Attribute Associations
comments = another.getComments();
position = another.getPosition();
endPosition = another.getEndPosition();
umpleClass = another.getUmpleClass();
umpleTrait = another.getUmpleTrait();
}
public boolean isConstant()
{
return "const".equals(getModifier());
}
public boolean isPrimitive()
{
return getType() == null || "String".equals(getType()) || "Integer".equals(getType()) || "Double".equals(getType()) || "Boolean".equals(getType()) || "Date".equals(getType()) || "Time".equals(getType());
}
public boolean isImmutable()
{
boolean varIsImmutable = super.isImmutable();
boolean classIsImmutable = (this.getUmpleClass() == null) ? false : getUmpleClass().isImmutable();
return (varIsImmutable || classIsImmutable);
}
public boolean isInternal()
{
return "internal".equals(getModifier());
}
public boolean isSettable()
{
return "settable".equals(getModifier());
}
public boolean isDefaulted()
{
return "defaulted".equals(getModifier());
}
public String getValue()
{
String possibleValue = codeblock.getCode();
return "".equals(possibleValue) ? super.getValue() : possibleValue;
}
public boolean setValue(String aValue)
{
aValue = normalizeValue(getType(),aValue);
codeblock.setCode(aValue);
return super.setValue(aValue);
}
public boolean setValue(String lang, String code)
{
codeblock.setCode(lang,code);
return true;
}
public String getFullType()
{
return this.getType() + (this.getIsList() ? "[]" : "");
}
public ArrayList<String> getMethodNames()
{
ArrayList<String> methodNames = new ArrayList<String>();
String attributeCapitalizedName = this.getUpperCaseName();
if (!this.isIsList())
{
if(!this.isInternal())
{
methodNames.add("get" + attributeCapitalizedName);
}
if(this.isIsLazy() || this.isSettable() || this.isDefaulted())
{
methodNames.add("set" + attributeCapitalizedName);
}
if(this.isDefaulted())
{
methodNames.add("reset" + attributeCapitalizedName);
methodNames.add("getDefault" + attributeCapitalizedName);
}
if(this.getType() != null && this.getType().equals("Boolean"))
{
methodNames.add("is" + attributeCapitalizedName);
}
}
else
{
String singularName = getUmpleClass().getSourceModel().getGlossary().getSingular(this.getName());
String singularCapitalizedName = singularName.substring(0, 1).toUpperCase() + singularName.substring(1);
if(!this.isInternal())
{
methodNames.add("get" + singularCapitalizedName);
methodNames.add("get" + attributeCapitalizedName);
methodNames.add("numberOf" + attributeCapitalizedName);
methodNames.add("has" + attributeCapitalizedName);
methodNames.add("indexOf" + singularCapitalizedName);
}
if(this.isIsLazy() || this.isSettable() || this.isDefaulted())
{
methodNames.add("add" + singularCapitalizedName);
methodNames.add("remove" + singularCapitalizedName);
}
}
return methodNames;
}
}
/*
*/
class Association
{
public Association(Association another){
//Association Attributes
this.name = another.getName();
this.isLeftNavigable = another.getIsLeftNavigable();
this.isRightNavigable = another.getIsRightNavigable();
this.isLeftComposition = another.getIsLeftComposition();
this.isRightComposition = another.getIsRightComposition();
this.positions = new ArrayList<Coordinate>();
for (Coordinate coordinate : another.getPositions()) {
this.positions.add(coordinate);
}
this.tokenPosition = another.getTokenPosition();
this.tokenEndPosition = another.getTokenEndPosition();
this.immutable = another.immutable;
//Association Associations
this.ends = new ArrayList<AssociationEnd>();
for (AssociationEnd associationEnd : another.getEnds()) {
this.ends.add(new AssociationEnd(associationEnd));
}
}
public void setLeftAndRight()
{
String name = this.getName();
int underscore = name.indexOf("__");
String nameOne = name.substring(0,underscore);
String nameTwo = name.substring(underscore + "__".length(), name.length());
if (nameOne.compareTo(nameTwo) > 0)
{
}
}
public int whoIsInvalid()
{
if (!getIsLeftNavigable() || !getIsRightNavigable())
{
return -1;
}
if (getEnd(0).getClassName().equals(getEnd(1).getClassName()))
{
if (getEnd(0).getMultiplicity().getLowerBound() != 0)
{
return 0;
}
else if (getEnd(1).getMultiplicity().getLowerBound() != 0)
{
return 1;
}
}
return -1;
}
public boolean isValid()
{
return whoIsInvalid() == -1;
}
public String getArrowString()
{
String arrow = "--";
if (getIsLeftComposition() && !getIsRightComposition() && getIsLeftNavigable() && getIsRightNavigable()) {
arrow = "<@>-";
}
else if (!getIsLeftComposition() && getIsRightComposition() && getIsLeftNavigable() && getIsRightNavigable()) {
arrow = "-<@>";
}
else if ( (!getIsLeftNavigable() || !getIsRightNavigable()) && (getIsLeftComposition() || getIsRightComposition())) {
arrow = "><";
}
else if (getIsRightComposition() && getIsLeftComposition())
{
arrow = "><";
}
else if (getIsLeftNavigable() && !getIsRightNavigable())
{
arrow = "<-";
}
else if (!getIsLeftNavigable() && getIsRightNavigable())
{
arrow = "->";
}
else if (!getIsLeftNavigable() && !getIsRightNavigable())
{
arrow = "><";
}
return arrow;
}
public String toGenericString()
{
String leftSide = getEnd(0).toGenericString();
String rightSide = getEnd(1).toGenericString();
if (leftSide.equals("n") && rightSide.equals("n") && !getEnd(0).toSimpleString().equals(getEnd(1).toSimpleString()))
{
return cruise.umple.util.StringFormatter.format("n {0} m",getArrowString());
}
else
{
return cruise.umple.util.StringFormatter.format("{0} {1} {2}",leftSide,getArrowString(),rightSide);
}
}
public String deriveName()
{
AssociationEnd firstEnd = this.getEnd(0);
AssociationEnd secondEnd = this.getEnd(1);
String firstClassName = firstEnd.getClassName();
String secondClassName = secondEnd.getClassName();
String firstRole = firstEnd.getDisplayRoleName().equals("") ? "" : ":" + firstEnd.getDisplayRoleName();
String secondRole = secondEnd.getDisplayRoleName().equals("") ? "" : ":" + secondEnd.getDisplayRoleName();
if (firstClassName.compareTo(secondClassName) <= 0)
{
return firstClassName + firstRole + "__" + secondClassName + secondRole;
}
else
{
return secondClassName + secondRole + "__" + firstClassName + firstRole;
}
}
public void setImmutable()
{
this.immutable = true;
}
public boolean isImmutable()
{
return this.immutable;
}
public boolean isComposition() {
return this.isLeftComposition || this.isRightComposition;
}
}
class ConstraintTree
{
/*
* Used by trees to add all the elements of another tree to this tree
* @param cv the constraint variable node to add to this tree(if it is a ConstraintTree it will add all of it's sub elements via the addElement method)
*/
public void addElementAll(ConstraintVariable cv)
{
if(cv == null)
{
return;
}
else
{
addElement(cv);
}
}
/*
* Negates a sub variable of the ConstriantTree recursively trying to do as much as it can, setting this ConstraintTree to show the ! symbol if this is the deepest ConstraintTree
* @param variable the sub constaint variable that is being negated. ConstraintOperators will call the negate method, ConstraintTrees will attempt to go deeper down the tree if that exists, trying to find a negatable target
*/
private boolean negateVariable(ConstraintVariable variable){
boolean wasOperationNegatable = false;
if((variable==null))
{
return false;
}
if(variable instanceof ConstraintOperator)
{
if(((ConstraintOperator)variable).isNegatable())
{
if(((ConstraintOperator)variable).negate())
{
return true;
}
else
{
boolean left = isNegateVariable(((ConstraintOperator)variable).getLeft());
boolean right = isNegateVariable(((ConstraintOperator)variable).getRight());
wasOperationNegatable = left&&right;
if(wasOperationNegatable)
{
left = negateVariable(((ConstraintOperator)variable).getLeft());
right = negateVariable(((ConstraintOperator)variable).getRight());
}
else
{
((ConstraintOperator)variable).negate();
}
}
}
}
else if(variable instanceof ConstraintTree)
{
wasOperationNegatable = ((ConstraintTree)variable).negate();
}
else if(variable instanceof ConstraintLiteral||variable instanceof ConstraintUnassignedName)
{
return false;
}
if(!wasOperationNegatable)
{
displayNegation = !displayNegation;
wasOperationNegatable=!wasOperationNegatable;
}
return wasOperationNegatable;
}
/*
To check if a subvariable of the ConstraintTree is negatable or not. Works like negateVariable but does not change the displayNegation.
*/
private boolean isNegateVariable(ConstraintVariable variable){
boolean wasOperationNegatable = false;
if((variable==null))
{
return false;
}
if(variable instanceof ConstraintOperator)
{
if(((ConstraintOperator)variable).isNegatable())
{
return true;
}
}
else if(variable instanceof ConstraintTree)
{
wasOperationNegatable = ((ConstraintTree)variable).isNegatable();
}
else if(variable instanceof ConstraintLiteral||variable instanceof ConstraintUnassignedName)
{
return false;
}
if(displayNegation)
{
wasOperationNegatable=true;
}
return wasOperationNegatable;
}
/*
* The public counterpart to the negateVariabe method, it negates this ConstraintTree's root, starting off the recursive decent into the negation of the tree
*/
public boolean negate()
{
return negateVariable(root);
}
/*
* The public counterpart to the isNegateVariabe method, it checks negativability of this ConstraintTree's root, starting off the recursive decent into the negation of the tree
*/
public boolean isNegatable()
{
return isNegateVariable(root);
}
/*
* Copies non-constraint data such as whether the tree should display the ! symbol and whether it should display ( ) around the treee
*/
ConstraintTree clone(ConstraintTree tree)
{
ConstraintTree aElement = createNew();
aElement.setDisplayNegation(tree.getDisplayNegation());
aElement.setShouldDisplayBrackets(tree.getShouldDisplayBrackets());
return aElement;
}
/*
* Creates a new instance of this class, it is used in clone and addElement in order to copy a tree so that there is a deep copy instead of a shallow one
* This method needs to be overrided for sub classes of ConstaintTree to function properly.
*/
ConstraintTree createNew()
{
return new ConstraintTree();
}
/*
* Adds a node to the tree, the three modes are
* - if nothing exists in the tree: set the element as the root
* - if the element is an operator: add the root if it is not null as an operand to the operator, and set the operator to the root
* - if there exists an operator: add the element as an operand to the operator.
* @param element to be added to the tree
*/
ConstraintVariable addElement(ConstraintVariable aElement)
{
++numberOfElements;
ConstraintOperator operator = null;
if(aElement instanceof ConstraintOperator)
{
operator = (ConstraintOperator)aElement;
aElement = new ConstraintOperator(operator.getValue());
addElementAll(operator.getLeft());
}
else if(aElement instanceof ConstraintTree)
{
ConstraintTree list = ((ConstraintTree)aElement);
aElement = clone(list);
((ConstraintTree)aElement).addElementAll(list.getRoot());
}
if(aElement instanceof ConstraintOperator)
{
requestor = ((ConstraintOperator)aElement);
requestor.addOperand(root);
root = requestor;
}
else
{
if(requestor!=null)
{
requestor.addOperand(aElement);
root = requestor;
requestor = null;
}
else
{
root = aElement;
}
if(aElement instanceof ConstraintNamed)
{
if(!"this".equals(((ConstraintNamed)aElement).getName()))
{
names.add(((ConstraintNamed)aElement).getName());
}
}
else if(aElement instanceof ConstraintTree)
{
names.addAll(((ConstraintTree)aElement).names);
}
}
if(aElement instanceof ConstraintOperator)
{
addElementAll(operator.getRight());
}
return aElement;
}
/*
* Whenever ConstraintTrees or named Constriants are added to the constraint tree, a record of that name is added to a set of names
* This method pretty prints that set of names.
*/
public String getNamedNames()
{
StringBuilder builder = new StringBuilder();
int i=0;
String last = "";
for(String name:names)
{
if(i>=names.size()-1)
{
last = name;
break;
}
builder.append(name);
if(names.size()>2)
{
builder.append(", ");
}
else builder.append(" ");
++i;
}
if(names.size()>1)builder.append("and ");
builder.append(last);
return builder.toString();
}
/*
* Iterator method, override the method from the Iterable<Constraint> interface that all ConstraintVariables inherit from
* Iterates over all of the root's elements, then returns itself
*/
public Iterator<ConstraintVariable> iterator()
{
final ConstraintTree myself = this;
return new Iterator<ConstraintVariable>()
{
ConstraintTree self;
boolean hasReturnedSelf;
Iterator<ConstraintVariable> iterator;
{
self = myself;
hasReturnedSelf = false;
if(self.getRoot()!=null)
{
iterator = self.getRoot().iterator();
}
}
public ConstraintVariable next()
{
if(iterator==null||!iterator.hasNext())
{
hasReturnedSelf = true;
return self;
}
else
{
return iterator.next();
}
}
public boolean hasNext()
{
return !hasReturnedSelf;
}
public void remove(){}
};
}
/*
* Mandatory type method for the SuperGenerator to distiguish easily between different ConstraintVariable types.
*/
public String getType(){ return "complex"; }
}
class TraceConstraint
{
ConstraintTree createNew()
{
TraceConstraint constraint = new TraceConstraint();
for(UmpleVariable uv:this.getVariables())
{
constraint.addVariable(uv);
}
return constraint;
}
public ConstraintVariable addElement(ConstraintVariable aElement)
{
if(aElement instanceof ConstraintUnassignedName)
{
ConstraintUnassignedName variable = (ConstraintUnassignedName)aElement;
MethodParameter foundParameter = null;
for(UmpleVariable uv:getVariables())
{
if(uv.getName().equals(variable.getValue()))
{
foundParameter = new MethodParameter(uv.getName(),uv.getType(),uv.getModifier(),uv.getValue(),false);
}
}
if(foundParameter!=null)
{
aElement = new ConstraintMethodParameter(foundParameter);
}
}
return super.addElement(aElement);
}
}
class Precondition
{
ConstraintTree createNew()
{
return new Precondition(method);
}
public ConstraintVariable addElement(ConstraintVariable aElement)
{
if(aElement instanceof ConstraintUnassignedName)
{
ConstraintUnassignedName name = (ConstraintUnassignedName)aElement;
MethodParameter foundParameter = null;
for(MethodParameter param:method.getMethodParameters())
{
if(param.getName().equals(name.getValue()))
{
foundParameter = param;
break;
}
}
if(foundParameter!=null)
{
aElement = new ConstraintMethodParameter(foundParameter);
}
}
return super.addElement(aElement);
}
}
class Postcondition
{
ConstraintTree createNew()
{
return new Postcondition(method);
}
public ConstraintVariable addElement(ConstraintVariable aElement)
{
if(aElement instanceof ConstraintUnassignedName)
{
ConstraintUnassignedName name = (ConstraintUnassignedName)aElement;
MethodParameter foundParameter = null;
for(MethodParameter param:method.getMethodParameters())
{
if(param.getName().equals(name.getValue()))
{
foundParameter = param;
break;
}
}
if(foundParameter!=null)
{
aElement = new ConstraintMethodParameter(foundParameter);
}
}
return super.addElement(aElement);
}
}
class ConstraintOperator
{
/*
* Returns which kind of operator this is based on the number of operands it has.
*/
public String getType(){ return numberOfSubConstraints()>0?numberOfSubConstraints()>1?"operatorTwo":"operatorOne":"operatorNone"; }
/*
* Carefully adds the operand on one side of the operator or the other, for example string literals are added in front, regardless of how they are arranged in the inputted constraint
* takes care of making sure cardinality calls the numberOf method, and if there is a number it puts it as the right operand(flipping ordinal operators)
*/
public void addOperand(ConstraintVariable variable)
{
if(variable!=null)
{
if(variable instanceof ConstraintLiteral)
{
if(variable instanceof ConstraintNumberLiteral)
{
correctForPrimitive();
subConstraints.add(variable);
}
else if(numberOfSubConstraints()>0)
{
subConstraints.add(0,variable);
}
else
{
subConstraints.add(variable);
}
}
else
{
if(numberOfSubConstraints()==0&&value.contains("cardinality"))
{
correctForCardinality(variable);
}
if(numberOfSubConstraints()==1&&getLeft() instanceof ConstraintNumberLiteral)
{
subConstraints.add(0,variable);
flip();
}
else
{
subConstraints.add(variable);
}
}
}
}
/*
* Tries to set associations so that they will use the numberOf method for the size.
* @param variable to the corrected
*/
public void correctForCardinality(ConstraintVariable variable)
{
if(variable == null)
{
return;
}
else if((variable instanceof ConstraintAssociation)&&value.contains("cardinality"))
{
((ConstraintAssociation)variable).setNumberOf(true);
}
else if((variable instanceof ConstraintTree)&&((ConstraintTree)variable).getNumberOfElements()>0)
{
correctForCardinality(((ConstraintTree)variable).getRoot());
}
else if(variable instanceof ConstraintOperator)
{
correctForCardinality(((ConstraintOperator)variable).getRight());
}
}
/*
* switches the .equals() style method for the primitive == or !=
*/
public void correctForPrimitive()
{
if("object==".equals(value))
{
value = "==";
}
else if("object!=".equals(value))
{
value = "!=";
}
}
/*
* If the number is being put on the right, when it was originally on the left, the operator has to flip, '>' to '<' and '<' to '>'
*/
public void flip()
{
if(">=".equals(value))
{
value = "<=";
}
else if(">=".equals(value))
{
value = "<=";
}
else if("<".equals(value))
{
value = ">";
}
else if(">".equals(value))
{
value = "<";
}
}
public boolean isNegatable()
{
if(".".equals(value)||",".equals(value)||"".equals(value))
{
return false;
}
return true;
}
/*
* If this method is reached by the negateVariable in ConstraintTree it means that the parent ConstraintTree doesn't have to display the negation, the operator will handle it instead.
*/
public boolean negate()
{
if ("".equals(value))
{
return false;
}
else if("object==".equals(value))
{
value = "object!=";
}
else if("object!=".equals(value))
{
value = "object==";
}
else if("==".equals(value))
{
value = "!=";
}
else if("!=".equals(value))
{
value = "==";
}
else if(">".equals(value))
{
value = "<=";
}
else if(">=".equals(value))
{
value = "<";
}
else if("<=".equals(value))
{
value = ">";
}
else if("<".equals(value))
{
value = ">=";
}
else if("cardinality==".equals(value))
{
value = "cardinality!=";
}
else if("cardinality!=".equals(value))
{
value = "cardinality==";
}
else if("cardinality>".equals(value))
{
value = "cardinality<=";
}
else if("cardinality>=".equals(value))
{
value = "cardinality<";
}
else if("cardinality<=".equals(value))
{
value = "cardinality>";
}
else if("cardinality<".equals(value))
{
value = "cardinality>=";
}
else if("&&".equals(value))
{
value = "||";
return false;
}
else if("||".equals(value))
{
value = "&&";
return false;
}
if(".".equals(value)||",".equals(value))
{
return false;
}
return true;
}
/*
* Iterators over the left, then this, then the right.
*/
public Iterator<ConstraintVariable> iterator()
{
final ConstraintVariable myself = this;
return new Iterator<ConstraintVariable>()
{
boolean hasReturnedSelf;
Iterator<ConstraintVariable> currentIterator;
ConstraintVariable self;
{
hasReturnedSelf = false;
self = myself;
if(getLeft()!=null)
{
currentIterator = getLeft().iterator();
}
}
public ConstraintVariable next()
{
if(currentIterator == null||!currentIterator.hasNext())
{
if(getRight()!=null&&!hasReturnedSelf)
{
currentIterator = getRight().iterator();
}
else
{
currentIterator = null;
}
hasReturnedSelf = true;
return self;
}
else
{
return currentIterator.next();
}
}
public boolean hasNext()
{
return (currentIterator!=null&&currentIterator.hasNext())||!hasReturnedSelf;
}
public void remove(){}
};
}
}
class ConstraintAttribute
{
String getName()
{
return attribute==null?null:attribute.getName();
}
/*
* A method for conveniently getting the contained attribute's container class.
*/
UmpleClassifier retrieveClassifier(){
UmpleClass containerClass = attribute.getUmpleClass();
if(containerClass==null)
{
UmpleTrait containerTrait = attribute.getUmpleTrait();
return containerTrait;
}
else
{
return containerClass;
}
}
public String getType(){ return getAttribute().getModifier().contains("internal")?"name":"attribute"; }
}
class ConstraintLiteral
{
public String getType(){ return "literal"; }
}
class ConstraintUnassignedName
{
String getName()
{
return getValue();
}
public String getType(){ return "name"; }
}
class ConstraintAssociation
{
String getName()
{
return association==null?null:association.getName();
}
/*
* A method for conveniently getting the contained association's container class.
*/
UmpleClassifier retrieveClassifier(){
UmpleClass containerClass = association.getUmpleClass();
if(containerClass==null)
{
UmpleTrait containerTrait = association.getUmpleTrait();
return containerTrait;
}
else
{
return containerClass;
}
}
public String getType(){ return numberOf?"associationNumberOf":index==-1?"associationList":"associationGet"; }
}
class ConstraintMethodParameter
{
String getName()
{
return parameter==null?"":parameter.getName();
}
public String getType(){ return "method parameter"; }
}
external interface Iterable<ConstraintVariable> {}
class ConstraintVariable
{
isA "Iterable<ConstraintVariable>";
depend java.util.Iterator;
abstract;
String getValue(CodeTranslator gen){
return gen.translate(getType(),this);
}
UmpleClassifier retrieveClassifier(){
return null;
}
Iterator<ConstraintVariable> iterator()
{
final ConstraintVariable myself = this;
return new Iterator<ConstraintVariable>()
{
boolean hasReturned;
ConstraintVariable self;
{
hasReturned = false;
self = myself;
}
public ConstraintVariable next()
{
if(hasReturned)
{
return null;
}
else
{
hasReturned = true;
return self;
}
}
public boolean hasNext()
{
return !hasReturned;
}
public void remove(){}
};
}
public abstract String getType();
}
class ConstraintState
{
String getName()
{
return state==null?null:state.getName();
}
public String getType() { return "state"; }
}
class ConstraintStateMachine
{
String getName()
{
return stateMachine==null?null:stateMachine.getName();
}
public String getType(){ return "statemachine"; }
}
class ConstraintPort
{
String getName()
{
return port==null?null:port.getName();
}
public String getType(){ return "port"; }
}
/*
* In Umple_Code.ump: Methods for computing compound properties
*/
class AssociationEnd
{
public AssociationEnd(AssociationEnd another) {
//AssociationEnd Attributes
this.roleName = another.getRoleName();
this.className = another.getClassName();
this.modifier = another.getModifier();
this.referenceToClassName = another.getReferenceToClassName();
this.multiplicity = another.getMultiplicity();
this.isDefaultRoleName = another.getIsDefaultRoleName();
this.priority = another.getPriority();
//AssociationEnd Associations
this.association = another.getAssociation();
//Helper Variables
this.cachedHashCode = another.cachedHashCode;
this.canSetMultiplicity = another.canSetMultiplicity;
this.canSetRoleName = another.canSetRoleName;
this.canSetClassName = another.canSetClassName;
this.canSetModifier = another.canSetModifier;
this.canSetReferenceToClassName = another.canSetReferenceToClassName;
}
private static int MULT_MANY = -1;
public boolean isNavigable()
{
return !getModifier().toLowerCase().equals("nonnavigable");
}
public String getLowerBoundString()
{
return getMultiplicity().getLowerBound() == -1 ? "*" : getMultiplicity().getLowerBound() + "";
}
public String getUpperBoundString()
{
return getMultiplicity().getUpperBound() == -1 ? "*" : getMultiplicity().getUpperBound() + "";
}
public String getDisplayRoleName()
{
return isDefaultRoleName ? "" : getRoleName();
}
public String toSimpleString()
{
if (getMultiplicity().getLowerBound() == 0 && getMultiplicity().getUpperBound() == MULT_MANY)
{
return formatEnd(getMultiplicity().getUpperBound());
}
else if (getMultiplicity().getLowerBound() == MULT_MANY && getMultiplicity().getUpperBound() == MULT_MANY)
{
return formatEnd(getMultiplicity().getLowerBound()) + ".." + formatEnd(getMultiplicity().getUpperBound());
}
else if (getMultiplicity().getLowerBound() == getMultiplicity().getUpperBound())
{
return formatEnd(getMultiplicity().getLowerBound());
}
else
{
return formatEnd(getMultiplicity().getLowerBound()) + ".." + formatEnd(getMultiplicity().getUpperBound());
}
}
public String toGenericString()
{
if (getMultiplicity().getLowerBound() == 0 && getMultiplicity().getUpperBound() == MULT_MANY)
{
return formatEnd(getMultiplicity().getUpperBound());
}
else if (getMultiplicity().getLowerBound() == MULT_MANY && getMultiplicity().getUpperBound() == MULT_MANY)
{
return formatEnd(getMultiplicity().getLowerBound()) + ".." + formatEnd(getMultiplicity().getUpperBound());
}
else if (getMultiplicity().getLowerBound() == getMultiplicity().getUpperBound())
{
return formatGenericEnd(getMultiplicity().getLowerBound(),"n");
}
else if (getMultiplicity().getLowerBound() == 0 || getMultiplicity().getLowerBound() == 1)
{
return getMultiplicity().getLowerBound() + ".." + formatGenericEnd(getMultiplicity().getUpperBound(),"n");
}
else
{
return formatGenericEnd(getMultiplicity().getLowerBound(),"n") + ".." + formatGenericEnd(getMultiplicity().getUpperBound(),"m");
}
}
public String toString()
{
String asText = "";
if (!getModifier().equals("internal"))
{
asText += getModifier() + " " + asText;
}
asText += toSimpleString();
if (getRoleName().length() > 0)
{
asText += " [" + roleName + "]";
}
if (getClassName().length() > 0)
{
asText += " " + className;
}
if (getReferenceToClassName().length() > 0)
{
asText += " -- " + referenceToClassName;
}
return asText;
}
private String formatEnd(int aValue)
{
return aValue == MULT_MANY ? "*" : aValue + "";
}
private String formatGenericEnd(int aValue, String defaultIfNotOneOrMany)
{
if (aValue == MULT_MANY)
{
return "*";
}
else if (aValue == 0 || aValue == 1)
{
return aValue + "";
}
else
{
return defaultIfNotOneOrMany;
}
}
}
/*
* In Umple_Code.ump: Methods for testing various complex properties
*/
class AssociationVariable
{
public AssociationVariable(AssociationVariable another){
super(another.getName(), another.getType(),another.getModifier(), another.getValue());
//AssociationVariable Attributes
this.multiplicity = another.getMultiplicity();
this.isNavigable = another.getIsNavigable();
this.priority = another.getPriority();
//AssociationVariable Associations
this.relatedAssociation = null;
this.comments = new ArrayList<Comment>();
for (Comment comment : another.getComments()) {
this.comments.add(comment);
}
this.umpleClass = another.getUmpleClass();
this.umpleTrait = another.getUmpleTrait();
//Helper Variables
//this.canSetIsNavigable = another.canSetIsNavigable;
}
public boolean isReflexive()
{
return getRelatedAssociation() != null && getType().equals(getRelatedAssociation().getType());
}
public boolean isSymmetricReflexive()
{
return getRelatedAssociation() != null && "symmetricreflexive".equals(getModifier());
}
public void configureRelatedAssociation(AssociationVariable newRelatedAssociation)
{
if (newRelatedAssociation == null || !getType().equals(newRelatedAssociation.getType()))
{
setRelatedAssociation(newRelatedAssociation);
}
else
{
multiplicity.minimizeRange(newRelatedAssociation.getMultiplicity());
setRelatedAssociation(this);
}
}
public static int min(int first, int second)
{
return first == -1 ? second : second == -1 ? first : Math.min(first, second);
}
public static int max(int first, int second)
{
return first == -1 ? first : second == -1 ? second : Math.max(first, second);
}
public boolean isMany()
{
return multiplicity.getUpperBound() == -1 || multiplicity.getUpperBound() > 1;
}
public boolean isOptionalN()
{
return multiplicity.getLowerBound() == 0 && multiplicity.getUpperBound() > 1;
}
public boolean isOne()
{
return multiplicity.getUpperBound() == 1;
}
public boolean isOnlyOne()
{
return multiplicity.getUpperBound() == 1 && multiplicity.getLowerBound() == 1;
}
public boolean isOptionalOne()
{
return multiplicity.getUpperBound() == 1 && multiplicity.getLowerBound() == 0;
}
public boolean isOptionalMany()
{
return multiplicity.getLowerBound() == 0 && isMany();
}
public boolean isUpperBounded()
{
return multiplicity.getUpperBound() >= 0;
}
public boolean isN()
{
return multiplicity.getLowerBound() > 1 && multiplicity.getLowerBound() == multiplicity.getUpperBound();
}
public boolean isMN()
{
return multiplicity.getLowerBound() > 0 && (multiplicity.getUpperBound() > multiplicity.getLowerBound() || multiplicity.getUpperBound() == -1);
}
public boolean isMStar()
{
return multiplicity.getLowerBound() > 0 && multiplicity.getUpperBound() == -1;
}
public boolean isStar()
{
return multiplicity.getUpperBound() == -1;
}
public boolean isMandatory()
{
return multiplicity.getLowerBound() > 0;
}
public boolean isMandatoryOne()
{
return multiplicity.getLowerBound() == 1 && multiplicity.getUpperBound() == 1;
}
public boolean isMandatoryMany()
{
return multiplicity.getLowerBound() > 0 && isMany();
}
public boolean isImmutable()
{
AssociationVariable related = getRelatedAssociation();
Boolean relatedAssocIsImmutable = (related == null) ? false : "immutable".equals(related.getModifier());
Boolean myUmpleClassIsImmutable =
(getIsNavigable() && getUmpleClass() != null) ? getUmpleClass().isImmutable() : false;
Boolean yourUmpleClassIsImmutable =
(related != null && related.getIsNavigable() && related.getUmpleClass() != null) ? related.getUmpleClass().isImmutable() : false;
return (super.isImmutable() || relatedAssocIsImmutable
|| myUmpleClassIsImmutable || yourUmpleClassIsImmutable);
}
public boolean setImmutable()
{
boolean wasSet = false;
if (canBeImmutable())
{
setModifier("immutable");
wasSet = true;
}
return wasSet;
}
public boolean isSorted()
{
return !priority.equals("");
}
private boolean canBeImmutable()
{
AssociationVariable related = getRelatedAssociation();
if (related == null) { return true; }
boolean canBe = true;
if (getIsNavigable() && related.getIsNavigable())
{
canBe = false;
}
else if (related.getIsNavigable() && (umpleClass != null) && !umpleClass.isImmutable())
{
canBe = false;
}
else if (getIsNavigable() && (related.getUmpleClass() != null) && !related.getUmpleClass().isImmutable())
{
canBe = false;
}
return canBe;
}
private boolean canBeRelatedAssociation(AssociationVariable related)
{
if (related == null)
{
return true;
}
Boolean myUmpleClassIsImmutable = (getUmpleClass() != null) ? getUmpleClass().isImmutable() : false;
Boolean yourUmpleClassIsImmutable = (related.getUmpleClass() != null) ? related.getUmpleClass().isImmutable() : false;
return UmpleClass.immutabilityAssociationRulesSatisfied(this, umpleClass, myUmpleClassIsImmutable,
related, related.getUmpleClass(), yourUmpleClassIsImmutable);
}
public ArrayList<String> getMethodNames()
{
if(!getIsNavigable())
{
return new ArrayList<String>();
}
ArrayList<String> methodNames = new ArrayList<String>();
String attributeCapitalizedName = this.getUpperCaseName();
String singularName = getUmpleClass().getSourceModel().getGlossary().getSingular(this.getName());
String singularCapitalizedName = singularName.substring(0, 1).toUpperCase() + singularName.substring(1);
if(isMany())
{
methodNames.add("get" + singularCapitalizedName);
methodNames.add("get" + attributeCapitalizedName);
methodNames.add("numberOf" + attributeCapitalizedName);
methodNames.add("has" + attributeCapitalizedName);
methodNames.add("indexOf" + singularCapitalizedName);
methodNames.add("minimumNumberOf" + attributeCapitalizedName);
methodNames.add("add" + singularCapitalizedName);
methodNames.add("add" + singularCapitalizedName + "At");
methodNames.add("addOrMove" + singularCapitalizedName + "At");
methodNames.add("remove" + singularCapitalizedName);
}
else
{
methodNames.add("get" + attributeCapitalizedName);
methodNames.add("set" + attributeCapitalizedName);
}
return methodNames;
}
}
/*
* In Umple_Code.ump: Methods for querying various propertiies of a Multiplicit
*/
class Multiplicity
{
public void setRange(String lowerBound, String upperBound)
{
minimum = lowerBound;
maximum = upperBound;
}
public String getRange()
{
String lowerBound = getLowerBound() == -1 ? "*" : getLowerBound() + "";
String upperBound = getUpperBound() == -1 ? "*" : getUpperBound() + "";
return StringFormatter.format("[{0},{1}]",lowerBound,upperBound);
}
public String[] getRangeParts()
{
String lowerBound = getLowerBound() == -1 ? "*" : getLowerBound() + "";
String upperBound = getUpperBound() == -1 ? "*" : getUpperBound() + "";
return new String[] { lowerBound, upperBound };
}
public boolean isValid()
{
if ("*".equals(getMinimum()))
{
return false;
}
if ("-1".equals(getMinimum()) || "-1".equals(getMaximum()) || "-1".equals(getBound()))
{
return false;
}
if (getLowerBound() < -1 || getUpperBound() < -1)
{
return false;
}
// Fix for issue 292
if (getUpperBound() == 0)
{
return false;
}
if (getLowerBound() > getUpperBound() && !isUpperBoundMany())
{
return false;
}
return true;
}
public void minimizeRange(Multiplicity compareTo)
{
if (compareTo.getLowerBound() > getLowerBound() && compareTo.minimum != null)
{
minimum = compareTo.minimum;
}
if (compareTo.getUpperBound() < getUpperBound() && compareTo.maximum != null && compareTo.getUpperBound() != -1)
{
maximum = compareTo.maximum;
}
}
public int getLowerBound()
{
if (getBound() != null)
{
return parseInt(getBound(),0);
}
else
{
return parseInt(getMinimum(),-1);
}
}
public int getUpperBound()
{
if (getBound() != null)
{
return parseInt(getBound(),-1);
}
else
{
return parseInt(getMaximum(),-1);
}
}
public boolean isLowerBoundMany()
{
return getLowerBound() == -1;
}
public boolean isUpperBoundMany()
{
return getUpperBound() == -1;
}
public boolean isLowerBoundNumeric()
{
return getLowerBound() >= -1;
}
public boolean isUpperBoundNumeric()
{
return getUpperBound() >= -1;
}
public boolean isMany()
{
return getUpperBound() > 1 || getUpperBound() == -1;
}
public boolean isOne()
{
return getUpperBound() == 1;
}
private int parseInt(String input, int defaultIfStar)
{
try
{
if ("*".equals(input))
{
return defaultIfStar;
}
else
{
return Integer.parseInt(input);
}
}
catch(Exception e)
{
return -2;
}
}
}
/*
*/
class GeneratedElement
{
private Map<String, String> lookups = new HashMap<String, String>();
private Map<String, List<String>> multiLookups = new HashMap<String,List<String>>();
public void setLookup(String aKey, String aValue)
{
lookups.put(aKey, aValue);
}
public String getLookup(String aKey)
{
if (aKey == null)
{
return null;
}
else
{
return lookups.get(aKey);
}
}
public boolean addMultiLookup(String aKey, String aValue)
{
List<String> oldList = null;
if (multiLookups.containsKey(aKey))
{
oldList = multiLookups.get(aKey);
}
else
{
oldList = new ArrayList<String>();
}
if (aValue == null || "".equals(aValue) || oldList.contains(aValue))
{
return false;
}
oldList.add(aValue);
multiLookups.put(aKey, oldList);
return true;
}
public String[] getMultiLookup(String aKey)
{
if (aKey == null || !multiLookups.containsKey(aKey))
{
return new String[0];
}
else
{
List<String> list = multiLookups.get(aKey);
return list.toArray(new String[list.size()]);
}
}
public String toString()
{
String answer = "<<";
for (String aKey : lookups.keySet())
{
answer += "[" + aKey + ":" + lookups.get(aKey) + "]";
}
answer += ">>";
return answer;
}
}
/*
*/
class Point
{
public static Point create(int n)
{
int p = (int)Math.sqrt(n) + 1;
if (n - (p-2)*p <= p)
{
return new Point(n - (p-2)*p, p);
}
else
{
return new Point(p, n - (p-1) * p);
}
}
public String toString()
{
return "(" + getX() + "," + getY() + ")";
}
}
/*
*/
class Coordinate
{
public Point getTopLeft()
{
return new Point(x,y);
}
public Point getTopRight()
{
return new Point(x+width,y);
}
public Point getBottomLeft()
{
return new Point(x,y+height);
}
public Point getBottomRight()
{
return new Point(x+width,y+height);
}
public Point getTopMiddle()
{
return new Point(x+width/2,y);
}
public Point getBottomMiddle()
{
return new Point(x+width/2,y+height);
}
public Point getRightMiddle()
{
return new Point(x+width,y+height/2);
}
public Point getLeftMiddle()
{
return new Point(x,y+height/2);
}
public String whereIs(Coordinate neighbour)
{
int topDeltaY = getTopMiddle().getY() - neighbour.getBottomMiddle().getY();
int topDeltaX = getTopMiddle().getX() - neighbour.getBottomMiddle().getX();
int bottomDeltaY = neighbour.getTopMiddle().getY() - getBottomMiddle().getY();
int bottomDeltaX = getBottomMiddle().getX() - neighbour.getTopMiddle().getX();
if (topDeltaY > 0 && Math.abs(topDeltaY) > Math.abs(topDeltaX))
{
return "top";
}
else if (bottomDeltaY > 0 && Math.abs(bottomDeltaY) > Math.abs(bottomDeltaX))
{
return "bottom";
}
else if (neighbour.getX() < getX())
{
return "left";
}
else
{
return "right";
}
}
public int distanceTo(Coordinate other)
{
int a = other.getX() - getX();
int b = other.getY() - getY();
int c = (int) Math.round(Math.sqrt(Math.pow(a,2) + Math.pow(b,2)));
return c;
}
public String toString()
{
return "(" + getX() + "," + getY() + "," + getWidth() + "," + getHeight() + ")";
}
private void updateStatus()
{
if (x == -1 && y == -1 && width == -1 && height == -1)
{
setStatus(Status.Undefined);
}
else
{
setStatus(Status.Explicit);
}
}
}
/*
*/
class Comment
{
Boolean isInline = true;
/**
* Used to take a comment and process it into a format appropriate for displaying in generated code.
*
* For example, you may want a bunch of inline comments put together and displayed as Javadoc. This accomplishes that (among others).
*
* @param type Indicates the type of comment which determines how the comments are formatted. The types are: Hash, Javadoc, Attribute Javadoc, Association Javadoc, Method Javadoc, RubyMultiline, RubyMultiline Internal and Multiline. Defaults to "//" if not specified.
* @param allComments A list of comments to be processed and formatted all together as one.
*
* @return The processed/formatted comment appropriate for use in generated code output.
*/
public static String format(String type,List<Comment> allComments)
{
return format(type, allComments, true);
}
public static String format(String type,List<Comment> allComments, boolean allowAnnotations)
{
//String commentDelimiter = type == "Hash" ? "# " : (type == "Javadoc") ? " * " : (type == "Attribute Javadoc") ? " * " : (type == "Association Javadoc") ? " * " : (type == "Method Javadoc") ? " * " : (type == "RubyMultiline") ? " " : (type == "Multiline") ? "" : "// ";
String commentDelimiter;
List<String> deferredAnnotations = new ArrayList<String>();
// Set the comment delimiter based on the type of the comment. (ex. For Javadoc prepend "*" before every comment line)
if (type == "Hash")
{
commentDelimiter = "# ";
}
else if (type == "Javadoc")
{
commentDelimiter = " * ";
}
else if (type == "Attribute Javadoc")
{
commentDelimiter = " * ";
}
else if (type == "Association Javadoc")
{
commentDelimiter = " * ";
}
else if (type == "Method Javadoc")
{
commentDelimiter = " * ";
}
else if (type == "RubyMultiline")
{
commentDelimiter = " ";
}
else if (type == "RubyMultiline Internal")
{
commentDelimiter = " ";
}
else if (type == "Multiline")
{
commentDelimiter = "";
}
else
{
commentDelimiter = "// ";
}
if (allComments.size() == 0)
{
return null;
}
String output = "";
Boolean foundComment = false;
for (Comment c : allComments)
{
boolean couldTreatAsAnnotation = allowAnnotations;
if (type == "RubyMultiline" || type == "RubyMultiline Internal") {
couldTreatAsAnnotation = false;
}
if (type == "Javadoc" || type == "Attribute Javadoc" || type == "Association Javadoc" || type == "Method Javadoc" || type == "RubyMultiline" || type == "RubyMultiline Internal")
{
int startIndex = 0;
// Go through each letter of the current comment to find start of content.
for (int i = 0; i < c.getText().length(); i++)
{
char letter = c.getText().charAt(i);
// Remove these letters until the actual content is found in the line.
if (letter == ' ' || letter == '\t' || letter == '*')
{
startIndex++;
}
// Comment content found, set comment to start here.
else
{
c.setText(c.getText().substring(startIndex));
break;
}
}
// Special case where the comment line had no content (only spaces, tabs or asterisks).
if (startIndex == c.getText().length())
{
c.setText(c.getText().substring(startIndex));
}
}
// If it is an annotation, add at end
if(c.isAnnotation() && couldTreatAsAnnotation) {
deferredAnnotations.add(c.getText());
}
else
{
foundComment = true;
output += commentDelimiter + c.getText() + "\n";
}
}
// Finalize the comment based on what type it was. (ex. For Javadoc place the "/**" and "*/" around the comment)
if(foundComment) {
if (type == "Javadoc")
{
output = "/**\n" + output + " */";
}
else if (type == "Attribute Javadoc")
{
output = " /**\n" + output + " */";
}
else if (type == "Association Javadoc")
{
output = " /**\n" + output + " */";
}
else if (type == "Method Javadoc")
{
output = " /**\n" + output + " */";
}
else if (type == "RubyMultiline")
{
// initialize sb at least as large as the output with 1 comment
StringBuilder sb = new StringBuilder( output.length() + 2 );
sb.append("#");
char c;
for( int i=0; i < output.length(); ++i ){
c = output.charAt(i);
sb.append(c);
if( (c == '\n') && (i != output.length()-1) ){
sb.append("#");
}
}
output = sb.toString();
}
else if (type == "RubyMultiline Internal")
{
// initialize sb at least as large as the output with 1 comment
StringBuilder sb = new StringBuilder( output.length() + 2 );
sb.append("#");
char c;
for( int i=0; i < output.length(); ++i ){
c = output.charAt(i);
sb.append(c);
if( (c == '\n') && (i != output.length()-1) ){
sb.append(" #");
}
}
output = sb.toString();
}
else if (type == "Multiline")
{
output = "/*\n" + output + "*/";
}
}
// Process all deferred annotations if any
boolean firstAnnotation = true;
for (String d: deferredAnnotations) {
if(firstAnnotation) {
output = output + "\n";
firstAnnotation = false;
}
output = output + " "+ d + "\n";
}
return output.trim();
}
}
class GeneralTPApplied {
Map<String,String> parameterMapping = new HashMap<String,String>();
//---------------------------------end----------------------------------------
//----------------------------------------------------------------------------
//---------------------------------Start--------------------------------------
private void ApplyTypeParametersToMethod(Method newMethod){
for (String strType : this.getParameterMapping().keySet()) {
String newName = this.getParameterMapping().get(strType);
if (newMethod.getType().equals(strType)){
newMethod.setType(newName);
}
for (int i = 0; i < newMethod.numberOfMethodParameters(); i++) {
if(newMethod.getMethodParameter(i).getType().equals(strType)){
newMethod.getMethodParameter(i).setType(newName);
}
}
}
}
//---------------------------------end----------------------------------------
//----------------------------------------------------------------------------
//---------------------------------Start--------------------------------------
public GeneralTPApplied(GeneralTPApplied another) {
if (another == null) return;
this.parameterMapping = new HashMap<String, String>(another.parameterMapping);
this.inheritanceName = another.inheritanceName;
positions = another.positions;
stateMachineModifiers = new ArrayList<>(another.getStateMachineModifiers());
parameters = new ArrayList<>( Arrays.asList(another.getParameters()));
methodTemplateSignatures = new ArrayList<>(another.getMethodTemplateSignatures());
stateMachineTemplateSignatures = new ArrayList<>(another.getStateMachineTemplateSignatures());
}
//---------------------------------end----------------------------------------
//----------------------------------------------------------------------------
//---------------------------------Start--------------------------------------
boolean hasMethodTemplateSignature(MethodTemplateSignature inMTSignature) {
for (MethodTemplateSignature mTSignature : getMethodTemplateSignatures()) {
if (compareTwoMethdos(mTSignature.getMethod(),inMTSignature.getMethod())) return true;
}
return false;
}
//---------------------------------end----------------------------------------
//----------------------------------------------------------------------------
//---------------------------------Start--------------------------------------
boolean hasStateMachineTemplateSignature(StateMachineTemplateSignature inSMTSignature) {
for (StateMachineTemplateSignature smTSignature : getStateMachineTemplateSignatures()) {
if (smTSignature.getSrcStateMachine().equals(inSMTSignature.getSrcStateMachine()) && smTSignature.numberOfSrcStates()==inSMTSignature.numberOfSrcStates()){
boolean find = true;
for (int i = 0; i<smTSignature.numberOfSrcStates() ;i++) {
if (!smTSignature.getSrcState(i).equals(inSMTSignature.getSrcState(i))) {
find = false;
break;
}
}
if (!find) continue;
//TODO I can raise a different error for each of the following conditions
if (smTSignature.getModifier().equals("-") && inSMTSignature.getModifier().equals("+")) return true;
if (smTSignature.getModifier().equals("+") && inSMTSignature.getModifier().equals("-")) return true;
if (smTSignature.getModifier().equals("-") && !inSMTSignature.getAlias().equals("")) return true;
if (!smTSignature.getAlias().equals("") && inSMTSignature.getModifier().equals("-")) return true;
if (!smTSignature.getDesStateMachine().equals(inSMTSignature.getDesStateMachine()) && smTSignature.numberOfDesStates()==0 && inSMTSignature.numberOfDesStates()==0) return true;
if (smTSignature.getMethodTemplateSignature()==null && inSMTSignature.getMethodTemplateSignature()==null){
if (smTSignature.getAlias().equals(inSMTSignature.getAlias())){
if ((smTSignature.getModifier().equals("+")&&inSMTSignature.getModifier().equals("+"))||(smTSignature.getModifier().equals("-")&&inSMTSignature.getModifier().equals("-")) ){
return true;
}
}
if (!smTSignature.getAlias().equals(inSMTSignature.getAlias()) && !smTSignature.getAlias().equals("") && !inSMTSignature.getAlias().equals("")) return true;
if (smTSignature.getDesStateMachine().equals(inSMTSignature.getDesStateMachine())) return true;
}
if (smTSignature.getMethodTemplateSignature()!=null && inSMTSignature.getMethodTemplateSignature()!=null){
if (smTSignature.getMethodTemplateSignature().getMethod().compareWithTheMethod(inSMTSignature.getMethodTemplateSignature().getMethod())){
if (smTSignature.getAlias().equals(inSMTSignature.getAlias())){
if ((smTSignature.getModifier().equals("+")&&inSMTSignature.getModifier().equals("+"))||(smTSignature.getModifier().equals("-")&&inSMTSignature.getModifier().equals("-")) ){
return true;
}
} else return true;
}
}
}
}
return false;
}
//---------------------------------end----------------------------------------
//----------------------------------------------------------------------------
//---------------------------------Start--------------------------------------
Boolean hasStateMachineModifier(StateMachineModifier inSMModifier) {
for (StateMachineModifier smModifier : getStateMachineModifiers()) {
if(inSMModifier instanceof EventModifier && smModifier instanceof EventModifier) {
if (inSMModifier.getModifier().equals(smModifier.getModifier())){
if( inSMModifier.getSrcStateMachine().equals(smModifier.getSrcStateMachine()) && Arrays.equals( ((EventModifier)inSMModifier).getSrcStates(), ((EventModifier)smModifier).getSrcStates() ) && ((EventModifier)inSMModifier).getMethod().compareWithTheMethod(((EventModifier)smModifier).getMethod()) ) {
if (((EventModifier)inSMModifier).getGuard().isEqualTo(((EventModifier)smModifier).getGuard())){
//raise a warning that they are equal.
return true;
}
}
} else if( inSMModifier.getSrcStateMachine().equals(smModifier.getSrcStateMachine()) && Arrays.equals( ((EventModifier)inSMModifier).getSrcStates(), ((EventModifier)smModifier).getSrcStates() ) && ((EventModifier)inSMModifier).getMethod().compareWithTheMethod(((EventModifier)smModifier).getMethod()) ) {
if (((EventModifier)inSMModifier).getGuard().isEqualTo(((EventModifier)smModifier).getGuard())){
//raise a error that they two operations cannot be applied to one state.
return true;
}
}
//---------------------------------------------------------------------------------------
} else if(inSMModifier instanceof StateModifier && smModifier instanceof StateModifier) {
if (inSMModifier.getModifier().equals(smModifier.getModifier())){
if( inSMModifier.getSrcStateMachine().equals(smModifier.getSrcStateMachine()) && Arrays.equals( ((StateModifier)inSMModifier).getSrcStates(), ((StateModifier)smModifier).getSrcStates() ) ) {
//raise a warning that they are equal.
return true;
}
} else if( inSMModifier.getSrcStateMachine().equals(smModifier.getSrcStateMachine()) && Arrays.equals( ((StateModifier)inSMModifier).getSrcStates(), ((StateModifier)smModifier).getSrcStates() ) ){
//raise a error that they two operations cannot be applied to one state.
return true;
}
//---------------------------------------------------------------------------------------
} else if (inSMModifier instanceof StateMachineModifier && smModifier instanceof StateMachineModifier){
if (inSMModifier.getModifier().equals(smModifier.getModifier())){
if (inSMModifier.getSrcStateMachine().equals(smModifier.getSrcStateMachine())){
//raise a warning that they are equal.
return true;
}
} else if (inSMModifier.getSrcStateMachine().equals(smModifier.getSrcStateMachine())){
//raise a error that they two operations cannot be applied to one state.
return true;
}
//---------------------------------------------------------------------------------------
} else if(inSMModifier instanceof ExtendStateByStateMachine && smModifier instanceof ExtendStateByStateMachine) {
//TODO: Explore this case more.
}
}
return false;
}
//---------------------------------end----------------------------------------
//----------------------------------------------------------------------------
//---------------------------------Start--------------------------------------
public MethodTemplateSignature hasMethod(Method inMethod){
for (MethodTemplateSignature mTSignature : getMethodTemplateSignatures()) {
Method newMethod = new Method(mTSignature.getMethod());
ApplyTypeParametersToMethod(newMethod);
if (compareTwoMethdos(newMethod,inMethod)) return mTSignature;
}
return null;
}
//---------------------------------end----------------------------------------
//----------------------------------------------------------------------------
//---------------------------------Start--------------------------------------
private boolean compareTwoMethdos(Method method1, Method method2){
if (method1.getName().equals(method2.getName())){
// if(method1.getType().equals(method2.getType())){
Integer numberOfParams = method1.getMethodParameters().size();
if ( numberOfParams== method2.getMethodParameters().size()) {
boolean allSame = true;
for (int i = 0; i < numberOfParams; i++)
{
if(!method1.getMethodParameter(i).getType().equals(method2.getMethodParameter(i).getType()))
{
allSame = false;
break;
}
}
if(allSame)
{
return true;
}
}
// }
}
return false;
}
//---------------------------------end----------------------------------------
//----------------------------------------------------------------------------
//---------------------------------Start--------------------------------------
public String getAssignedStateMachineNewName(String srName){
for (StateMachineTemplateSignature smTSignature : getStateMachineTemplateSignatures()) {
if (smTSignature.getSrcStateMachine().equals(srName) && smTSignature.getSrcStates().length==0 && smTSignature.getAlias()!="" ) return smTSignature.getAlias();
}
return "";
}
//---------------------------------end----------------------------------------
//----------------------------------------------------------------------------
//---------------------------------Start--------------------------------------
}
class MethodTemplateSignature{
MethodTemplateSignature(MethodTemplateSignature another)
{
this.modifier = another.getModifier();
this.alias = another.getAlias();
this.method = new Method(another.getMethod());
}
//---------------------------------end----------------------------------------
//----------------------------------------------------------------------------
//---------------------------------Start--------------------------------------
}
class ModelConstraintResult
{
depend cruise.umple.parser.Position;
Position position;
int error;
target;
source;
}
class ModelConstraint
{
depend cruise.umple.compiler.*;
depend cruise.umple.parser.Position;
Position position;
0..1 parentConstraint -- * ModelConstraint;
String source = "this";
lazy String target;
String linkNext = "";
lazy String link;
ModelConstraint mostRecent = { getModelConstraint(numberOfModelConstraints()-1) }
const ModelConstraintResult SUCCESS = new ModelConstraintResult(null,-1,null,null);
const ModelConstraintResult AND = new ModelConstraintResult(null,-1,null,null);
const ModelConstraintResult OR = new ModelConstraintResult(null,-1,null,null);
before addModelConstraint { if(numberOfModelConstraints()>0)getMostRecent().setLink(getLinkNext()); }
public void addAssociationEnd(Multiplicity multiplicity)
{
if(getModelConstraint(numberOfModelConstraints()-1) instanceof ModelConstraintAssociation)
{
getModelConstraint(numberOfModelConstraints()-1).addAssociationEnd(multiplicity);
}
}
public void setAssociationType(String type)
{
if(getModelConstraint(numberOfModelConstraints()-1) instanceof ModelConstraintAssociation)
{
getModelConstraint(numberOfModelConstraints()-1).setAssociationType(type);
}
}
public ModelConstraintResult evaluate(UmpleClassifier uClassifier){
List<ModelConstraintResult> results = new ArrayList<ModelConstraintResult>();
for(ModelConstraint modelConstraint:getModelConstraints())
{
results.add(modelConstraint.evaluate(uClassifier));
if(!"".equals(modelConstraint.getLink()))
{
results.add("and".equals(modelConstraint.getLink())?ModelConstraint.AND:"or".equals(modelConstraint.getLink())?ModelConstraint.OR:null);
}
}
for(int i=1;i<results.size();)
{
if(results.get(i)==ModelConstraint.AND)
{
if(!results.get(i-1).equals(ModelConstraint.SUCCESS))
{
return results.get(i-1);
}
if(!results.get(i+1).equals(ModelConstraint.SUCCESS))
{
return results.get(i+1);
}
results.remove(i);
results.remove(i);
}
else
{
i+=2;
}
}
for(ModelConstraintResult i:results)
{
if(i==ModelConstraint.SUCCESS){
return ModelConstraint.SUCCESS;
}
}
return results.size()>0?results.get(0):ModelConstraint.SUCCESS;
}
}
class ModelConstraintAssociation
{
isA ModelConstraint;
depend cruise.umple.compiler.*;
depend cruise.umple.parser.Position;
Multiplicity leftHandMultiplicity = new Multiplicity();
Multiplicity rightHandMultiplicity = new Multiplicity();
type = "--";
boolean left = true;
after constructor { leftHandMultiplicity.setBound("*"); }
after constructor { rightHandMultiplicity.setBound("*"); }
public void addAssociationEnd(Multiplicity multiplicity)
{
if(left)
{
leftHandMultiplicity = multiplicity;
}
else
{
rightHandMultiplicity = multiplicity;
}
left = false;
}
public void setAssociationType(String aType)
{
type = aType;
left = false;
}
public ModelConstraintResult evaluate(UmpleClassifier uClassifier)
{
ModelConstraintResult evaluation = super.evaluate(uClassifier);
if(!evaluation.equals(ModelConstraint.SUCCESS))
{
return evaluation;
}
if("this".equals(getSource()))
{
setSource(uClassifier.getName());
}
if(type.equals("<-"))
{
String temp = getSource();
setSource(getTarget());
setTarget(temp);
Multiplicity tempMultiplicity = rightHandMultiplicity;
rightHandMultiplicity = leftHandMultiplicity;
leftHandMultiplicity = tempMultiplicity;
}
if(uClassifier instanceof UmpleClass)
{
UmpleClass uClass = null;
uClass = ((UmpleClass)uClassifier).getSourceModel().getUmpleClass(getSource());
if(uClass == null)
{
return new ModelConstraintResult(getPosition(),94,getTarget(),getSource());
}
for(Association association:uClass.getAssociations())
{
AssociationEnd theirs = null;
AssociationEnd mine = null;
if(association.getEnd(0).getClassName().equals(uClass.getName()))
{
theirs = association.getEnd(1);
mine = association.getEnd(0);
}
else if(association.getEnd(1).getClassName().equals(uClass.getName()))
{
theirs = association.getEnd(0);