How to kill a Rhino script - java

We are using Rhino to execute Javascript inside our Java app. We make use of some Rhino-specific features so we can’t upgrade to Nashorn.
The problem we have is that scripts are created by users, and when we execute them, if there is a mistake like an infinite loop, it keeps executing forever. We want to set a time limit of something like 30 seconds.
Is there a way to kill a script when the timeout is hit?

You should extend the ContextFactory class and override the method observeInstructionCount(Context ctx, int instructionCount). This method will be called periodically by Rhino and you can check how long it has been running so far with something like this:
public class ScriptDynamicScopeFactory extends ContextFactory {
#Override
protected Context makeContext() {
ScriptContext ctx = new ScriptContext();
ctx.setInstructionObserverThreshold(10000);
return ctx;
}
#Override
protected void observeInstructionCount(Context ctx, int instructionCount) {
long currentTime = System.currentTimeMillis();
long executionTime = (currentTime - ((ScriptContext) ctx).startTime());
// do something if execution time is greater then your timeout
}
}
Notice that you also need to override makeContext() to set how often your observer will be called. Keep in mind that this is the number of instructions executed, which means that it won't get called consistently every X ms. If one instruction takes a lot (for example, calling your Java app), this might not work well, but I think it will do a good job in almost all cases.

You can stop loop from running by creating a dummy debugger and add it to the javascript directly like this:
mContext = Context.enter();
ObservingDebugger observingDebugger = new ObservingDebugger();
mContext.setDebugger(observingDebugger, new Integer(0));
mContext.setGeneratingDebug(true);
mContext.setOptimizationLevel(-1);
Then through the java program, you create a class that looks like this:
public class ObservingDebugger implements Debugger
{
boolean isDisconnected = false;
private DebugFrame debugFrame = null;
public boolean isDisconnected() {
return isDisconnected;
}
public void setDisconnected(boolean isDisconnected) {
this.isDisconnected = isDisconnected;
if(debugFrame != null){
((ObservingDebugFrame)debugFrame).setDisconnected(isDisconnected);
}
}
public ObservingDebugger() {
}
public DebugFrame getFrame(Context cx, DebuggableScript fnOrScript)
{
if(debugFrame == null){
debugFrame = new ObservingDebugFrame(isDisconnected);
}
return debugFrame;
}
#Override
public void handleCompilationDone(Context arg0, DebuggableScript arg1, String arg2) { } }
// internal ObservingDebugFrame class
class ObservingDebugFrame implements DebugFrame
{
boolean isDisconnected = false;
public boolean isDisconnected() {
return isDisconnected;
}
public void setDisconnected(boolean isDisconnected) {
this.isDisconnected = isDisconnected;
}
ObservingDebugFrame(boolean isDisconnected)
{
this.isDisconnected = isDisconnected;
}
public void onEnter(Context cx, Scriptable activation,
Scriptable thisObj, Object[] args)
{ }
public void onLineChange(Context cx, int lineNumber)
{
if(isDisconnected){
throw new RuntimeException("Script Execution terminaed");
}
}
public void onExceptionThrown(Context cx, Throwable ex)
{ }
public void onExit(Context cx, boolean byThrow,
Object resultOrException)
{ }
#Override
public void onDebuggerStatement(Context arg0) { } }
Then to set the timer of the program, you import:
import java.util.Timer;
Then you set your timer prefernece for the ObservingDebugger:
timer.schedule(new TimerTask() {
#Override
public void run() {
// code here
}
}, 2*60*1000);
// Since Java-8
timer.schedule(() -> /* your database code here */, 2*60*1000);

Related

Variablelistener corruption with anchorshadowedvariable in optaplanner

