You are not logged in.
Hi!
First of all I explain what I do:
I have script file A and script file B - both are in folder which is "Share folder for web access".
In script B I have defined classes which I use in script A.
In script A I do:
GLOBALS.exec("/fileserver/bin/shared/B.groovy");
I don't restart Report Server when I change script here.
I call script A from URL and I get result as JSON.
When I make changes in script A everything works as I expect.
Problem is when I change sth inside class in script B because I cannot see changes of script B from script A...
What's strange if I change name in script B (class name or method name) I get an exception, but when I change sth only inside method of class in script B and call script A I don't see changes which I made in script B.
Is there any caching? Can I foce ReportServer to reload attached script without restarting ReportServer every time I make changes in script?
Last edited by Patryx (2019-07-02 08:23:11)
Offline
I notice that if I go to Report Server Administration, open Terminal and execute script B, than it also starts to work properly. Could you explain how to write script to use in GLOBALS.exec?
Offline
Hi Patryx,
please post a minimal version of both scripts where this happens. Ideal would be only one method and a simple output in the method.
Regards,
Eduardo
Offline
Script A.groovy:
/* Add nested script files with classes */
GLOBALS.exec("/fileserver/bin/shared/B.groovy");
return new MyError(code: 403, message: "Forbidden eror!").createJsonObject().toString();
Script B.groovy:
/* Script with utils classes */
import org.json.*;
/* Class MyError */
public class MyError {
public int code
public String message
public JSONObject createJsonObject(String rootName = "error") {
JSONObject jo = new JSONObject();
jo.put("code", this.code ?: JSONObject.NULL);
jo.put("message", this.message ?: JSONObject.NULL);
if (rootName) {
JSONObject mainObj = new JSONObject();
mainObj.put(rootName, jo ?: JSONObject.NULL);
return mainObj;
}
return jo;
}
}
When I call script:
http://.../reportserver/scriptAccess?path=/bin/shared/A.groovy
I get such a result:
{"error":{"code":403,"message":"Forbidden eror!"}}
Then I change file B.Groovy adding one line:
jo.put("test", "added test msg"); // new added field
/* Script with utils classes */
import org.json.*;
/* Class MyError */
public class MyError {
public int code
public String message
public JSONObject createJsonObject(String rootName = "error") {
JSONObject jo = new JSONObject();
jo.put("code", this.code ?: JSONObject.NULL);
jo.put("message", this.message ?: JSONObject.NULL);
jo.put("test", "added test msg"); // new added field
if (rootName) {
JSONObject mainObj = new JSONObject();
mainObj.put(rootName, jo ?: JSONObject.NULL);
return mainObj;
}
return jo;
}
}
When call url again I get the same result:
{"error":{"code":403,"message":"Forbidden eror!"}}
There should have been a field: "test":"added test msg".
Offline
Hi Patryx,
here you have a lot of things, including JSON, etc. Does this also happen for a more minimal example? E.g. without JSON. Just some printout lines. If I understand correctly your description it should, or ? If yes please post the most minimal example you can think of where this happens.
Regards,
Eduardo
Offline
Hi Eduardo,
It's a minimal one...
I changed for you:
A.groovy:
/* Add nested script files with classes */
GLOBALS.exec("/fileserver/bin/shared/B.groovy");
return new MyError().prepareString();
B.groovy:
/* Class MyError */
public class MyError {
public String prepareString() {
return "Easy example v1";
}
}
As result:
Easy example v1
I change B.groovy:
/* Class MyError */
public class MyError {
public String prepareString() {
return "Easy example v2";
}
}
I get the same string with v1 as a result to call the script A.groovy again. Changing browser doesn't help (not connected with session).
The example doesn't matter in this case...
Last edited by Patryx (2019-07-02 13:45:39)
Offline
Hi Patryx,
thanks for the simple scripts. Compiled scripts are being cached, yes. We will think of a solution of being able to clear the cache, maybe a new terminal command or similar: RS-2755
I will update here when I have more information.
Regards,
Eduardo
Offline
Hi Eduardo,
I would be gratefull if I have oportunity to clear such a cache, in terminal or maybe in script before doing GLOBALS.exec.
Any workaround till that time to force to clear a cache? I think restarting ReportServer does not always help, am I right?
Offline
Hi Patryx,
yes, both ideas seem good. I noted both into the ticket.
Restarting reportserver should always help as a workaround.
Regards,
Eduardo
Offline
Hi,
Unfortunately restarting server doesn't help!
In my script "A.groovy" I have GLOBALS.exec("B.groovy") and GLOBALS.exec("C.groovy").
"B.groovy" has some utils methods shared between other scripts. "C.groovy" has some classes used by some scripts.
After restarting the server I call from url:
http://reportbase/reportserver/scriptAccess?path=/bin/shared/A.groovy&exception=true
And I get an error that classes (defined in "C.groovy") are unabled to resolve
If I want to use script "A.groovy" I have to do FIRST:
1) use Terminal and exec C.groovy
2) or call first http://reportbase/reportserver/scriptAccess?path=/bin/shared/C.groovy
After that "A.groovy" works as I expected...
What's interesting I don't have problem with "B.groovy" - the methods work and are seen by script "A.groovy" without any calling/executiong before.
As a result I think that there is asynchronous mechanism to load scripts for the first time after restarting server so I cannot use GLOBALS.exec at all...
How can I fix this problem?
I see only one solution nowadays: copy contents of script "B.groovy" and "C.groovy" into "A.groovy" and all other scripts when I used GLOBALS.exec...
But the solution is totally inconvenient
Offline
Hi Eduardo!
Is the problem RS-2755 with caching scripts used in GLOBALS.exec(...) resolved in RS 3.1.0 version?
Can I now be sure that all scripts used in GLOBALS.exec(...) will be included in the right order (no asynchronous loading)?
Offline
Hi Patryx,
as you can check in the release notes, RS-2755 was not included in the 3.1.0 beta.
Regards,
Eduardo
Offline
Hi,
Unfortunately restarting server doesn't help!
In my script "A.groovy" I have GLOBALS.exec("B.groovy") and GLOBALS.exec("C.groovy").
"B.groovy" has some utils methods shared between other scripts. "C.groovy" has some classes used by some scripts.
After restarting the server I call from url:http://reportbase/reportserver/scriptAccess?path=/bin/shared/A.groovy&exception=true
And I get an error that classes (defined in "C.groovy") are unabled to resolve
If I want to use script "A.groovy" I have to do FIRST:
1) use Terminal and exec C.groovy
2) or call first http://reportbase/reportserver/scriptAccess?path=/bin/shared/C.groovyAfter that "A.groovy" works as I expected...
What's interesting I don't have problem with "B.groovy" - the methods work and are seen by script "A.groovy" without any calling/executiong before.As a result I think that there is asynchronous mechanism to load scripts for the first time after restarting server so I cannot use GLOBALS.exec at all...
How can I fix this problem?I see only one solution nowadays: copy contents of script "B.groovy" and "C.groovy" into "A.groovy" and all other scripts when I used GLOBALS.exec...
But the solution is totally inconvenient
Hi Patryx,
for completeness:
this has always worked as designed. We are looking into the caching issues, but the problem you describe here is not directly related to caching.
In your case, you have A.groovy, B.groovy and C.groovy, where B and C are classes. In this case, you cannot use
GLOBALS.exec()
as groovy tries to compile A and cannot resolve B if you create an instance like this:
new B()
The same for C.
So in this case you have to use:
def bSource = GLOBALS.read('/fileserver/bin/B.groovy')
def bClass = new GroovyClassLoader(getClass().classLoader).parseClass( bSource )
// don't use clazz.newInstance(): https://stackoverflow.com/questions/195321/why-is-class-newinstance-evil
// use getDeclaredConstructor() instead:
def bInstance = bClass.getDeclaredConstructor().newInstance()
return bInstance.prepareString()
for loading the class in B.groovy into the class loader and creating an instance of B. The same for C.
As of ReportServer 4.5.0 you can use the more compact form:
def bClass = GLOBALS.loadClass('B.groovy', 'net.datenwerke.rs.samples.tools.nesting.nestedclass.B')
def bInstance = GLOBALS.newInstance()
I created these two examples for demonstration and will include this information in the documentation:
https://github.com/infofabrik/reportser … estedclass
and
https://github.com/infofabrik/reportser … tipleclass
Regarding the cache issue: I will write here when we have more information.
Regards,
Eduardo
Offline
Note that if your .groovy files contain multiple classes, you can use something similar as this example:
https://github.com/infofabrik/reportser … tipleclass
Regards,
Eduardo
Offline
Hi,
regarding cache:
we improved the internal cache implementation, so it will work better in the next ReportServer version 4.5.0. Nevertheless, in some cases, the cache does not work as expected: we discovered it is a Groovy bug which we will send to the Groovy team.
For these cases we added a "clearInternalScriptCache" command that allows to manually clear the script cache. This will also be available as a service: net.datenwerke.rs.scripting.service.scripting.ScriptingService.clearCache()
Regards,
Eduardo
Offline
Hi,
we released RS 4.5.0 where the "clearInternalScriptCache" is available: https://forum.reportserver.net/viewtopic.php?id=3428
https://reportserver.net/releasenotes/RS4.5.0.html
Regards,
Eduardo
Offline