Invoke PHP code from Java (Scala) and get result - java

This seems to have been asked in several places and has been marked as "closed" and "off-topic". However, people seem to have this problem constantly
invoking a php method from java (closed)
Calling PHP from Java (closed)
How can I run PHP code within a Java application? (closed)
This answer in the last question partly answers this but does not clarify how to read the outputs.
I finally found the answer to the question:
How do I run a PHP program from within Java and obtain its output?
To give more context, someone has given me a PHP file containing code for some method foo that returns a string. How do we invoke this from JVM?
Searching on Google is not helpful as all articles I found don't explain how to call PHP from Java but rather Java from PHP.
The answer below explains how to do this using the PHP/Java bridge.
The answer is in Scala but would be easy to read for Java programmers.

Code created from this SO answer and this example:
package javaphp
import javax.script.ScriptEngineManager
import php.java.bridge._
import php.java.script._
import php.java.servlet._
object JVM{ // shared object for PHP/JVM communication
var out = ""
def put(s:String) = {
out = s
}
}
object Test extends App {
val engine = (new ScriptEngineManager).getEngineByExtension("php")
val oldCode = """
<?php
function foo() {
return 'hello';
// some code that returns string
}
?>
"""
val newCode = """
<?php
$ans = foo();
java('javaphp.JVM')->put($ans);
?>
"""+oldCode
// below evaluates and returns
JVM.out = "" //reset shared output
engine.eval(newCode)
println("output is : "+JVM.out) // prints hello
}
To run this file:
Install PHP, Scala and set path correctly. Then create a file php.scala with the above code. Then run:
scalac php.scala
and
scala javaphp.Test

Related

Unable to convert Java getBytes() to php

