Service.doInvoke from thread

I am attempting to call a custom IS65 service using Service.doInvoke from a Java Thread that was lauched from within the IS. My thread code is within a custom jar that is deployed to the IS lib/jars directory. At IS startup a static method is called in a class within the custom jar which launches several worker threads. Those threads read events from a webMethods broker and when they have work to do (events are received) they need to call back to a service in the IS. However, when that service is called from the thread I get an java.lang.NullPointerException as listed below. Can anyone help?

java.lang.NullPointerException
at com.wm.app.b2b.server.invoke.InvokeManager.invoke(InvokeManager.java:413)
at com.wm.app.b2b.server.invoke.InvokeManager.invoke(InvokeManager.java:369)
at com.wm.app.b2b.server.ServiceManager.invoke(ServiceManager.java:246)
at com.wm.app.b2b.server.ServiceManager.invoke(ServiceManager.java:113)
at com.wm.app.b2b.server.Service.doInvoke(Service.java:635)
at com.wm.app.b2b.server.Service.doInvoke(Service.java:584)
at com.sbux.broker.Client.callService(Client.java:364)
at com.sbux.broker.Client.process(Client.java:316)
at com.sbux.broker.ClientWorkManager$ClientWorkThread.run(ClientWorkManager.java:90)

Sample code (nothing is null in the service call):

    // create input for service call
    IData input = IDataFactory.create();
    IDataCursor inputCursor = input.getCursor();
    inputCursor.insertAfter( this.serviceDataKey, xmlDoc );

    // generate service call
    try{
        NSName svcName = NSName.create(this.serviceName);
        
        if(svcName==null) LOG.error("svcName is null");
        if(input==null) LOG.error("input is null");

        Service.doInvoke( svcName, input );
        callResult = true;
    }
    catch(Throwable t) {
        LOG.error("Client service call exception: "
                + "\n\tClient   : " + this.clientName
                + "\n\tService  : " + this.serviceName
                + "\n\tException: " + t
            );
        t.printStackTrace();
        callResult = false;
    }
    finally {
        inputCursor.destroy();
    }

How is the main thread started during start-up?
Also, how are these worker threads created? You’ll have some issues if you try to do Service.doInvoke from generic Java threads as it will miss some Session info. Instead, use Service.doThreadInvoke to spawn threads.

Thank you for reaching out to help. Answers to usage question:

During server startup we have an initialization service that is called that makes a call to a static method (BrokerController.initialize()) that lives in a jar that we have deployed to the server.

That method creates several supporting objects one of which contains a list of worker Threads (yep, java Threads) and another that contains a list of objects that have the need to call back to IS services in the integration server.

As the worker threads find work to do (i.e. find out there are broker events to process) they pass the work along to one of the other objects to do the work of calling the IS service.

Thank you again for any help you can provide.

What I’ve been trying tonight is to somehow retain the “Session” or “InvokeState” in order to make the call work. But each time I get the same error. This is a tough one for me.

My first recommendation is to rework your solution to get rid of the .jar file and use the built-in facilities of IS to interact with the Broker. I imagine you’re trying to leverage some library from way back when IS and Broker weren’t so integrated. Long term, I think you’ll be better off if you abandon that library. Of course, that’s just a preliminary opinion based on the info at hand.

You’re not going to be able to “retain” any session. You’ll need to create one (or more). Here’s a code snippet that used unpublished classes to do what you’re looking for:

// Place this code in a method in the library. It
// will not have an IS session/context established but needs
// one to invoke the desired service. This code mimics what
// the Scheduler does to establish a session when running a
// scheduled task.
IData input = IDataFactory.create();
IDataCursor idc = input.getCursor();
IDataUtil.put(idc, “foo”, “some parameter”);
IDataUtil.put(idc, “bar”, “another input to the service”);
idc.destroy();
// UserManager not documented; User is
User u = UserManager.getUser(“Administrator”); // May want to make the username configurable
// StateManager not documented; Session is
// The next line is the method signature
// public static Session StateManager.createContext(long timeout, String name, User sessionUser)
Session s = StateManager.createContext(0x7fffffffL, “system”, u);
s.setUser(u); // documented
s.clearModified(); // not documented
try
{
// Session.invoke not documented
s.invoke(u, NSName.create(“the.name.of.your:service”), Values.use(input));
// Undocumented class–shortcut to do what pub.flow:debugLog does
JournalLogger.log(JournalLogger.LOG_MSG, JournalLogger.FAC_DEBUG,
JournalLogger.DEBUG, “I did some work”);
}
catch(Exception e)
{
// You may want/need to do something else here
ServerAPI.logError(e);
e.printStackTrace(System.out);
}
finally
{
// StateManager not documented
StateManager.deleteContext(s.getSessionID());
}

1 Like

Thank you for your help. I am heading into the office and will try it when I finally get there. We have a couple of reasons to own the code between IS and the broker…so I’m definitely trying to get over this hump.

Thanks again for the code snippit. I’m hoping this will do the trick.

Thank you very much for your help. Worked like a charm. I’m going to play around with it to be sure I understand how sessions may timeout and/or break but I believe I am on my way.

Sorry, I am confused…As reamon said…why not create Trigger and invoke flow service from there??

Yes, known problem.
Session is tied to thread. When You are creating Your own thread it is a wild thread - not tied to any IS managed Session object - no Session no awareness of IS runtime and there is the error.

This implies that there is a bug in IS. Was that your intent?

Not bug in IS, just problem to find out what to do in this case for the first time (API documentation problem maybe or lack of the knowledge)

Hi Reamon,

I am trying to invoke a service inside a thread class and getting null pointer exception. My requirement is to kill the thread when the service which is invoked by doInvoke() function takes long time to run than the specified timeout. This doInvoke() function resides inside a thread class. So killing thread will kill the execution of the service. Can you please help me in this regard.

IDataCursor pipelineCursor = pipeline.getCursor();
try
{
FPImpServiceN m1=new FPImpServiceN();
Thread t1 =new Thread(m1);
t1.start();

}
catch(Exception e)
{
throw new ServiceException(e);
}
pipelineCursor.destroy();

Code in source:

static class FPImpServiceN implements Runnable
{
public void run()
{
try
{
NSName nsName = NSName.create( “threadsPOC.services:new_javaService” );
IData outputData = Service.doInvoke( nsName, null ); // Getting Null pointer exception here //
}
catch(Exception e)
{
com.wm.util.JournalLogger.log( com.wm.util.JournalLogger.INFO, com.wm.util.JournalLogger.FAC_FLOW_SVC, com.wm.util.JournalLogger.DEBUG, e);
}
}
}