LibertyのEJBをtWASから使う（備忘録）

# 目的

Libertyで実行するEJBにtWASからアクセスするテストをしたときの備忘録です。

# EJBの作り直し

ThinClientでも実行したいので、EJBの作り直しをしました。
EclipseのEJBプロジェクトでSession BeansをNewして作成します。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/262366/9fc9288a-d6e3-77f6-11a1-e9c7c6e96ffd.png)

以下のような画面にしてRemote interfaceを用意します。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/262366/aee01440-a50e-2730-1005-6abff8200739.png)

Home Interfaceを用意します。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/262366/97007949-feda-25ab-d482-dad0773104c5.png)


Hello.javaにメソッドを追加します。
```
package pdprof.ejb;

import javax.ejb.Remote;
import javax.ejb.RemoteHome;
import javax.ejb.Stateless;
import pdprof.ejb.view.HelloRemote;
import pdprof.ejb.view.HelloRemoteHome;

/**
 * Session Bean implementation class Hello
 */
@Stateless(mappedName = "ejb/Hello")
@Remote(HelloRemote.class)
@RemoteHome(HelloRemoteHome.class)
public class Hello implements HelloRemote {

    /**
     * Default constructor. 
     */
    public Hello() {
        // TODO Auto-generated constructor stub
    }
    
    public String hello() {
    	return "Hello!!";
    }

}
```

作成したメソッドをEJBのメソッドとして使えるようにPromoteします。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/262366/89b62c08-7d1b-0a00-28d0-30f4c7a2dd47.png)

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/262366/af8ea360-a5f2-f9e3-8f0f-9c0a392c95b9.png)

そうするとHelloRemote.javaにhello()メソッドが追加されています。

Annotationを手書きで追加を試みましたが、うまくいかず結果としてGUIで作成する方法が簡単でした。一度作成することで同じような構成をGUIを使わずに真似してかけるようになるかと思います。


# ServletのEJBアノテーションでJNDIのLookupが失敗する

EJBの定義が変わってしまったことでサーブレットのEJBアノテーションの指定ではJNDIのLookupが失敗してしまうので修正しました。Hello から HelloRemoteに変更です。Business Interface作成の影響と思われます。

```
＠EJB
HelloRemote hello;
```

# launchClient で tWASにアクセス

順に構成をためしていくので、アクセスが問題ないと考えられる組み合わせから試します。

tWAS上のEJBはdumpNameSpace.sh で確認できます。

```
[was@17c043663791 ejb-ear.ear]$ /opt/IBM/WebSphere/AppServer/bin/dumpNameSpace.sh -username wsadmin -password passw0rd | grep Hello     
   18 (top)/nodes/DefaultNode01/servers/server1/pdprof.ejb.view.HelloRemote
   18                                                    pdprof.ejb.view.HelloRemote
   49 (top)/nodes/DefaultNode01/servers/server1/pdprof.ejb.view.HelloRemoteHome
   49                                                    pdprof.ejb.view.HelloRemoteHome
   66 (top)/nodes/DefaultNode01/servers/server1/ejb/ejb-ear/ejb-lib.jar/Hello#pdprof.ejb.view.HelloRemoteHome
   66                                                    pdprof.ejb.view.HelloRemoteHome
   67 (top)/nodes/DefaultNode01/servers/server1/ejb/ejb-ear/ejb-lib.jar/Hello#pdprof.ejb.view.HelloRemote
   67                                                    pdprof.ejb.view.HelloRemote
  108 (top)/applications/com.ibm.ws.AppNameSpaces/ejb-ear/root/ejb-lib/Hello!pdprof.ejb.view.HelloRemoteHome
  108                                                    pdprof.ejb.view.HelloRemoteHome
  109 (top)/applications/com.ibm.ws.AppNameSpaces/ejb-ear/root/ejb-lib/Hello!pdprof.ejb.view.HelloRemote
  109                                                    pdprof.ejb.view.HelloRemote
  132 (top)/applications/ejb-ear/ejb-lib/Hello!pdprof.ejb.view.HelloRemote
  132                                                    pdprof.ejb.view.HelloRemote
  133 (top)/applications/ejb-ear/ejb-lib/Hello!pdprof.ejb.view.HelloRemoteHome
  133                                                    pdprof.ejb.view.HelloRemoteHome
```

