Nube can't connect to DB

Hi, I’m new to the SDK. I have written some Java utilities years ago, but nothing as complex as this. My project involves extending scripting. I have down loaded the scripting-rpc example, and ran it to get an idea of how this all works. I used the client-designer-gateway archetype to setup the project, then followed the scripting-rpc example in setting up my code. First I used the multiply method to test my project, success. I then setup my first method passed in my parameter and returned a result, success. Now I am trying to connect to the DB. It appears I have a bit to learn about connecting to the DB. I have tried to use the very limited information in the SDK programming guide, and what I could find here in the forum, and the Java Docs. Trying to use the GatewayContext to make a connection to the DB, does not appear to be working. I am not receiving any errors, other than the nullpointer exception as a result of it not working. Here is a screen shot of the debugger.

Thank You,

Anthony Todd

On line 17 you set context to null, then try to call a method on it on line 23. There’s nothing in between to make it not null. You must use the context object you are given in your module’s gateway setup hook.

1 Like

Hi Phil,

Yeah, I didn’t think the null was right, but it satisfied the not being initialized. I had tried many other things prior to that, and was at my wits end. I have been looking at the setup in the gateway hook and I see how I could run the queries there, but that is not where I need to run them. I need to run them from the gateway script module where my methods live. I have several hundred methods each with their own queries to implement. Is there a way to pass the gateway context to the gateway script module? I have also been trying to set up multiple gateway script modules with no luck, if you have any suggestions there. As you can see I am no Java guru, but I hope to get there eventually.

Thanks,

Anthony Todd

There are a few techniques possible. Most commonly, save the gateway context in a field of your gateway hook. This allows you to pass the context into any RPC implementation’s constructor and into script module instances (instead of static script modules). So too with registering expression functions. In a pinch, your hook could save the context into a private static field, and provide a static method to retrieve it when needed.

Hi Phil,

Passing the context to the constructor did not work due to timing. Setup runs after everything is done, so a null was passed. I was however able to setup a static method in the gateway hook that works fine. My other question was concerning registering multiple RPC classes with the RPCHandler in the gateway hook. Any suggestions?

Thanks,

Anthony Todd

You cannot. Only one RPC class per module ID.

This doesn't make sense. The gateway hook instance's getRPCHandler() method is called for each client or designer when an RPC call needs to be looked up. This absolutely happens after the Hook is both setup and started. Create your RPC implementation class in this method of your hook, possibly with caching per session.

The creation of the RPC implementation was definitely running before the setup. I stepped through it a half dozen times in the debugger, just to be sure of what I was seeing. I didn’t try putting it into another method. It is working fine with the static method, and unless there is a serious performance hit… I have other fish to fry right now. perhaps I will revisit it later.

Wow… just one RPC class per module? I have hundreds of methods to implement, and it would sure be nice to be able to categorize them a bit more. The scripting library I am converting, has it broken up into 24 shared scripts with between 5 and 30 methods in each. C’est la vie…

Thanks,

Anthony Todd

You don't have to actually put your implementations in the RPC handler. It's still going to have a hundred+ methods on it, but you can dispatch those methods to implementations organized in whatever scheme you want.

Hi Kevin,

Could you explain in more detail, how this would be implemented? Remember I am new to all of this. If you have some examples, that would be great.

Thanks,

Anthony Todd

I think it’s best you stick to the most straightforward method you can understand.

Getting fancy and adding a bunch of indirection to try and organize things just confuses the situation a bit.

1 Like

Hi Kevin,

I would really like to see what you had suggested. A large part of this endeavor is to explore and develop best practices. The reason for exploring modules in the first place… Is to create standard, revision controlled, script extension libraries which are fast and easy to deploy and update, for our developers in the field. We currently have a large collection of scripts, which are becoming unwieldy. Anything I can do to make the end product easier to maintain in the future, is part of my mission. I am extremely interested in learning how to build this thing first time right. If this takes extra time and effort in the beginning, so be it.

Thanks,

Anthony Todd

This is based around the idea that RPC calls are usually to bridge scripting calls added in the client/designer to their gateway implementations.

Define some RPC interfaces in common:

interface FooFunctions {
    void foo1();
    String foo2();
}
interface BarFunctions {
    void bar1();
    String bar2();
}

In the gateway (client/designer too, but they just invoke RPC using the above interface), you presumably have some script modules:

class FooScriptModule implements FooFunctions {

    @Override
    public void foo1() {
        System.out.println("foo1");
    }

