Skip to content

Commit

Permalink
Merge pull request #1815 from umple/refactorInnotaiveToComp
Browse files Browse the repository at this point in the history
A generator to refactor annotative mixsets into compositional mixsets
  • Loading branch information
TimLethbridge committed Aug 3, 2021
2 parents e8085a9 + c8ce512 commit 80fefdc
Show file tree
Hide file tree
Showing 7 changed files with 215 additions and 10 deletions.
2 changes: 2 additions & 0 deletions cruise.umple/src/Generator.ump
Expand Up @@ -78,6 +78,7 @@ use EventSequenceGenerator, FeatureDiagramCo, EntityRelationshipCon, Simulate
use XtextGenerator, JsonGenerator, JsonMixedGenerator, StructureDiagramGenerator , GvStateDiagramGenerator;
use StateTableGenerator, SuperGvGeneratorGenerator, HtmlGenerator, UmpleModelWalkerGenerator, CodeAnalysisGenerator;
use AlloyGenerator, NuSMVGenerators, NuSMVGenerator, NuSMVOptimizerGenerator, SimpleMetricsGenerator, CodeGvClassDiagramGenerator;
use UmpleAnnotaiveToCompositionGenerator;
//End

// Base case generator, allows compilation without generation for testing command line, since Java is default
Expand Down Expand Up @@ -124,5 +125,6 @@ mixset SuperGvGeneratorGenerator{ use generators/Generator_SuperGvGenerator.ump;
mixset HtmlGenerator{ use generators/Generator_Html.ump;}
mixset UmpleModelWalkerGenerator{ use generators/Generator_UmpleModelWalker.ump;}
mixset CodeAnalysisGenerator{ use generators/Generator_CodeAnalysis.ump;}
mixset UmpleAnnotaiveToCompositionGenerator { use generators/Generator_CodeAnnotaiveToComposition.ump; }
//End

4 changes: 2 additions & 2 deletions cruise.umple/src/class/UmpleInternalParser_CodeClass.ump
Expand Up @@ -3287,7 +3287,7 @@ private Boolean checkIsDistributed(UmpleInterface uInterface)
String methodCode = token.getValue();
// process mixsets inside code
mixset Mixset {
methodCode = processInlineMixset(token.getValue());
methodCode = processInlineMixset(token.getValue(), meth);
} // end of MIXSET
cb.setCode(methodCode);
aMethod.setCodePosition(token.getPosition());
Expand Down Expand Up @@ -4107,7 +4107,7 @@ private Boolean checkIsDistributed(UmpleInterface uInterface)
{
String aspectCode = sub.getValue();
mixset Mixset {
aspectCode = processInlineMixset(sub.getValue());
aspectCode = processInlineMixset(sub.getValue(), null);
}
if(langs.size()==0)
{
Expand Down
135 changes: 135 additions & 0 deletions cruise.umple/src/generators/Generator_CodeAnnotaiveToComposition.ump
@@ -0,0 +1,135 @@
/*

Copyright: All contributers to the Umple Project

This file is made available subject to the open source license found at:
http://umple.org/license

*/

namespace cruise.umple.compiler;

class UmpleAnnotaiveToCompositionGenerator
{
isA CodeGeneratorWithSubptions;
depend java.io.*;
depend java.util.*;
depend cruise.umple.util.*;
depend cruise.umple.compiler.exceptions.*;
depend java.util.stream.Collectors;
UmpleModel model = null;
String output = "";

fileExtension= ".ump";

// CENTRAL GENERATE METHOD

public void generate(){
StringBuilder code = new StringBuilder();
List<Mixset> mixsetList = model.getMixsetOrFiles().stream().filter(mixset -> mixset.getIsMixset()).map(obj -> (Mixset)obj).collect(Collectors.toList());
code.append("/* \n");
code.append("Annotaive fragments are refactored into composition fragments. \n");
code.append("Total mixsts definitions: "+mixsetList.size());
code.append("\n*/ \n");
code.append("//*** \n");
code.append("//Coarse-grained variability : \n");

for (Mixset aMixset: mixsetList)
{
code.append("\n");
code.append("mixset "+aMixset.getMixsetName() + " { ") ;
for (MixsetFragment mFragment : aMixset.getMixsetFragments())
{
code.append("\n// Fragment source file: "+mFragment.getOriginalUmpFile().getFileName());
code.append("\n// Line : "+mFragment.getOriginalUmpLine());
code.append("\n"+mFragment.getBody());
code.append("\n");
}
code.append("\n}\n") ;
}
//
code.append("//*** \n");
code.append("//Fine-grained variability : \n");
//
int labelCount= 1;
List<UmpleClass> umpleClasses = model.getUmpleClasses().stream().filter(classM -> classM.getMethods().size() > 0).collect(Collectors.toList());
for (UmpleClass aClass : umpleClasses)
{
String className = aClass.getName();
String classInlineMixset ="";
try
{
List<Method> methodsWithInlineMixset = aClass.getMethods().stream().filter(classM -> classM.getMethodBody() != null).collect(Collectors.toList());
for (Method method : methodsWithInlineMixset)
{
List<MixsetInMethod> mixsetInMethodList = method.getMethodBody().getMixsetInMethods();
for (MixsetInMethod mixsetInMethod : mixsetInMethodList)
{
// prepare parameter types
String injectionParameters = "";
List<String> paramList = method.getMethodParameters().stream().map(aParam -> aParam.getType()).collect(Collectors.toList());
String paramListCommaSeparated = String.join(",", paramList);
if(paramList.size() > 0)
injectionParameters = "("+paramListCommaSeparated+ ")";
// define a labeled aspect injection.
String mixsetBody = mixsetInMethod.getMixsetFragment();
mixsetBody = mixsetBody.substring(mixsetBody.indexOf("{"));
classInlineMixset+="mixset " + mixsetInMethod.getMixsetName() + " { \n";
classInlineMixset+=" class " + className + " { \n"; // start class definition
classInlineMixset+=" before "+ "Lable_"+mixsetInMethod.getMixsetName()+"_"+labelCount+":"+ method.getName()+ injectionParameters+"\n "+ mixsetBody;
classInlineMixset+=" } \n";
classInlineMixset+="} \n"; // end class definition.
labelCount ++;
// two empty line after each aspect injection.
classInlineMixset+="\n\n";
}
}
if(classInlineMixset.trim().length() > 1)
{
code.append(classInlineMixset);
}
}
catch(NullPointerException ex)
{
continue;
}
}
code.append("\n");
model.setCode(code.toString());
writeModel();
}


private String spacer(int num)
{
StringBuilder space = new StringBuilder();
for (int i = 0; i < num; i++)
{
space.append(" ");
}
return space.toString();
}

private void writeModel()
{
try
{
String path = model.getUmpleFile().getPath();
File file = new File(path);
file.mkdirs();
String modelFilename = path + File.separator + model.getUmpleFile().getSimpleFileName()+"_refactoredToComposition" + this.fileExtension ;
BufferedWriter bw = new BufferedWriter(new FileWriter(modelFilename));
bw.write(model.getCode());
bw.flush();
bw.close();
}
catch (Exception e)
{
throw new UmpleCompilerException("There was a problem with generating UmpleSelf code." + e, e);
}
}



}

31 changes: 23 additions & 8 deletions cruise.umple/src/mixset/UmpleInternalParser_CodeMixset.ump
Expand Up @@ -368,6 +368,17 @@ class UmpleInternalParser

mixsetFragmentLineNumber = mixsetFragmentPosition.getLineNumber();
UmpleFile mixsetFragmentUmpleFile = model.getUmpleFile(); // where the mixset keyword is encountered. Not the use statement
// Start: update the fragment file if the fragment came from a file included by use statement.
Token lookForUseStToken = token;
while((lookForUseStToken = lookForUseStToken.getParentToken()) != null)
{
if(lookForUseStToken.is("useStatement"))
{
mixsetFragmentUmpleFile = new UmpleFile(lookForUseStToken.getSubToken("use").getValue());
break;
}
}
//End
MixsetFragment mixsetFragment = new MixsetFragment(mixsetFragmentUmpleFile, mixsetFragmentLineNumber, mixsetBody);
return mixsetFragment;
}
Expand Down Expand Up @@ -452,14 +463,18 @@ class UmpleInternalParser
}
}
// a helper method that process pure code to either remove it or to let mixset content stay.
private String processInlineMixset(String methodCode) {
// process mixsets inside code
ArrayList<MixsetInMethod> mixsetInCodeList = MethodBody.getMixsetsFromCode(methodCode) ;
for (MixsetInMethod aMixsetInMethod : mixsetInCodeList)
{
// update the code according to use statements (of mixsets)
methodCode = MethodBody.handelMixsetInsideMethod(this.getModel(), aMixsetInMethod, methodCode);
}
private String processInlineMixset(String methodCode, MethodBody methodBody) {
// process mixsets inside code
ArrayList<MixsetInMethod> mixsetInCodeList = MethodBody.getMixsetsFromCode(methodCode) ;
for (MixsetInMethod aMixsetInMethod : mixsetInCodeList)
{
// update the code according to use statements (of mixsets)
methodCode = MethodBody.handelMixsetInsideMethod(this.getModel(), aMixsetInMethod, methodCode);
if(methodBody !=null)
{
methodBody.addMixsetInMethod(aMixsetInMethod);
}
}
return methodCode;
}
}
Expand Down
Expand Up @@ -14,6 +14,8 @@
import cruise.umple.compiler.exceptions.*;
import cruise.umple.compiler.php.PhpClassGenerator;
import java.io.File;
import cruise.umple.compiler.UmpleAnnotaiveToCompositionGenerator;


