3

仕様 (JSR 318: Enterprise JavaBeans, Version 3.1, ch. 22: Embeddable Usage) で説明されているEJBContainer.createEJBContainer API を使用して、組み込み可能な JBoss を試しています

概要

  • メイン メソッドを正常に呼び出すと、セッション Bean の呼び出しが成功します。"java:jboss/UserTransaction"ただし、JNDI オブジェクトを javax.transaction.UserTransaction にキャストできないため、クラスローディングの問題があるようです。
  • したがって、ここではJBoss Modulesのクラスローディング マジックが必要になると思います。私の試みでは、createEJBContainer は EJBContainerProvider を見つけられず、EJBException をスローします。

すべての質問で、後続の詳細をすべて読む必要があるわけではないことに注意してください。読みにくい場合は、質問セクションをご覧ください。ありがとう!

環境

JBoss AS 7.1.1.Final (jboss-as-7.1.1.Final.zip で、logging conf のみが standalone.xml で変更されています)
(最初は、実際のターゲット環境である JBoss EAP 6.0.1 GA - 同じ問題)
Oracle JDK 1.7 .0_11
Windows 7 プロ 64 ビット

詳細

ステートレス セッション Bean

package test.helloworld.impl;

import javax.ejb.Remote;
import javax.ejb.Stateless;
import test.helloworld.api.HelloWorld;

@Stateless
@Remote(HelloWorld.class)
public class HelloWorldBean implements HelloWorld
{
    @Override
    public String salute()
    {
        return "Hello, world";
    }
}

... とそのビジネス インターフェース:

package test.helloworld.api;

public interface HelloWorld
{
    String salute();
}

クライアントプログラム

package test.helloworld.client;

import static java.lang.System.out;
import java.io.File;
import java.util.HashMap;
import java.util.Map;
import javax.ejb.embeddable.EJBContainer;
import javax.naming.Context;
import javax.transaction.UserTransaction;
import test.helloworld.api.HelloWorld;


public class HelloWorldEmbeddedEjbTestClient
{
    public static void main(String[] args)
    {
        int status = 1;

        try
        {
            main();
            status = 0;
        }
        catch (Throwable e)
        {
            e.printStackTrace(System.err);
            System.err.flush();
        }
        finally
        {
            // Simply returning from main leaves some thread (and
            // hence the JVM) running for another 60s, so force exit
            System.exit(status);
        }
    }


    private static void main() throws Exception
    {
        Map<String, Object> properties = new HashMap<String, Object>();
        properties.put(EJBContainer.MODULES, new File[]{new File("./HelloWorld-EJB.jar")});
        EJBContainer container = EJBContainer.createEJBContainer(properties);

        try
        {
            Context jndiContext = container.getContext();
            Object serviceObj = jndiContext.lookup("java:global/HelloWorld-EJB/HelloWorldBean");
            out.println("service:\t" + serviceObj);
            HelloWorld service = (HelloWorld) serviceObj;
            out.println("result:\t" + service.salute());

            callInTx(service, jndiContext);
        }
        finally
        {
            out.println("closing EJBContainer...");
            container.close();
            out.println("EJBContainer closed.");
        }
    }


    private static void callInTx(HelloWorld service, Context jndiContext) throws Exception
    {
        UserTransaction tx = (UserTransaction) jndiContext.lookup("java:jboss/UserTransaction");
        tx.begin();
        out.println("result in tx:\t" + service.salute());
        tx.commit();
    }
}

包装

C:\eclipse\projects\HelloWorldSlSB-Client\rt\HelloWorld-API.jar:

META-INF/MANIFEST.MF
test/helloworld/api/HelloWorld.class

C:\eclipse\projects\HelloWorldSlSB-Client\rt\HelloWorld-EJB.jar:

META-INF/MANIFEST.MF
META-INF/jboss-deployment-structure.xml
test/helloworld/impl/HelloWorldBean.class
test/helloworld/api/HelloWorld.class

HelloWorld-EJB.jar:META-INF/jboss-deployment-structure.xml:

<?xml version="1.0" encoding="ISO-8859-1"?>
<jboss-deployment-structure>
    <deployment>
        <dependencies></dependencies>
        <exclusions>
            <module name="Classpath"/>
        </exclusions>
    </deployment>
</jboss-deployment-structure>

