Skip to main content


Eclipse Community Forums
Forum Search:

Search      Help    Register    Login    Home
Home » Modeling » M2T (model-to-text transformation) » [Acceleo 3] Prevent elements from being parsed more than once(Reflexsive Template call with nested for loops parses model elemnts more than once)
[Acceleo 3] Prevent elements from being parsed more than once [message #554381] Sun, 22 August 2010 18:06 Go to next message
No real name is currently offline No real nameFriend
Messages: 8
Registered: August 2010
Junior Member
Hello
Firstable I want to excuse myself for my bad english language skills. Im a student from Germany and I use Acceleo within my Master Thesis. I ran into a problem that I couldn't solve with the help of the documentation or the existing forum posts. I really hope someone can help me.
The Problem I have is the following:

I try to generate XML Code : I have written one Template which parses the relevant Modelelements and generates the XML Tags and . All XML Tags and the Child elements of an XML Tag are generated via a reflexsive template call. Lets assume we have the following XML Tags <foo> , <bar1>,<bar2>,<bar3> . In general I want to create the following XML Structures
The XML element <foo> "wraps" each other Tag (bar1,bar2,bar3)

<foo>
<bar></bar>
</foo>
<foo>
<bar1></bar1>
</foo>
<foo>
<bar2></bar2>
</foo>

The XML element <foo> "holds" each other Tag (bar1,bar2,bar3)

<foo>
<bar1></bar1><bar2></bar2><bar3></bar3>
</foo>

The XML element <foo> "hods" no other Tag

<foo></foo>
<bar1></bar1>
.......

The Following "Pseude Code" discribes the Template for the Genration of the XML Code and its Structure. I really hope this makes things clear.
........
[template public genTags(element : Element)]
[if (element.isWrapsEachChild())]
[for (child : Element | element.getChildren())]
[genOpeningTag(element)/]
[genTags (child)/]
[genClosingTag(element)/]
[/for]
[elseif (element.isHoldsChildren()) ]
[genOpeningTag(element)/]
[for (child : Element | element.getChildren())]
[genTags (child)/]
[/for]
[genClosingTag(element)/]
[else if(element.isHoldsNoChildren()) ]
[genOpeningTag(element)/]
[genClosingTag(element)/]
[/if]
[for (child : Element | element.getChildren())]
[genTags (child)/]
[/for]
[/if]
[/template]

The Problem is that I have two for loops which are parsing the child elements, Therefore the child elements are parsed more than once and therefore also created more than once. I know that it is not possible in Acceleo to define a global Variable to store the elements which are already generated. Furthermore Variables are final. Furthermore its not possible to break or stop a loop. Is there any way to define a condition which prevents elements from beeing parsed again ?

I have also tried to pass the generated Elements via a parameter each time I call the template recursively without any luck. I also tried to store and read the id of the already generated Elements in a separate File. I called a Java service Method for this. In order to keeps things synchronized I put a wait() after the flush() (To wait until the Operating System has finished writing into the file). But it seems that the template call is still faster then writing into the file I assume that a Java method which is called by a Template is run in a separate Thread. Is this right ? The following two methods I use to read and write the ids in a separate file

public void write(String elementId) {
FileWriter writer;
try {
writer = new FileWriter("path to exisiting file", true);
writer.write(elementId + "\n");
writer.flush();
writer.close();
wait(1000);
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}

}

public boolean read(String elementId) {
FileReader fr;
boolean found = false;
try {
fr = new FileReader("path to existing File");
BufferedReader br = new BufferedReader(fr);
String s;
while ((s = br.readLine()) != null && found == false) {
if (s.trim().replace("\n", "").equals(id.trim().replace("\n", "")))
{ found = true;
}
}
fr.close();
} catch (FileNotFoundException e) {
// TODO Auto-generated catch block
e.printStackTrace();
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
return found;
}

Another thing I tried was to store the ids of generated elements in a Databasetable. I also called a java service method in the Template to do that. The following method I used to

public void writeID(String id) {
Connection conn;
try { Class.forName("com.mysql.jdbc.Driver").newInstance();
String url = "jdbc:mysql://URL FOR DB";
conn = DriverManager.getConnection(url, "username", "password");
Statement st = conn.createStatement();
st.executeUpdate("INSERT IGNORE INTO IDTABLE" + "VALUES ('" + id + "')");
conn.close();
} catch (ClassNotFoundException ex) {
System.err.println(ex.getMessage());
} catch (IllegalAccessException ex) {
System.err.println(ex.getMessage());
} catch (InstantiationException ex) {
System.err.println(ex.getMessage());
} finally {
return;
}
}

For some reason the Java Service method is not executed correctly. Its not going into the try block. When I execute the method as a Java Program it works. Actually im stuck and I'm really thankfull for any help.

[Updated on: Sun, 22 August 2010 18:32]

Report message to a moderator

Re: [Acceleo 3] Prevent elements from being parsed more than once [message #554402 is a reply to message #554381] Sun, 22 August 2010 20:05 Go to previous messageGo to next message
s2o  is currently offline s2o Friend
Messages: 4
Registered: August 2010
Junior Member
Hi,

I'm sorry, if I understand, you wanna do something like http://www.15seconds.com/issue/000803.htm

well, really a recursive function tree. If this is true, you don't need / have to use global variables. The mistake should be in your function... I don't know where Smile

I searched something like "recursive function tree" in google.

s2o.
Re: [Acceleo 3] Prevent elements from being parsed more than once [message #554442 is a reply to message #554381] Mon, 23 August 2010 08:08 Go to previous messageGo to next message
Stephane Begaudeau is currently offline Stephane BegaudeauFriend
Messages: 454
Registered: April 2010
Location: Nantes (France)
Senior Member

Hi,

If you want to prevent elements from being parsed more than once, you can create an utility class in order to keep a list of what you have manipulated. In order to be sure that it works, I have created an example in which I don't want to manipulate two classes with names that have the same length. I'm sure you can try something like this: Click me !!

Stephane Begaudeau, Obeo
Re: [Acceleo 3] Prevent elements from being parsed more than once [message #554678 is a reply to message #554381] Tue, 24 August 2010 05:20 Go to previous messageGo to next message
No real name is currently offline No real nameFriend
Messages: 8
Registered: August 2010
Junior Member
I manged to solve my problem by using a recursive algorithm to parse the tree structure of my Model. Thanks to everyone for your help.
Re: [Acceleo 3] Prevent elements from being parsed more than once [message #555525 is a reply to message #554678] Fri, 27 August 2010 02:55 Go to previous messageGo to next message
No real name is currently offline No real nameFriend
Messages: 8
Registered: August 2010
Junior Member
[query public hasBeenGenerated(id : String) : Boolean = invoke('org.pim.uml2.common.Utility',
'hasBeenGenerated(java.lang.String)', Sequence{id})/]

public static List<String> list = new ArrayList<String>();

public boolean hasBeenGenerated(String id) {
boolean result = false;
for (String str : list) {
if (str.trim() == id.trim()) {
result = true;
}
if (!result) {
list.add(id);
}
}
return list.contains(id);
}

i tried to use the utility because the model im using do not a "real" tree strucuture as it turned out thats why i need to store the parsed elements. Well the java service method always return me an empty string. an the execution of the template is stopped . I dont know what im doing wrong
Re: [Acceleo 3] Prevent elements from being parsed more than once [message #555526 is a reply to message #554678] Fri, 27 August 2010 03:04 Go to previous messageGo to next message
No real name is currently offline No real nameFriend
Messages: 8
Registered: August 2010
Junior Member
public static List<String> list = new ArrayList<String>();

public boolean hasBeenGenerated(String id) {
boolean result = false;
for (String str : list) {
if (str == id) {
result = true;
}
if (!result) {
list.add(id);
}
}
return result;
}

[query public hasBeenGenerated(id : String) : Boolean = invoke('org.pim.uml2.common.Utility',
'hasBeenGenerated(java.lang.String)', Sequence{id})/]

i tried to implement the utility class but when i call the java service via the query the tempate returns me an empty string. I dont know what im doing wrong. Please help me

[Updated on: Fri, 27 August 2010 03:28]

Report message to a moderator

Re: [Acceleo 3] Prevent elements from being parsed more than once [message #555553 is a reply to message #554381] Fri, 27 August 2010 07:13 Go to previous messageGo to next message
Stephane Begaudeau is currently offline Stephane BegaudeauFriend
Messages: 454
Registered: April 2010
Location: Nantes (France)
Senior Member

Hi,

With the following instruction it won't work: "if (str == id)"
You should use "str.equals(id)" or "str.equalsIgnoreCase(id)" to compare two strings but not "=="

Stephane Begaudeau, Obeo
Re: [Acceleo 3] Prevent elements from being parsed more than once [message #555742 is a reply to message #555553] Sat, 28 August 2010 04:50 Go to previous messageGo to next message
No real name is currently offline No real nameFriend
Messages: 8
Registered: August 2010
Junior Member
Hi

I changed the Method as you have suggested but unfortunatly its still not working the way it should do. I have debugged the template and the result of the java service method is 'Invalid_Class' which i think is equivalent to 'null' . Thats means that there must be an error while the execution of the java service method. Therefore i have made some test and reduced the Java Service Method so it just returns a boolean value and nothing else but the result is still 'Invalid_Class'. I have made a picture of the debug result. The picture also shows the Template and the java service method i call.

http://a.imageshack.us/img695/4218/invalidclass2.jpg

Im sorry to bother you with this again. But i have no idea why the java method returns 'Invalid_Class'. Hope the picture helps
Re: [Acceleo 3] Prevent elements from being parsed more than once [message #555760 is a reply to message #554381] Sat, 28 August 2010 11:18 Go to previous messageGo to next message
No real name is currently offline No real nameFriend
Messages: 8
Registered: August 2010
Junior Member
Well i found the Problem there was a mistake in the package path that i used in the invoke method.

But i have a question. How long does an Object life that holds the java service method when it is called in a template. What happens to the object when a template is called recursivly. Is it still the same object that is refernced by the mathod call or is a new instance generated. Im asking this because when i parse my model . The java service method i wrote always returns false even though an element is parsed more than once. One explanation for that would be that each time i call the template recursivly it creates a new Object which holds an empty List. Am i wrong or right ?
Re: [Acceleo 3] Prevent elements from being parsed more than once [message #555772 is a reply to message #555760] Sat, 28 August 2010 12:48 Go to previous messageGo to next message
No real name is currently offline No real nameFriend
Messages: 8
Registered: August 2010
Junior Member
As far as i understand it the variable in the Java service Method is defined static which means its independant from the existance of an object from this class. Does this mean that when i call a Java Method from my template there is no instance which gets generated ?. If that is the case what happens to the static variable after the execution of the method ? Is it still referenced by the template ? What happens when a template is called recursive like i have to to do. Is there any reference remaining or does the garbage collector delete everything ? Is there any Lifecircle Management ? Maybe i got it totally wrong.
Re: [Acceleo 3] Prevent elements from beeing parsed more then once [message #555921 is a reply to message #554381] Mon, 30 August 2010 09:05 Go to previous message
Laurent Goubet is currently offline Laurent GoubetFriend
Messages: 1876
Registered: July 2009
Senior Member
This is a multi-part message in MIME format.
--------------060001010207030007070809
Content-Type: text/plain; charset=UTF-8; format=flowed
Content-Transfer-Encoding: 7bit

Hi Andre,

Taking this thread "en route" isn't really easy ... I think there's a
lot of confusion here with the java services, databases and whatnot.

If I understand the core question well, you have a problem with this
generating tags more than once for a given element :

[template public genTags(element : Element)]
[if (element.isWrapsEachChild())]
[for (child : Element | element.getChildren())]
[genOpeningTag(element)/]
[genTags (child)/]
[genClosingTag(element)/]
[/for]
[elseif (element.isHoldsChildren()) ]
[genOpeningTag(element)/]
[for (child : Element | element.getChildren())]
[genTags (child)/]
[/for]
[genClosingTag(element)/]
[else if(element.isHoldsNoChildren()) ]
[genOpeningTag(element)/]
[genClosingTag(element)/]
[/if]
[for (child : Element | element.getChildren())]
[genTags (child)/]
[/for]
[/if]
[/template]

I copy/pasted the code from your first post.

1 - Was that copy pasted from your module? if yes, Acceleo shouldn't
compile, you have an orphan "[/if]" at the end of this template.
2 - Exactly which for loop poses a problem to you? if it is the last,
couldn't you put this last loop in an "else" clause of your main if/else?
3 - You can set guards on for loops, couldn't it help? [for (child :
Element | ...) ? (element.isWrapsEachChild())/] for example.

Couldn't you use :

[template public genTags(element : Element)]
[if (element.isWrapsEachChild())]
[for (child : Element | element.getChildren())]
[genOpeningTag(element)/]
[genTags (child)/]
[genClosingTag(element)/]
[/for]
[else]
[genOpeningTag(element)/]
[if (element.isHoldsChildren()]
[element.getChildren().genTags()/]
[/if]
[genClosingTag(element)/]
[/if]
[/template]

Please hold the question(s) concise :p.

Laurent Goubet
Obeo

--------------060001010207030007070809
Content-Type: text/x-vcard; charset=utf-8;
name="laurent_goubet.vcf"
Content-Transfer-Encoding: base64
Content-Disposition: attachment;
filename="laurent_goubet.vcf"

YmVnaW46dmNhcmQNCmZuOkxhdXJlbnQgR291YmV0DQpuOkdvdWJldDtMYXVy ZW50DQpvcmc6
PGEgaHJlZj0iaHR0cDovL3d3dy5vYmVvLmZyIj5PYmVvPC9hPg0KZW1haWw7 aW50ZXJuZXQ6
bGF1cmVudC5nb3ViZXRAb2Jlby5mcg0KdXJsOmh0dHA6Ly93d3cub2Jlby5m cg0KdmVyc2lv
bjoyLjENCmVuZDp2Y2FyZA0KDQo=
--------------060001010207030007070809--
Previous Topic:[Acceleo 3] hasStereotype
Next Topic:[Acceleo] How to determine why a template isn't called
Goto Forum:
  


Current Time: Wed Jan 22 00:05:42 GMT 2020

Powered by FUDForum. Page generated in 0.01674 seconds
.:: Contact :: Home ::.

Powered by: FUDforum 3.0.2.
Copyright ©2001-2010 FUDforum Bulletin Board Software

Back to the top