I'm running JS from a Java web application and have setup a Sealed
shared scope as described here http://www.mozilla.org/rhino/scopes.html.
For each "request" where I need to run JS I setup a new scope and
point the prototype to the sealedSharedScope.
I have found that if I seal the shared scope itself
( sealedSharedScope.sealObject(); ) then I get this exception when I
attempt to use Java classes from within a script.
org.mozilla.javascript.EvaluatorException: Cannot modify a property of
a sealed object: getClass. (/initSharedScope.js#44)
I have traced the root cause down to inside:
org.mozilla.javascript.NativeJavaTopPackage.init(Context cx,
Scriptable scope, boolean sealed)
Inside the init() method this call is made which attempts to define a
property in the parent scope for the function "getClass".
getClass.exportAsScopeProperty(); // line 139
It then throws the exception because the scope has been sealed.
If I don't call sealedSharedScope.sealObject(); then everything works
with no exception. But of course the scope isn't sealed and this is
too dangerous for untrusted JS in a shared environment.
I've tried adding the "dynamic scope" but this made no difference.
It appears that using a Sealed Shared Scope and Java classes is
incompatible. Is there some way to make this work?
Note if you test this with some common java classes like
"java.lang.String" it works fine as it appears some common classes are
predefined in the scope or pre-cached.
Note I also use a ClassShutter to limit the java classes allowed to
safe classes.
in my hierarchy of scopes I solved the problem "how to use Java classes from Rhino scopes" like this:
I've got my sealed scopes called "root scopes" - with some basic functionality and sealed, to prevent people from introducing global variables, modify things at all - scripts can only introduce (their local) variables.
Then I have scopes called "run scopes" - I'm creating them with parent set to my root scopes, so they have access to my global environment. Now, regarding the Java class use, I'm doing Scriptable importer=new ImporterTopLevel(cx) + run_scope.setPrototype(importer).
So my run scopes can import more stuff than my sealed root scopes have imported before ... works pretty well. These run scopes live as long as their associated object in my Java environment exists ... And the single run scopes will not put more and more stuff in the global scopes, if the run scope goes out of use, it's imports will follow ...
cu
Merten
Using Rhino 1.7R1
_______________________________________________
dev-tech-js-engine-rhino mailing list
dev-tech-js-...@lists.mozilla.org
https://lists.mozilla.org/listinfo/dev-tech-js-engine-rhino
I believe this is a bug that is actually fixed in the latest release
candidate regarding the lazy loading of certain Rhino properties. I'm
still on an older release, though, so my sealed scope initializer
looks like this:
topLevel = cx.initStandardObjects(null, true);
//Force all the stuff we need to be loaded. These objects
are meant to be lazy
//loaded by Rhino but that doesn't work since the scope is
sealed.
String loadMe = "RegExp; getClass; java; Packages;
JavaAdapter;";
cx.evaluateString(topLevel, loadMe, "lazyLoad", 0, null);
topLevel.sealObject();
Just by mentioning the properties in the loadMe string, Rhino puts
these in the scope before it is sealed. Obviously if you need other
features like E4X, you could mention those in the loadMe string too.
HTH,
A
Thanks a lot, that did the trick.
Maybe someone with access can put a note about this in the discussion
about scopes on this page http://www.mozilla.org/rhino/scopes.html as
it would have saved me a lot of time and frustration.
Thanks for the suggestion. I took a look at ImporterTopLevel but
didn't really see how this helped, it just moved the problem to a
different scope since if I sealed the importer scope I ended up with
the same exception. The other thing is that ImporterTopLevel does a
Context.initStandardObjects() which is an expensive operation which I
only want to do once, in the shared sealed scope.
I found the reply by wolffiex to solve the problem by forcing the
shared scope to load the needed properties before it gets sealed.
Maybe the insertion of "Packages" as described by wolffiex does the trick for ALL classes later on, not sure - anyway, for me it's fine that my run scopes can load whatever they want, I just wanted to ensure that they do not store all their stuff somewhere in the hierarchy of parent scopes.
cu
Merten
I've moved the content over to the MDC wiki:
https://developer.mozilla.org/En/Rhino_documentation/Scopes_and_Contexts
Can you modify with your change?
Thanks,
Norris
Yes, I've added this note to the end of the Sealed Shared Scope
section:
Note that currently in order to use Java classes (LiveConnect) from a
sealed shared scope you need to pre-load a number of objects needed
for LiveConnect into the scope before it gets sealed. These objects
would normally be lazy loaded but the lazy loading fails if the scope
is sealed.
ScriptableObject sealedSharedScope = cx.initStandardObjects(null,
true);
// Force the LiveConnect stuff to be loaded.
String loadMe = "RegExp; getClass; java; Packages; JavaAdapter;";
cx.evaluateString(sealedSharedScope , loadMe, "lazyLoad", 0,
null);
sealedSharedScope .sealObject();