Connecting a JMS Client to a remote unmanaged (standalone) Kie Server

A reader commented that he was having issues connecting to a remote (standalone) instance of the Kie Server (thank you, Theodoros, for inspiring this write up).

Upon reproducing/researching the issue he mentioned, I noticed others seemed to have suffered from similar error messages.

Here is the process I took to connect a JMS client to a remote standalone Kie Server instance.

Disclaimer: There are several permutations of processes you could take to get this working.  I am no way claiming this setup is the best and/or recommended, as I still need to verify this with my team mates, so please keep that in mind.

Server Side

  1.  Download Wildfly 10.1.0.Final.
    wget http://download.jboss.org/wildfly/10.1.0.Final/wildfly-10.1.0.Final.zip
  2. Add a user/password, so we can authenticate on the client side.
    (-a is for the ApplicationManagement realm)

    ./add-user.sh -a -u 'admin' -p 'admin' -ro 'admin, guest, kie-server'

    (default is ManagementRealm)

    ./add-user.sh -u 'admin' -p 'admin' -ro 'admin, guest, kie-server'
  3. Obtain a Kie Server war (if you wish, build from source).For Wildfly, you should use the kie-server-*-SNAPSHOT-ee7.war.  For simplicity, rename this to kie-server.war and then copy it to Wildfly’s deployment directory.
    cp kie-server.war ~/wildfly-10.1.0.Final/standalone/deployments/
  4.  Start the server.
    ./standalone.sh --server-config=standalone-full.xml

