Could we optimize the Helper.linkMap API?
adinn Apr 4, 2018 6:56 AMHi Rajiv,
rajiv.shivane wrote:
Now that you mention switching from a HashMap to field, it reminds me of a feature request. I will start a new thread about it, but here is roughly what I was thinking:
In our usage, there are many times a RuleHelper wants to store some properties against an object that was instrumented. For example when a user does DataSource.getConnection(), we want to store the Datasource.name onto the connection, so that later when we enter/exit methods on the Connection object the RuleHelper has access to the DataSource name. Today we keep these properties against the object in a WeakHashMap. It would be a lot more convenient if we added a HashMap field to all the classes we do bytecode transformation and the RuleHelpers had access to this HashMap. That way it would be simpler, performant, less prone to GC errors etc
Have you looked at the linkMap API in the standard Helper? I think this ought to do what you want. The basic API is
public void link(Object key, Object value) adds a link from key to value in the default LinkMap --- equivalent to calling link("default", key, value)
public Object linked(Object key) retrieves the value linked by key in the default LinkMap or null if no such key exists --- equivalent to calling linked("default", key)
public void link(Object linkMapId, Object key, Object value) inserts a link from key to value in the LinkMap identified by linkMapId, creating the LinkMap if needed
public Object linked(Object linkMapId, Object key) retrieves the value linked by key in the LinkMap identified by linkMapId or null if no such LinkMap or key is found
So, if I am understanding your requirement correctly you could use the following rule to establish the link:
RULE label Connection with DataSource name CLASS DataSource METHOD getConnection AT RETURN DO link($!, $0.name) ENDRULE
Other rules which have a handle on the connection (say it is parameter or local var $connection) would use a rule (BIND) var to downcast the retrieved link to a String
RULE use connection data source name . . . BIND name : String = linked($connection) DO . . . ENDRULE
The default LinkMap is often all you need. However, occasionally you need to create multiple links from the same object and that is where alternative LinkMaps become useful. Imagine you sometimes want to retrieve the dataSource and other times just want the name. In that case you would install the two values in two different named LinkMaps
. . . DO link("dataSourceName", $!, $0.name); link("dataSource", $!, $0); ENDRULE
You would then pass the appropriate LinkMap id at the point of retrieval
Rule use connection data source name . . . BIND name : String = linked("dataSourceName", $connection) DO . . . ENDRULE
or
Rule use connection data source . . . BIND dataSource : org.my.package.DataSource = linked("dataSource", $connection) DO . . . ENDRULE
I hope that is what you need. If not perhaps you could explain your use case in a bit more detail.
regards,
Andrew Dinn