WildFly: EJB invocations from a remote client

余生颓废 提交于 2019-12-11 03:17:38

问题


I was trying to lookup and call an EJB deployed as EAR in WildFly. I have tried different ways.

Properties properties = new Properties();
properties.put(Context.INITIAL_CONTEXT_FACTORY, "org.jboss.naming.remote.client.InitialContextFactory");        
properties.put(Context.PROVIDER_URL, "remote://localhost:4447");
properties.put(Context.SECURITY_PRINCIPAL, myUser);
properties.put(Context.SECURITY_CREDENTIALS, myPassword);    
properties.put(Context.URL_PKG_PREFIXES, "org.jboss.ejb.client.naming");

InitialContext context = new InitialContext(properties);
Object object = context.lookup(jndi);
MyService service = (MyService)object;
System.out.println(service.echo("JYM"));

It has thrown:

javax.naming.NamingException: Failed to connect to any server. Servers tried: [remote://localhost:4447]
    at org.jboss.naming.remote.client.HaRemoteNamingStore.failOverSequence(HaRemoteNamingStore.java:213)
    at org.jboss.naming.remote.client.HaRemoteNamingStore.namingStore(HaRemoteNamingStore.java:144)
    at org.jboss.naming.remote.client.HaRemoteNamingStore.namingOperation(HaRemoteNamingStore.java:125)
    at org.jboss.naming.remote.client.HaRemoteNamingStore.lookup(HaRemoteNamingStore.java:241)
    at org.jboss.naming.remote.client.RemoteContext.lookup(RemoteContext.java:79)
    at org.jboss.naming.remote.client.RemoteContext.lookup(RemoteContext.java:83)
    at javax.naming.InitialContext.lookup(InitialContext.java:417)
    at com.app.test.service.MyServiceTest.echo(MyServiceTest.java:60)

If I add the following properties:

properties.put(Context.URL_PKG_PREFIXES, "org.jboss.ejb.client.naming");
properties.put("jboss.ejb.client.scoped.context", "true");

I recieved:

java.lang.IllegalStateException: EJBCLIENT000025: No EJB receiver available for handling [appName:roolafic, moduleName:usermanagement, distinctName:] combination for invocation context org.jboss.ejb.client.EJBClientInvocationContext@3c0f93f1
    at org.jboss.ejb.client.EJBClientContext.requireEJBReceiver(EJBClientContext.java:749)
    at org.jboss.ejb.client.ReceiverInterceptor.handleInvocation(ReceiverInterceptor.java:116)
    at org.jboss.ejb.client.EJBClientInvocationContext.sendRequest(EJBClientInvocationContext.java:183)
    at org.jboss.ejb.client.EJBInvocationHandler.sendRequestWithPossibleRetries(EJBInvocationHandler.java:253)
    at org.jboss.ejb.client.EJBInvocationHandler.doInvoke(EJBInvocationHandler.java:198)
    at org.jboss.ejb.client.EJBInvocationHandler.doInvoke(EJBInvocationHandler.java:181)
    at org.jboss.ejb.client.EJBInvocationHandler.invoke(EJBInvocationHandler.java:144)
    at com.sun.proxy.$Proxy4.echo(Unknown Source)
    at com.app.test.service.MyServiceTest.echo(MyServiceTest.java:62)

Then I saw a Jboss forum post which says to use http-remoting instead of remote. But that also didn't work. Even using port 8080.

I have tried the way mentioned here. But it seems that it would not work for my case. Though I have placed the jboss-ejb-client.properties in the same directory from where I am running my client method from Eclipse.


回答1:


After spending almost half a day I found the solution. Here it is:

public static <T> T connectEJB(String jndi) throws NamingException {
    Properties clientProperties = new Properties();
    clientProperties.put("remote.connectionprovider.create.options.org.xnio.Options.SSL_ENABLED", "false");
    clientProperties.put("remote.connections", "default");
    clientProperties.put("remote.connection.default.port", myPort);
    clientProperties.put("remote.connection.default.host", myHost);
    clientProperties.put("remote.connection.default.username", myUser);
    clientProperties.put("remote.connection.default.password", myPassword);
    clientProperties.put("remote.connection.default.connect.options.org.xnio.Options.SASL_POLICY_NOANONYMOUS", "false");

    EJBClientConfiguration ejbClientConfiguration = new PropertiesBasedEJBClientConfiguration(clientProperties);
    ContextSelector<EJBClientContext> contextSelector = new ConfigBasedEJBClientContextSelector(ejbClientConfiguration);
    EJBClientContext.setSelector(contextSelector);

    Properties properties = new Properties();
    properties.put(Context.URL_PKG_PREFIXES, "org.jboss.ejb.client.naming");
    Context context = new InitialContext(properties);
    return (T) context.lookup(jndi);
}

For more information see here. Hope it will be helpful to others.




回答2:


I have encountered the same exception on Wildfly 10.

While following some important references:

Namely documentation on establishing remote EJB connection on: https://docs.jboss.org/author/display/WFLY10/EJB+invocations+from+a+remote+client+using+JNDI

java.lang.IllegalStateException: EJBCLIENT000025:

No EJB receiver available for handling [appName:, moduleName:wildfly10-test-client-remote-ejb, distinctName:] combination for invocation context org.jboss.ejb.client.EJBClientInvocationContext@1b26f7b2 at org.jboss.ejb.client.EJBClientContext.requireEJBReceiver(EJBClientContext.java:798) at org.jboss.ejb.client.ReceiverInterceptor.handleInvocation(ReceiverInterceptor.java:128) at org.jboss.ejb.client.EJBClientInvocationContext.sendRequest(EJBClientInvocationContext.java:186) at org.jboss.ejb.client.EJBInvocationHandler.sendRequestWithPossibleRetries(EJBInvocationHandler.java:255) at org.jboss.ejb.client.EJBInvocationHandler.doInvoke(EJBInvocationHandler.java:200) at org.jboss.ejb.client.EJBInvocationHandler.doInvoke(EJBInvocationHandler.java:183) at org.jboss.ejb.client.EJBInvocationHandler.invoke(EJBInvocationHandler.java:146) at com.sun.proxy.$Proxy6.doWork(Unknown Source) at ejb.InvokeRemoteEjbTest.testThatFailsWithEJBCLIENT000025(InvokeRemoteEjbTest.java:90)

  at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)  at

sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62) at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43) at java.lang.reflect.Method.invoke(Method.java:498) at org.junit.runners.model.FrameworkMethod$1.runReflectiveCall(FrameworkMethod.java:50) at org.junit.internal.runners.model.ReflectiveCallable.run(ReflectiveCallable.java:12) at org.junit.runners.model.FrameworkMethod.invokeExplosively(FrameworkMethod.java:47) at org.junit.internal.runners.statements.InvokeMethod.evaluate(InvokeMethod.java:17) at org.junit.internal.runners.statements.RunBefores.evaluate(RunBefores.java:26) at org.junit.runners.ParentRunner.runLeaf(ParentRunner.java:325) at org.junit.runners.BlockJUnit4ClassRunner.runChild(BlockJUnit4ClassRunner.java:78) at org.junit.runners.BlockJUnit4ClassRunner.runChild(BlockJUnit4ClassRunner.java:57) at org.junit.runners.ParentRunner$3.run(ParentRunner.java:290) at org.junit.runners.ParentRunner$1.schedule(ParentRunner.java:71) at org.junit.runners.ParentRunner.runChildren(ParentRunner.java:288) at org.junit.runners.ParentRunner.access$000(ParentRunner.java:58) at org.junit.runners.ParentRunner$2.evaluate(ParentRunner.java:268) at org.junit.runners.ParentRunner.run(ParentRunner.java:363) at org.eclipse.jdt.internal.junit4.runner.JUnit4TestReference.run(JUnit4TestReference.java:86) at org.eclipse.jdt.internal.junit.runner.TestExecution.run(TestExecution.java:38) at org.eclipse.jdt.internal.junit.runner.RemoteTestRunner.runTests(RemoteTestRunner.java:459) at org.eclipse.jdt.internal.junit.runner.RemoteTestRunner.runTests(RemoteTestRunner.java:675) at org.eclipse.jdt.internal.junit.runner.RemoteTestRunner.run(RemoteTestRunner.java:382) at org.eclipse.jdt.internal.junit.runner.RemoteTestRunner.main(RemoteTestRunner.java:192)

But this test exception was not alone, I also had on the console the following exception:

