Stephen Smith's Blog

All things Sage 300…

The Sage 300 ERP Java API

with 11 comments


With version 6.0A of Sage 300 ERP we introduced a native Java API to all the Sage 300 Business Logic (Views). We did this in support of our SData implementation which we wrote in Java. This API allows Java programmers to access all the Sage 300 ERP business logic along the same lines as our .Net API and our COM API. This API isn’t built on top of either COM or .Net, it talks directly to the underlying C DLLs in System Manager. This then provides better performance, as well as allows us to compile this part of the system for Linux with no Microsoft dependencies. Internally we usually refer to this API as SAJava.

All the Sage 300 Business Logic objects have the same API, this makes it easier for us to produce these different APIs to facilitate interoperability with all sorts of external systems, allowing the programmers there to write code in a natural manner where any required interop layer is provided by us. The Java API uses a Java Native Interface (JNI) interop layer to talk to our Windows DLLs (or Linux shared objects). This is a one way communication where we only use this to call the DLLs, we never have the DLLs calling our Java code (this direction is often dangerous and leads to the problems often encountered with JNI). Our JNI code handles all the data conversions between Java and C as well as provides exception handling to trap and handle exceptions that can happen in C code (like bad pointers).

I’ve blogged about this API a bit indirectly in the past when talking about how to write server side code for our SData service, for instance here, here and here. Generally to add custom programming to SData feeds you write Java classes that inherit from our standard SData classes to provide this. When you interact with the Views in this environment you use this Java API, but all the libraries are already included and all the details of signing on are handled for you. The framework starts you off at a point where you can directly open and call Views. In this posting we’ll back up a bit to cover full usage, unlike the case where the SData programming framework does a lot of the work for you. So that you can use this API directly in isolation without requiring any other framework.

Getting Started

First to use the Java API, you need to include its jar file into your project. This file is located in the Tomcat\lib folder. This changed a bit between version 6.0A and then the 2012 version. For 6.0A the folder is: C:\Program Files (x86)\Common Files\Sage\Sage ERP Accpac\Tomcat\lib and the file is SystemManager.jar. For the 2012 version the folder is: C:\Program Files (x86)\Common Files\Sage\Sage 300 ERP\Tomcat\lib and the file is com.sage.accpac.sdk.accpac.sajava-6.1.jar. Then you need to import the classes into any source file that uses them via:


Once you have these things included in your Java project you can start creating objects and calling methods. However due to security you first must sign-on to a session and then create all other objects from this session.

The documentation is in the form of JavaDoc and is located on the DPP Wiki. The 2012 version is here: You can find all the classes, methods and properties here. To access this, you must be part of the Sage 300 ERP Developer Program. A key benefit to joining this program is access to this wiki which contains all the developer documentation that we produce.

Signing On

First you must create a session with some code like:

Session session;
session = new Session(new ProgramSet(), new SharedDataSet(), "ADMIN",
     "ADMIN", "SAMINC", new Date());

This will sign-on your session to the company SAMINC using today’s date as the session date. The ProgramSet and SharedDataSet are used when we deploy in a hosted configuration and run multi-tenant. In this case they must be setup correctly by the system to configure which tenant this session is for. In most normal on-premise applications the indicated calls are fine to give the one default tenant that exists.

Then you must create a program from the session:

Program program;
program = new Program(session, "XZ", "XZ0001", "61A");

If you read my last blog post, this might appear a bit backwards to the COM API where this looks like the session.Init call that comes first. This is true, but the information is required regardless.

Using Views

Now that you have a program you can start opening and using Views. As an example, let’s look at a method that enters A/R Invoices. Like many things I started with macro recording to get the right Views and some syntax. Macro recording produces VBA code, but it isn’t hard to convert this to Java quickly. Anyone familiar with Sage 300 ERP macro recording will recognize the style and variable names in the following method. This method assumes there are class variables for the program and session that were created as indicated above. The key point of the following example is to show how to open Views, compose Views and then use the Views. For more general information on Sage 300 ERP’s Views have a look at this and this.

    public String enterARInvoices()


        int iEntry;
        int iDetail;
        int numEntries = 20;
        int numDetails = 5;
        String sBatchNum;

        View ARINVOICE1batch = new View(program, "AR0031");
        View ARINVOICE1header = new View(program, "AR0032");
        View ARINVOICE1detail1 = new View(program, "AR0033");
        View ARINVOICE1detail2 = new View(program, "AR0034");
        View ARINVOICE1detail3 = new View(program, "AR0402");
        View ARINVOICE1detail4 = new View(program, "AR0401");
        View ARCUSTOMER1header = new View(program, "AR0024");

        ARINVOICE1batch.compose ( ARINVOICE1header );
        ARINVOICE1header.compose (ARINVOICE1batch, ARINVOICE1detail1, ARINVOICE1detail2, ARINVOICE1detail3, null);
        ARINVOICE1detail1.compose (ARINVOICE1header, ARINVOICE1batch, ARINVOICE1detail4);
        ARINVOICE1detail2.compose (ARINVOICE1header);
        ARINVOICE1detail3.compose (ARINVOICE1header);
        ARINVOICE1detail4.compose (ARINVOICE1detail1);

        // Create the batch

        ARINVOICE1batch.set("PROCESSCMD","1");      // Process Command


        sBatchNum = ARINVOICE1batch.get("CNTBTCH").toString();

        // Loop through creating the entries

        for ( iEntry = 0; iEntry < numEntries; iEntry++ )



                if ( false == ARCUSTOMER1header.goNext() )

                ARINVOICE1header.set("IDCUST", "1200");

                for ( iDetail = 0; iDetail < numDetails; iDetail++ )
                    ARINVOICE1detail1.recordGenerate (RecordGenerateMode.NoInsert);

                    ARINVOICE1detail1.set("IDITEM", "CA-78" );                     // Item Number



            catch( Exception e )
                int count = program.getErrors().getCount();
                if ( 0 == count )
                for ( int i = 0; i < count; i++ )

        return( sBatchNum );

