1 2 3 4 5 6 Previous Next 79 Replies Latest reply on Jan 10, 2013 6:57 PM by mevans7 Go to original post
      • 45. Re: How to call a remote EJB without a property file?
        bernd.koecke

        I don't say that the routing code should be part of the clients side business code. But as mentioned above, we provide a helper JAR anyway and I would like to hide the additional code there. The usage of CDI makes no big difference for me. Because just the code behind the CDI annotations needs to do the routing stuff.

         

        I don't want to bother anyone. As Radek mentioned, I'm really thankful for the work of the JBoss guys . I'm asking, because I would like to use an API which stays at least for the 7.1 final release when I code the remaining part. For this I got a more than sufficient answer. And when there are others which are interessted in such a functionality, I think we should discuss the design in the community. I really don't expect that JBoss provides the code to me.

        • 46. Re: How to call a remote EJB without a property file?
          rodakr

          What I mean is to use embeded Container for StandAlone Client. This way I should have no difference in Code  if the Client is Stand Alone Client or a Client inside J EE Container Calling another J EE Container.

          see how the lookup is done here ....  https://community.jboss.org/wiki/EJB31Embeddable

          So embedded Container does remote lookup to j ee remote server. You just need some configuration, as you have to configure on server config for J EE Server to  J EE to Server EJB calls which works just with injection..@EJB

          • 47. Re: How to call a remote EJB without a property file?
            ktfan

            Hi Jaikiran Pai:

             

              Is there a ready solution regarding this thread ? If there is, may I get the link to this info ?

            • 48. Re: How to call a remote EJB without a property file?
              jaikiran

              fan kam thong wrote:

               

              Hi Jaikiran Pai:

               

                Is there a ready solution regarding this thread ? If there is, may I get the link to this info ?

              There are many things discussed in this thread, so if you have a specific question then please create a separate thread to discuss it, in order to avoid any confusion.

              • 49. Re: How to call a remote EJB without a property file?
                sumitsu

                Based on my reading of previous posts in this thread, it seems that there are essentially 3 ways to remotely invoke EJBs via JNDI in AS 7.1:

                 

                1. Use the procedure outlined in the documentation (https://docs.jboss.org/author/display/AS71/EJB+invocations+from+a+remote+client+using+JNDI).  This method requires a properties file jboss-ejb-client.properties which must be loaded on the client-side classpath, and cannot be changed within the client's JVM life cycle (save, perhaps, for some nasty manipulations of the ClassLoaders).
                2. Use the custom procedure for setting the EJBClientContext selector outlined by Jaikiran Pai (https://community.jboss.org/message/647202#647202).  This method permits the remote invocation parameters to be set programmatically/dynamically, and removes the need for the client-side jboss-ejb-client.properties file, but requires that the client-side code have dependencies on JBoss's proprietary EJB-client invocation code.  More worryingly (at least from my perspective), the fact that EJBClientContext.setSelector(...) is a static method invocation strongly suggests to me that this method is not thread-safe, and therefore not an option for any client which could have multiple threads invoking disparate JBoss servers using different sets of configuration properties.
                3. The "old fashioned way", per markus78's post (https://community.jboss.org/message/715650#715650).  I'd be perfectly happy with this approach, if I could get it to work, but thus far I've run into the now-dreaded "No EJB receiver available for handling" IllegalStateException on every attempt.

                 

                Please correct anything mistaken in the above summary.

                 

                Are there any other options?  I'm looking for a method which is both (a) thread-safe, such that multiple client threads can perform remote invocations on separate servers without affecting the rest of the client JVM and (b) programmatic, such that the configuration can be sourced from somewhere other than a classpath properties file and can be altered dynamically.

                 

                Is there a way to meet those criteria using the AS7 EJB Client API?

                • 50. Re: How to call a remote EJB without a property file?
                  rodakr

                  Here is one little note about choices ( a gem ) from Stuart and Jason

                   

                  https://docs.jboss.org/author/display/AS71/JNDI+Reference

                   

                  This discusion was based on jboss 7.1 beta. In meantime there is 7.1 final and 7.1.1 final and backward remoting support matured!

                   

                  Your assumtion over static Method beening not Thread Safe is wrong. Static Method is 100% Thread Safe :-)

                   

                  Here is one way to do this:  https://community.jboss.org/thread/196422

                   

                  But my choice will be EE Application Client without programmatic configuration in code for two reasons.

                  1)  same code for standalone client to Server,  Server to Server call

                  2) there is no point to do this dynamically in source code...!

                  If configuration change, you have to publish this information sowhere and you are back in static config :-) 

                  Only think you could win, would be no need to restart, but for stand alone client... it doesn't matter.

                  And on Server Side you have to change Server configuration which is referenced in client.... see this https://docs.jboss.org/author/display/AS71/EJB+invocations+from+a+remote+server+instance

                  no need to do any thing programatically in code... :-)

                  • 51. Re: How to call a remote EJB without a property file?
                    bernd.koecke

                    I don't think that it is such a bad thing to have the possibility for influencing the client side. This doesn't mean that all clients need to do this and programmtic can mean that it is done by an additional library e.g. activated as a META-INF/service. So it need not be part of the clients business code. And it need not be provided completly by JBoss. May be it is an add on, provided by the community. But I was to busy the last weeks to play around with it. Hopefully that will change soon.

                    • 52. Re: How to call a remote EJB without a property file?
                      sumitsu

                      Radek, thanks for the link to the AS 7.1 JNDI documentation.  Certainly, it is possible to write thread-safe static methods.  I do not, however, see anything to indicate that this particular static method EJBClientContext.setSelector(...) is thread-safe.  From the code on github (https://github.com/jbossas/jboss-ejb-client/blob/master/src/main/java/org/jboss/ejb/client/EJBClientContext.java):

                       

                      /**
                       * EJB client context selector. By default the {@link ConfigBasedEJBClientContextSelector} is used.
                       */
                      private static volatile ContextSelector<EJBClientContext> SELECTOR;
                      

                      ...

                       

                      /**
                      * Sets the EJB client context selector. Replaces the existing selector, which is then returned by this method
                      *
                      * @param newSelector The selector to set. Cannot be null
                      * @return Returns the previously set EJB client context selector.
                      * @throws SecurityException if a security manager is installed and you do not have the {@code setEJBClientContextSelector}
                      * {@link RuntimePermission}
                      */
                      public static ContextSelector<EJBClientContext> setSelector(final ContextSelector<EJBClientContext> newSelector) {
                          if (newSelector == null) {
                              throw new IllegalArgumentException("EJB client context selector cannot be set to null");
                          }
                          if (SELECTOR_LOCKED) {
                              throw new SecurityException("EJB client context selector may not be changed");
                          }
                          final SecurityManager sm = System.getSecurityManager();
                          if (sm != null) {
                              sm.checkPermission(SET_SELECTOR_PERMISSION);
                          }
                          final ContextSelector<EJBClientContext> oldSelector = SELECTOR;
                          SELECTOR = newSelector;
                          return oldSelector;
                      }
                      

                       

                      I could certainly be missing something, so please let me know if I am.

                       

                      My first impression, however, is that the above code is not thread-safe.  There is nothing to prevent the case where one thread sets the selector once, then another thread sets a different selector, then the first thread carries out a remote invocation -- which presumably uses the static SELECTOR field that has been changed without the knowledge of the first thread.  (For that matter, setSelector is not even synchronized, so I do not see how the client avoids concurrency problems even within that method.  Again, let me know if there is something I am failing to see...)

                       

                      (edited by Branden Smith to correct the link URL)

                      • 53. Re: How to call a remote EJB without a property file?
                        rodakr

                        It is Thread Safe, you overseeing keywork volatile....!

                         

                        private static volatile ContextSelector<EJBClientContext> SELECTOR;

                         

                        And there will be no problem with other Threads as well.

                        You have to trust hard core programmers :-)

                        • 54. Re: How to call a remote EJB without a property file?
                          gwwallace

                          The use of keyword volatile doesnt protect against the value being overridden by another thread. It just guarantees that all

                          threads see the same value in the volatile variable.

                           

                          So between the setting of SELECTOR and its use in one thread, it could have been overwritten many times by other threads.

                           

                          Branden's question still stands.

                          • 55. Re: How to call a remote EJB without a property file?
                            rodakr

                            .... the question was if this static Method is Thread Safe. And the answer is yes. You will have same result using synchronized keyword!

                            How do you use it is another question...

                             

                            I agree, I don't see how setting selector and making lookup can be atomic....

                            • 56. Re: How to call a remote EJB without a property file?
                              sumitsu

                              Radek, I think I see the source of the confusion: I was ambiguous with my terminology in my original post, using the word "method" both in the Java sense and in the conversational sense meaning "a way of doing something".  I'm not debating the thread-safety of the Java-method EJBClientContext.setSelector(...) in and of itself; I am concerned about the thread-safety of this overall approach-of-performing-a-remote-invocation.  Sorry for the confusion; here's how I should have phrased my summary of option #2 (changes in red):

                               

                              Branden Smith wrote:

                               

                              1. ...
                              2. Use the custom procedure for setting the EJBClientContext selector outlined by Jaikiran Pai (https://community.jboss.org/message/647202#647202).  This approach permits the remote invocation parameters to be set programmatically/dynamically, and removes the need for the client-side jboss-ejb-client.properties file, but requires that the client-side code have dependencies on JBoss's proprietary EJB-client invocation code.  More worryingly (at least from my perspective), the fact that EJBClientContext.setSelector(...) is a static method invocation strongly suggests to me that this approach is not thread-safe, and therefore not an option for any client which could have multiple threads invoking disparate JBoss servers using different sets of configuration properties.

                               

                              • 57. Re: How to call a remote EJB without a property file?
                                sumitsu

                                I have verified that the programmatic approach Jaikiran outlined to remote EJB invocation (without jboss-ejb-client.properties) is not thread-safe.   I wrote a simple threaded test client wherein one thread sets the selector using a set of properties which reference a working JBoss AS 7.1 instance where my EJB is deployed, then sleeps for a certain amount of time.  Meanwhile, a second thread comes in and resets the selector using a set of properties which point to nowhere, after which the first thread wakes up and attempts the invocation.  My tests show that both threads fail to invoke in this circumstance; as a control, if I remove the second thread invocation, the first thread invokes the remote EJB successfully.

                                 

                                Here is my test code (apologies for the long code block):

                                 

                                public class RemoteTestClient extends Thread {
                                
                                    public void test_AS7props() throws NamingException {
                                        Context ctx;
                                        RemoteTestRemote rsr;
                                        Properties jndiProps;
                                        EJBClientConfiguration ejbcc;
                                        ContextSelector<EJBClientContext> ejbCtxSel;
                                        
                                        jndiProps = new Properties();
                                        jndiProps.put(Context.URL_PKG_PREFIXES, "org.jboss.ejb.client.naming");
                                        
                                        System.err.println("[thread-" + Thread.currentThread().getId() + "]: Starting...");System.err.flush();
                                        
                                        ejbcc = new PropertiesBasedEJBClientConfiguration(invokeProps);
                                        ejbCtxSel = new ConfigBasedEJBClientContextSelector(ejbcc);
                                        
                                        System.err.println("[thread-" + Thread.currentThread().getId() + "]: setting Selector...");System.err.flush();
                                        
                                        ////////////////////////////////////////
                                        // static call to setSelector...      //
                                        ////////////////////////////////////////
                                        EJBClientContext.setSelector(ejbCtxSel);
                                        ////////////////////////////////////////
                                    
                                        System.err.println("[thread-" + Thread.currentThread().getId() + "]: Selector RESET! selector=" + EJBClientContext.getCurrent());System.err.flush();
                                        
                                        ctx = new InitialContext(jndiProps);
                                        
                                        System.err.println("[thread-" + Thread.currentThread().getId() + "]: ..::SLEEP: " + clientSideDelayMilliSec);System.err.flush();
                                        try {
                                            Thread.sleep(clientSideDelayMilliSec);
                                        } catch (InterruptedException iExc) {
                                            iExc.printStackTrace();
                                        }
                                        System.err.println("[thread-" + Thread.currentThread().getId() + "]: WAKE! about to lookup; selector=" + EJBClientContext.getCurrent());System.err.flush();
                                        
                                        rsr = (RemoteTestRemote) ctx.lookup("ejb:RemoteTest/RemoteTest/RemoteTest-name!com.liaison.timeouttest.RemoteTestRemote");
                                        System.err.println("[thread-" + Thread.currentThread().getId() + "]: lookup complete! about to invoke...");System.err.flush();
                                        rsr.test(0);
                                        System.err.println("[thread-" + Thread.currentThread().getId() + "]: INVOKE COMPLETE!");System.err.flush();
                                        ctx.close();
                                    }
                                    
                                    @Override
                                    public void run() {
                                        System.err.println("Starting thread: " + Thread.currentThread().getId());System.err.flush();
                                        try {
                                            test_AS7props();
                                        } catch (Exception ex) {
                                            ex.printStackTrace();
                                        }
                                    }
                                    
                                    public RemoteTestClient(long clientSideDelayMilliSec, Properties invokeProps) {
                                        this.clientSideDelayMilliSec = clientSideDelayMilliSec;
                                        this.invokeProps = invokeProps;
                                    }
                                    public RemoteTestClient() {
                                        this(0, null);
                                    }
                                    
                                    public static void main(String[] arguments) {
                                        RemoteTestClient hscA;
                                        RemoteTestClient hscB;
                                        Properties invokePropsA;
                                        Properties invokePropsB;
                                
                                        invokePropsA = new Properties();
                                        invokePropsA.put("endpoint.name", "client-endpoint");
                                        invokePropsA.put("remote.connectionprovider.create.options.org.xnio.Options.SSL_ENABLED", "false");
                                        invokePropsA.put("remote.connections", "default");
                                        invokePropsA.put("remote.connection.default.host", "SUCCESS-HOST");
                                        invokePropsA.put("remote.connection.default.port", "18000");
                                        invokePropsA.put("remote.connection.default.connect.options.org.xnio.Options.SASL_POLICY_NOANONYMOUS", "false");
                                        invokePropsA.put("remote.connection.default.username", "TestUser");
                                        invokePropsA.put("remote.connection.default.password", "TestPass");
                                
                                        invokePropsB = new Properties();
                                        invokePropsB.put("endpoint.name", "client-endpoint");
                                        invokePropsB.put("remote.connectionprovider.create.options.org.xnio.Options.SSL_ENABLED", "false");
                                        invokePropsB.put("remote.connections", "default");
                                        invokePropsB.put("remote.connection.default.host", "FAILURE-HOST");
                                        invokePropsB.put("remote.connection.default.port", "18000");
                                        invokePropsB.put("remote.connection.default.connect.options.org.xnio.Options.SASL_POLICY_NOANONYMOUS", "false");
                                        invokePropsB.put("remote.connection.default.username", "TestUser");
                                        invokePropsB.put("remote.connection.default.password", "TestPass");
                                        
                                        try {
                                            hscA = new RemoteTestClient(15000, invokePropsA);
                                            hscB = new RemoteTestClient(1500, invokePropsB);
                                            hscA.start();
                                            try {
                                                Thread.sleep(3000);
                                            } catch (InterruptedException iExc) {
                                                iExc.printStackTrace();
                                            }
                                            hscB.start();
                                        } catch (Exception exc) {
                                            exc.printStackTrace();
                                        }
                                    }
                                }
                                

                                 

                                Here are the results of the test, showing both invocation failures:

                                 

                                Starting thread: 9
                                [thread-9]: Starting...
                                log4j:WARN No appenders could be found for logger (org.jboss.logging).
                                log4j:WARN Please initialize the log4j system properly.
                                [thread-9]: setting Selector...
                                [thread-9]: Selector RESET! selector=org.jboss.ejb.client.EJBClientContext@5cb1e877
                                [thread-9]: ..::SLEEP: 15000
                                Starting thread: 10
                                [thread-10]: Starting...
                                [thread-10]: setting Selector...
                                [thread-10]: Selector RESET! selector=org.jboss.ejb.client.EJBClientContext@7362e07d
                                [thread-10]: ..::SLEEP: 1500
                                [thread-10]: WAKE! about to lookup; selector=org.jboss.ejb.client.EJBClientContext@7362e07d
                                [thread-10]: lookup complete! about to invoke...
                                java.lang.IllegalStateException: No EJB receiver available for handling [appName:RemoteTest,modulename:RemoteTest,distinctname:] combination
                                    at org.jboss.ejb.client.EJBClientContext.requireEJBReceiver(EJBClientContext.java:530)
                                    at org.jboss.ejb.client.ReceiverInterceptor.handleInvocation(ReceiverInterceptor.java:84)
                                    at org.jboss.ejb.client.EJBClientInvocationContext.sendRequest(EJBClientInvocationContext.java:175)
                                    at org.jboss.ejb.client.EJBInvocationHandler.doInvoke(EJBInvocationHandler.java:136)
                                    at org.jboss.ejb.client.EJBInvocationHandler.doInvoke(EJBInvocationHandler.java:121)
                                    at org.jboss.ejb.client.EJBInvocationHandler.invoke(EJBInvocationHandler.java:104)
                                    at $Proxy0.test(Unknown Source)
                                    at com.liaison.timeouttestclient.RemoteTestClient.stall_AS7props(RemoteTestClient.java:135)
                                    at com.liaison.timeouttestclient.RemoteTestClient.run(RemoteTestClient.java:144)
                                [thread-9]: WAKE! about to lookup; selector=org.jboss.ejb.client.EJBClientContext@7362e07d
                                [thread-9]: lookup complete! about to invoke...
                                java.lang.IllegalStateException: No EJB receiver available for handling [appName:RemoteTest,modulename:RemoteTest,distinctname:] combination
                                    at org.jboss.ejb.client.EJBClientContext.requireEJBReceiver(EJBClientContext.java:530)
                                    at org.jboss.ejb.client.ReceiverInterceptor.handleInvocation(ReceiverInterceptor.java:84)
                                    at org.jboss.ejb.client.EJBClientInvocationContext.sendRequest(EJBClientInvocationContext.java:175)
                                    at org.jboss.ejb.client.EJBInvocationHandler.doInvoke(EJBInvocationHandler.java:136)
                                    at org.jboss.ejb.client.EJBInvocationHandler.doInvoke(EJBInvocationHandler.java:121)
                                    at org.jboss.ejb.client.EJBInvocationHandler.invoke(EJBInvocationHandler.java:104)
                                    at $Proxy0.test(Unknown Source)
                                    at com.liaison.timeouttestclient.RemoteTestClient.stall_AS7props(RemoteTestClient.java:135)
                                    at com.liaison.timeouttestclient.RemoteTestClient.run(RemoteTestClient.java:144)
                                

                                 

                                On the other hand, if I comment out this line (the second thread which resets the selector to the "bad" properties):

                                 

                                //hscB.start();
                                

                                 

                                ... then I get a successful invocation:

                                 

                                Starting thread: 9
                                [thread-9]: Starting...
                                log4j:WARN No appenders could be found for logger (org.jboss.logging).
                                log4j:WARN Please initialize the log4j system properly.
                                [thread-9]: setting Selector...
                                [thread-9]: Selector RESET! selector=org.jboss.ejb.client.EJBClientContext@5cb1e877
                                [thread-9]: ..::SLEEP: 15000
                                [thread-9]: WAKE! about to lookup; selector=org.jboss.ejb.client.EJBClientContext@5cb1e877
                                [thread-9]: lookup complete! about to invoke...
                                [thread-9]: INVOKE COMPLETE!
                                

                                 

                                It's not necessarily the case that there's something "wrong" with the approach Jaikiran outlined -- it may just be that it was never designed for multi-threaded clients, or at least not for clients wherein separate threads might require different AS connectivity parameters.

                                 

                                That said, I'm still looking for a thread-safe, programmatic way to perform a remote invocation via JNDI to an EJB deployed to AS 7.1.x.  I've downloaded the jboss-ejb-client project from github (https://github.com/jbossas/jboss-ejb-client) and I may try my hand at extending it accordingly, if I can find some time.  In the meantime, if Jaikiran (or anyone else who has worked on this) would like to weigh in, I'd definitely much appreciate any suggestions.

                                • 58. Re: How to call a remote EJB without a property file?
                                  rodakr

                                  I know what you mean, but it's not fault of static method.... problem is setting SELECTOR and performe lookup is not atomic.

                                  • 59. Re: How to call a remote EJB without a property file?
                                    rodakr

                                    .... ok another way ( I guest will be depracted some day... ) is using remote:

                                     

                                     

                                    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");

                                    remoteContext = new InitialContext(env);


                                    AS 7.1 also provides the java:jboss/exported context, entries bound to this context are accessible over remote JNDI.


                                    so if jndi name of your EJB is under java:jboss/exported/...

                                    you should be able to lookup it with method above :-)