Stephen Smith's Blog

Musings on Machine Learning…

The Accpac Server Side Programming Model

with 7 comments


Introduction

I 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 Accpac Views (Business Logic) and to hook in your logic where you need it.

We are currently in the process of moving all our VB6 based UI forms to the web. I described this process here. The VB UI Forms talked directly to our Accpac Business Logic using our View API via the Accpac COM API. This interface worked well since it gave complete control over the Business Logic for both our UI Forms as well as for ISV’s integrating to Accpac. However this API doesn’t work well in the Web, it is too fine grained and results in far too much communication between the client and server. Over the Internet this then becomes quite slow.

To address the problem with the Accpac View API, we have adopted SData as our exclusive client/server communications protocol for our Web version. This protocol is a true REST based modern Web Services interface that will have the same role that the Accpac COM API had in the VB world. I’ve blogged on SData  a few times: here, here, here and here. Basically we want to limit ourselves to at most one server call per user interaction. The VB UIs would often make quite a few. So what do we do with all the VB logic that does all this Business Logic communication?

Basically if you find a number of Accpac COM API calls in a VB program, then this code needs to be moved to the server and programmed there. Then the client should be setup so it can call this code either as a function using an SData service operation, or accessed via a virtual field (calculated field) in the SData feed. JavaScript and AJAX actually make it hard to make several calls in a row to the server, since due to the asynchronous nature, you have to send a request, set a callback and then in that callback make the next call and so on. Chaining asynchronous calls in a row this way is rather tedious and error prone programming. In a way, this is a good thing since it discourages making more than one call at a time, which is what you want for maximum efficiency.

You might ask why we don’t just move all this code into the Views? The main reason for Sage is that we are maintaining both the Web UIs and VB UIs in parallel for quite some time. As a result of this we don’t want to have to change or re-test the VB UIs, so we don’t want to change the Views at all. Plus a lot of this logic that exists in the VB UIs, really doesn’t belong in the Views, but it doesn’t belong in the Web browser either. Hence we have this solution. It’s also nice because it moves all new programming out of C into the nice object oriented world of Java.

Also remember that your SData feeds aren’t only used by your UI forms. They are also a general programming interface for any third party ISV or integrator to use to tie into Accpac. So when designing your SData feeds keep third parties integrating via SData in mind as well as your Web UI programmers.

Server Side Architecture

There are basically a couple of ways to structure this. You can return one or more virtual fields which are calculated on the server by doing regular Accpac View calls and other programming logic, these are good if the data is always relevant, or relevant when the other fields are relevant. The other way is to access the code via an SData service call. An SData service call is basically a custom call to the server to do some processing, you can send in any number of parameters you may require and you can receive back a number of fields with the results. You can add service calls to regular data SData feeds, then these operate in a similar manner to how Views like OEORDH behave. The OEORDH view is a data view on the order header database tables, but additionally it can do processing like calculate taxes which is invoked by its viewProcess entry point. So if you have a data feed you can add some virtual fields and/or you can add some service processing calls. The nice things about these processing calls is that they can use any existing view fields and view state automatically. Additionally you can also create standalone SData service calls which have no data feed associated with them.

Inside our SData processing program, at one end SData requests come in. These are translated into View operations and then at the other end, the Views are called through our Java View API (SAJava). SData feeds correspond to a whole set of header/detail Views, so each SData request could potentially be operating on a whole set of Accpac Views via the normal header/detail View protocols.

So we have the SData request come and this is processed by the ResourceKind. The ResourceKind operates on an SDataViewSet, think of this as all the header/detail views composed together. In the SDataViewSet are a number of SDataViews and in each SDataView there are a whole bunch of SDataViewFields. Then the SDataView and SDataViewField talk to the Java class versions of our View API in the SAJava layer to do the real work. Basically we allow you to either extend or create any of the classes in the middle and give an organized way to have your classes used either in conjunction with our classes or instead of our classes. Since we are in the object oriented world of Java, when you extend one of our classes you only need to do the bare minimum work required to accomplish your goal, there is no extra overhead like we had in the C and VB world with our template approach to things. Typically you would create brand new SDataViewFields with no associated ViewField for virtual or calculated fields. If you want to just slightly change the behavior of the existing ViewField then you can extend that existing one. Similarly you can extend the SDataView class for a View to change or enhance the behavior of the base View. Generally this is much easier than sub-classing Views in C.

Running Your Classes

How do we get our classes to be run in this framework from the SData service running under Tomcat? It all starts with the classmap/resourcemap files. All the SData feeds for an application are defined in its classmap.xml file which is located in C:\”Program Files (x86)\Common Files\Sage\Sage Accpac\Tomcat6\portal\sageERP\application” where application is something like oe61a. The classmap.xml file provides the name of the SData feed, an additional configuration file for the feed called a resoucemap.xml file and the name of the class to run for this feed. This class is then loaded dynamically by our SData service when this feed is first accessed. Since it is Tomcat that loads the class for us, it must be located somewhere in the classpath for Tomcat which is typically the Tomcat\lib folder (usually in a jar file containing all your classes).

<?xml version="1.0" encoding="UTF-8"?>
    <classMap>
        <contracts>
            <contract name="accpac">
                 <resources>
                     <resource name="oeorders"
                         className="com.sage.accpac.oe61a.oe1100.server.OEOrdersResourceKind">
                         <parameters>
                             <parameter name="ResourceMapFile" value="OEOrderViewMapping.xml" />
                         </parameters>
                      </resource>
                   </resources>
            </contract>
      </contracts>
</classMap>