I am attempting to convert the following Java code to PHP but I'm having issues with finding the equivalent of getBytes()
JAVA CODE
import java.math.BigInteger;
public class Test {
public static void main(String[] ar){
String a="4F23DE12";
BigInteger b = new BigInteger(a.getBytes());
System.out.println(b); //Result is 3766753334112104754
}
}
The Java result is 3766753334112104754 but my attempt with PHP is not giving the same result.
PHP CODE
use phpseclib3\Math\BigInteger;
$a="4F23DE12";
$b = new BigInteger($a);
echo $b; //Result is 4
The PHP result is 4. The issue seems to be from getBytes() and I have tried String to byte array in php and php equivalent of java getBytes() but still no solution.
In debugging it, I also tried System.out.println("4F23DE12".getBytes()); in Java, the result was [B#6d06d69c but I haven't found an exact equivalent in PHP.
Please I will appreciate any help on how to use PHP to get the same Java result (3766753334112104754)
My question was solved by #ErwinBolwidt. Check the comments for more info.
With #ErwinBolwidt solution, the PHP equivalent of "4F23DE12".getBytes() is new BigInteger("4F23DE12", 256).
Both will give you 3766753334112104754

How to read a proto3 custom option from Java

Given the following service:
message Message {
string content = 1;
}
service EchoService {
rpc echo (Message) returns (Message) {
option (google.api.http) = { get: "/echo" };
}
}
I want to read the option from Java. My understand is the following code should work:
HttpRule rule = Message.getDescriptor()
.getOptions()
.getExtension(AnnotationsProto.http)
However this doesn't compile, complaining about typing issues where it cannot resolve the method.
I am trying to follow this: https://developers.google.com/protocol-buffers/docs/proto.html#customoptions
So the question is, how do I read the option from Java?
Well this is embarrassing, its actually a completely different type.
AnnotationsProto.http implements type with a generic of MethodOptions (https://developers.google.com/protocol-buffers/docs/reference/java/com/google/protobuf/DescriptorProtos.MethodOptions.html)
Whereas Message.getDescriptor().getOptions().getExtensions() is expecting a parameter with a generic of MessageOptions (https://developers.google.com/protocol-buffers/docs/reference/java/com/google/protobuf/DescriptorProtos.MessageOptions.html)
MethodOptions vs MessageOptions - perhaps I need to get down to specsavers...
The following groovy code will fetch the http annotation
import com.google.api.AnnotationsProto
def methodDescriptorSupplier = (ProtoMethodDescriptorSupplier) grpcMethodDescriptor.getSchemaDescriptor()
def extension = methodDescriptorSupplier.getMethodDescriptor().getOptions().getExtension(AnnotationsProto.http)

Run contents of string in java [duplicate]

This question already has answers here:
Run piece of code contained in a String
(9 answers)
Closed 6 years ago.
Lets say i have this String: String run = "System.out.println\(\"Hello\"\)". What i want to do is run what is in the string to output Hello in console.
Maybe there is a method like String.run()?
Try BeanShell , build your app with jar library.
import bsh.Interpreter;
private void runString(String code){
Interpreter interpreter = new Interpreter();
try {
interpreter.set("context", this);//set any variable, you can refer to it directly from string
interpreter.eval(code);//execute code
}
catch (Exception e){//handle exception
e.printStackTrace();
}
}
Maybe in Java 9 you could use the REPL but as it's not there yet You would need to
* create a temporary file with a class with a know to You API
* run javac on it and compile it
* load the compiled class with a class loader
* run the code
If You want to do is running dynamically defined scripts in Your code then You could use Nashorn and JavaScript. It would do what You want. Also You could use Groovy in your project instead of Java - the syntax is similar to Java but Groovy is a dynamic language.
No, you cannot do it and there's no method to run this command in String. Anything withing the double quotes becomes String literals only and compiler doesn't take care of any command written in that.

pyspark: call a custom java function from pyspark. Do I need Java_Gateway?

I wrote the following MyPythonGateway.java so that I can call my custom java class from Python:
public class MyPythonGateway {
public String findMyNum(String input) {
return MyUtiltity.parse(input).getMyNum();
}
public static void main(String[] args) {
GatewayServer server = new GatewayServer(new MyPythonGateway());
server.start();
}
}
and here is how I used it in my Python code:
def main():
gateway = JavaGateway() # connect to the JVM
myObj = gateway.entry_point.findMyNum("1234 GOOD DAY")
print(myObj)
if __name__ == '__main__':
main()
Now I want to use MyPythonGateway.findMyNum() function from PySpark, not just a standalone python script. I did the following:
myNum = sparkcontext._jvm.myPackage.MyPythonGateway.findMyNum("1234 GOOD DAY")
print(myNum)
However, I got the following error:
... line 43, in main:
myNum = sparkcontext._jvm.myPackage.MyPythonGateway.findMyNum("1234 GOOD DAY")
File "/home/edamameQ/spark-1.5.2/python/lib/py4j-0.8.2.1-src.zip/py4j/java_gateway.py", line 726, in __getattr__
py4j.protocol.Py4JError: Trying to call a package.
So what did I miss here? I don't know if I should run a separate JavaApplication of MyPythonGateway to start a gateway server when using pyspark. Please advice. Thanks!
Below is exactly what I need:
input.map(f)
def f(row):
// call MyUtility.java
// x = MyUtility.parse(row).getMyNum()
// return x
What would be the best way to approach this? Thanks!
First of all the error you see usually means the class you're trying to use is not accessible. So most likely it is a CLASSPATH issue.
Regarding general idea there are two important issues:
you cannot access SparkContext inside an action or transformation so using PySpark gateway won't work (see How to use Java/Scala function from an action or a transformation? for some details)). If you want to use Py4J from the workers you'll have to start a separate gateways on each worker machine.
you really don't want to pass data between Python an JVM this way. Py4J is not designed for data intensive tasks.
In PySpark before start calling the method -
myNum = sparkcontext._jvm.myPackage.MyPythonGateway.findMyNum("1234 GOOD DAY")
you have to import MyPythonGateway java class as follows
java_import(sparkContext._jvm, "myPackage.MyPythonGateway")
myPythonGateway = spark.sparkContext._jvm.MyPythonGateway()
myPythonGateway.findMyNum("1234 GOOD DAY")
specify the jar containing myPackage.MyPythonGateway with --jars option in spark-submit
If input.map(f) has inputs as an RDD for example, this might work, since you can't access the JVM variable (attached to spark context) inside the executor for a map function of an RDD (and to my knowledge there is no equivalent for #transient lazy val in pyspark).
def pythonGatewayIterator(iterator):
results = []
jvm = py4j.java_gateway.JavaGateway().jvm
mygw = jvm.myPackage.MyPythonGateway()
for value in iterator:
results.append(mygw.findMyNum(value))
return results
inputs.mapPartitions(pythonGatewayIterator)
all you need to do is compile jar and add to pyspark classpath with --jars or --driver-class-path spark submit options. Then access class and method with below code-
sc._jvm.com.company.MyClass.func1()
where sc - spark context
Tested with Spark 2.3. Keep in mind, you can call JVM class method only from driver program and not executor.

Reading BSTR in JAVA through JACOB

I am trying to access a device through a COM object in a JAVA interface.
The particular call (as described by the manufacturer) is:
Name: ScanUSB
Parameters: [out] VARIANT* serialNumbers
Use: serialNumbers is a pointer to a VARIANT containing an array of BSTR.
The exact call doesn't matter, but I need to feed it a BSTR array through the Java interface. A VB demo for the COM interface simply does this with the commandlm_Co1.ScanUSB(snNum), with Dim snNum As Object = Nothing. The Items in snNum are then displayed in a dropdown menu.
I am trying to do this with JACOB, as I have had the most luck with communication. This is more or less what I am using:
import com.jacob.com.Variant;
import com.jacob.com.Dispatch;
public class JunoReader {
public JunoReader() {
Dispatch oOphirLink = new Dispatch("clsid:{--the id of the device here--}");
Variant snNum = new Variant();
Variant testing = Dispatch.call(oOphirLink,"ScanUSB", snNum);
println(testing);
}
}
When I run this, everything compiles properly and I can confirm that I am communicating with the device, but all I get back is the null Variant that I put in.
My question is: How can I feed a BSTR array to a COM object through a JAVA interface?
Thanks!
So, one month and zero free time later, I have an answer to my own question and that answer is "Use Python".
Python allows users to access COM objects with the comtypes module, effectively with a single command:
from comtypes.client import CreateObject
target_guid = CreateObject("{TARGET-COM-CLSID-HERE}")
This allows python to talk with whatever the COM object is, so there was none of the trouble that Java was giving me. The single line: target_guid.ScanUSB() produced (u'717610',), the serial number of the target device. Notice that Python has no trouble reading the Unicode produced by the COM object.
The second trick involves Python's COM server, generated with the win32com module. Because the COM servers can be registered to Windows, I don't have to worry about where the dll is located. All I need is the clsid. To build the python COM server, I followed the instructions for a "quick start to server side COM and Python". So what does it all look like?
Python code:
class OphirPyCOM:
_reg_clsid_ = "{PYTHON-COM-CLSID-HERE}"
_reg_desc_ = "Python COM server"
_reg_progid_ = "Python COM server"
_public_methods_ = [ 'Hello',
'ConnectOphir',
'ScanUSB', """More methods here"""
]
_public_attrs_ = ["""Some public attributes"""]
_readonly_attrs_ = ["""some read-only attributes"""]
def __init__(self):
"""some variables declared here"""
def Hello(self, who):
"""Verifies a connection"""
return "{PYTHON-COM-CLSID-HERE}" + str(who)
def ConnectOphir(self,clsid):
"""Connects to the target COM Object"""
from comtypes.client import CreateObject
self.target_guid = CreateObject(clsid)
return "OphirLMMeasurement object created."
def ScanUSB(self):
"""Communicates with the target device"""
self.connected_inst = self.target_guid.ScanUSB()
for i in range(0,len(self.connected_inst)):
self.inst_list.append(str(self.connected_inst[i]))
return self.inst_list
if __name__ == "__main__":
# use 'python com.py' to register the COM server
# use 'python com.py --unregister' to unregister it
print "Registering COM server..."
import win32com.server.register
win32com.server.register.UseCommandLine(OphirPyCOM)
We can run that with the command line and get it registered. Then we take the values over to Java with JACOB:
import com.jacob.com.Variant;
import com.jacob.com.Dispatch;
public class JunoReader {
String pyClsid = "{PYTHON-COM-CLSID-HERE}"; // This is where your python COM clsid goes
String opClsid = "{TARGET-COM-CLSID-HERE}"; // This is where your ultimate target clsid goes
public JunoReader() {
_pyClsid = "clsid:" + pyClsid
// This finds the COM object location:
Dispatch oOphirLink = new Dispatch(_pyClsid);
}
public String HandShake() {
String _talkBack = "is connected.";
Variant _handShake = Dispatch.call(oOphirLink,"Hello",_talkBack); // I am trying to look for the Juno...
return (_handShake.toString());
}
public String ConnectOphir() {
Variant _connectOphir = Dispatch.call(oOphirLink,"ConnectOphir", opClsid); // Connect to the target COM object
return (_connectOphir.toString());
}
public String ScanUSB() {
Variant _serialNumberList = Dispatch.call(oOphirLink,"ScanUSB"); // This scans the USB ports for devices
return (_serialNumberList.toString());
}
}
calling JunoReader.ScanUSB() produces: 717610, exactly like it is supposed to. Implementing the subsequent methods of the manufacturer dll allowed me to read data from this device into a Java applet. Problem solved.
A caveat: you may need to unregister the Python COM every time you change the change the source file and then re-register with a different clsid. Java was having a tough time establishing a connection to the updated code unless I used a new clsid every time I changed the file.
Why did I spend all this time typing this up? Because most of the advice related to reading native data types into Java involved some version of JNI and JNA. I spent weeks trying to get the tutorials to compile and didn't make any progress. On the other hand, I thought of this approach yesterday and can now communicate with my device through Java. The Python COM server provided a simple, straightforward way to interface Java with native applications. No UnsatisfiedLinkErrors, no Can't find librarys, no Classpath and JAVA_HOME issues. I didn't need to learn C or C++ and all the Python tutorials worked as described with no necessary modification.
To summarize, if you are having trouble reading native data types into Java, just set up a Python COM server and let Python's dynamic typing do the work for you.

Categories

Resources