nekop's blog

OpenShift / JBoss / WildFly / Infinispanの中の人 http://twitter.com/nekop

JBoss EAP 6.2で全部入りEJB

JBoss / WildFly (全部俺) Advent Calendar 2013の11日目です。

EJBのリモート呼び出しは通常はコンテナが備えるプロプライエタリプロトコル(native protocol)で呼び出されますが、RMI-IIOPだったりJAX-WS, JAX-RSなどからも呼び出せます。というわけで全部から呼び出せる呼び出しインタフェース豊富なEJBを作ってみようと思います。

最終的に以下の6クラスできました。

  • EJB本体
  • EJB Remote Interface
  • EJB Local Interface (with JAX-RS, JAX-WS annotations)
  • JAX-RS Application
  • EJB2 Home Interface
  • EJB2 Remote Interface

EJBのリモート呼び出しにはリモートインタフェースが必要です。また、JAX-RSJAX-WSEJBのリモートインタフェースから呼び出す必要はなく、EJBローカルインタフェースを使うことになりますから、ローカルインタフェースも必要になります。@LocalBeanを利用したNo-interface viewはローカル限定でJAX-RSなどとは組み合わせ可能ですが、EJBリモートインタフェースとの組み合わせができなくなってしまうため今回は登場しません。

RMI-IIOPはEJB2のビューを要する機能なのでejb-jarじゃないと認識されません。そのため、クラスは全てejb-jarにパッケージし、JAX-RSを有効化するために空のWARと共にEARにしなければなりません。RMI-IIOPなEJBをWARにパッケージングして、META-INF/jboss-ejb3.xmlやWEB-INF/jboss-ejb3.xmlも含めるテストもやってみたのですが当然のごとくIIOP側にバインドされませんでした。普通はRMI-IIOPなんていう超レガシーは使わないのでWAR一個で大丈夫なはずです。

あとWARにした場合にちょっともにょったのですが、JRubyクライアントから参照しようと思った時にWARファイルはクラスパスに含めることができないので、target/classesを参照するようにたり、ライブラリjarを作ったりしないとダメなのがまた微妙です。

ソースのツリーはhttps://github.com/nekop/java-examples/tree/master/ee6-ejb-interfacesに、ファイル一覧はhttps://github.com/nekop/java-examples/tree/master/ee6-ejb-interfaces/src/main/java/com/github/nekop/examplesにあります。すごい適当に書いてます。

クライアントはパラメータにnative, iiop, ws, rsがあり、呼び出しインタフェースを切り換えるようにしました。JAX-RSのクライアントはいかようにも実装できるのですが、とりあえずRESTEasyのふつうのクライアントAPIで実装しています。

require 'java'

JBOSS_HOME="/home/nekop/eap6"

require "./target/ee6-ejb-interfaces.jar"
require "#{JBOSS_HOME}/bin/client/jboss-client.jar"
require "#{JBOSS_HOME}/modules/system/layers/base/org/jboss/resteasy/resteasy-jaxrs/main/resteasy-jaxrs-2.3.7.Final-redhat-2.jar"
require "#{JBOSS_HOME}/modules/system/layers/base/javax/ws/rs/api/main/jboss-jaxrs-api_1.1_spec-1.0.1.Final-redhat-2.jar"
require "#{JBOSS_HOME}/modules/system/layers/base/org/apache/httpcomponents/main/httpclient-4.2.1-redhat-1.jar"
require "#{JBOSS_HOME}/modules/system/layers/base/org/apache/httpcomponents/main/httpcore-4.2.1-redhat-1.jar"
require "#{JBOSS_HOME}/modules/system/layers/base/org/slf4j/jcl-over-slf4j/main/jcl-over-slf4j-1.7.2.redhat-2.jar"
require "#{JBOSS_HOME}/modules/system/layers/base/org/slf4j/main/slf4j-api-1.7.2.redhat-2.jar"

java_import "java.util.Properties"
java_import "javax.naming.Context"
java_import "javax.naming.InitialContext"

def initial_context
  p = Properties.new()
  p.put("remote.connections", "default")
  p.put("remote.connection.default.port", "4447")
  p.put("remote.connection.default.host", "localhost")
  p.put("remote.connectionprovider.create.options.org.xnio.Options.SSL_ENABLED", "false")
  p.put(Context.URL_PKG_PREFIXES, "org.jboss.ejb.client.naming")
  p.put("org.jboss.ejb.client.scoped.context", true)
  InitialContext.new(p)
end

def corba_initial_context
  p = Properties.new()
  p.put(Context.INITIAL_CONTEXT_FACTORY,
        "com.sun.jndi.cosnaming.CNCtxFactory")
  p.put(Context.PROVIDER_URL, "corbaloc:iiop:localhost:3528/JBoss/Naming/root")
  InitialContext.new(p)
end

def hello_slsb(ejb_context)
  ear_name = "ee6-ejb-interfaces"
  ejbjar_name = "ee6-ejb-interfaces"
  ejb_name = "Hello"
  interface_name = "com.github.nekop.examples.HelloRemote"
  ejb_context.lookup("#{ear_name}/#{ejbjar_name}/#{ejb_name}!#{interface_name}")
end

type = ARGV.shift
case type
when "native"
  ejb_context = initial_context.lookup("ejb:")
  begin
    bean = hello_slsb(ejb_context)
    bean.hello("world")
  ensure
    begin
      ejb_context.close
    rescue
      # no-op
    end
  end
when "iiop"
  java_import "com.github.nekop.examples.HelloEJB2Home"
  java.lang.System::setProperty("com.sun.CORBA.ORBUseDynamicStub", "true")
  o = corba_initial_context.lookup("Hello")
  home = javax.rmi.PortableRemoteObject.narrow(o, HelloEJB2Home.java_class)
  bean = home.create()
  bean.hello("world")
when "ws"
  java_import "java.net.URL"
  java_import "javax.xml.namespace.QName"
  java_import "javax.xml.ws.Service"
  java_import "com.github.nekop.examples.HelloLocal"
  ejbjar_name = "ee6-ejb-interfaces"
  ejb_name = "Hello"
  wsdlLocation = URL.new("http://127.0.0.1:8080/#{ejbjar_name}/#{ejb_name}?wsdl")
  serviceName = QName.new("http://examples.nekop.github.com/", "#{ejb_name}Service")
  portName = QName.new("http://examples.nekop.github.com/", "#{ejb_name}Port")
  service = Service.create(wsdlLocation, serviceName)
  bean = service.getPort(portName, HelloLocal.java_class)
  bean.hello("world")
when "rs"
  java_import "org.jboss.resteasy.client.ClientRequest"
  war_name = "ee6-ejb-interfaces-web"
  url = "http://localhost:8080/#{war_name}/rest/hello/world"
  request = ClientRequest.new(url)
  request.get(java.lang.String.java_class);  
else
  puts "unko"
end