C:\eclipse\projects\HelloWorldSlSB-Client\rt\modules\test\helloworld\client\main\HelloWorldSlSB-Client.jar:

META-INF/MANIFEST.MF
test/helloworld/client/HelloWorldEmbeddedEjbTestClient.class

C:\eclipse\projects\HelloWorldSlSB-Client\rt\modules\test\helloworld\client\main\module.xml:

    <main-class name="test.helloworld.client.HelloWorldEmbeddedEjbTestClient"/>

    <resources>
        <resource-root path="HelloWorldSlSB-Client.jar"/>
    </resources>

    <dependencies>
        <module name="javax.api"/>
        <module name="javax.ejb.api"/>
        <module name="org.jboss.as.embedded" export="true"/>
<!--
        <module name="org.jboss.as.server" export="true"/>
-->
    </dependencies>
</module>

すべての META-INF/MANIFEST.MF ファイルには、「Manifest-Version: 1.0」しか含まれていません。

結果

直接呼び出し

-Xmx512m -XX:MaxPermSize=256mクラスパス を指定して HelloWorldEmbeddedEjbTestClient.main を直接呼び出すと、

C:\eclipse\output\HelloWorldSlSB-Client
C:\java\jboss-as-7\jboss-modules.jar
C:\java\jboss-as-7\modules\org\jboss\as\embedded\main\jboss-as-embedded-7.1.1.Final.jar
C:\java\jboss-as-7\modules\javax\ejb\api\main\jboss-ejb-api_3.1_spec-1.0.1.Final.jar
C:\java\jboss-as-7\modules\javax\transaction\api\main\jboss-transaction-api_1.1_spec-1.0.0.Final.jar
C:\java\jboss-as-7\modules\org\jboss\logging\main\jboss-logging-3.1.0.GA.jar
C:\java\jboss-as-7\modules\org\jboss\as\controller-client\main\jboss-as-controller-client-7.1.1.Final.jar
C:\java\jboss-as-7\modules\org\jboss\logmanager\main\jboss-logmanager-1.2.2.GA.jar
C:\java\jboss-as-7\modules\org\jboss\dmr\main\jboss-dmr-1.1.1.Final.jar
C:\eclipse\projects\HelloWorldSlSB-Client\rt\HelloWorld-API.jar

およびシステム プロパティ

-Duser.language=en
-Djboss.home=c:/java/jboss-as-7
-Djboss.home.dir=c:/java/jboss-as-7
-Dorg.jboss.as.embedded.ejb3.BARREN=true
-Dfile.encoding=ISO-8859-1

EJB 呼び出しは成功しますが、JNDI オブジェクト「java:jboss/UserTransaction」を javax.transaction.UserTransaction にキャストできません。

...
19:21:01,875 INFO  [org.jboss.ejb.client] (main) JBoss EJB Client version 1.0.5.Final
service:    Proxy for remote EJB StatelessEJBLocator{appName='', moduleName='HelloWorld-EJB', distinctName='', beanName='HelloWorldBean', view='interface test.helloworld.api.HelloWorld'}
result: Hello, world
closing EJBContainer...
19:21:06,362 INFO  [org.jboss.as.server.deployment] (MSC service thread 1-7) JBAS015877: Stopped deployment HelloWorld-EJB.jar in 90ms
19:21:06,370 INFO  [org.jboss.as.repository] (pool-9-thread-1) JBAS014901: Content removed from location c:\java\jboss-as-7\standalone\data\content\35\424415b9a67d64fe8a6dc7ee0700480282f34b\content
19:21:06,370 INFO  [org.jboss.as.server] (pool-9-thread-1) JBAS018558: Undeployed "HelloWorld-EJB.jar"
19:21:06,390 INFO  [org.jboss.as.osgi] (MSC service thread 1-1) JBAS011942: Stopping OSGi Framework
EJBContainer closed.
java.lang.ClassCastException: org.jboss.tm.usertx.client.ServerVMClientUserTransaction cannot be cast to javax.transaction.UserTransaction
    at test.helloworld.client.HelloWorldEmbeddedEjbTestClient.callInTx(HelloWorldEmbeddedEjbTestClient.java:65)
    at test.helloworld.client.HelloWorldEmbeddedEjbTestClient.main(HelloWorldEmbeddedEjbTestClient.java:52)
    at test.helloworld.client.HelloWorldEmbeddedEjbTestClient.main(HelloWorldEmbeddedEjbTestClient.java:21)