Notice that you can explicitly close things by calling the dispose method. This is usually preferred to waiting for the Java garbage collector to reclaim things, it tends to keep down resource usage if you are opening and closing things a lot.


If a call fails, there are a couple of cases. If it’s a simple expected thing like reaching the end of records when fetching through them then the routine will return a simple return code that you can easily handle in your code. If something worse happens then the routine will throw an exception. As in other Sage 300 ERP APIs, there is an error stack which will contain possibly a number of error messages explaining what went wrong. In the catch expression above we first check if there are any errors on the error stack, if not then we print the stack trace to allow debugging of what went wrong. Otherwise we loop through the Sage 300 errors and print them for diagnostic purposes. When programming Sage 300 ERP, always make sure you have an error handler as it can give you very good information when debugging your program.


The Sage 300 ERP Java API gives yet another tool for integrators to integrate to Sage 300 ERP from external systems. It is ideal for Java programmers who would like to write their integration entirely in Java. This is often a benefit when the SDK for the external system is itself written around the Java programming language.

11 Responses

Subscribe to comments with RSS.

  1. Hi Stephen,
    I tried a small example program using your code as a reference. It is designed to simply print all customer names. The program compiles fine in Eclipse, however fails on running at the creation of the session (session = new Session…). Are you missing something in the initialisation process of your code? Following is the source code and the error.

    package accpactest;

    import java.util.Date;


    public class AccpacTest {
    private static Program program;
    private static Session session;

    public static void main(String[] args) {
    try {
    session = new Session(new ProgramSet(), new SharedDataSet(), “ADMIN”, “ADMIN”, “SAMINC”, new Date());
    program = new Program(session, “XZ”, “XZ0001”, “61A”);
    View customer = new View(program, “AR0024”);
    customer.filterSelect(“”, true, 1, View.FilterOrigin.FromStart);
    while (customer.goNext()) {
    System.out.println(customer.getField(“namecust”) + “\n”);


    catch (Exception ex) {
    int count = program.getErrors().getCount();
    if (0 == count) {
    for (int i = 0; i < count; i++) {

    Error console message follows:

    Exception in thread "main" java.lang.NoClassDefFoundError: org/slf4j/LoggerFactory
    at accpactest.AccpacTest.main(
    Caused by: java.lang.ClassNotFoundException: org.slf4j.LoggerFactory
    at$ Source)
    at$ Source)
    at Method)
    at Source)
    at java.lang.ClassLoader.loadClass(Unknown Source)
    at sun.misc.Launcher$AppClassLoader.loadClass(Unknown Source)
    at java.lang.ClassLoader.loadClass(Unknown Source)
    … 2 more

    Martin Williams

    January 6, 2013 at 2:57 pm

    • Sorry you also need to add references for org.slf4j.slf4j-api.jar and org.slf4j.slf4j-log4j12.jar. These are used by SAJava for logging purposes.


      January 8, 2013 at 1:09 am

      • Oops forgot log4j.log4j.jar which is needed as well.


        January 16, 2013 at 11:47 pm

      • Stephen, I did try that library also, however, I was getting the following error:

        “Exception in thread “main” java.lang.UnsatisfiedLinkError: no A4wapiShim in java.library.path”.

        I got a sample application from DPP Support which contained only the com.sage.accpac.sdk.accpac.sajava-6.1.jar, slf4-api-1.7.2.jar and slf4j-simple.1.7.2.jar. With these three external libraries, I was able to get the test application running.

        Thank you for the assistance. This is a very useful blog.

        Martin Williams

        January 17, 2013 at 1:44 pm

  2. […] Introduction With version 6.0A of Sage 300 ERP we introduced a native Java API to all the Sage 300 Business Logic (Views). We did this in support of our SData implementation which we wrote in Java….  […]

  3. […] still are tightly integrated to Sage 300 ERP via one of our APIs such as the COM API, .Net API or Java API. You can add arbitrary EXE programs to the Desktop as icons and launch them just like any other […]

  4. Hey Stephen, this whole java stuff is new to me, but I have a customer who is using the Order Entry in CRM and I need to make what would seem to be an easy change but I have no idea where to begin. In the order details grid when the user selects the item number it shows the total qty available, however that number is not correct. The actual total qty available should be the qty available minus the qty on sales order to show what’s available to put on the order. So all I want to do is add a new calculated field which takes the qty available and subtract the qty on s/o to bring back the actual qty available. You mentioned extending the existing java code to override properties or methods. Do you have any complete examples of how to do this? Thanks Stephen.

    Brad Edwards

    December 12, 2013 at 5:18 pm

  5. […] Sajava.jar: This is the Java side of our Java JNI interface. This allows Java programs to easily call Java classes to interface to our Business Logic Views. For more on this interface see this article. […]

  6. Hi Stephen,

    How do we handle concurrency when we are looking to post multiple transactions using a single user id from say an external app using the Java API. for e.g submitting 5 to 6 order transactions concurrently?


    November 12, 2015 at 9:30 am

    • If you are using multi-threading then each thread has to have its own session. You can’t have multiple threads sharing a session. Then you will get multi-user conflicts usually due to contentions on things like options records. It doesn’t matter if you are using different Sage 300 users or not, the multi-user contention will be the same.


      November 12, 2015 at 5:25 pm

Leave a Reply

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

You are commenting using your 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 )

Google+ photo

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

Connecting to %s

%d bloggers like this: