Some Eclipse Foundation services are deprecated, or will be soon. Please ensure you've read this important communication.
Bug 339203 - Invalid evaluation of Java Service wrapper when using constant parameters
Summary: Invalid evaluation of Java Service wrapper when using constant parameters
Status: CLOSED INVALID
Alias: None
Product: Acceleo
Classification: Modeling
Component: Core (show other bugs)
Version: unspecified   Edit
Hardware: PC Windows XP
: P3 minor
Target Milestone: ---   Edit
Assignee: Project Inbox CLA
QA Contact:
URL:
Whiteboard:
Keywords:
Depends on:
Blocks:
 
Reported: 2011-03-08 07:17 EST by Rainer Menke CLA
Modified: 2011-03-08 07:58 EST (History)
1 user (show)

See Also:


Attachments

Note You need to log in before you can comment on or make changes to this bug.
Description Rainer Menke CLA 2011-03-08 07:17:14 EST
Build Identifier: I20100608-0911

Wrote a simple ecore-Model for property-Files, and made a simple test whether the definition and usage of variables is possible. I used Acceleo 3.1.0M5 for this. In the template I store for some reasons values temporary to access them for a later usage. If I use the java service with a static parameter, it seems like this java service call is optimized to be executed just one time.

First write a simple template, where two java services are used, one is for setting, the other for reading internal values:
[comment encoding = UTF-8 /]
[module generate('properties')/]

[query public setGlobalProperty(property: String , value: String) : Boolean = invoke('org.eclipse.acceleo.module.sample.services.GlobalProperties','setProperty(java.lang.String, java.lang.String)',Sequence{property,value})/]
[query public getGlobalProperty(property: String) : String = invoke('org.eclipse.acceleo.module.sample.services.GlobalProperties','getProperty(java.lang.String)',Sequence{property})/]

[template public generate(p : PropertiesType)]
	
[file ('props.txt', false, 'UTF-8')]
	[for ( pp : PropertyType | p.property ) ]
		[setGlobalProperty('lastProperty',pp.name)/]
		[setGlobalProperty(pp.name, pp.value)/]
Save of '[pp.name/]' with '[pp.value/]'
		[let last : String = pp.name ]
1.) read '[last/]' with '[getGlobalProperty(last)/]'
		[/let]
		[let last : String = getGlobalProperty('lastProperty') ]
2.) read '[last/]' with '[getGlobalProperty(last)/]'
		[/let]
	[/for]
[/file]
	
[/template]

2.) Implement the java services:
public class GlobalProperties {
	private static Properties properties = new Properties();
	public static String getProperty( String property ) {
		String value = properties.getProperty( property );
		System.out.println( "getProperty: property '" + property + "' value '" + value + "'" );
		return value;
	}
	public static void setProperty(String property,String value) {
		String _value = properties.getProperty( property );
		System.out.println( "setProperty: property '" + property + "' value '" + value + "' replacing '" + _value + "'" );
		properties.setProperty( property, value );
		_value = properties.getProperty( property );
		System.out.println( "setProperty: property '" + property + "' value '" + _value + "'" );
	}
}

Under the console you see:

setProperty: property 'lastProperty' value 'a' replacing 'null'
setProperty: property 'lastProperty' value 'a'
setProperty: property 'a' value 'b' replacing 'null'
setProperty: property 'a' value 'b'
getProperty: property 'a' value 'b'
getProperty: property 'lastProperty' value 'a'
setProperty: property 'lastProperty' value 'b' replacing 'a'
setProperty: property 'lastProperty' value 'b'
setProperty: property 'b' value 'c' replacing 'null'
setProperty: property 'b' value 'c'
getProperty: property 'b' value 'c'
setProperty: property 'lastProperty' value 'd' replacing 'b'
setProperty: property 'lastProperty' value 'd'
setProperty: property 'd' value 'e' replacing 'null'
setProperty: property 'd' value 'e'
getProperty: property 'd' value 'e'

As result the following is produced:

Save of 'a' with 'b'
1.) read 'a' with 'b'
2.) read 'a' with 'b'
		
Save of 'b' with 'c'
1.) read 'b' with 'c'
2.) read 'a' with 'b'
		
		
Save of 'd' with 'e'
1.) read 'd' with 'e'
2.) read 'a' with 'b'


Reproducible: Always

Steps to Reproduce:
1.) Take some input model (independent)
2.) Build two java services, one for storing, one for accessing 
3.) Write a template where the values of some variables are exchanged during the generation phase

See the details for implementation ;-)
Comment 1 Rainer Menke CLA 2011-03-08 07:44:08 EST
Same works, if a "random" function with no parameter is used. Only iff a service wrapper has at least one parameter, which is not constant, the service wrapper is invoked multiple times.
Comment 2 Stephane Begaudeau CLA 2011-03-08 07:58:37 EST
I haven't read in detail your example but this sentence seems to explain your whole problem: "it seems like this java service call is optimized to be executed just one time." The problem is not the Java service, the problem comes from the query.

Your Java service is inside of a query. A query has its result stored in a cache, if you call it twice in a row with the same argument, we won't execute it again, we will look for the result in the cache. You should try with the [invoke(...)/] in a template like this:

[template public setGlobalProperty(property: String , value: String)][invoke('org.eclipse.acceleo.module.sample.services.GlobalProperties','setProperty(java.lang.String, java.lang.String)',Sequence{property,value})/][/template]

and

[template public getGlobalProperty(property: String)]
[invoke('org.eclipse.acceleo.module.sample.services.GlobalProperties','getProperty(java.lang.String)',Sequence{property})/][/template]

With a query, "getGlobalProperty('lastProperty')" will always be evaluated only one time since it always uses the same parameter.

If you want to improve the performances of a generator, you can use some well chosen queries for the big operations on your model like MyModelRoot.eAllContents() for example.