This is then your resourceKind. This will be a Java class that extends one of our standard resourceKinds in our SDK (such as ViewResourceKind). From here you can then load other classes to act as your SDataViewSets, SDataViews and SDataFields. So for instance to provide your own SDataViewSet you would override the createSDataViewSet method:

   /**
    * provides a {@link OEOrdersSDataViewSet} subclass of the required class as
    * described by the superclass documentation:
    * <p>
    *
    * {@inheritDoc}
    */
   @Override
   protected SDataViewSet createSDataViewSet(Program program, Resource resource)
   {
      if (null == oeordhQ)
         oeordhQ = getResourceContext().getAccpacProgram().openView(OEORDH.VIEW,
               OpenModes.None, 0, OpenDirectives.InstanceOpen);
      return new OEOrdersSDataViewSet(program, resource, oeordhQ);
   }

Then in the SDataViewSet (OEOrdersSDataViewSet in this case), you can override any individual SDataView components you like:

   /**
    * provides application-specific subclasses of the {@link SDataView} class as
    * described by the superclass documentation:
    * <p>
    * {@inheritDoc}
    */
   @Override
   protected SDataView createView(final String rid, final Resource resource)
   {
      switch (A4wapi.utlObjStrToID(rid))
      {
         case OEORDH.VIEWNUMBER:
            return new OEOrdersHeaderView(this, rid, resource);
         case OEORDD.VIEWNUMBER:
            return new OEOrdersDetailView(this, rid, resource);
         case OEORDDD.VIEWNUMBER:
            return new OEOrdersKittingDetailView(this, rid, resource);
         case OEORDDB.VIEWNUMBER:
            return new OEOrdersBOMDetailView(this, rid, resource);
         case OEORDDS.VIEWNUMBER:
            return new OEOrdersDetailSerialView(this, rid, resource);
         case OEORDQ.VIEWNUMBER:
            return new OEOrdersQuoteView(this, rid, resource, oeordhQ);
         default:
            return super.createView(rid, resource);
      }
   }

Similarly from the SDataView you can create all your virtual SDataViewFields:

   @Override
   public synchronized VirtualField createVirtualField(ResourceVirtualField field)
   {
      if (PMConstants.EntryDetailPropertyNames.CALC_PJC_RESOURCE_DESC.equals(field.getName()))
      {
         pjcResourceDescriptionAdapter = new PJCResourceDescriptionAdapter(getSet().getProgram(),
                this, field);
         return pjcResourceDescriptionAdapter;
      }
      else if (PMConstants.EntryDetailPropertyNames.UFMTCONTNO.equals(field.getName()))
      {
         //We have to manually calculated the unformatted contract number
         // - because the UFMTCONTNO in the Order
         //Details view only gets calculated by the view when the Contract field is PUT
         // - not when you are browsing through the details.
         return new PJCUnformattedContractAdapter(getSet().getProgram(), this, field);
      }
      else if (VIRTUALFLD_ITEMNO_MISCCHARGE.equals(field.getName()))
         return new CalcItemNoMiscCharge(this, field);
      else if (CALC_COMPLETE.equals(field.getName()))
      {
         return new OEOrdersDetailCompleteVirtualField(this, field);
      }
…
      else
         return super.createVirtualField(field);
   }

For any virtual fields that you add, you also need to add then to the <virtualFields> section of the resourceMap.xml file for the SData feed. Otherwise they won’t be included in the feed.

SDataView extends the SAJava View object which is a complete rendition of the View API as a Java class. This means you have full use of that View automatically. Plus you can then open and use any other Views you wish, plus use any other methods in the SAJava interface. Plus use any other Java programming libraries or facilities you like.

This blog posting is already getting quite long and all we’ve done so far is show how to setup the framework so you can start to do your work. I planned to include a number of examples of some things you can do here, but I think I’ll leave that for another posting so I can give a few more varieties of examples.

Summary

This server framework is intended to allow you a great deal of power to extend and customize the Accpac Business Logic as it is fed into SData feeds. It gives you very fine grained control over the existing Business Logic allowing you to change and extend the behavior. The previous VB UIs were architected using a standard three-tier client/server model; however, on the Web, much of the previous VB UI programming moves to the server. We don’t want to put this logic in the Views since it really is UI logic and not true business logic, so now we have the UI layer split between the server and client and then the Business Logic and Database Layers the same as before.

In the Web world, now that the Browsers have become quite powerful rich client environments, there is a lot of debate as to how much logic should run in the Browser and how much on the server. Generally we’ve kept quite a bit of UI logic in the Browser, but we move anything to the server that would require more than one round trip to the server to do the job.

Written by smist08

October 15, 2011 at 9:10 pm

7 Responses

Subscribe to comments with RSS.

  1. Nice post! Thanks, Stephen!

    Django Dunn

    October 16, 2011 at 1:08 am

  2. Thanks. good pics of information.

    IDMSys

    October 16, 2011 at 4:01 am

  3. +1

    James Hutchison

    October 16, 2011 at 9:03 pm

  4. […] week I blogged on the structure of our new Sage 300 server side programming framework. This week I’ll present a few examples of the sorts of things you can do. Of course from this […]

  5. […] of blog posts talking about our new Sage 300 ERP (the product formally known as Sage ERP Accpac) server side programming framework and gave some examples. This week we are going to start turning our attention to the client side. […]

  6. […] blogged on the enhancements for the framework for creating custom SData feeds for applications here and here. In this posting I’m looking at enhancements to our core SData protocol support. We’ve […]

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


Leave a reply to James Hutchison Cancel reply

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