public class UmpleMixsetTest {

Expand Down Expand Up @@ -697,5 +699,25 @@ public void inlineMixsetsInsideAspectCode()
//delete generated file
SampleFileWriter.destroy(umpleParserTest.pathToInput+"/AspectClass.java");
}
@Test
public void refactorInlineMixsetIntoCompMixset()
{
UmpleFile umpleFile = new UmpleFile(umpleParserTest.pathToInput,"parseRefactorInlineMixsetIntoCompMixset.ump");
UmpleModel umpModel = new UmpleModel(umpleFile);
umpModel.setShouldGenerate(true);
umpModel.run();
UmpleAnnotaiveToCompositionGenerator umpleAnnotaiveToCompositionGenerator = new UmpleAnnotaiveToCompositionGenerator();
umpleAnnotaiveToCompositionGenerator.setModel(umpModel);
umpleAnnotaiveToCompositionGenerator.generate();
String generatedFile = umpleParserTest.pathToInput+"/parseRefactorInlineMixsetIntoCompMixset_refactoredToComposition.ump";
SampleFileWriter.assertFileExists(generatedFile);
String templateGeneratedCode = SampleFileWriter.readContent(new File(generatedFile));
// included mixsets
Assert.assertTrue(templateGeneratedCode.contains("class Bank { 1 -- 1..* Branch; }"));
SampleFileWriter.destroy(generatedFile);
SampleFileWriter.destroy(umpleParserTest.pathToInput+"/Bank.java");
SampleFileWriter.destroy(umpleParserTest.pathToInput+"/Account.java");
SampleFileWriter.destroy(umpleParserTest.pathToInput+"/Branch.java");
}

}
@@ -0,0 +1,29 @@
class Bank {
1 -- * Account;
mixset Multibranch
{
1 -- 1..* Branch;
}

/*
void withdraw(int amount){
if (amount > 0)
//some code
mixset Multibranch
{
amount = amount - someFees;
}
}
*/
}

mixset Multibranch {
class Branch {
Integer id; String address;
}
}

class Account {
owner; Integer number; Integer balance;
mixset Multibranch { * -- 1 Branch;}
}
2 changes: 2 additions & 0 deletions umpleonline/scripts/compiler_config.php
Expand Up @@ -313,6 +313,8 @@ function generateMenu($buttonSuffix)
<option value=\"html:CodeAnalysis\">Code Analysis</option>
<option value=\"java:USE\">USE Model</option>
<option value=\"java:UmpleSelf\">Internal Umple Representation</option>
<option id=\"genUmpleAnnotaiveToComposition\" value=\"java:UmpleAnnotaiveToComposition\" >Compositional Mixsets from Inline Mixsets </option>
</select>
</li>
<li id=\"ttGenerateCode\">
Expand Down

0 comments on commit 80fefdc

Please sign in to comment.