    @Override
    public String foo2() {
        return "foo2";
    }

}
class BarScriptModule implements BarFunctions {

    @Override
    public void bar1() {
        System.out.println("bar1");
    }

    @Override
    public String bar2() {
        return "bar2";
    }

}

Now you need an RPC handler, but you don’t want to clutter it… let’s get tricky.

public interface FooFunctionsMixin extends FooFunctions {

    FooScriptModule fooScriptModule();

    default void foo1() {
        fooScriptModule().foo1();
    }

    default String foo2() {
        return fooScriptModule().foo2();
    }

}
public interface BarFunctionsMixin extends BarFunctions {

    BarScriptModule barScriptModule();

    default void bar1() {
        barScriptModule().bar1();
    }

    default String bar2() {
        return barScriptModule().bar2();
    }

}
public class MyRpcHandler implements FooFunctionsMixin, BarFunctionsMixin {

    private final GatewayContext context;
    private final ClientReqSession session;
    private final FooScriptModule fooScriptModule;
    private final BarScriptModule barScriptModule;

    public MyRpcHandler(
        GatewayContext context,
        ClientReqSession session) {

        this.context = context;
        this.session = session;

        // Create your script modules, or maybe pass them in as
        // parameters instead. Whatever works for your application.
        fooScriptModule = new FooScriptModule();
        barScriptModule = new BarScriptModule();
    }

    @Override
    public FooScriptModule fooScriptModule() {
        return fooScriptModule;
    }

    @Override
    public BarScriptModule barScriptModule() {
        return barScriptModule;
    }

}

In your case, you might have a script module and “mixin” for each of the 24 scripts, if that makes sense for you. The RPC handler will just have 24 xyzScriptModule() methods and implement 24 “mixin” interfaces. Whatever methods belong to each of those 24 scripts go on the other classes we defined here.

Caveat: I haven’t actually verified this mixin shenanigans works with the RPC mechanism. If it doesn’t, you’d just forgo the mixin interfaces and have 100+ calls on your RPC handler that delegate to the appropriate script module.

Thanks Kevin,

I am going to have to set this up in a test module, and play around with it a bit in the debugger, to figure out exactly what you are doing. I think I have the gist of it, and I believe this will accomplish what I need to do.

Thanks again,

Anthony Todd

Do all the scripts in the libraries you are trying to replace require RPC? It seems strange that you have such a complex communications API. I mean, your jython scripts in Ignition don’t natively invoke RPC, unless you’re using sendMessage() or the newer sendRequest() in every one of them.

If you are just trying to have a single implementation of your scripts, put them into a common jar that is loaded in all scopes, with the appropriate calls in each initializeScriptManager() hook method. You can load multiple different classes as scripting extensions.

This is an excellent question. I took what you're asking at face value, but like I mentioned in my explanation of the mixin trickery, RPC is usually reserved for the case when your scripting function implementation has to be executed on the gateway instead of in the client/designer.

Hi Guys,

When looking through the SDK programming guide, and then looking at the example code offered, perhaps I misunderstood. As I explained in my initial post… " I’m new to the SDK. I have written some Java utilities years ago, but nothing as complex as this. My project involves extending scripting. I have down loaded the scripting-rpc example, and ran it to get an idea of how this all works. I used the client-designer-gateway archetype to setup the project, then followed the scripting-rpc example in setting up my code." I took the example scripting-rpc to be “this is how to extend the scripting”. I did not find anything that really said if that’s what it was, but it worked. I thought maybe the module code needed to run on the server. If there is a better way… I am ready and willing… we will see if I am able. I hate starting over, but if that’s the best approach, let’s go.

SO let me make it perfectly clear what the objective is. To convert existing python scripting libraries to a module exposing the functions to the scripting at both the client and the gateway. Just about all of these functions involve DB access. The purpose is to supply standard libraries that are version controlled, easy to load, and update.

What’s next?

Thanks,

Anthony Todd

You do not need any RPC to simply re-implement jython as java. In the simplest case, just create a class full of static methods with the names you want to appear in the system.something namespace. In your case, you will have to have different client/designer vs. gateway implementations due to the differences in accessing the database. See AbstractDBUtilities for inspiration.

I’m afraid there’s no real shortcut for the learning curve.

Kevin?

Would you like to weigh in here before I give my 2 cents worth?

You can run DB queries through ClientDBUtilities or RPC your calls to the gateway, it doesn’t matter. ClientDBUtilities is just sending them off to the gateway to run anyway.