Stephen Smith's Blog

Musings on Machine Learning…

Writing Server Side Code for Accpac 6 Web UIs

with 11 comments


We discussed how to create Accpac 6 Web based UIs in https://smist08.wordpress.com/2010/08/14/creating-a-web-form-for-accpac-6/ and how to write code that runs as JavaScript in the Browser in https://smist08.wordpress.com/2010/08/21/client-logic-for-an-accpac-6-web-form/. This blog posting looks at how you can write server side code in Java to assist your UIs do their job more efficiently.

Accpac 6 Web UIs communicate with the Server using SData (https://smist08.wordpress.com/2009/11/24/sdata-in-sage-erp-accpac-6/ and http://sdata.sage.com/) which is a REST based Web Services protocol. On the Server we run a Java application that converts incoming SData requests into Accpac View calls. Accpac Views are the business logic objects within Accpac. The Accpac business logic is remaining largely unchanged in this new environment and it’s the job of this Java application to convert the new world into the older world.

Theoretically then, you could do much of what we are talking about directly in the Views. We could expose new calculated fields or new functionality directly from the Views. However Views are used by all sorts of things including VB based UIs, macros, import/export as well as by third party applications. We don’t want to clutter up the Views with lots of extra logic needed to support or optimize the new Web based UIs. What we are looking to do is split the code that used to run entirely in VB UIs to half run in the browser and half run on the server. We also want to provide support for our Web based UIs to minimize program size running in the Browser and to minimize the number of RPC (remote procedure calls) they need to make to the server. The current VB UIs call many Views at once to do what they need, but this won’t work so well over the Internet since it will require many SData calls to do things, we really want to consolidate all the info the UI requires in one feed, so it only needs to do one SData call to get everything it needs.

Within the SData server’s configuration are a number of XML files that define all the SData feeds for the various accounting applications. For each application there is a classmap.xml file that lists all the feeds and the Java class that processes that feed. Then for each feed there is a specific resourcemap.xml file that defines various properties or configurations for that feed such as which Views is sits on, or some extra fields to present. To add an SData feed on top of an existing View is easy and just a matter of creating these simple XML files. There is a generic class ViewResourceKind that will provide standard SData functionality for any View. But if you want to add your own functionality you need to extend one of our classes and add your own logic.

The hardest way to implement an SData service is to create a class that implements our SDataResourceKind interface. This interface defines what a class needs to implement in order to be used as an SData feed from our SData application server. Here you need to do all the work, but if you want to implement a feed that hasn’t got anything to do with normal Accpac processing, perhaps this is a way to go. Fortunately we provide a class that implements this interface that you can extend. This is the ViewResourceKind class, mentioned previously, that implements SData on top of a View. This is really intended for data type Views. You can extend this to add fields and/or provide other helpful services for your UI form (or other consumer of your SData feed).

SData provides data type feeds similar to Views built closely over database tables, but it also provides “service” feeds that are similar to Accpac superviews. These feeds are meant to perform service type operations like printing a report, posting a batch or doing a calculation. They can operate asynchronously, meaning the originating call returns immediately, but then can poll the service for status updates (which can be used to update a meter control).

Here is a bit of sample code from the SData service that provides the data for the pie charts in the G/L Balance Sheet data snapshot.

public class GLBALSHTService extends BaseService
{
   private final SDataView            viewGLFSUM;
   private final List<ServiceField>   requestFields;
   private final List<ServiceField>   responseFields;
   private static final String        STR_RSCID  = "GLBALSHTSP";
   private boolean                    bPermitted = false;
   private GLLanguageResourceContents GLLanguageResource;
   public GLBALSHTService(final ApplicationContext applicationContext, final ResourceContextImpl resourceContext,
         final Resource resource, final Service service, final SDataViewSet viewSet)
   {
      super(applicationContext, resourceContext, resource, service, viewSet);
      viewGLFSUM = new SDataView(getResourceContext().getAccpacProgram(), GLFSUM.VIEW, resource);
      bPermitted = getResourceContext().getAccpacProgram().isPermitted(STR_RSCID);
      if (!bPermitted)
      {
         String appVersion;
         String appLang;
         //language dependent resource content is only used when access is not permitted.
         appVersion = resourceContext.getAccpacProgram().getActiveApplications().get(GLLanguageResourceContents.APPL)
               .getAppVersion();
         appLang = viewGLFSUM.getProgram().getSession().getUserLanguage();
         GLLanguageResource = new GLLanguageResourceContents(appVersion, appLang);
      }
      requestFields = new ArrayList<ServiceField>();
      responseFields = new ArrayList<ServiceField>();
      setupRequestFields();
      setupResponseFields();
    }
   @Override
   public void shutdown()
   {
      if (this.viewGLFSUM != null)
         this.viewGLFSUM.dispose();
   }
    private void setupRequestFields()
   {
      requestFields.add(ServiceHelper.viewFieldToServiceField(viewGLFSUM.getFields().get(GLFSUM.IDX_YEAR)));
      requestFields.add(ServiceHelper.viewFieldToServiceField(viewGLFSUM.getFields().get(GLFSUM.IDX_PERIOD)));
      requestFields.add(ServiceHelper.viewFieldToServiceField(viewGLFSUM.getFields().get(GLFSUM.IDX_PERIODS)));
   }
   private void setupResponseFields()
   {
      responseFields.add(ServiceHelper.viewFieldToServiceField(viewGLFSUM.getFields().get(GLFSUM.IDX_ENDDATE)));
      responseFields.add(ServiceHelper.viewFieldToServiceField(viewGLFSUM.getFields().get(GLFSUM.IDX_CASH)));
     // … Lots more response fields defined …
   }
   protected List<ServiceField> createRequestFields(final SDataRequest request)
   {
      return requestFields;
   }
   @Override
   protected List<ServiceField> createResponseFields(final SDataRequest request)
   {
      return responseFields;
   }
   @Override
   protected List<ServiceField> execute(SDataResourceElement payload, SDataRequest request, AsyncStatusListener listener)
   {
      List<ServiceField> list = new ArrayList<ServiceField>();
      if (!bPermitted)
      {
         throw (new RuntimeException(GLLanguageResource.getValue(GlobalContent.ACCESS_DENIED_MSG.toString()), null));
      }
      int errorCode;
      this.viewGLFSUM.recordClear();
      setGLFSUMViewFieldsValue(payload);
      MeterEventListener meterListener = null;
      if (listener != null)
      {
         meterListener = new MeterListener(listener, listener.getProgress().getProgressPct(),
               TrackingPayload.PROGRESSPCT_GET_RESULT);
      }
      errorCode = viewGLFSUM.process(meterListener);
      if (errorCode > 0)
      {
         throw (new RuntimeException(null, null));
      }
      list.add(ServiceHelper.viewFieldToServiceField(viewGLFSUM.getFields().get(GLFSUM.IDX_ENDDATE)));
      list.add(ServiceHelper.viewFieldToServiceField(viewGLFSUM.getFields().get(GLFSUM.IDX_CASH)));
      // … Lots more reponse fields added …
      return list;
   }
 
   /**
    * function to set field value
    */
   private void setGLFSUMViewFieldsValue(SDataResourceElement payload)
   {
      for (SDataResourceElement elem : payload.getContents())
      {
         final String name = elem.getName();
         String value = (String)elem.getValue();
         if (value != null)
         {
            viewGLFSUM.putBySDataPropertyName(name, value, Boolean.FALSE);
         }
      }
   } 
   /**
    * set the default value for the request fields
    */
   @Override
   protected List<ServiceField> createTemplateFields(final SDataRequest request)
   {
      List<ServiceField> list = new ArrayList<ServiceField>();
      this.viewGLFSUM.recordClear(); 
      list.add(ServiceHelper.viewFieldToServiceField(viewGLFSUM.getFields().get(GLFSUM.IDX_YEAR)));
      list.add(ServiceHelper.viewFieldToServiceField(viewGLFSUM.getFields().get(GLFSUM.IDX_PERIOD)));
      return list;
   }
}

 

This service is then defined in the GLServiceMap.xml file under the tomcat\portal directory:

<?xml version="1.0" encoding="UTF-8"?>
<serviceMap>
<services>
       <service
         className="com.sage.accpac.gl60a.common.server.GLBALSHTService">
       </service>
… other definitions …
</services>   
</serviceMap> 

 

In the execute method, notice the View calls to the GLSUM View. You can see calls to recordClear and process. Basically these are calls to our Java JNI layer (Java Native Interface, http://en.wikipedia.org/wiki/Java_Native_Interface). Here we have a hierarchy of classes very similar to what we had in COM for VB programming where you can access all the View methods as well as a selection of convenient other System Manager APIs.

The basic logic here is to first initialize the operation in the constructor, get the input fields from the SData feed (the request fields as in setupRequestFields), perform the various View operations that are required (the execute method) and then setup the response fields to send back to the UI running in the Browser (created in setupResponseFields and then set in the execute method).

Hopefully, this gives a bit of a flavor for what sort of programming goes on the server for helping User Interface programs from an SData point of view.

Written by smist08

August 28, 2010 at 4:21 pm

Posted in sage 300

Tagged with , , , ,

11 Responses

Subscribe to comments with RSS.

  1. […] is a great post written by Stephen Smith regarding how you can write server side code in Java to assist your UIs do […]

  2. […] Forms in Sage ERP Accpac 6 Creating a Web Form for Accpac 6 Client Logic for an Accpac 6 Web Form Writing Server Side Code for Accpac 6 Web UIs Preparing for the Sage ERP Accpac 6.0A […]

  3. […] previously blogged on server side programming for the new Web version of Sage ERP Accpac here. However we’ve improved how you do this quite a bit making it much easier to interact with the […]

  4. Great post! can you give us samples in C# as well???

    KenLongcrier

    February 22, 2012 at 5:49 pm

    • Sorry but this is a Java only framework. You have to extend Java classes and run under the JVM under Tomcat.

      smist08

      February 22, 2012 at 10:24 pm

      • So, being new to Accpac, wanted to know if Sage had ported over to Java completely for ERP Accpac 6.0.

        Tipton Loo

        March 14, 2012 at 6:20 pm

      • Not completely. All new Web work is being done in Java. However the existing business logic remains as it is.

        smist08

        March 14, 2012 at 9:18 pm

  5. […] to define custom Java classes to process the SData requests, I’ve covered this a bit in other blog postings, but won’t go into that here, since this article is only considering what can be done by editing […]

  6. OK, looking over this code, it appears that I can access the AOM by defining the objects in a RESTful service the same as I do the 5.4 .NET WebService, but a code example that actually does this would be of great use in helping me convert 100s of lines of code.

    KenLongcrier

    August 10, 2012 at 9:58 pm

  7. Thanks for the server-side Java example. It makes me wonder, though, are there any Java examples for SData clients? On http://sage.github.com/SData-2.0/ I see libraries for C#, Javascript and Ruby, but not Java. Is a Java SData client library coming soon?

    Brian

    August 28, 2012 at 6:58 pm

  8. […] 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 […]


Leave a comment

This site uses Akismet to reduce spam. Learn how your comment data is processed.