NFO: XNIO version 3.3.4.Final Feb 13, 2017 12:42:28 PM org.xnio.nio.NioXnio INFO: XNIO NIO Implementation Version 3.3.4.Final Feb 13, 2017 12:42:28 PM org.jboss.remoting3.EndpointImpl INFO: JBoss Remoting version 4.0.18.Final Feb 13, 2017 12:42:28 PM org.jboss.ejb.client.EJBClient INFO: JBoss EJB Client version 2.1.4.Final Feb 13, 2017 12:42:28 PM org.jboss.ejb.client.remoting.ConfigBasedEJBClientContextSelector setupEJBReceivers WARN: Could not register a EJB receiver for connection to localhost:4447 java.io.EOFException: XNIO000812: Connection closed unexpectedly at org.xnio.http.HttpUpgrade$HttpUpgradeState$UpgradeResultListener.handleEvent(HttpUpgrade.java:416) at org.xnio.http.HttpUpgrade$HttpUpgradeState$UpgradeResultListener.handleEvent(HttpUpgrade.java:400) at org.xnio.ChannelListeners.invokeChannelListener(ChannelListeners.java:92) at org.xnio.conduits.ReadReadyHandler$ChannelListenerHandler.readReady(ReadReadyHandler.java:66) at org.xnio.nio.NioSocketConduit.handleReady(NioSocketConduit.java:88) at org.xnio.nio.WorkerThread.run(WorkerThread.java:559) at ...asynchronous invocation...(Unknown Source) at org.jboss.remoting3.EndpointImpl.doConnect(EndpointImpl.java:294) at org.jboss.remoting3.EndpointImpl.connect(EndpointImpl.java:416) at org.jboss.ejb.client.remoting.EndpointPool$PooledEndpoint.connect(EndpointPool.java:192) at org.jboss.ejb.client.remoting.NetworkUtil.connect(NetworkUtil.java:153) at org.jboss.ejb.client.remoting.NetworkUtil.connect(NetworkUtil.java:133) at org.jboss.ejb.client.remoting.ConnectionPool.getConnection(ConnectionPool.java:78) at org.jboss.ejb.client.remoting.RemotingConnectionManager.getConnection(RemotingConnectionManager.java:51)

at org.jboss.ejb.client.remoting.ConfigBasedEJBClientContextSelector.setupEJBReceivers(ConfigBasedEJBClientContextSelector.java:161)

at org.jboss.ejb.client.remoting.ConfigBasedEJBClientContextSelector.getCurrent(ConfigBasedEJBClientContextSelector.java:118) at org.jboss.ejb.client.remoting.ConfigBasedEJBClientContextSelector.getCurrent(ConfigBasedEJBClientContextSelector.java:47) at org.jboss.ejb.client.EJBClientContext.getCurrent(EJBClientContext.java:281) at org.jboss.ejb.client.EJBClientContext.requireCurrent(EJBClientContext.java:291) at org.jboss.ejb.client.EJBInvocationHandler.doInvoke(EJBInvocationHandler.java:178) at org.jboss.ejb.client.EJBInvocationHandler.invoke(EJBInvocationHandler.java:146) at com.sun.proxy.$Proxy6.doWork(Unknown Source) at ejb.InvokeRemoteEjbTest.testThatFailsWithEJBCLIENT000025(InvokeRemoteEjbTest.java:90)

  at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)  at

sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62) at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43) at java.lang.reflect.Method.invoke(Method.java:498) at org.junit.runners.model.FrameworkMethod$1.runReflectiveCall(FrameworkMethod.java:50) at org.junit.internal.runners.model.ReflectiveCallable.run(ReflectiveCallable.java:12) at org.junit.runners.model.FrameworkMethod.invokeExplosively(FrameworkMethod.java:47) at org.junit.internal.runners.statements.InvokeMethod.evaluate(InvokeMethod.java:17) at org.junit.internal.runners.statements.RunBefores.evaluate(RunBefores.java:26) at org.junit.runners.ParentRunner.runLeaf(ParentRunner.java:325) at org.junit.runners.BlockJUnit4ClassRunner.runChild(BlockJUnit4ClassRunner.java:78) at org.junit.runners.BlockJUnit4ClassRunner.runChild(BlockJUnit4ClassRunner.java:57) at org.junit.runners.ParentRunner$3.run(ParentRunner.java:290) at org.junit.runners.ParentRunner$1.schedule(ParentRunner.java:71) at org.junit.runners.ParentRunner.runChildren(ParentRunner.java:288) at org.junit.runners.ParentRunner.access$000(ParentRunner.java:58) at org.junit.runners.ParentRunner$2.evaluate(ParentRunner.java:268) at org.junit.runners.ParentRunner.run(ParentRunner.java:363) at org.eclipse.jdt.internal.junit4.runner.JUnit4TestReference.run(JUnit4TestReference.java:86) at org.eclipse.jdt.internal.junit.runner.TestExecution.run(TestExecution.java:38) at org.eclipse.jdt.internal.junit.runner.RemoteTestRunner.runTests(RemoteTestRunner.java:459) at org.eclipse.jdt.internal.junit.runner.RemoteTestRunner.runTests(RemoteTestRunner.java:675) at org.eclipse.jdt.internal.junit.runner.RemoteTestRunner.run(RemoteTestRunner.java:382) at org.eclipse.jdt.internal.junit.runner.RemoteTestRunner.main(RemoteTestRunner.java:192)