(少し奇妙に見えます。なぜなら、例外は main の最後でキャッチされて出力されるからです。しかし、もちろん、コンテナが閉じられる前に発生します。)

デバッガーは、JNDI オブジェクトの getClass().getClassLoader() が org.jboss.modules.ModuleClassLoader
ModuleClassLoader for Module "org.jboss.jboss-transaction-spi:main" from local module loader @4b436982 (roots: c:\java\jboss-as-7\modules)
であり、その getClass().getInterfaces()[0] /* == interface javax.transaction.UserTransaction */.getClassLoader()であることを示します。ただし、UserTransaction.class.getClassLoader()は
ModuleClassLoader for Module "javax.transaction.api:main" from local module loader @4b436982 (roots: c:\java\jboss-as-7\modules)
、sun.misc.Launcher$AppClassLoader 型です。

jboss-modules.jar の呼び出し

java -jar jboss-modules.jarクラスパスを使用して org.jboss.modules.Main.main (つまり、何を行うか) を介して呼び出されます

C:\java\jboss-as-7\jboss-modules.jar

上記のシステム プロパティ、および引数

-mp "C:\java\jboss-as-7\modules;C:\eclipse\projects\HelloWorldSlSB-Client\rt\modules"
test.helloworld.client

createEJBContainer ですでに失敗しています。

javax.ejb.EJBException: Unable to instantiate container with factories []
    at javax.ejb.embeddable.EJBContainer.createEJBContainer(EJBContainer.java:97)
    at test.helloworld.client.HelloWorldEmbeddedEjbTestClient.main(HelloWorldEmbeddedEjbTestClient.java:42)
    at test.helloworld.client.HelloWorldEmbeddedEjbTestClient.main(HelloWorldEmbeddedEjbTestClient.java:21)
    at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
    at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:57)
    at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
    at java.lang.reflect.Method.invoke(Method.java:601)
    at org.jboss.modules.Module.run(Module.java:260)
    at org.jboss.modules.Main.main(Main.java:291)

デバッグは、メソッド EJBContainer.findAllFactories() で、リソース「META-INF/services/javax.ejb.spi.EJBContainerProvider」がスレッド コンテキスト クラスローダに見つからないために発生することを示しています。
ModuleClassLoader for Module "test.helloworld.client:main" from local module loader @1afec586 (roots: C:\java\jboss-as-7\modules,C:\eclipse\projects\HelloWorldSlSB-Client\rt\modules)

質問

  • 誰かがこれを修正する方法を知っていますか、または仕事に似たものを得ましたか?
  • 通常の JBoss インストールは適切な出発点ですか、それとも特定の組み込み可能なバリアントが必要ですか?
  • UserTransaction は組み込み可能なシナリオでも使用できるはずですか?
    • そうであれば、JPA 2 CMT エンティティと従来の JDBC コードの両方に 1 つの XA データソースを使用できるということですか? 両方とも同じトランザクションに参加できますか (たとえば、JDBC コードは java.sql.Connection.setAutoCommit(false) で tx を開始し、次に TransactionAttributeType.REQUIRED で EJB を呼び出します)?
  • 誰かが私にいくつかのドキュメントを教えてもらえますか? 私が見つけたのは、標準の EJB 3.1 の方法ではなく、JBoss 固有の API を使用した古いものに関するものだけです。
    • できれば、テストフレームワークなしで使用する方法を文書化してください。これは、本番環境で使用するために評価しているためです。

すべて (または :-) の一部を読んでくれてありがとう!

4

1 に答える 1

2

META-INF/サービスを明示的にインポートする必要があることを読んだことを思い出した後、JBossモジュールの方法の解決策を見つけました。したがって、クライアントの module.xml には が必要で、services="import"次のようになります。

C:\eclipse\projects\HelloWorldSlSB-Client\rt\modules\test\helloworld\client\main\module.xml:

<?xml version="1.0" encoding="ISO-8859-1"?>
<module xmlns="urn:jboss:module:1.1" name="test.helloworld.client">
    <main-class name="test.helloworld.client.HelloWorldEmbeddedEjbTestClient"/>

    <resources>
        <resource-root path="HelloWorldSlSB-Client.jar"/>
    </resources>

    <dependencies>
        <module name="javax.api"/>
        <module name="javax.ejb.api"/>
        <module name="org.jboss.as.embedded" services="import"/>
        <module name="org.jboss.logmanager"/>
        <module name="test.helloworld"/>
    </dependencies>
