Problems encountered with Java Gateway
Problems encountered with Java Gateway
I am writing a framework for use on the Java Gateway. The role of the framework is:
1. Import the framework jar file into ensemble studio (test completed);
2. In the framework jar, handle the related functions of the remaining jar files (the rest of the jar files are written by colleagues).
The general idea is as follows:
Send: Ensemble Java Gateway -> Framework Jar -> Plugin Jar (colleagues write, processing data).
Returns: Plugin Jar (processed return data) ->Framework Jar->Ensemble Java Gateway.
The problems I encountered were:
I refer to gson and Bouncy Castle in Plugin Jar, but only one (gson or Bouncy Castle) can be loaded when running.
How can I solve this problem, my call in ensemble is as follows:
/// d ##class(PRD.Test).OnProcessInput()
ClassMethod OnProcessInput()
{
Set val = 0
Set gateway = ##class(%Net.Remote.Gateway).%New()
// Below is the port and connection address.
Do gateway.%Connect("127.0.0.1", 55555)
// The following EnterTestClass must match the Java class name.
Set javaObj = ##class(test.Main).%New(gateway)
// The following enter is the public static method in the Java class.
Set val = javaObj.run(gateway,"testdemo.jar","test.EnterTestClass","generatorPassword")
Set val = javaObj.run(gateway,"testdemo.jar","test.EnterTestClass","uuid")
w val,!
}In the Java framework:
/**
* Inherit URLClassLoader to load the jar file
*
* @Version: 2018/3/16 15:18
*/
Public class MyClassLoader extends URLClassLoader {
Public MyClassLoader(URL[] urls) {
Super(urls);
}
Public MyClassLoader(URL[] urls, ClassLoader parent) {
Super(urls, parent);
}
Public void addJar(URL url) {
this.addURL(url);
}
}Load the jar tool:
Import org.slf4j.Logger;
Import org.slf4j.LoggerFactory;
Import java.io.File;
Import java.lang.reflect.Method;
Import java.net.URL;
Import java.net.URLClassLoader;
Import java.util.ArrayList;
Import java.util.List;
/**
* jar file loading tool class.
*
* @Version: 2018/3/15 16:42
*/
Public class LoadJarUtil {
Private static final Logger logger = LoggerFactory.getLogger(LoadJarUtil.class);
Private LoadJarUtil() {
}
Private static LoadJarUtil loadJarUtil = null;
/**
* Class loader for loading jar files.
*/
Private static MyClassLoader classLoader = null;
/**
URLURLLoader's addURL method
*/
Private static Method addURL = initAddMethod();
Public MyClassLoader getMyClassLoader() {
Return classLoader;
}
Public static LoadJarUtil getInstance() {
If (loadJarUtil == null) {
loadJarUtil = new LoadJarUtil();
}
//
If (classLoader == null) {
URL[] urls = new URL[]{};
classLoader = new MyClassLoader(urls);
}
Return loadJarUtil;
}
/**
* Initialization method
*/
Private static final Method initAddMethod() {
Try {
Logger.info ("initialize JAR package loader...");
Method add = URLClassLoader.class
.getDeclaredMethod("addURL", new Class[]{URL.class});
add.setAccessible(true);
Return add;
} Catch (Exception e) {
Logger.error("Initial JAR package loader failed, failure reason:" + e.getMessage());
}
Logger.error("initialize JAR package loader failed, unknown cause of failure");
Return null;
}
/**
* Loop through the directory to find out all JARs
*/
Private final void loopFiles(File file, List<File> files) {
If (file.isDirectory()) {
Logger.info("[{}] traverses the specified path and searches for all jar files", file.getAbsolutePath());
File[] tmps = file.listFiles();
For (File tmp : tmps) {
loopFiles(tmp, files);
}
} Else {
If (file.getAbsolutePath().endsWith(".jar")) {
Files.add(file);
}
}
}
/**
* <pre>
* Load JAR file
* </pre>
*
* @param file
*/
Public final void loadJarFile(File file) {
Try {
Logger.info("[{}] loads the jar file...", file.getAbsolutePath());
// classLoader.addJar(file.toURI().toURL());
addURL.invoke(classLoader, new Object[]{file.toURI().toURL()});
} Catch (Exception e) {
Logger.error("[{}] failed to load jar file, failure reason: %s", file.getAbsolutePath(), e.getMessage());
}
}
/**
* <pre>
* Load all JAR files from a directory
* </pre>
*/
Public final void loadJarPath(final String jarFilePath) {
Logger.info("[{}] loads all jar files from the specified directory.", jarFilePath);
List<File> files = new ArrayList<File>();
File lib = new File(jarFilePath);
loopFiles(lib, files);
For (File file : files) {
loadJarFile(file);
}
Logger.info("[{}] loads all jar files from the specified directory successfully.", jarFilePath);
}
}
(Framework)Main: execution method:
/**
* Load the Jar file and read Class, call the method and get the return value (if any).
*
* @param pluginJarName jar file name.
* @param className class name to call
* @param methodName method name
* @param array of array parameters (does not deal with specific types, all handled as String.)
* @return
*/
Public static Object run(final String pluginJarName, String className, String methodName, final Object[] array) {
Logger.info ("The log module is loaded...");
Logger.info ("Jar package needed to load the system...");
LoadJarUtil.getInstance().loadJarPath(Constats.getConfigPath() + PropertiesUtil.getInstance().readKeyValue(Constats.JARLIBPATH));
Logger.info ("Jar Package Required for Loading System...");
Logger.info ("Start execution program: [jar file name: {}], [file name: {}], [method name: {}], [parameter list: {}]", pluginJarName, className, methodName, Arrays.toString(array));
// // Custom ClassLoader to load jar file
MyClassLoader classLoader = LoadJarUtil.getInstance().getMyClassLoader();
Object result = null;
Try {
// Load the jar file for a specific path
Logger.info ("Start loading jar files...");
classLoader.addJar(new File(Constats.getConfigPath() + PropertiesUtil.getInstance().readKeyValue(Constats.JARPLUGPATH) + pluginJarName).toURI().toURL());
// dynamically load the class file of a particular class in the jar file
Class<?> clazz = classLoader.loadClass(className);
If (null != array && array.length > 0) {
Class<?>[] methodType = new Class[array.length];
For (int i = 0; i < array.length; i++) {
methodType[i] = String.class;
}
Logger.info("Start calling the specified method and passing in parameters...");
// Get the specific method to be called getName(String xx)
Method method = clazz.getMethod(methodName, methodType);
//Call the method to get the return value of the method.
// Create an instance of the reflection class first, that is, the method that calls the class may not be statically statically decorated.
Result = method.invoke(clazz.newInstance(), array).toString();
} Else {
// No parameter, no return value
Logger.info("Start calling the specified method and passing in parameters...");
Method methodD = clazz.getDeclaredMethod(methodName);
Result = methodD.invoke(clazz.newInstance());
}
} Catch (Exception e) {
e.printStackTrace();
Logger.error("Execute Jar file exception, exception message:[{}],\nDetailed message:--", e.getMessage());
} finally {
// //Close class loader
Try {
classLoader.close();
} Catch (IOException e) {
Logger.error("Exception closing class loader, exception message: [{}]", e.getMessage());
}
}
Logger.info("Execution result:{}", result);
Logger.info ("execution of the specified Jar file");
Return result;
}Plugin Jar:
Import java.io.BufferedWriter;
Import java.io.File;
Import java.io.FileWriter;
Import java.io.IOException;
Import java.security.Security;
Import java.time.LocalDateTime;
Import java.util.Map;
Import java.util.UUID;
Import com.google.gson.Gson;
Import com.google.gson.reflect.TypeToken;
Import org.bouncycastle.jce.provider.BouncyCastleProvider;
/**
* Ensemble connection Java class example.
*
* @Version: 2018/3/15 12:13
*/
Public class EnterTestClass {
Private static final String STATICFILEPATH = "D:\\EnterTestClass.txt";
/**
* Generate password message.
* <p>
* Parameters have a return value.
*
* @param name
* @param password
* @return
* @throws IOException
*/
Public String generatorPassword() throws IOException {
Security.addProvider(new BouncyCastleProvider());
String name="test";
String password="-demo";
String passnew = name + password;
User user = new User(name, password);
String result = "[ generatorPassword ] :" + LocalDateTime.now().toString() + ", method parameter [user:" + name + ", password:" + password + "], user output toString():" + user.toString() + ", generated password:" + password + org.bouncycastle.util.encoders.Hex.toHexString(passnew.getBytes());
Write(result);
Return result;
}
/**
* Only write messages to the file system.
* <p>
* No parameters, no return value.
*
* @throws IOException
*/
Public void writeMessage() throws IOException {
Write("[ writeMessage ] :" + LocalDateTime.now().toString() + "Generated data message.");
}
/**
* Write file messages, do not call.
*
* @param text
* @throws IOException
*/
Private void write(String text) throws IOException {
File file = new File(STATICFILEPATH);
If (!file.exists()) {
Try {
file.createNewFile();
} Catch (IOException e) {
e.printStackTrace();
}
}
BufferedWriter bf = new BufferedWriter(new FileWriter(file.getAbsoluteFile()));
Bf.append(text);
Bf.close();
}
/**
* Each call returns a different uuid. It writes a file message to the file system.
*
* @return
* @throws IOException
*/
Public String uuid() throws IOException {
File file = new File("D:\\EnterTestClass.txt");
If (!file.exists()) {
Try {
file.createNewFile();
} Catch (IOException e) {
e.printStackTrace();
}
}
String jsonString = "{\"uid\":\"189024\", \"region\":\"SouthChina\", \"order\":29021.98}";
Gson gson = new Gson();
Map<String, String> retMap = gson.fromJson(jsonString,
New TypeToken<Map<String, String>>() {
}.getType());
String origin = retMap.get("uid").toString();
String destination = retMap.get("region").toString();
Write("[ uuid ] :" + LocalDateTime.now().toString() + "---" + origin + "---" + destination);
Return UUID.randomUUID().toString();
}
}Comments
You can try referring the multiple jar files as list to gateway.
Set AssemblyFileNameWithPath1="jar path 1"
Set AssemblyFileNameWithPath2="jar path 2"
Set gateway=##class(%Net.Remote.Gateway).%New()
Set classpath=##class(%ListOfDataTypes).%New()
Do classpath.Insert(AssemblyFileNameWithPath1)
Do classpath.Insert(AssemblyFileNameWithPath2)
Set status=gateway.%Connect(Host,Port,NameSpace,10,classpath)