Lookupさせるのは

-  java:global/ejb-ear/ejb-lib/Hello!pdprof.ejb.view.HelloRemote
-  java:app/ejb-lib/Hello!pdprof.ejb.view.HelloRemote
-  ejb/ejb-ear/ejb-lib.jar/Hello#pdprof.ejb.view.HelloRemote
    -  Lookupのもとが /nodes/DefaultNode01/servers/server1 であるためその先
-  java:comp/env/twas/ejb/Hello
    -  上のものを application-client.xml と ibm-application-client-bnd.xml に書いて参照


LaunchClientはサーバーにデプロイ後に以下の手順で実行しました。更新してデプロイする度に実行することになるので、コピーするものを準備しておくと作業が早くなります。

```
cd /opt/IBM/WebSphere/AppServer/profiles/AppSrv01/config/cells/DefaultCell01/applications/ejb-ear.ear
/opt/IBM/WebSphere/AppServer/bin/createEJBStubs.sh ejb-ear.ear
mkdir unzip;cd unzip;unzip ../ejb-ear.ear;cd ..
/opt/IBM/WebSphere/AppServer/bin/launchClient.sh ejb-ear.ear -CCclasspath=$PWD/unzip/ejb-lib.jar
```


# ThinClientでtWASにアクセス

前までに実行していた createEJBStubs.sh が忘れやすい処理なので、ThinClient動かすなら必要なことを残して置きます。

https://www.ibm.com/docs/ja/was-nd/9.0.5?topic=applications-running-thin-client-enterprise-javabeans-ejb

WAS同梱のJavaを使ってThinClientとしてtWASにアクセスします。
WASの環境なので

com.ibm.SSL.ConfigURL
com.ibm.CORBA.ConfigURL

が使えます。

```
/opt/IBM/WebSphere/AppServer/java/8.0/bin/java \
-classpath /opt/IBM/WebSphere/AppServer/runtimes/com.ibm.ws.ejb.thinclient_9.0.jar:$PWD/unzip/ejb-lib.jar:$PWD/unzip/ejb-client.jar \
-Djava.naming.provider.url=iiop://localhost:2809 \
-Dcom.ibm.SSL.ConfigURL=file:///opt/IBM/WebSphere/AppServer/profiles/AppSrv01/properties/ssl.client.props \
-Dcom.ibm.CORBA.ConfigURL=file:///opt/IBM/WebSphere/AppServer/profiles/AppSrv01/properties/sas.client.props \
Main
```

# launchClientでLibertyにアクセス

次にLibertyにアクセスします。コンテナー間での通信をしたいので、networkを作成することにしました。

```
$ podman network create pdprof-network
pdprof-network

$ podman network inspect pdprof-network
[
     {
          "name": "pdprof-network",
          "id": "418c96d79ef374bb42fd7e6e66ba8eac59860da30f9290dc1aaf40890af15440",
          "driver": "bridge",
          "network_interface": "podman1",
          "created": "2024-11-25T01:29:41.803460871+09:00",
          "subnets": [
               {
                    "subnet": "10.89.0.0/24",
                    "gateway": "10.89.0.1"
               }
          ],
          "ipv6_enabled": false,
          "internal": false,
          "dns_enabled": true,
          "ipam_options": {
               "driver": "host-local"
          }
     }
]
```

podman start の時に --network pdprof-network で同じネットワークになり、コンテナ名での名前解決が出きるようになります。

Liberty側の通信を受け入れる設定を追加するのに iiopEndpoint を指定しました。

```
    <iiopEndpoint id="defaultIiopEndpoint" host="ejb-jndi" iiopPort="2809">
	    <iiopsOptions iiopsPort="9402" sslRef="defaultSSLConfig"/>
    </iiopEndpoint>
    <orb id="defaultOrb">
	    <serverPolicy.csiv2>
		    <layers>
			    <authenticationLayer establishTrustInClient="Never"/>
		    </layers>
	    </serverPolicy.csiv2>
    </orb>
```

providerURLの接続先を変えてアクセスする。
- launchClient
```
/opt/IBM/WebSphere/AppServer/bin/launchClient.sh ejb-ear.ear \
-CCclasspath=$PWD/unzip/ejb-lib.jar \
-CCproviderURL=corbaloc:iiop:ejb-jndi:2809
```