Client Side

  1. Clone the sample client and run (mvn clean install)We expect the client to establish a connection to the remote Kie Server by retrieving the Kie Server’s RemoteConnectionFactory via its initial context.
    package org.anbaker;
    
    import static org.junit.Assert.assertEquals;
    
    import java.net.URL;
    import java.util.Properties;
    
    import javax.jms.ConnectionFactory;
    import javax.jms.Queue;
    import javax.naming.InitialContext;
    import javax.naming.NamingException;
    
    import org.junit.Test;
    import org.kie.server.api.model.KieServerStateInfo;
    import org.kie.server.api.model.ServiceResponse;
    import org.kie.server.api.model.ServiceResponse.ResponseType;
    import org.kie.server.client.KieServicesClient;
    import org.kie.server.client.KieServicesConfiguration;
    import org.kie.server.client.KieServicesFactory;
    
    public class TestRemoteAPI {
    
    private static final String REMOTING_URL = "http://the.server.ip.address:8080/kie-server/services/rest/server";
    
    private static final String USER = "admin";
    private static final String PASSWORD = "admin";
    
    private static final String CONNECTION_FACTORY = new String("jms/RemoteConnectionFactory");
    private static final String REQUEST_QUEUE_JNDI = new String("jms/queue/KIE.SERVER.REQUEST");
    private static final String RESPONSE_QUEUE_JNDI = new String("jms/queue/KIE.SERVER.RESPONSE");
    
    private KieServicesConfiguration conf;
    private KieServicesClient kieServicesClient;
    
    private static InitialContext getRemoteInitialContext(URL url, String user, String password) {
    
    Properties initialProps = new Properties();
    
    initialProps.setProperty(InitialContext.INITIAL_CONTEXT_FACTORY,
    "org.jboss.naming.remote.client.InitialContextFactory");
    initialProps.setProperty(InitialContext.PROVIDER_URL, "remote://" + url.getHost() + ":4447");
    initialProps.setProperty(InitialContext.SECURITY_PRINCIPAL, user);
    initialProps.setProperty(InitialContext.SECURITY_CREDENTIALS, password);
    
    for (Object keyObj : initialProps.keySet()) {
    String key = (String) keyObj;
    System.setProperty(key, (String) initialProps.get(key));
    }
    try {
    return new InitialContext(initialProps);
    } catch (NamingException e) {
    throw new IllegalStateException("Could not construct initial context for JMS", e);
    }
    }
    
    @Test
    public void testClientConnectionToRemoteKieServer() throws Exception {
    
    InitialContext context = getRemoteInitialContext(new URL(REMOTING_URL), USER, PASSWORD);
    
    Queue requestQueue = (Queue) context.lookup(REQUEST_QUEUE_JNDI);
    Queue responseQueue = (Queue) context.lookup(RESPONSE_QUEUE_JNDI);
    ConnectionFactory connectionFactory = (ConnectionFactory) context.lookup(CONNECTION_FACTORY);
    
    conf = KieServicesFactory.newJMSConfiguration(connectionFactory, requestQueue, responseQueue, USER, PASSWORD);
    
    // you will need to add any custom classes needed for your kjars
    // Set<Class<?>> extraClassList = new HashSet<Class<?>>();
    // extraClassList.add(YourCustomClass.class);
    // conf.addExtraClasses(extraClassList);
    
    kieServicesClient = KieServicesFactory.newKieServicesClient(conf);
    
    ServiceResponse<KieServerStateInfo> response = kieServicesClient.getServerState();
    
    assertEquals(ResponseType.SUCCESS, response.getType());
    }
    }
    

    (You will need these dependencies in your pom, FYI)

       <dependency>
         <groupId>org.kie.server</groupId>
         <artifactId>kie-server-client</artifactId>
         <version>6.5.0.Final</version>
         <scope>provided</scope>
       </dependency>
    
       <dependency>
         <groupId>org.wildfly</groupId>
         <artifactId>wildfly-jms-client-bom</artifactId>
         <version>10.1.0.Final</version>
         <type>pom</type>
       </dependency>
  2.  Once you build the example, you’ll find that we can’t connect to the server.  You may see an error similar to the following:
     javax.naming.NamingException: Failed to create remoting connection [Root exception is java.lang.RuntimeException: Operation failed with status WAITING]
     at org.jboss.naming.remote.client.ClientUtil.namingException(ClientUtil.java:36)
     at org.jboss.naming.remote.client.InitialContextFactory.getInitialContext(InitialContextFactory.java:117)
     at javax.naming.spi.NamingManager.getInitialContext(NamingManager.java:684)
     at javax.naming.InitialContext.getDefaultInitCtx(InitialContext.java:313)
     at javax.naming.InitialContext.init(InitialContext.java:244)
     at javax.naming.InitialContext.(InitialContext.java:216)
     at TestDemo2.testJms(TestDemo2.java:37)
     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.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.apache.maven.surefire.junit4.JUnit4Provider.execute(JUnit4Provider.java:252)
     at org.apache.maven.surefire.junit4.JUnit4Provider.executeTestSet(JUnit4Provider.java:141)
     at org.apache.maven.surefire.junit4.JUnit4Provider.invoke(JUnit4Provider.java:112)
     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.apache.maven.surefire.util.ReflectionUtils.invokeMethodWithArray(ReflectionUtils.java:189)
     at org.apache.maven.surefire.booter.ProviderFactory$ProviderProxy.invoke(ProviderFactory.java:165)
     at org.apache.maven.surefire.booter.ProviderFactory.invokeProvider(ProviderFactory.java:85)
     at org.apache.maven.surefire.booter.ForkedBooter.runSuitesInProcess(ForkedBooter.java:115)
     at org.apache.maven.surefire.booter.ForkedBooter.main(ForkedBooter.java:75)
    Caused by: java.lang.RuntimeException: Operation failed with status WAITING
     at org.jboss.naming.remote.protocol.IoFutureHelper.get(IoFutureHelper.java:89)
     at org.jboss.naming.remote.client.cache.ConnectionCache.get(ConnectionCache.java:42)
     at org.jboss.naming.remote.client.InitialContextFactory.createConnection(InitialContextFactory.java:153)
     at org.jboss.naming.remote.client.InitialContextFactory.getOrCreateConnection(InitialContextFactory.java:126)
     at org.jboss.naming.remote.client.InitialContextFactory.getInitialContext(InitialContextFactory.java:106)
     ... 34 more
  3. To resolve this, I had to make a few changes to our standalone-full.xml (bold indicate additions):
       <subsystem xmlns="urn:jboss:domain:remoting:3.0">
         <endpoint/>
         <http-connector name="http-remoting-connector" connector-ref="default" security-realm="ApplicationRealm"/>
         <connector name="remoting-connector" socket-binding="remoting"/>
       </subsystem>
                                   .
                                   .
                                   .
     <interfaces>
       <interface name="management">
         <inet-address value="${jboss.bind.address.management:127.0.0.1}"/>
       </interface>
       <interface name="public">
         <inet-address value="${jboss.bind.address:127.0.0.1SERVER.IP.ADDRESS}"/>
       </interface>
       <interface name="unsecure">
         <inet-address value="${jboss.bind.address.unsecure:127.0.0.1}"/>
       </interface>
     </interfaces>
                                   . 
                                   . 
                                   .
      <socket-binding-group name="standard-sockets" default-interface="public" port-offset="${jboss.socket.binding.port-offset:0}">
        <socket-binding name="management-http" interface="management" port="${jboss.management.http.port:9990}"/>
        <socket-binding name="management-https" interface="management" port="${jboss.management.https.port:9993}"/>
        <socket-binding name="ajp" port="${jboss.ajp.port:8009}"/>
        <socket-binding name="http" port="${jboss.http.port:8080}"/>
        <socket-binding name="https" port="${jboss.https.port:8443}"/>
        <socket-binding name="iiop" interface="unsecure" port="3528"/>
        <socket-binding name="iiop-ssl" interface="unsecure" port="3529"/>
        <socket-binding name="txn-recovery-environment" port="4712"/>
        <socket-binding name="txn-status-manager" port="4713"/>
        <socket-binding name="remoting" interface="public" port="4447"/>
        <outbound-socket-binding name="mail-smtp">
          <remote-destination host="localhost" port="25"/>
        </outbound-socket-binding>
      </socket-binding-group>
  4. Restart your Wildfly instance, and you should find that the test runs successfully.

 

Hope this helps! 🙂

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out /  Change )

Google photo

You are commenting using your Google account. Log Out /  Change )

Twitter picture

You are commenting using your Twitter account. Log Out /  Change )

Facebook photo

You are commenting using your Facebook account. Log Out /  Change )

Connecting to %s