In order to call EJB components in applications deployed with Appeon, Appeon provides its own EJB solution which includes a customized object (EJBObject object in Appeon Workarounds PBL), a DLL (eonejbclient.dll), and a bridge (Appeon Bridge). With this EJB solution you can call an EJB component in both the PowerBuilder Client/Server application and the deployed Appeon application.
Compared to the EJB solution of PowerBuilder, Appeon EJB solution can support more complex parameters such as Structure; and there is no need to generate the proxy object in PowerBuilder.
eonejbclient.dll -- Located in the same folder as the Appeon Workarounds PBL, this DLL is used by the PowerBuilder Client/Server application only, not by the deployed Appeon application. If you want to make the PowerBuilder Client/Server application call the EJB component successfully using the same Appeon EJB solution as the deployed application uses, make sure this DLL is included in the PowerBuilder application directory on the client machine.
The Appeon EJB solution supports calling EJB 1.x/2.x/3.x components deployed to the J2EE-compliant application servers only (no .NET IIS application server). The certified supported application server includes WildFly 10, JBoss EAP 6.x, WebSphere 7/8/8.5, & WebLogic 12c.
JBoss application server requires no EJB proxy generated, but WebLogic and WebSphere application server requires you to generate the EJB proxy and copy the generated EJB proxy to Appeon Bridge.
To generate the EJB proxy in the WebSphere application server:
-
Run the DOS command window as an administrator, and then change the directory to IBM\WebSphere\AppServer\bin.
-
Execute this command:
createEJBStubs.bat name of the JAR file or EAR file
To generate the EJB proxy in the WebLogic application server:
-
Run the DOS command window as an administrator, and then change the directory to domains\base_domain\bin.
-
Execute this command:
setDomainEnv.cmd
-
Change the directory back to domains\base_domain\bin, and execute this command:
java weblogic.appc name of the JAR file or EAR file
The proxy functions will be automatically generated into the JAR file and the JAR file that contains the proxy functions is what we call the EJB proxy. Follow the next section to copy/bundle the EJB proxy to the Appeon Bridge.
Introduction to Appeon Bridge
Appeon Bridge is a standard J2EE-compliant Web application that can be deployed to any J2EE compliant application server regardless of whether EJB components exist on the server. It functions as the medium between the clients and EJB components, and can be deployed by installing the appeonbridge.war file, which is located in %appeon%\plugin\appeonbridege under the PowerServer installation folder.
Bundle EJB proxy with Appeon Bridge
Before deploying Appeon Bridge to the application server, you must bundle the EJB proxy (JAR file) with Appeon Bridge to implement the communication to EJB components.
Three ways of bundling the EJB proxy with Appeon Bridge:
-
Method 1: Add the proxy to the lib directory in the appeonbridge.war file. Since the appeonbridge.war file is a ZIP file, you can check the directory in the WAR file with a third-party tool such as WinZip.
-
Navigate to %appeon%\plugin\appeonbridge folder and open appeonbridge.war with the third-party tool such as WinZip. %appeon% indicates the installation folder of the PowerServer.
-
Navigate to the folder where the EJB proxy is located.
-
Copy the entire folder of the EJB proxy to the appeonbridge.war\WEB-INF\lib directory (you will need to create the lib folder first).
This method does not work for EJB 3.x in JBoss; try the second method if you are using EJB 3.x in JBoss.
-
-
Method 2: Add the classes of the EJB component to the classes directory in the appeonbridge.war file.
-
Navigate to %appeon%\plugin\appeonbridge folder and open appeonbridge.war with the third-party tool such as WinZip. %appeon% indicates the installation folder of the PowerServer.
-
Navigate to the folder where the EJB classes are located.
-
Copy the entire folder of the EJB classes to the appeonbridge.war\WEB-INF\classes directory.
-
-
Method 3: Copy the EJB proxy to the lib directory in the Java Web server, and add the lib directory (where the proxy is stored) to the CLASSPATH environment variable of the machine that hosts the Java Web server.
Now you are ready to deploy the following files to the application server one by one:
-
Appeon Bridge (appeonbridge.war) which includes the EJB proxy. View Generate the EJB proxy for how to generate the EJB proxy and Bundle EJB proxy with Appeon Bridge for how to copy the EJB proxy into appeonbridge.war.
-
Original JAR file for the EJB component without the EJB proxy functions.
-
PowerBuilder application that calls the EJB component. View Call EJB component in PowerBuilder application for how to write PowerScript to call the EJB component functions.
Deploying any of the above files is the same as deploying the file server. Please refer to the corresponding Deploying the Appeon File Server section under Configuring and deploying the file server. (Or you can refer to documents provided by the corresponding server vendors for the deployment instructions, as deploying the above file is the same as deploying any other applications.)
This section guides you through writing PowerScript to call the EJB component. Appeon provides an object called EJBObject in the Appeon Workarounds PBL to call the EJB component, and provides Appeon Bridge to communicate with the EJB component.
Step 1: Add the Appeon Workarounds PBL to the Library Search Path of your PowerBuilder application.
Step 2: Declare the EJBObject object.
Step 3: Configure the connection string, call the EJBObject connectserver function to connect with Appeon Bridge on the application server.
The connection string varies according to the application server. View connectserver to determine the connection string.
Step 4: Create the instance for EJB component using EJBObject lookupjndi function or createremoteinstance function.
Note: For EJB 3.x, lookupjndi function works exactly as the createremoteinstance function; both functions can directly return the corresponding instance session handle; while for EJB 2.x, lookupjndi function will need to obtain the home interface of the EJB component first, for example, ls_msg = lo_ejb.lookupjndi ("TestSBeanLess",ref ll_homeHandle), before it can return the corresponding instance handle.
The JNDI name has to be accurate, and it varies according to the application server. For WebSphere, you will also need to set the JNDI name first in the WebSphere console. View JNDI Name for more information.
Step 5: If the function to be called contains parameter(s), call the EJBObject registering functions to register the parameter.
Step 6: Call the EJBObject invoking component functions to invoke the EJB component method.
Step 7: Destroy the instance and disconnect from the application server.
Below is a PowerScript code example that calls an EJB 3.x component:
ejbobject lo_ejb //Declare EJBobject long ll_bean = 0 //For receiving instance's handle string ls_prop[5] string ls_serurl,ls_msg,ls_msg1,ls_parm //appeonbridge URL ls_serurl = "http://"+ip+":"+port1+"/appeonbridge/Dispatch" ls_prop[1]= is_appname //the deployed Appeon app name ls_prop[2]="javax.naming.Context.INITIAL_CONTEXT_FACTORY= 'org.jboss.as.naming.InitialContextFactory'" ls_prop[3]="javax.naming.Context.PROVIDER_URL='remote://"+ip+":"+port2+"'" ls_prop[4]= "username=" ls_prop[5]= "password=" ls_msg = lo_ejb.connectserver(ls_serurl, ls_prop) //Connect with server if ls_msg = "" then //Connection is successful else MessageBox("Not connected!",ls_msg) end if ls_jndi = sle_54.text //JNDI name has to be accurate otherwise instance will fail to create //EJB 3.x supports passing any character in the third parameter ls_msg = lo_ejb.createremoteinstance(ls_jndi,"AllDataType","sayHello", ref ll_bean) if ls_msg = "" then //Instance is created successfully sle_53.text = string(ll_bean) else MessageBox("createremoteinstance Failed!",ls_msg) end if ls_parm = "127.0.0.1" //Register the parameter that will be called by the EJB functions ls_msg = lo_ejb.regstring(ls_parm) if ls_msg = "" then else MessageBox("Regstring Failed !",ls_msg) end if //Call the function. Function name is case sensitive ls_msg = lo_ejb.invokeretstring(ll_bean,"sayHello1",true, ref ls_msg1) if ls_msg = "" then //Called successfully sle_52.text = ls_msg1 else MessageBox("invokestring Failed!",ls_msg) end if //Disconnect from server ls_msg = lo_ejb.destroyremoteinstance(ll_bean) if ls_msg <> '' then MessageBox("destroyremoteinstance Failed!",ls_msg) end if ls_msg = lo_ejb.disconnection( ) if ls_msg <> '' then MessageBox("disconnection Failed!",ls_msg) end if
Different application servers have different JNDI names.
JNDI name for JBoss
To call EJB 3.x in JBoss, the JNDI name should be in this format: ejb:" + appName + "/" + moduleName + "/" + distinctName + "/" + beanName + "!" + viewClassName
appName: name of the EAR file. If it is JAR file instead of EAR file, then leave this empty.
moduleName: name of the deployed JAR file; file extension should not be contained here, for example, HelloWorld.
distinctName: if no such name is defined, then leave this empty.
beanName: name of the implementation class.
viewClassName: name of the interface and package, for example, com.ibytecode.business.HelloWorld.
JNDI name for WebSphere
To call EJB in WebSphere, you will need to define the JNDI name by yourself:
-
Log into the WebSphere Administration console.
-
In the left pane, expand Applications > Application Types, and then select WebSphere enterprise applications.
-
In the right pane, click the name of the EJB component, and then click Bind EJB Business or EJB JNDI Names.
-
Define the name in the JNDI Name text box.
JNDI name for WebLogic
To call EJB in WebLogic 12c, you can find out the JNDI name here:
-
Log into the WebLogic Server Administration Console.
-
In the left pane, expand Environment > Servers.
-
On the Server summary page, click the name of the server.
-
On the server Settings page, click View JNDI Tree.
The JNDI tree is displayed in a new browser window.
-
In the left pane for the JNDI tree, expand the java:global node, find the EJB component, expand the component to find the class, and select the class.
The Bind Name displayed in the right page is the JNDI name you are looking for.
Appeon EJBObject object implements the interaction between client and Appeon Bridge. To use this object, you need to load appeon_workaround.pbl into your application.
EJBObject object provides the following functions to perform the relevant actions:
Function |
Description |
---|---|
Connecting and disconnecting to Appeon Bridge |
|
Obtaining the home interface of an EJB component |
|
Creating and destroying the instance for an EJB component |
|
Registering parameters |
|
Invoking EJB components |
|
Setting the language of the error message |
Description
Connects a client application to Appeon Bridge.
Syntax
EJBObject.ConnectServer(string url, string properties[])
Parameter |
Description |
---|---|
EJBobject |
A reference of an EJBobject. |
url |
URL with port, where Appeon Bridge is installed. Different application servers have different URL. See below for examples. |
properties[] |
Properties of Appeon Bridge. |
Return value
String.
Returns empty string ("") if it succeeds.
Here are a few examples of the URL for different application servers:
Example for EJB 1.x/2.x in JBoss:
String ls_serurl,ls_prop[5] ls_serurl = "http://127.0.0.1:8080/appeonbridge/Dispatch" ls_prop[1]= "testappeon" //name of the deployed Appeon application ls_prop[2]= "javax.naming.Context.INITIAL_CONTEXT_FACTORY='org.jnp.interfaces.NamingContextFactory'" ls_prop[3]= "javax.naming.Context.PROVIDER_URL='jnp://127.0.0.1:8080'" ls_prop[4]= "username=" ls_prop[5]= "password="
Example for EJB 3.x in JBoss:
String ls_serurl,ls_prop[5] ls_serurl= "http://127.0.0.1:8080/appeonbridge/Dispatch" ls_prop[1]= "testappeon" //name of the deployed Appeon application ls_prop[2]= "javax.naming.Context.INITIAL_CONTEXT_FACTORY= 'org.jboss.as.naming.InitialContextFactory'" ls_prop[3]= "javax.naming.Context.PROVIDER_URL= 'remote://127.0.0.1:4447'"//default port is 4447. //Port number can be configured in {$Home_DIR}\standalone\configuration\standalone.xml. ls_prop[4]= "username=" ls_prop[5]= "password="
Example for WebSphere:
String ls_serurl,ls_prop[5] ls_serurl = "http://127.0.0.1:9080/appeonbridge/Dispatch" ls_prop[1]= "testappeon" //name of the deployed Appeon application ls_prop[2]="javax.naming.Context.INITIAL_CONTEXT_FACTORY='com.ibm.websphere.naming.WsnInitialContextFactory'" ls_prop[3]= "javax.naming.Context.PROVIDER_URL='iiop://127.0.0.1:2809'"//default port is 2809. //Port number can be obtained or changed in WebSphere console > server1 > BOOTSTRAP_ADDRESS. ls_prop[4]= "username=admin" ls_prop[5]= "password=admin"
Example for WebLogic:
String ls_serurl,ls_prop[5] ls_serurl = "http://127.0.0.1:7001/appeonbridge/Dispatch" ls_prop[1]= "testappeon" //name of the deployed Appeon application ls_prop[2]= "javax.naming.Context.INITIAL_CONTEXT_FACTORY='weblogic.jndi.WLInitialContextFactory'" ls_prop[3]= "javax.naming.Context.PROVIDER_URL='t3://127.0.0.1:7001'" ls_prop[4]= "username=weblogic" ls_prop[5]= "password=appeon123"
Description
Disconnects a client application from Appeon Bridge.
Syntax
EJBObject.DisConnection()
Parameter |
Description |
---|---|
EJBobject |
A reference of an EJBobject. |
Return value
String.
Returns empty string ("") if it succeeds.
Description
Obtains the home interface of an EJB component in order to create an instance for the component.
Syntax
EJBObject.lookupjndi (string jndiname, ref long objid)
Parameter |
Description |
---|---|
EJBObject |
A reference of an EJBobject. |
jndiname |
The JNDI name of the EJB component. |
objid |
The handle to the EJB home interface. |
Return value
String.
Returns empty string ("") if it succeeds.
Description
Sets the language of the error message in PowerBuilder IDE.
Syntax
EJBObject.initlocallanguage (long nlocalcode)
Parameter |
Description |
---|---|
EJBObject |
A reference of an EJBobject. |
nlocalcode |
A long value representing different languages. 0 - English (default) 1 - Japanese 2 - Korean 3 - Simplified Chinese 4 - Traditional Chinese |
Return value
Long.
Invokeretblob |
Invokeretblobarray |
Invokeretbool |
Invokeretboolarray |
Invokeretchar |
Invokeretchararray |
Invokeretdate |
Invokeretdatearray |
Invokeretdatetime |
Invokeretdatetimearray |
Invokeretdouble |
Invokeretdoublearray |
Invokeretint |
Invokeretintarray |
Invokeretlong |
Invokeretlongarray |
Invokeretreal |
Invokeretrealarray |
Invokeretstring |
Invokeretstringarray |
Invokerettime |
Invokerettimearray |
Invokeretuint |
Invokeretuintarray |
Invokeretulong |
Invokeretulongarray |
Invokeretstru |
Invokeretstruarray |
Invokeretvoid |
Description
Invoke an EJB component which returns a particular data type. All methods will share the same parameters, syntax and return value.
Syntax
string EJBObject.Invokeblob(long objid, string methodname, boolean autoremove, ref blob retval)
Parameter |
Description |
---|---|
EJBObject |
A reference of an EJBobject. |
objid |
The handle to the component method. |
methodname |
The name of the invoking component method. |
autoremove |
Unsupported. Input false. |
retval |
The return value of invoking the EJB component method. This parameter does not provided in the Invokeretvoid method. The data type of the retval argument keeps the consistence with the data type used in the invoking methods, except the Invokeretstru and Invokeretstruarray, the data type of the retval arguments for the two methods are both blob. |
Return value
String.
Returns empty string ("") if it succeeds.
Usage
Variables cannot be null for structure and array.
For a structure to be registered, variables can be:
-
char, string, boolean, int, unit, long, ulong, real, double, datetime, date or time.
-
an array of the above types. The maximum dimension is 3.
-
a structure or a 1-dimensional structure array. And the array must be a fixed array.
For a return value of structure type, variables can be:
-
char, string, boolean, blob, int, unit, long, ulong, real, double, datetime, date or time.
-
a multidimensional array of the above types.
-
a structure or a 1-dimensional structure array. And the array must be a fixed array.
Register functions are provided to register parameters with different data type. Except RegStruct and RegstructArray, all functions will share the same parameters, syntax, return value.
RegChar |
RegCharArray |
RegDate |
RegDateArray |
RegDateTime |
RegDateTimeArray |
RegDouble |
RegDoubleArray |
RegInt |
RegIntArray |
RegLong |
RegLongArray |
RegReal |
RegRealArray |
RegString |
RegStringArray |
RegBlob |
RegBlobArray |
RegBool |
RegBoolArray |
RegTime |
RegTimeArray |
RegUInt |
RegUIntArray |
RegULong |
RegULongArray |
RegStruct |
RegStructArray |
Description
Registers a parameter with a certain data type. Syntax below takes RegBlob as an example.
Syntax
EJBObject.RegBlob(blob data)
Parameter |
Description |
---|---|
EJBObject |
A reference of an EJBobject. |
data |
The parameter to be registered. Its name can be user-defined, but its type must be consistent with the data type specified in the Register method. |
Return value
String.
Returns empty string ("") if it succeeds.
Description
Registers a structure or structure array. The two functions will share the same parameters, syntax, return value. Syntax below takes regstructarrary as an example.
Syntax
EJBObject.regstructarrary (any data [], string javaclassname, readonly classdefinition cdef)
Parameter |
Description |
---|---|
EJBObject |
A reference of an EJBobject. |
data |
The parameter to be registered and the name is user-defined. |
javaclassname |
The name of the corresponding Java class in application server. |
cdef |
ClassDefinition property of structure. |
Return value
String.
Returns empty string ("") if it succeeds.
Usage
Variables cannot be null for structure and array.
For a structure to be registered, variables can be:
-
char, string, bool, int, unit, long, ulong, real, double, datetime, date or time.
-
an array of the above types. The maximum dimension is 3.
-
a structure or a 1-dimensional structure array. And the array must be a fixed array.
-
(Only for RegStruct method) For the javaclassname parameter, input the full name of the Java class on EJB server corresponding to the structure you defined in PowerBuilder. For example, a.b.c.d.myclassName.
Description
Creates the instance for an EJB component.
Syntax
EJBObject.CreateRemoteInstance(string jndiname, string homename, string methodname, ref long beanid)
Parameter |
Description |
---|---|
EJBObject |
A reference of an EJBobject. |
jndiname |
The JNDI name of the EJB component. |
homename |
The name of the home interface of an EJB component. |
methodname |
The name of the method. |
beanid |
The handle to the EJB component. |
Return value
String.
Returns empty string ("") if it succeeds.
Description
Destroys the instance for an EJB component.
Syntax
EJBObject.DestroyRemoteInstance(long objid)
Parameter |
Description |
---|---|
EJBObject |
A reference of an EJBobject. |
objid |
The handle to the EJB component. |
Return value
String.
Returns empty string ("") if it succeeds.
-
Appeon Bridge maps datatypes (except structure) between Java and PowerBuilder is shown as below.
PowerBuilder data types
Java data types
Char
char
String
String
Boolean
boolean
Int
short
Unit
int
Long
int
Ulong
long
LongLong
long
Real
float
Double
double
Decimal
java.math.BigDecimal
Number
double
Timestamp
java.sql.Timestamp
Datetime
java.sql.Timestamp
Date
java.util.Date
Time
java.sql.Time
Blob
byte[]
-
With Appeon EJB solution, Structure data can be passed when invoking EJB components. To implement this, you need to define a Java class in the EJB components. There are two necessary elements in Java Class: 1) private static String PBMap[] and 2) implementing java.io.Serializable interface. In PBMap array you need to map the members with the identical order and datatype to a PowerBuilder Structure.
Following is an example of defining a Java class (please note that the member variables should be in lower case.)
package test; import java.io.Serializable; public class Simple implements Serializable { private short l_int; private boolean b_bool; private String s_string; private static String PBMap[] = {"l_int", "b_bool", "s_string"}; public String[] getPBMap() { return PBMap; } public boolean isB_bool() { return b_bool; } public short getL_int() { return l_int; } public String getS_string() { return s_string; } public void setB_bool(boolean b_bool) { this.b_bool = b_bool; } public void setL_int(short l_int) { this.l_int = l_int; } public void setS_string(String s_string) { this.s_string = s_string; } }