From: <php...@li...> - 2006-11-17 15:54:16
|
Sorry, once again ;-) I wrote this little part of a Java method for testing: PhpScriptEngine engine = new PhpScriptEngine(); String s = "<?php \n"; s += "require_once 'MyClass.php'; \n"; s += "java_context()->setAttribute( 'obj', new MyClass(), 100 ); \n"; s += "java_context()->call(java_closure()); \n"; s += "?>"; engine.eval( new StringReader(s) ); Invocable inv = (Invocable) engine; inv.invokeMethod( engine.get("obj"), "saySomething", new Object() ); The resulting errors are: java.lang.NullPointerException at java.lang.reflect.Proxy.getInvocationHandler(Proxy.java:636) at php.java.script.PhpScriptEngine.invokeMethod(PhpScriptEngine.java:202) at Bootstrap.main(Bootstrap.java:30) Nov 17 16:30:28 JavaBridge ERROR: PHP Warning: Argument is not (or does not contain) Java object(s). in - on line 3 The NullPointerException happens in the line where invokeMethod is called. Line 3 of the PHP script is the one where setAttribute() is called. As I understand the error message text, it is not possible to set a PHP object as an attribute to the java context, but only Java objects? Another thing I tried was: String s = "<?php \n"; s += "require_once 'MyClass.php'; \n"; s += "$obj = new MyClass(); \n"; s += "java_context()->call(java_closure()); \n"; s += "?>"; but there was the same NullPointerException. This was inspired from the Javascript example provided by SUN here: https://java.sun.com/javase/6/docs/technotes/guides/scripting/programmer_guide/index.html#invoke ScriptEngineManager manager = new ScriptEngineManager(); ScriptEngine engine = manager.getEngineByName("JavaScript"); String script = "var obj = new Object(); obj.hello = function(name) { print('Hello, ' + name); }"; engine.eval(script); Invocable inv = (Invocable) engine; Object obj = engine.get("obj"); inv.invokeMethod(obj, "hello", "Script Method !!" ); Any chance todo something similar with PHP? Regards, Verena |
From: <php...@li...> - 2006-11-17 18:40:34
|
Hi Verena, > PhpScriptEngine engine = new PhpScriptEngine(); > String s = "<?php \n"; > s += "java_context()->setAttribute( 'obj', new > MyClass(), 100 ); \n"; > s += "java_context()->call(java_closure()); \n"; > s += "?>"; > engine.eval( new StringReader(s) ); the above code should work, it evaluates the php script stored in the Java string s. However, you'll get a warning that the instance of MyClass is not a Java object. Use java_closure(new MyClass()) instead. > Invocable inv = (Invocable) engine; > inv.invokeMethod( engine.get("obj"), "saySomething", > new Object() ); You will get a null pointer exception because obj is bound to null, see the warning above. Furthermore you have captured the top-level environment, but you probably want to invoke methods from MyClass(). Frameworks such as Java Server Faces allow you to define PHP beans and to inject these beans into the framework: http://php-java-bridge.cvs.sourceforge.net/php-java-bridge/php-java-bridge/examples/java-server-faces/helloWorld.php?revision=1.6&view=markup java_context()->call(java_closure(new helloWorld())) ||include("index.php"); The above code creates an instance of the PHP helloWorld() class, creates a Java proxy for it and then calls the framework (the java_context()->call magic does this). When the call() failed (which means that the first request came in from the web server, and not from the framework), we redirect to index.php, which forwards the browser to the framework, which in turn evaluates the PHP script. The script creates the PHP bean and injects it into the framework. After that the framework holds a reference to the PHP bean and can call its methods: http://php-java-bridge.cvs.sourceforge.net/php-java-bridge/php-java-bridge/server/php/java/faces/Script.java?revision=1.6&view=markup return ((Invocable)((PhpFacesContext)FacesContext.getCurrentInstance()).getScriptEngine(this, new URL(script))).invoke(name, args); I think this is exactly what you want. The only difference is that the above method calls out to a URL instead of a local script file. > String script = "var obj = new Object(); > obj.hello = function(name) > { print('Hello, ' + name); }"; > Any chance todo something similar with PHP? It is certainly possible to automatically call java_closure(), when a php object is passed to a Java procedure. But for several reasons we've decided to require java_closure(php_object). Furthermore, if I understand the above code correctly, the "new Object()" above instanciates a Java object, not an object from the js script interpreter. Regards, Jost Boekemeier ___________________________________________________________ Telefonate ohne weitere Kosten vom PC zum PC: http://messenger.yahoo.de |
From: <php...@li...> - 2006-11-20 15:36:44
|
Am Freitag, 17. November 2006 19:40 schrieb php...@li...: > However, you'll get a warning that the instance of > MyClass is not a Java object. Use > > java_closure(new MyClass()) > > instead. OK, this is working now without the warning. > > > Invocable inv = (Invocable) engine; > > inv.invokeMethod( engine.get("obj"), "saySomething", > > new Object() ); > > You will get a null pointer exception because obj is > bound to null, see the warning above. Furthermore you > have captured the top-level environment, but you > probably want to invoke methods from MyClass(). Why did I capture the top-level environment? I thought with engine.get("obj") I get the PHP object returned and so the method saySomething is invoked on that object? What is the correct syntax to invoke a method on MyClass()? I tried this: PhpScriptEngine engine = new PhpScriptEngine(); String s = "<?php \n"; s += "require_once 'MyClass.php'; \n"; s += "java_context()->setAttribute( 'obj', java_closure(new MyClass()), 100 ); \n"; s += "?>"; engine.eval( new StringReader(s) ); Invocable inv = (Invocable) engine; inv.invokeMethod( engine.get("obj"), "saySomething", new Object() ); and it results in this error message: Nov 20 10:55:20 JavaBridge ERROR: An exception occured: java.io.IOException: Bad file descriptor java.io.IOException: Bad file descriptor at java.io.FileOutputStream.writeBytes(Native Method) at java.io.FileOutputStream.write(FileOutputStream.java:260) at java.io.ByteArrayOutputStream.writeTo(ByteArrayOutputStream.java:109) at php.java.bridge.Response$Writer.flush(Response.java:125) at php.java.bridge.Response.flush(Response.java:671) at php.java.bridge.ClassicResponse.copyResponse(ClassicResponse.java:82) at php.java.bridge.Request.handleSubRequests(Request.java:607) at php.java.bridge.PhpProcedure.invoke(PhpProcedure.java:77) at php.java.bridge.PhpProcedure.invoke(PhpProcedure.java:95) at php.java.script.PhpScriptEngine.invokeMethod(PhpScriptEngine.java:204) at Bootstrap.main(Bootstrap.java:39) Bootstrap.java, line 39 is the last one showed above. > [...] > > return > ((Invocable)((PhpFacesContext)FacesContext.getCurrentInstance()).getScriptE >ngine(this, new URL(script))).invoke(name, args); > > I think this is exactly what you want. The only > difference is that the above method calls out to a URL > instead of a local script file. Yes, it sounds like, but actually I'm not sure how to do it. This faces things are about the web framework, aren't they? So how do I transform this to a J2SE app? In the code example I can't see how to call a method on a previously instanciated PHP object. It only uses the invoke Method with 2 parameters (invokeFunction). > > String script = "var obj = new Object(); > > obj.hello = function(name) > > { print('Hello, ' + name); }"; > > > > Any chance todo something similar with PHP? > > It is certainly possible to automatically call > java_closure(), when a php object is passed to a Java > procedure. But for several reasons we've decided to > require java_closure(php_object). Furthermore, if I > understand the above code correctly, the "new > Object()" above instanciates a Java object, not an > object from the js script interpreter. No, it instanciates a JavaSript object which has one method called hello. But if the only difference to this snippet and the possibiblities of the php-java bridge is the automatic call to java_close(), it is similar enough for my project. Regards, Verena |
From: <php...@li...> - 2006-11-20 18:42:33
|
Hi Verena, > Why did I capture the top-level environment? java_closure() without any arguments captures the top-level environment, creates and returns a Java proxy for it. Of cause you could use invocable.invokeMethod(engine.get(objectBinding),...) to call a method[1]. But if you don't have more than one PHP class per php file, this shouldn't be necessary; you can capture the object directly, which has the advantage that you don't need to keep a dictionary of additional symbol->object bindings. > thought with engine.get("obj") > I get the PHP object returned Yes. (you'll get a Java proxy for the PHP object). > and so the method > saySomething is invoked on > that object? Yes. > What is the correct syntax to invoke a method on > MyClass()? > > I tried this: > PhpScriptEngine engine = new PhpScriptEngine(); > String s = "<?php \n"; > s += "require_once 'MyClass.php'; \n"; > s += "java_context()->setAttribute( 'obj', > java_closure(new MyClass()), > 100 ); \n"; > s += "?>"; > engine.eval( new StringReader(s) ); > Invocable inv = (Invocable) engine; > inv.invokeMethod( engine.get("obj"), "saySomething", > new Object() ); The above script is not invocable. The last line of a invocable PHP script must contain: java_context()->call(java_closure()); > java.io.IOException: Bad file descriptor > at java.io.FileOutputStream.writeBytes(Native Well, PHP simply terminates after a PHP script is executed. To keep it, you must suspend it and pass control back to the Java continuation. The java_context()->call(kont) calls the Java continuation with the PHP continuation as its argument, so that the Java continuation can call back into the PHP continuation kont whenever necessary: kont.call(scriptEngine.getContinuation()); Of course the above PHP<->Java continuation passing style is hidden behind the JSR223 interfaces. But on the PHP side the java_context()->call() must exist, otherwise the PHP script cannot be called from a (potentially) remote Java script engine interface. > Yes, it sounds like, but actually I'm not sure how > to do it. This faces things > are about the web framework, aren't they? In practice, yes. > So how do > I transform this to a > J2SE app? Just create one public PHP class per PHP file. Example file my/foo.php, my/bar.php foo.php: class my_Foo { function toString() {return "foo";} } java_context()->call(java_closure(new myFoo()); bar.php: class my_Bar { function toString() {return "bar";} } java_context()->call(java_closure(new myBar()); Now you need a XML file which describes your PHP "beans", or simply hard-code the names in your code: ScriptEngineManager m = new ScriptEngineManager(); ScriptEngine foo = m.getEngineByName("php"); foo.eval(new FileReader("my/foo.php")); ScriptEngine bar = m.getEngineByName("php"); bar.eval(new FileReader("my/bar.php")); // now you can call methods from the foo and bar // PHP classes > No, it instanciates a JavaSript object which has one > method called hello. Interesting. I thought that unlike PHP, the JavaScript object hierarchy is not orthogonal to the Java object hierarchy. Regards, Jost Boekemeier [1] In the old JSR223 proposal the invokeMethod() and invokeProcedure() methods where called "invoke()". ___________________________________________________________ Telefonate ohne weitere Kosten vom PC zum PC: http://messenger.yahoo.de |