JNDIのLookup先の一部は成功しているので、動作していることが確認できる。


# ThinClientでLibertyにアクセス

java.naming.provider.url=iiop://ejb-jndi:2809 の部分で接続先を変更して実行する。

- ThinClient
```
/opt/IBM/WebSphere/AppServer/java/8.0/bin/java \
-classpath /opt/IBM/WebSphere/AppServer/runtimes/com.ibm.ws.ejb.thinclient_9.0.jar:$PWD/unzip/ejb-lib.jar:$PWD/unzip/ejb-client.jar \
-Djava.naming.provider.url=iiop://ejb-jndi:2809 \
-Dcom.ibm.SSL.ConfigURL=file:///opt/IBM/WebSphere/AppServer/profiles/AppSrv01/properties/ssl.client.props \
-Dcom.ibm.CORBA.ConfigURL=file:///opt/IBM/WebSphere/AppServer/profiles/AppSrv01/properties/sas.client.props \
Main
```

ThinClientではこれまでのすべてのJNDI Lookupが失敗してしまったので、Lookup先の追加が必要になります。ログを確認すると

```
CNTR0167I: The server is binding the pdprof.ejb.view.HelloRemote interface of the Hello enterprise bean in the ejb-lib.jar module of the ejb-ear application.  
The binding location is: ejb/ejb-ear/ejb-lib.jar/Hello#pdprof.ejb.view.HelloRemote
```

とでているので１つは問題なさそうなだが失敗してしまいます。

https://www.ibm.com/docs/ja/was-liberty/base?topic=liberty-using-enterprise-javabeans-remote-interfaces

を確認し

```
Object found = c.lookup("ejb/global/ExampleApp/ExampleModule/ExampleBean!com.ibm.example.ExampleRemoteInterface");
```

となっていたので、ejb/global/ejb-ear/ejb-lib/Hello!pdprof.ejb.view.HelloRemote を lookupさせます。これで、ThinClientでもLibertyに接続できるのが確認できました。ここでLookup先に

- ejb/global/ejb-ear/ejb-lib/Hello!pdprof.ejb.view.HelloRemote
- java:comp/liberty/ejb/Hello
    - 上のものを application-client.xml と ibm-application-client-bnd.xml に書いて参照

を追加しました。

試しに実行すると、dumpNameSpace.sh -host ejb-jndi -root default で確認出来ました。
```
/opt/IBM/WebSphere/AppServer/bin/dumpNameSpace.sh -host ejb-jndi -root default    

Getting the initial context
Getting the starting context
 
==============================================================================
Name Space Dump
   Context factory: com.ibm.websphere.naming.WsnInitialContextFactory
   Provider URL: corbaloc:iiop:ejb-jndi:2809
   Requested root context: default
   Starting context: (top)=WebSphere Name Tree Root
   Formatting rules: jndi
   Time of dump: Mon Nov 25 16:11:35 UTC 2024
==============================================================================
 
 
==============================================================================
Beginning of Name Space Dump
==============================================================================
 
    1 (top)                                              
    2 (top)/ejb                                          com.ibm.ws.naming.jndicos.CNContextImpl
    3 (top)/ejb/global                                   com.ibm.ws.naming.jndicos.CNContextImpl
    4 (top)/ejb/global/ejb-ear                           com.ibm.ws.naming.jndicos.CNContextImpl
    5 (top)/ejb/global/ejb-ear/ejb-lib                   com.ibm.ws.naming.jndicos.CNContextImpl
    6 (top)/ejb/global/ejb-ear/ejb-lib/Hello!pdprof.ejb.view.HelloRemoteHome
    6                                                    org.omg.stub.java.rmi._Remote_Stub
    7 (top)/ejb/global/ejb-ear/ejb-lib/Hello!pdprof.ejb.view.HelloRemote
    7                                                    org.omg.stub.java.rmi._Remote_Stub
 
==============================================================================
End of Name Space Dump
==============================================================================
```

# ThinClientをIBM Java以外で動作させる

WASのJavaで動作させているので、それ以外のJavaでも動作させるようにします。前にも見たページなのだけど、

