Home > front end >  UniObjects for Java how to open sessions to emulate connection pooling
UniObjects for Java how to open sessions to emulate connection pooling

Time:01-19

I'm developing an API that connects UniVerse database to a REST endopoint. The problem is that we dont have license for native connection pooling using the UniVerse library for Java.

This software is developed in Java using Spring Boot, and the way I open sessions to universe

uniSession = uniJava.openSession();
 uniSession.setHostName(server);
 uniSession.setUserName(userName);
 uniSession.setPassword(password);
 uniSession.setAccountPath(accountPath);
 uniSession.connect(); 

I iterate over that and save sessions in a list "freeSession", when I get a request I pop a session from that list, move it to "occupiedSession", use it and return back to "freeSession".

but the problem is that in the list of sessios all are the "same". I mean, I can't recieve concurrent petitions because my API only have "one sesion" to interact with UniVerse server.

CodePudding user response:

Try upgrading to the latest version of UniObjects for Java in UniDK 5.2.1. I'm guessing that using UniJava may have exhibited that behavior in an older version. As long as you're just running BASIC programs, I'm guessing you will not run into any compatibility issues with 10.1.21:

  1. Visit https://rbc.rocketsoftware.com/u2bcesdinternal.asp?pid=100000047043&product=U2CL and download the U2 Current Clients installer

OR (for the long way)

  1. Visit https://rbc.rocketsoftware.com/buildmatrix.asp
  2. Select U2 Clients for the product and Windows for the platform
  3. Use the Product link in the Downloads column to download the installer

Honestly, I am using UniObjects for Java (in UniDK 5.2.1) to connect to Universe from a Spring Boot app, and I am able to create and maintain multiple parallel connections using similar code to you. If I get ten simultaneous web requests, I can see ten independent uvcs/defcs connections in Universe. The only thing I am doing differently is using the latest jars and I'm just creating a new instance of UniSession (and then later calling connect, like you) with:

UniSession uniSession = new UniSession();

instead of

UniSession uniSession = uniJava.openSession();

However, UniJava in the latest version seems to do basically the same thing as creating a new instance, but with some additional logging and tracking.

I did have someone at Rocket tell me at some point that the normal Universe license agreement forbids connection pool recreations, thus forcing you to purchase a connection pool licenses. I don't have the license handy to confirm. However, I cannot recommend purchasing connection pool licenses either without meeting with Rocket to talk specifics about your app requirements as it scales. Depending on load, durability, and performance requirements, you may need to spread read operations over multiple Universe replications, which isn't supported well/cost effectively by the published connection pool licensing model.

CodePudding user response:

It's been a while, and I don't have access to the code anymore, but I dealt with a similar problem years ago. The solution used a semaphore to help with the concurrency. Create a connection pool class that can be shared globally. When calling code needs a unisession, the connection pool grabs one if available, otherwise it blocks the calling thread until one becomes available. You don't want to hard code the count or the connection parameters like in this example (most of which was copied from the semaphore javadocs), of course.

import java.util.concurrent.Semaphore;

public class ConnectionPool
{
    private static final int COUNT = 5;
    private static final ConnectionPool INSTANCE = new ConnectionPool();

    private final Semaphore available = new Semaphore(COUNT, true);
    protected UniSession[] items =  new UniSession[COUNT];

    protected boolean[] used = new boolean[COUNT];
    protected UniJava uniJava = new UniJava();

    private ConnectionPool() {
        for (int i = 0; i < COUNT; i  ) {
            items[i] = uniJava.openSession();
            items[i].setHostName("server name");
            items[i].setUserName("user name");
            items[i].setPassword("password");
            items[i].setAccountPath("account path");
            items[i].connect();
        }
    }

    public static ConnectionPool getInstance() {
        return INSTANCE;
    }

    public UniSession borrow() throws InterruptedException {
        available.acquire();
        return getNextAvailableItem();
    }

    public void release(UniSession session) {
        if (markAsUnused(session))
            available.release();
    }

    protected synchronized UniSession getNextAvailableItem() {
        for (int i = 0; i < COUNT;   i) {
            if (!used[i]) {
                used[i] = true;
                return items[i];
            }
        }
        return null;
    }

    protected synchronized boolean markAsUnused(Object item) {
        for (int i = 0; i < COUNT;   i) {
            if (item == items[i]) {
                if (used[i]) {
                    used[i] = false;
                    return true;
                } else
                    return false;
            }
        }
        return false;
    }

}

Then in your API code, when you need a unisession, you'd borrow one from the pool, making sure to release it when you're done with it. Something like this:

UniSession uniSession = null;

try {
    uniSession = ConnectionPool.getInstance().borrow();
    
    // do work
    
} finally {
    ConnectionPool.getInstance().release(uniSession);
}

This lets your application reuse a pool of sessions, and the number of sessions never exceeds the count you specify.

  •  Tags:  
  • Related