The critical point is the following. (1) Jboss seems to have two different layers of code that behave differently. The first one, is the JNDI initial context, that works properly when you connect to a "remoting" port such as the old traditional port 4447.

So when you do in your code for the JNDI context something like:

final Properties env = new Properties();
        env.put(Context.INITIAL_CONTEXT_FACTORY, org.jboss.naming.remote.client.InitialContextFactory.class.getName());
        env.put(Context.PROVIDER_URL, "remote://localhost:4447");            

        // why is this needed?
        // This is an important property to set if you want to do EJB invocations via the remote-naming project
        env.put("jboss.naming.client.ejb.context", true);

        // Lookup optimization for @Stateless EJBs.
        // https://docs.jboss.org/author/display/AS71/Remote+EJB+invocations+via+JNDI+-+EJB+client+API+or+remote-naming+project
        // section: Why use the EJB client API approach then?
        env.put(Context.URL_PKG_PREFIXES, "org.jboss.ejb.client.naming");

        // authenticate
        env.put(Context.SECURITY_PRINCIPAL, "adminUser");
        env.put(Context.SECURITY_CREDENTIALS, "adminPassword");
        initialContext = new InitialContext(env);

You are OK geting the Remote EJB out of the server, you have the proxy in hand. Where things go really wrong, is when you take the proxu and do something like:

remoteEJB.doWorkg();

This happens because the Lookup logic and execute logic on the proxy are not exactly the same, namely, the execute logic is looking for these:

"No EJB receiver available for handling "

based on the configuration file: "jboss-ejb-client.properties"

That yous should have in your classpath to run your system test. Or your client application.

Now, when you go to this: jboss-ejb-client.properties

You can try to confiugure your "remoting" port 4447, but this goes very wrong, because the modern remote EJB client that you get out of using the;

 <dependency>
        <groupId>org.wildfly</groupId>
        <artifactId>wildfly-ejb-client-bom</artifactId>
        <version>10.0.0.Final</version>
        <type>pom</type>
        <scope>test</scope>
    </dependency>

This client expects that your wildfly 10 is configured with the todays default configuration, where remoting can be serviced from normal HTTP sockets. So it wants to do an HTTP socket upgrade to TCP pretty much like what happens with web sockets. This will not work on your: 4447 socket, which has never been from conception an http socket.

So when I finally went to look how the remote subsystem is configured, I needed to fatten it with the following:

  <subsystem xmlns="urn:jboss:domain:remoting:3.0">
            <endpoint/>
            <connector name="remoting-connector" socket-binding="remoting" security-realm="ApplicationRealm"/>
            <http-connector name="http-remoting-connector" connector-ref="default" security-realm="ApplicationRealm"/>
        </subsystem>

The http-connector is the new addition. Now, as far as JNDI initial context setup is concerned, it does not matter if I usee port 4447 or 8080, both work. To keep consistent, i do not use the 4447 port .. which is still open, and I use the 8080 port. Hoever, for 8080 pot your provider URL has to be adapted as follows:

env.put(Context.PROVIDER_URL, "http-remoting://localhost:8080");

My recommendation is: configure both port 4447 and 8080 for your remote ejb subsytem. But for Client conneciton use port 8080, both for JNDI lookup and EJB execution.

The wildfly exception in this case is borderline useless, it does not help that much the developer figuring out what is going wrong.

The key to this problem was seing the HTTP connection upgrade problem and figuring out that that behavior is obviously wrong for socket 4447.

Finally, just for reference. Your ejb-client.proeprties file should be something of the form:

#QUOTE:
#First the endpoint.name property. 
#We mentioned earlier that the EJB receivers will communicate with the server for EJB invocations.
#Internally, they use JBoss Remoting project to carry out the communication. 
#The endpoint.name property represents the name that will be used to create the client side of the enpdoint. 
# The endpoint.name property is optional and if not specified in the jboss-ejb-client.properties file, it will default to "config-based-ejb-client-endpoint" name.
# https://docs.jboss.org/author/display/WFLY10/EJB+invocations+from+a+remote+client+using+JNDI
endpoint.name=client-endpoint
remote.connectionprovider.create.options.org.xnio.Options.SSL_ENABLED=false

remote.connections=default

remote.connection.default.host=localhost
remote.connection.default.port=8080
remote.connection.default.connect.options.org.xnio.Options.SASL_POLICY_NOANONYMOUS=false

remote.connection.default.username=youAppServerAdmin
remote.connection.default.password=youAppServerAdminPass

The key thing to keep in mind is that the PORT on the above file should be an HTTP port and not a "remoting" port like 4447. At least in wildfly 10, for older versions I am not sure.

Good luck.



来源:https://stackoverflow.com/questions/20817223/wildfly-ejb-invocations-from-a-remote-client

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!