https://www.ibm.com/docs/ja/was-nd/9.0.5?topic=applications-running-thin-client-enterprise-javabeans-ejb

と、WASについていた ssl.client.propsを見ながら以下のようにして /tmp/ssl.client.propsとして保管します。
```
user.root=/opt/IBM/WebSphere/AppServer/profiles/AppSrv01
com.ibm.ssl.alias=DefaultSSLSettings
com.ibm.ssl.protocol=TLSv1.2
com.ibm.ssl.trustManager=SunX509
com.ibm.ssl.keyManager=SunX509
com.ibm.ssl.contextProvider=SunJSSE
com.ibm.ssl.keyStoreType=PKCS12
com.ibm.ssl.keyStoreProvider=SUN
com.ibm.ssl.keyStore=${user.root}/etc/key.p12
com.ibm.ssl.keyStorePassword={xor}CDo9Hgw=
com.ibm.ssl.trustStoreType=PKCS12
com.ibm.ssl.trustStoreProvider=SUN
com.ibm.ssl.trustStore=${user.root}/etc/trust.p12
com.ibm.ssl.trustStorePassword={xor}CDo9Hgw=
```

Javaは tWASの環境にOSデフォルトのjavaを導入することにします。podmanでrootでbashを起動して導入します。

```
podman exec -u 0 -it was90-ejb bash
dnf -y install java-1.8.0
```

でうまくいくはずなのですが、container起動時に指定したネットワークが違うせいか、外部ネットワークに接続できていないので、build時に導入できるようにDockerfileを書きます。

Javaの導入ディレクトリを確認します。OSファイルの変更もするので、-u 0 で動かす必要があります。
```
# ls -l /usr/bin/java
lrwxrwxrwx. 1 root root 22 Nov 25 15:32 /usr/bin/java -> /etc/alternatives/java
# ls -al /etc/alternatives/java
lrwxrwxrwx. 1 root root 71 Nov 25 15:32 /etc/alternatives/java -> /usr/lib/jvm/java-1.8.0-openjdk-1.8.0.432.b06-2.el8.x86_64/jre/bin/java
# cd /usr/lib/jvm
# ls -al
total 0
drwxr-xr-x. 3 root root 183 Nov 25 15:32 .
dr-xr-xr-x. 1 root root 160 Nov 25 15:32 ..
drwxr-xr-x. 3 root root  17 Nov 25 15:32 java-1.8.0-openjdk-1.8.0.432.b06-2.el8.x86_64
lrwxrwxrwx. 1 root root  21 Nov 25 15:32 jre -> /etc/alternatives/jre
lrwxrwxrwx. 1 root root  27 Nov 25 15:32 jre-1.8.0 -> /etc/alternatives/jre_1.8.0
lrwxrwxrwx. 1 root root  35 Nov 25 15:32 jre-1.8.0-openjdk -> /etc/alternatives/jre_1.8.0_openjdk
lrwxrwxrwx. 1 root root  49 Oct 13 19:16 jre-1.8.0-openjdk-1.8.0.432.b06-2.el8.x86_64 -> java-1.8.0-openjdk-1.8.0.432.b06-2.el8.x86_64/jre
lrwxrwxrwx. 1 root root  29 Nov 25 15:32 jre-openjdk -> /etc/alternatives/jre_openjdk
```

細かいバージョンが変わってもいいようにパスの指定は必要そうだけど、今回は 

```
cd /usr/lib/jvm/jre/lib/
mkdir endorsed
cp /opt/IBM/WebSphere/AppServer/runtimes/endorsed/endorsed_apis_9.0.jar .
```

にします。-classpathに/opt/IBM/WebSphere/AppServer/runtimes/com.ibm.ws.orb_9.0.jarを追加して、-Dcom.ibm.SSL.ConfigURL=file:///tmp/ssl.client.props のようにSSLの指定も変更します。

