|
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
|