I am trying to solve a planning problem which look like the Time window vehicule routing problem.
So I am looking for a Solution containing a list of tasks. Tasks can be assigneed to one of two workers.
My Task class looks like that (I didn't cut/paste all the getters and setters here) :
#PlanningEntity(difficultyComparatorClass = TaskDifficultyComparator.class)
public class Task implements Location {
private String location;
private LocalTime arrivalTime;
private Location previousLocation;
private Task nextTask;
private StartLocal startLocal;
private Duration taskDuration = Duration.ofMinutes(20);
private LocalTime readyTime;
private LocalTime dueTime;
#PlanningVariable(valueRangeProviderRefs = {"tasks", "startLocal"},
graphType = PlanningVariableGraphType.CHAINED)
public Location getPreviousLocation() {
return previousLocation;
}
public void setPreviousLocation(Location previousLocation) {
this.previousLocation = previousLocation;
}
#Override
public String {return location;}
#Override
public void setLocation(String location) {this.location = location;}
public int getTimeToGoTo(Location location) {
....
}
#AnchorShadowVariable(sourceVariableName = "previousLocation")
public StartLocal getStartLocal() {
return startLocal;
}
public void setStartLocal(StartLocal startLocal) {
this.startLocal = startLocal;
}
#CustomShadowVariable(variableListenerClass = ArrivalTimeVariableListener.class,
sources = {#CustomShadowVariable.Source(variableName = "previousLocation")})
public LocalTime getArrivalTime() {
return arrivalTime;
}
public void setArrivalTime(LocalTime arrivalTime) {
this.arrivalTime = arrivalTime;
}
}
And my variable listener class is :
public class ArrivalTimeVariableListener implements VariableListener<Task> {
#Override
public void beforeEntityAdded(ScoreDirector scoreDirector, Task task) {}
#Override
public void afterEntityAdded(ScoreDirector scoreDirector, Task task) {
updateArrivalTime(scoreDirector, task);
}
#Override
public void beforeVariableChanged(ScoreDirector scoreDirector, Task task) { }
#Override
public void afterVariableChanged(ScoreDirector scoreDirector, Task task) {
updateArrivalTime(scoreDirector, task);
}
#Override
public void beforeEntityRemoved(ScoreDirector scoreDirector, Task task) { }
#Override
public void afterEntityRemoved(ScoreDirector scoreDirector, Task task) { }
private void updateArrivalTime(ScoreDirector scoreDirector, Task task){
LocalTime arrivalTimeInThisLocation = calculateArrivalTime(task);
Task shadowTask = task;
while (shadowTask != null) {
scoreDirector.beforeVariableChanged(shadowTask, "arrivalTime");
shadowTask.setArrivalTime(arrivalTimeInThisLocation);
scoreDirector.afterVariableChanged(shadowTask, "arrivalTime");
shadowTask = shadowTask.getNextTask();
if(shadowTask!=null)arrivalTimeInThisLocation = calculateArrivalTime(shadowTask);
}
}
#VisibleForTesting
static public LocalTime calculateArrivalTime(Task task){
LocalTime whenArriveAtPreviousLocation = task.getPreviousLocation().getArrivalTime();
int secondsToGo = task.getTimeToGoTo(task.getPreviousLocation());
long secondsToCompleteLastTask = 0;
if(task.getPreviousLocation() instanceof Task){
secondsToCompleteLastTask = ((Task) task.getPreviousLocation()).getTaskDuration().getSeconds();
}
LocalTime whenArriveInThisLocationASAP = whenArriveAtPreviousLocation.
plusSeconds(secondsToCompleteLastTask).
plusSeconds(secondsToGo);
if(whenArriveInThisLocationASAP.isAfter(task.getReadyTime())){
return whenArriveInThisLocationASAP;
}
return task.getReadyTime();
}
}
When I try to solve my problem I have the following error :
VariableListener corruption: the entity (Task s shadow variable (Task.arrivalTime)'s corrupted value (09:32) changed to uncorrupted value (09:33) after all VariableListeners were triggered without changes to the genuine variables.
Probably the VariableListener class for that shadow variable (Task.arrivalTime) forgot to update it when one of its sources changed after completedAction (Initial score calculated).
I know that this issue is a duplicate of this one.
But I read (very very) carrefully answer of this SOF question, and I can't understand what I am doing wrong.
I well understood, role of the variable listener in my use case is to update the "arrivalTime" of the tasks following the tasks we just change. Isn't it ?
Ok, I found what I did wrong.
What I did wrong is hard to see in my question. The problem was that I initialize my solution's shadows variable to a non null value. I had the following code in my unit test :
Task task1 = new Task();
task1.setPreviousTask(task0);
task0.setNextTask(task1);
//...
solution.computeAllArrivalTimes();
This is not a good idea to initialize shadows variable and Planning variables. If I set them to null, then every things works like a charm.
I just need to add some null check in "calculateArrivalTime" to allow this method to be called.
Add updateArrivaltime() to method beforeValueChanged().
My guess is that you're on FULL_ASSERT.

How to add a hook to save event for existing DataObject in NetBeans?

I want to make some processing every time when a particular DataObject is saved. If I understand NetBeans IDE API correctly, there is an Savable interface that can be used to implement saving options for custom editors. The problem here is that I do not want to implement my own editor, nor DataObject. I have a MIME type that is edited by a default Gsf editor (the common scripting language api) and has a GsfDataObject (I expect with the DOSavable). I want to keep all that way, just to add a hook, maybe a callback method or something, that would be called every time a save is done upon a given GsfDataObject (and I want a default save action be called, I dont want to override it).
So far I came to this simple solution but it seems ugly (it is more or less inspired by http://wiki.netbeans.org/DevFaqListenForSaveEvents ):
// I have a FileObject fobj
final DataObject dobj = DataObject.find(fobj);
dobj.addPropertyChangeListener(new PropertyChangeListener() {
#Override
public void propertyChange(PropertyChangeEvent evt) {
if (evt.getPropertyName().equals(DataObject.PROP_MODIFIED)) {
if (!((Boolean) evt.getOldValue()) & ((Boolean) evt.getNewValue())) {
System.out.println(">>>> here it gets modified");
} else {
System.out.println(">>>> here the data object gets saved");
}
}
}
});
However, this is not called only when the save is done, but also when the file gets modified, but then the modifications are reverted by Ctrl + Z. It only checks whether the data object changes its state from modified to unmodified. Is there a way to hook to a save event only?
P.S.: I tried to call new SJDOSavable(dobj).add(); in the moment when the DataObject gets modified and then to remove it in the other branch. However, the handleSave method does not get called. SJDOSavable class is a simple Savable implemented according to DOSavable from the DataSystems API:
private static final class SJDOSavable extends AbstractSavable implements Icon {
final DataObject obj;
public SJDOSavable(DataObject obj) {
this.obj = obj;
}
#Override
public String findDisplayName() {
return obj.getNodeDelegate().getDisplayName();
}
#Override
protected void handleSave() throws IOException {
System.out.println(">>>>> but this does not get called");
}
#Override
public boolean equals(Object other) {
if (other instanceof SJDOSavable) {
SJDOSavable dos = (SJDOSavable) other;
return obj.equals(dos.obj);
}
return false;
}
#Override
public int hashCode() {
return obj.hashCode();
}
final void remove() {
unregister();
}
final void add() {
register();
}
#Override
public void paintIcon(Component c, Graphics g, int x, int y) {
icon().paintIcon(c, g, x, y);
}
#Override
public int getIconWidth() {
return icon().getIconWidth();
}
#Override
public int getIconHeight() {
return icon().getIconHeight();
}
private Icon icon() {
return ImageUtilities.image2Icon(obj.getNodeDelegate().getIcon(BeanInfo.ICON_COLOR_16x16));
}
}
Did you try this ?
http://wiki.netbeans.org/DevFaqListenForSaveEvents
Also if you want to listen to global Save events, it seems you can do that now.
https://netbeans.org/bugzilla/show_bug.cgi?id=140719

How to return String in anonymous class for a method returning void

I'm bit confused. I have the following:
public static String showInputDialog() {
Form frm = new Form();
final Command cmd = new Command("Ok");
final TextField txt = new TextField("Enter the text", null, 1024, 0);
frm.addCommand(cmd);
frm.append(txt);
frm.setCommandListener(new CommandListener() {
public void commandAction(Command c, Displayable d) {
if (c == cmd) {
return txt.getString(); // Error !!
} else {
return null; // Error !!
}
}
});
}
As you can see, I want to return the input dialog string, while the anonymous class method should return void. How can I resolve this problem?
This does not work as you expected.
I see there are already some solutions, but I feel a bit more discussion about what is actually going on might be helpful.
When you call the frm.setCommandListener(new CommandListener() { ... }) the code presents the user with a dialog where she can type in some text and submit, but the code does not stop and wait until the user finishes.
Instead the code continues to execute - without yielding the result. Only after the user finished typing and submits, you get called back to process the result - which might happen much later, or not at all.
I guess you have some code calling this method like:
public void someMethod(int foo, String bar) {
[...]
String result = MyInputForm.showInputDialog();
// do something with the result
System.out.println("hey, got a result "+ result);
[...]
}
Instead you need to reorganize this. First write a helper class handling the result:
public static class MyCallBack {
public MyCallBack(... /* here pass in what you need to process the result*/) {
... remember necessary stuff in instance variables
}
public void processResult(String result) {
// do something with the result
System.out.println("hey, got a result "+ result);
[...]
}
}
then the calling side does just:
public void someMethod(int foo, String bar) {
[...]
MyInputForm.showInputDialog( new MyCallBack(... here pass in stuff ...) );
[...]
}
and the actual code has to be changed to:
public static String showInputDialog(final MyCallBack callback) {
Form frm = new Form();
final Command cmd = new Command("Ok");
final TextField txt = new TextField("Enter the text", null, 1024, 0);
frm.addCommand(cmd);
frm.append(txt);
frm.setCommandListener(new CommandListener() {
public void commandAction(Command c, Displayable d) {
if (c == cmd) {
return callback.processResult(txt.getString());
} else {
return; // or just omit the else part
}
}
});
}
Two issues:
this way of programming feels pretty backwards, but it is really the way it works.
what feels not right is that I need to define a second helper class aside of the CommandListener. That is really not good style. I hope it can be improved, but as I do not see the complete code (which would be too much information anyway), I have to leave it to you to improve the code and get rid of the clutter. While I feel you want to have a modular, reusable input dialog helper, this might not be the best approach; better define the Form,TextField and Command directly where you need the result and get that running. Make it reusable in a second step after you get it running.
You don't need to return it if you instead do something with the String or store it somewhere, for example:
static String result;
public String commandAction(Command c, Displayable d) {
if (c == cmd) {
result = txt.getString();
} else {
result = null;
}
}
Although you'll have threading issues to deal with.
Given that CommandListener is fixed, 2 possible options are
Use a class member variable in the outer class & assign to that variable instead
private static String myText;
...
public static String showInputDialog() {
...
frm.setCommandListener(new CommandListener() {
public void commandAction(Command c, Displayable d) {
if (c == cmd) {
myText = txt.getString();
} else {
myText = null;
}
}
});
}
or Create a concrete implementation of your CommandListener and set the return value as a property of the new implementation
I would have a look at making the method/variable in this snippet non-static...
You cant return the string because you dont know when the listener will be called.
You can do something with it once you have the string though.
public static void showInputDialog() {
StringHandler sh = new StringHandler();
frm.setCommandListener(new CommandListener() {
public void commandAction(Command c, Displayable d) {
if (c == cmd) {
sh.handle(txt.getString());
} else {
sh.handle(null);
}
}
});}
public class StringHandler {
public void handle(String s){
// Do something with that string.
}
}

How can I provide a pseudo file system for r.js?

Ok, so r.js can run on Rhino. Which is great.
To do the stuff it needs to do.
On rhino it basically uses java.io.File, java.io.FileOutputStream and java.io.FileInputStream to achieve the filesystem modifications that it needs to do.
(Background: I am working on delivering a better development experience for Maven based Java/Javascript developers. Being Maven, there is the power of convention and the power of being opinionated. You can see the progress at jszip.org.)
So what I want to do is have the on-disk structure appear by magic as a virtual file system.
So on disk we will have a structure like so:
/
/module1/src/main/js/controllers/controller.js
/module2/src/main/js/models/model.js
/module3/src/main/js/views/view.js
/webapp/src/build/js/profile.js
/webapp/src/main/js/main.js
/webapp/src/main/webapp/index.html
The /webapp/src/build/js/profile.js should look something like this:
({
appDir: "src",
baseUrl:".",
dir: "target",
optimize: "closure",
modules:[
{
name:"main"
}
]
})
Such that
when r.js asks for new File("src/main.js") I will actually give it new File("/webapp/src/main/js/main.js")
when it asks for new File("profile.js") I will give it new File("/webapp/src/build/js/profile.js")
when it asks for new File("controllers/controller.js") I will give it new File("/module1/src/main/js/controllers/controller.js")
when it asks for new File("target") I will give it new File("/webapp/target/webapp-1.0-SNAPSHOT").
I have no issue writing the three mock classes required, i.e. the ones to use in place of java.io.File, java.io.FileInputStream and java.io.FileOutputStream,
Some questions such as this have answers that point to things like ClassShutter, which I can see I could use like this:
context.setClassShutter(new ClassShutter() {
public boolean visibleToScripts(String fullClassName) {
if (File.class.getName().equals(fullClassName)) return false;
if (FileOutputStream.class.getName().equals(fullClassName)) return false;
if (FileInputStream.class.getName().equals(fullClassName)) return false;
return true;
}
});
To hide the original implementations.
The problem is then getting Rhino to resolve the sandboxed equivalents... I keep on getting
TypeError: [JavaPackage java.io.File] is not a function, it is object.
Even if I prefix the call with a prior execution of java.io.File = org.jszip.rhino.SandboxFile map my sandboxed implementation over the now missing java.io.File
I could even consider using search and replace on the loaded r.js file just prior to compiling it... but I feel there must be a better way.
Does anyone have any hints?
Ok, after much experimentation, this seems to be the way to do this:
Scriptable scope = context.newObject(global);
scope.setPrototype(global);
scope.setParentScope(null);
NativeJavaTopPackage $packages = (NativeJavaTopPackage) global.get("Packages");
NativeJavaPackage $java = (NativeJavaPackage) $packages.get("java");
NativeJavaPackage $java_io = (NativeJavaPackage) $java.get("io");
ProxyNativeJavaPackage proxy$java = new ProxyNativeJavaPackage($java);
ProxyNativeJavaPackage proxy$java_io = new ProxyNativeJavaPackage($java_io);
proxy$java_io.put("File", scope, get(scope, "Packages." + PseudoFile.class.getName()));
proxy$java_io.put("FileInputStream", scope,
get(scope, "Packages." + PseudoFileInputStream.class.getName()));
proxy$java_io.put("FileOutputStream", scope,
get(scope, "Packages." + PseudoFileOutputStream.class.getName()));
proxy$java.put("io", scope, proxy$java_io);
scope.put("java", scope, proxy$java);
There is a helper method:
private static Object get(Scriptable scope, String name) {
Scriptable cur = scope;
for (String part : StringUtils.split(name, ".")) {
Object next = cur.get(part, scope);
if (next instanceof Scriptable) {
cur = (Scriptable) next;
} else {
return null;
}
}
return cur;
}
And where ProxyNativeJavaPackage is something like
public class ProxyNativeJavaPackage extends ScriptableObject implements Serializable {
static final long serialVersionUID = 1L;
protected final NativeJavaPackage delegate;
private final Map<String, Object> mutations = new HashMap<String, Object>();
public ProxyNativeJavaPackage(NativeJavaPackage delegate) {
delegate.getClass();
this.delegate = delegate;
}
#Override
public String getClassName() {
return delegate.getClassName();
}
#Override
public boolean has(String id, Scriptable start) {
return mutations.containsKey(id) ? mutations.get(id) != null : delegate.has(id, start);
}
#Override
public boolean has(int index, Scriptable start) {
return delegate.has(index, start);
}
#Override
public void put(String id, Scriptable start, Object value) {
mutations.put(id, value);
}
#Override
public void put(int index, Scriptable start, Object value) {
delegate.put(index, start, value);
}
#Override
public Object get(String id, Scriptable start) {
if (mutations.containsKey(id)) {
return mutations.get(id);
}
return delegate.get(id, start);
}
#Override
public Object get(int index, Scriptable start) {
return delegate.get(index, start);
}
#Override
public Object getDefaultValue(Class<?> ignored) {
return toString();
}
#Override
public String toString() {
return delegate.toString();
}
#Override
public boolean equals(Object obj) {
if (obj instanceof ProxyNativeJavaPackage) {
ProxyNativeJavaPackage that = (ProxyNativeJavaPackage) obj;
return delegate.equals(that.delegate) && mutations.equals(that.mutations);
}
return false;
}
#Override
public int hashCode() {
return delegate.hashCode();
}
}
That still leaves the original classes at Packages.java.io.File etc, but for the r.js requirement this is sufficient, and it should be possible for others to extend this trick to the general case.

Black Berry - How to avoid this infinite loop in this FieldChangeListener.fieldChanged

I need to format the string entered by the user on a EditField.
This is my code:
input = new BorderedEditField(20, BasicEditField.FILTER_NUMERIC);
input.setChangeListener(new FieldChangeListener() {
public void fieldChanged(Field field, int context) {
input.setText(pruebaTexto(input.getText()));
}
});
public static String pruebaTexto(String r){
return r+"0";
}
But it ends on a stackoverflow error caused apparently because of an infinite loop.
What is wrong with the code?
You can prevent the recursion by checking whether this is an internal update.
For Blackberry, this is done by checking the value of context
input.setChangeListener(new FieldChangeListener() {
public void fieldChanged(Field field, int context) {
if (context != FieldChangeListener.PROGRAMMATIC) {
input.setText(pruebaTexto(input.getText()));
}
}
});
This is a non-Blackberry-specific solution that will work for any variety of listener:
input.setChangeListener(new FieldChangeListener() {
private boolean internalCall = false;
public void fieldChanged(Field field, int context) {
if (!internalCall) {
internalCall = true;
try {
input.setText(pruebaTexto(input.getText()));
}
finally {
internalCall = false;
}
}
}
});
Check the API documentation of net.rim.device.api.ui.FieldChangeListener.
When the method void fieldChanged(Field field, int context) gets invoked you can check the parameter context against the value FieldChangeListener.PROGRAMMATIC.
If context is equals to FieldChangeListener.PROGRAMMATIC, then the change was made programmatically, otherwise it was an user interaction.

Categories