```
/usr/bin/java \
-classpath /opt/IBM/WebSphere/AppServer/runtimes/com.ibm.ws.ejb.thinclient_9.0.jar:/opt/IBM/WebSphere/AppServer/runtimes/:/opt/IBM/WebSphere/AppServer/runtimes/com.ibm.ws.orb_9.0.jar:$PWD/unzip/ejb-lib.jar:$PWD/unzip/ejb-client.jar \
-Djava.naming.provider.url=iiop://ejb-jndi:2809 \
-Dcom.ibm.SSL.ConfigURL=file:///tmp/ssl.client.props \
-Dcom.ibm.CORBA.ConfigURL=file:///opt/IBM/WebSphere/AppServer/profiles/AppSrv01/properties/sas.client.props \
Main
```

これで動くようになります。ThinClientで動作するはずのLookupでもcom.ibm.ssl.protocolの指定が原因でSSL接続が失敗してしまうことも起きてしまったので、例外を確認しながら対応をすすめます。

発生した例外
```
Caused by: org.omg.CORBA.COMM_FAILURE: CAUGHT_EXCEPTION_WHILE_CONFIGURING_SSL_CLIENT_SOCKET Exception=java.lang.IllegalArgumentException: Unsupported protocolTLS  vmcid: 0x49421000  minor code: 112  completed: No
	at com.ibm.ws.security.orbssl.WSSSLClientSocketFactoryImpl.createSSLSocket(WSSSLClientSocketFactoryImpl.java:248)
	at com.ibm.ws.orbimpl.transport.WSSSLTransportConnection.createSocket(WSSSLTransportConnection.java:258)
	at com.ibm.CORBA.transport.TransportConnectionBase.connect(TransportConnectionBase.java:353)
	at com.ibm.ws.orbimpl.transport.WSTransport$1.run(WSTransport.java:503)
	at com.ibm.ws.security.util.AccessController.doPrivileged(AccessController.java:118)
	at com.ibm.ws.orbimpl.transport.WSTransport.getConnection(WSTransport.java:500)
	at com.ibm.CORBA.transport.TransportBase.getConnection(TransportBase.java:182)
	at com.ibm.rmi.iiop.TransportManager.get(TransportManager.java:98)
	at com.ibm.rmi.iiop.GIOPImpl.getConnection(GIOPImpl.java:134)
	at com.ibm.rmi.iiop.GIOPImpl.locate(GIOPImpl.java:230)
	at com.ibm.rmi.corba.ClientDelegate.locate(ClientDelegate.java:1740)
	at com.ibm.rmi.corba.ClientDelegate._createRequest(ClientDelegate.java:1765)
	at com.ibm.rmi.corba.ClientDelegate.createRequest(ClientDelegate.java:1050)
	at com.ibm.rmi.corba.ClientDelegate.createRequest(ClientDelegate.java:1135)
	... 20 more
```

このエラーは com.ibm.ssl.protocol=TLS の指定が原因で起きていて、TLSv1.2を指定することで接続ができました。

# Liberty clientから Libertyに接続する。

Liberty clientで動かす Application ClientのMaiクラスは @EJBが使えて、このアノテーションがあるとlaunchClientやThinClientではエラーになってしまったので、別のEnterprise Applicationを作成してApplication Clientだけ違うものをパッケージするように構成しました。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/262366/fe614ec5-4a9f-c9f8-f6ea-2485941d4812.png)

パッケージの時の参照構造は以下でどちらも同じejb-ear.earとしてexportする。アプリケーション名が変わってしまうとJNDI名が変わってしまうので、同じ名前で動作させる方が問題になりにくい。
- ejb-ear (tWAS用 Enterprise Application)
    - ejb-client 
    - ejb-hello
    - ejb-lib
- ejb-liberty-ear (Liberty用　Enterprise Application)
    - ejb-liberty-client
    - ejb-hello
    - ejb-lib


接続先のLibertyサーバーの指定は

```client.xml
    <orb id="defaultOrb" nameService="corbaname::localhost:2809">
        <clientPolicy.clientContainerCsiv2>
		    <layers>
                <authenticationLayer user="wsadmin" password="passw0rd" />
		    </layers>
	 	</clientPolicy.clientContainerCsiv2>
    </orb>
```

で指定します。認証情報も指定します。java.naming.provilder.url システムプロパティを指定して動作しませんでした。

# まとめ

今回は launchClient, Thin Client, Liberty Client からLiberty ServerのEJBにアクセスするため、試した内容を備忘録として残しました。構成や手順もまとまってきたので、次は自動化して手順を忘れてしまっても環境が構築できるようにします。