</module>

また、システム プロパティjava.util.logging.managerをに設定するようにエラー メッセージが表示されたので、対応するVM 引数をorg.jboss.logmanager.LogManager追加しました。-D次に来たClassNotFoundException: org.jboss.logmanager.LogManagerので、上記のlogmanager依存関係を追加しました。

EJB jar をcreateEJBContainerMap 引数に入れるだけでは、クライアントがそれを確認するのに十分ではなかったため、EJB は、クライアントが明示的に依存できるモジュールでもある必要があるようです (<module name="test.helloworld"/>上記)。そこで、HelloWorld-API.jar と HelloWorld-EJB.jar をディレクトリmodulePath /test/helloworld/main/ (つまり、C:\eclipse\projects\HelloWorldSlSB-Client\rt\modules\test\helloworld\main) に移動し、それに応じてパスをnew File("./HelloWorld-EJB.jar")入力し、それらに module.xml を追加しました。

C:\eclipse\projects\HelloWorldSlSB-Client\rt\modules\test\helloworld\main\module.xml:

<?xml version="1.0" encoding="ISO-8859-1"?>
<module xmlns="urn:jboss:module:1.1" name="test.helloworld">
    <resources>
        <resource-root path="HelloWorld-API.jar"/>
        <resource-root path="HelloWorld-EJB.jar"/>
    </resources>
</module>

test/helloworld/api/HelloWorld.classEJB jar から削除しました。必須ではありませんが、おそらくよりクリーンです。

編集 2013-02-27 : より単純な動作呼び出しが見つかりました。まだ を使用していますorg.jboss.modules.Mainが、EJB がデプロイされているため、埋め込み以外の使用と module.xml ファイルは必要ありません。そして、代わりcreateEJBContainer()に EJB jar を-cp引数に含めたので、引数なしで十分になりました。

%JBOSS_HOME%\standalone\deployments には以下が含まれます

HelloWorld-API.jar
HelloWorld-EJB.jar

HelloWorld-EJB.jar:

META-INF/MANIFEST.MF
META-INF/jboss-deployment-structure.xml
test/helloworld/impl/HelloWorldBean.class

HelloWorld-EJB.jar:META-INF/jboss-deployment-structure.xml:

<?xml version="1.0" encoding="ISO-8859-1"?>
<jboss-deployment-structure>
    <deployment>
        <dependencies>
            <module name="deployment.HelloWorld-API.jar"/>
        </dependencies>
        <exclusions>
            <module name="Classpath"/>
        </exclusions>
    </deployment>
</jboss-deployment-structure>

呼び出し:

C:\java\jdk1.7\bin\java -Xmx512m -XX:MaxPermSize=256m -Duser.language=en
-Djboss.home=c:/java/jboss-as-7 -Djboss.home.dir=c:/java/jboss-as-7
-Djava.util.logging.manager=org.jboss.logmanager.LogManager
-classpath "C:\java\jboss-as-7\jboss-modules.jar"
org.jboss.modules.Main
-mp "C:\java\jboss-as-7\modules"
-dep "javax.ejb.api, org.jboss.as.embedded, org.jboss.logmanager"
-cp "C:\eclipse\output\HelloWorldSlSB-Client;C:\java\jboss-as-7\standalone\deployments\HelloWorld-API.jar;C:\java\jboss-as-7\standalone\deployments\HelloWorld-EJB.jar"
test.helloworld.client.HelloWorldEmbeddedEjbTestClient

ディレクトリ C:\eclipse\projects\HelloWorldSlSB-Client\rt\modules: 空、使用されなくなりました。

編集終了 2013-02-27

残りの質問

  • 誰かが org.jboss.modules.Main を実行せずに直接呼び出しを取得する方法を知っている場合でも、知りたいです。
  • ドキュメントへのリンクは引き続き大歓迎です。
  • UserTransaction / JDBC に関する質問

ところで、評判の良い人なら jboss-modules のようなタグを追加できるのではないでしょうか?

于 2013-02-25T17:48:31.110 に答える