Developing H5 Client scripts – Part 2

I am learning to develop H5 Client scripts for a customer; see my previous post for the beginning.

To give back

My customer Chris Bullock thought client side scripts are pretty awesome, and said it would be cool if there was a library of what other M3 users have done. I proposed to post the script here with his permission, and he agreed for the love to give back.

Functional requirement

The requirement is to develop a script for M3. Purchase Order. Receive Goods – PPS300/E in H5 Client that pulls values from a related field in M3 and populates it in another field. Basically getting attribute values from purchase order line, concatenating their values, then populate that in the Lot number field on the purchase order receipt screen.

More specifically, when the user is receiving goods for a purchase order in PPS300/E, the script should automatically set the Location (WHSL) and Lot number (BANO) with the correct values to not let the user enter incorrect values by accident even with the F4-Browse:


Here is the preliminary script I developed:

var PPS300E_BANO = new function () {
	var color = 'rgb(250, 255, 189)';
	this.Init = function (scriptArgs) {
		var controller = scriptArgs.controller;
		var content = controller.GetContentElement();
		var IBITNO = content.GetElement('IBITNO')[0]; // Item number
		var IBPUNO = content.GetElement('IBPUNO')[0]; // Purchase order number
		var IBPNLI = content.GetElement('IBPNLI')[0]; // Purchase order line
		var WLWHSL = content.GetElement('WLWHSL')[0]; // Location
		var WRBANO = content.GetElement('WRBANO')[0]; // Lot number
		// ensure the Item group is MAT
		ScriptUtil.ApiRequest('/execute/MMS200MI/Get;returncols=ITGR?ITNO=' + encodeURIComponent(IBITNO.value), response => {
			var ITGR = response.MIRecord[0].NameValue[0].Value.trim();
			if (ITGR !== 'MAT') {
			if (!WLWHSL.readOnly && WLWHSL.value === '') {
				// hard-code the Location to YARD
				WLWHSL.value = 'YARD';
				// color the field = color; = color;
			// get the Attribute number
			ScriptUtil.ApiRequest('/execute/PPS200MI/GetLine;returncols=ATNR?PUNO=' + encodeURIComponent(IBPUNO.value) + '&PNLI=' + encodeURIComponent(IBPNLI.value), response => {
				var ATNR = response.MIRecord[0].NameValue[0].Value.trim();
				// get the attributes
				ScriptUtil.ApiRequest('/execute/ATS101MI/LstAttributes;returncols=AALF?ATNR=' + encodeURIComponent(ATNR), response => {
					// calculate the Lot number
					var BANO = '';
					response.MIRecord.forEach(e => BANO += e.NameValue[0].Value.trim());
					if (!WRBANO.readOnly && WRBANO.value === '') {
						// set the Lot number
						WRBANO.value = BANO;
						// color the field = color; = color;
				}, (error, message) => MainController.Current.ShowDialog([error, message]));
			}, (error, message) => MainController.Current.ShowDialog([error, message]));
		}, (error, message) => MainController.Current.ShowDialog([error, message]));

Development time

When I develop the script, I alternate between pieces of code in Chrome’s JavaScript console and debugger, and the assembled script in a text editor, iteratively until it’s ready, testing along the way with ScriptName.Init({ 'controller': getActiveController() }):


The result is the following, the script sets the Location and Lot number, and highlights them in yellow with the same color as the web browser’s autofill color to indicate that it autofilled the values:

At this point, the user can verify the values and click Next (or press ENTER) to persist the values in M3.


There are several problems with this script:

  1. The script is not able to tell apart whether the user entered the record with Option 1-Create or with Option 2-Change. In the former case, the script should set the values because the values have never been set; but in the latter case, the script should not set the values because they have already been set. I tried controller.Response.ControlData.Bookmark.Opt but it returns "2" for both Options 1-Create and 2-Change which is wrong. We are running M3 UI Adapter version In a thread with Reah, she said if we upgrade M3 UI Adapter to version, I will be able to use controller.GetMode() instead. To be continued.
  2. To make M3 API calls, I use ScriptUtil.ApiRequest. But as of M3 UI Adapter version, that method is deprecated and replaced by MIService. See my thread with Reah. To be continued.


There is this corner case in usability, unrelated to H5 Client scripts:

Initially, the customer wanted me to set the fields and disable them, no matter what. That works if the user creates a new record with Option 1-Create. But if the user enters an existing record with Option 2-Change and there are already values that another user has previously set, what should the script do? Should the script assume the values are correct and let it be? In which case the script could have guessed incorrectly and leave incorrect values behind (false negative). Or should the script assume the values are incorrect and reset them? In which case the script could have guessed incorrectly and contradict the intention of the previous user (false positive). Furthermore, if the script does reset the values, how will the user know those are new values to persist? Will highlighting in yellow be enough? Or will the user incorrectly assume those are the values currently persisted in M3? I have to read more about WebKit’s autofill design decisions and learn from it. For now, I apply the weakest enforcement: if the field is blank, set it; otherwise, do not; and never disable it.


There are several pending issues:

  • Upgrade M3 UI Adapter to the latest version
  • Use controller.GetMode() to tell apart Option 1-Create and 2-Change
  • Replace ScriptUtil.ApiRequest by MIService
  • Usability: disable the two fields while calling the M3 API, indicate activity (spinning wheel), revert when done, cancel if gone (ENTER, F3, F5, F12)
  • Add exception handling: if == null, try/catch, if response.Message, if !response.MIRecord
  • Compose the promises sequentially with request1.then(request2).then(request3) or Promise.all([request1, request2, request3]) instead of nesting them with request1({ request2({ request3() }) })
  • Use JavaScript async/await for ease of source code reading
  • Use Visual Studio and TypeScript as recommended by the M3 H5 Development Guide (H5 Script SDK)


That was my preliminary script for H5 Client while I am learning how to develop them. I still have to learn more about H5 scripts and autofill, solve current problems, and address pending issues.

Special thanks to my customer Chris Bullock.

Infor M3 open source platform announcement thing

Let’s talk about the Infor M3 open source platform announcement thing.


In 2015, Infor announced: “The latest Infor M3 solution now features an open source based Linux platform as a deployment choice to reduce total cost of ownership for customers.”

It is admirable to support open source software, so please join us in congratulating Infor.

What about free/libre software?

It would have been more admirable to support free/libre software. The open source movement and the free/libre software movement are related but distinct; freedom is more important than open source.

Supported platform

The following documentation, M3 Core 13.4 Installation Guides Red Hat Linux > M3 Core Installation Planning Guide – RHEL > Introduction and overview > Installation Scenarios > Recommendations, says M3 Core is now available as an option on “Red Hat Enterprise Linux as operating system and Postgres Plus Advanced Server as database […] If the M3 Database Server is installed on Red Hat Enterprise Linux, the Postgres Plus Advanced Server must be used.”

Red Hat Enterprise Linux

Red Hat Enterprise Linux is a commercial product. Its source code is open and provided at no cost, but it is not provided in compiled form. To use it, we have to either buy it or go through the difficult compilation and derivative processes.

As a side note, Red Hat has controversy in the community with their non-free/libre licensing and inclusion of binary blobs [1] and as such is not endorsed by the Free Software Foundation [2].

EnterpriseDB Postgres Plus Advanced Server

EnterpriseDB Postgres Plus Advanced Server is also a commercial product, even though based on the open source PostgreSQL, it is provided at cost, and its source code is not available:

Technical reason?

Besides understandably not being able to support every combination of platform, are there any technical reasons for M3 to HAVE TO use Red Hat Enterprise Linux and EnterpriseDB Postgres Plus Advanced Server, and not Fedora, CentOS, Debian, Ubuntu, Suse, PostgreSQL?

Business collaboration?

Does it have anything to do with Infor’s joint collaboration with Red Hat and EnterpriseDB for Infor LN?

Wasn’t there something similar with the Intentia and IBM alliance [3] [4], where Movex Workplace HAD TO use the Enterprise Edition of IBM WebSphere Application Server for no apparent technical reason?

What about the community?

Infor uses a lot of free/libre software on free/libre licenses such as BSD, GPL and Apache. For example, this is the (not cleaned-up) list of about 100 projects used by one of the components of M3, the Infor Grid:

antlr antlr-runtime aopalliance-repackaged asm asm-commons asm-tree bcmail-jdk16 bcprov-jdk16 commonj.sdo commons-daemon commons-fileupload commons-logging commons-math3 ctivation cxf-api cxf-rt-bindings-soap cxf-rt-bindings-xml cxf-rt-core cxf-rt-databinding-jaxb cxf-rt-databinding-xmlbeans cxf-rt-frontend-jaxws cxf-rt-frontend-simple cxf-rt-management cxf-rt-transports-http cxf-rt-ws-addr cxf-rt-ws-policy cxf-rt-ws-rm cxf-rt-ws-security decision-trees derbyclient drools-compiler drools-core ecj eclipselink ehcache-core geronimo-javamail_1.4_spec groovy-all hk2-api hk2-locator hk2-utils izpack-api izpack-tools jackson-core-asl jackson-jaxrs jackson-mapper-asl jackson-xc javassist javax-websocket-client-impl javax-websocket-server-impl javax.annotation-api javax.el javax.inject javax.persistence javax.servlet-api javax.servlet.jsp javax.servlet.jsp-api javax.servlet.jsp.jstl javax.websocket-api jcommander jersey-client jersey-common jersey-container-servlet jersey-container-servlet-core jersey-core jersey-guava jersey-json jersey-media-json-jackson jersey-media-multipart jersey-multipart jersey-server jersey-servlet jetty-annotations jetty-continuation jetty-http jetty-io jetty-jndi jetty-jsp jetty-plus jetty-schemas jetty-security jetty-server jetty-servlet jetty-servlets jetty-util jetty-webapp jetty-xml jna jna-platform joda-time jsr166 jt400_jdk16 knowledge-api knowledge-internal-api linked-binaries liquibase log-viewer mail maven-shared-utils mimepull mockito-all mvel2 neethi ojalgo ojdbc6 org.apache.taglibs.standard.glassfish org.eclipse.jdt.core osgi-resource-locator postgresql scripting-client slf4j-api slf4j-grid sqljdbc4 stax2-api stringtemplate tasks validation-api websocket-api websocket-client websocket-common websocket-server websocket-servlet windowsjnasecurity woodstox-core-asl wsdl4j wss4j xml-resolver xmlbeans xmlschema-core xmlsec

Does Infor contribute back to the free/libre software community? Individual Infor developers probably contribute to free/libre software with bug fixes and documentation (congratulations). But I have not seen Infor as a company officially sponsor events, fund projects, contribute code, or provide developers to free/libre software. I do not know that they do or that they do not. If you know, please leave me a comment.


It is admirable that Infor provides M3 based on an open source platform as an option, it illustrates Infor’s commitment to the cloud and open platforms. However, the narrative is not clear as the required “open source” platform actually requires commercial products, at cost, that have restrictive licenses, with closed source code, possibly due to a business collaboration. For-profit corporations can choose to be commercial, closed source, and collaborate with partners, to fund product development and to protect intellectual property, but then the narrative should be made clear. Is there a technical reason? Is Infor misappropriating “open source”? Is Infor giving back to the free/libre software community? What do you think? Let me know in the comments below.

Developing H5 Client scripts – Part 1

The day came I have to develop a script for Infor M3 H5 Client with M3 API calls for a customer. This post will add to my previous post, to Scott’s three previous posts, and to Karin’s previous post.


Scripts for H5 Client are written in the JavaScript programming language (ECMAScript). Scripts for Infor Smart Office are written in the JScript.NET programming language. Programs for M3 are written in the Java programming language. Despite the similarities, the three languages are different. Smart Office scripts will NOT execute in H5 Client; you will have to re-write most of the code and be familiar with functional programming, jQuery, Deferred, Promises, etc.; it is like back in the days of IBrix.


Here is the M3 H5 Development Guide:


Here are some tips to convert a Smart Office script to an H5 Client script:

Example of a minimal script for Smart Office:

package MForms.JScript {
	class Test {
		public function Init(element: Object, args: Object, controller : Object, debug : Object) {
			debug.WriteLine('Hello, World!');

The equivalent script for H5 Client:

var Test = new function () {
	this.Init = function (scriptArgs) {
		console.log('Hello, World!');

Various ways to get a field and its value compared to norpe’s guide for Smart Office:

var controller = scriptArgs.controller;
var host = controller.ParentWindow;
ScriptUtil.FindChild($, 'WRCUNM')[0]
ScriptUtil.FindChild(host, 'WRCUNM')[0]

UPDATE 2017-06-06: According to the H5 Development Guide, the above is not the recommended API, but controller.GetContentElement().GetElement("WRCUNM") instead.

Example to call an M3 API in H5 script:

ScriptUtil.ApiRequest('/execute/CRS610MI/LstByNumber', result => console.log(result), (error, message) => console.log([error, message]))

UPDATE 2017-06-06: According to the H5 Development Guide, the above is not the recommended API, but MIService.Current.execute|executeRequest instead, but I get error ‘MIService is not defined’; perhaps I do not have the latest version of H5 Client.

Chrome Developer tools

Use the Google Chrome Developer tools:

Use it for the list of global variables, code completion, type reflection, console, dynamic execution, debugger, network monitor, DOM, styles:

Pause execution to introspect global variables:

UPDATE 2017-06-06: In the JavaScript console, you can get the current controller with getActiveController() or MainController.Current.Instances.host_X where X is the controller number.

Administrative tool

Use the administrative tool to import/export H5 scripts:

UPDATE 2017-06-06: To update a script, simply re-import it, click Yes to override, and refresh the M3 panel with Actions > Refresh-F5; there is no cache thus no need to add the version number in the script file name unlike Smart Office.


Attach the script to the panel as usual at Tools > Personalize > Scripts:

Select Actions > Refresh-F5 to load the script:

Use the JavaScript debugger statement in your script to pause execution and invoke the Chrome debugger:

Call M3 API, and refer to my previous post:


That was a quick look at how to develop scripts for Infor M3 H5 Client including calls to M3 API.

Thanks to Scott Campbell of Potato IT for the first look.

Please like, comment, subscribe, share, come author with us, or look at other ways to contribute.

Related documentation

M3 MI Data Import for Web Services (MDIWS)

I just learned the existence of the M3 MI Data Import for Web Services (MDIWS), which is the equivalent of the traditional M3 Data Import (MDI) but using the M3 API REST/JSON endpoint instead of the traditional proprietary binary endpoint.

The tool and documentation are straightforward, so I will just promote it here with some screenshots:

Here are the executable and documentation:

Here is a sample semicolon separated CSV file with data, no header:

Here is the tool in action:

As a reference, here is the traditional M3 Data Import tool:

Thanks Björn P. for the tool.

That’s it!

Access Control on Grid Management Pages

It is my great pleasure to be an author of M3 Ideas. Thanks very much for Thibaud’s invitation.

I put my foot into M3 water five years ago and M3 Ideas has been giving me great help in developing my technical skills since then. It is my great honor to share my work and make contributions to it.

The issue of access control on grid management pages has been a trouble to me for nearly two years. The installation web page of ISO, in our case, http://BE Server:19005/LSO/index.html is very close to the grid information page, http://BE Server:19005/grid/info.html and the grid management pages, http://BE Server:19005/grid/ui/#. It is fairly easy for a user with web skills to figure out the latter two web pages and he/she can explore and check basically all the grid information.

Although the grid management pages requires credentials to log on to be able to start or stop a process, a user actually can try the default account,  and the famous password, which are mentioned by the Companion, to get full control. This is not a joke, but a real case. It makes M3 system really vulnerable. Even if users do not make any actions to it, there is no sense and it is ridiculous to disclose all the system information to the public.

We did raise InforXtreme case for Infor to fix it. However, they could not give a robust solution after a long time discussion. The reason is the grid management pages and LSO is sharing the same Java process in the BE server. If you check the TCP connections and processes using netstat in the BE server, you would find there is no way to tell which connection is from the grid management pages visit or from LSO request, which is the biggest technical challenge.

After many tests it seems the most feasible solution is to analyze each incoming and outgoing TCP packet in the BE sever to see whether there are any patterns. If we can be 100% sure that a remote IP address is visiting the grid management pages according to the patterns, then we can apply IPSec to block it automatically. Although it means that IP address cannot use LSO as well, it can be sorted out by manually removing it from the black list given a promise is made not to visit again. If the promise is broken, there is no second chance for them. It is something like Damocles’ Sword.

So I made a Console Application using C# as follows.

using System;
using System.Collections.Generic;
using SharpPcap;
using SharpPcap.LibPcap;
using System.Text;
using System.Net.Mail;
using System.Diagnostics;

namespace CA_Grid
class CA_Grid
static List<string> jsIPList;

static void Main(string[] args)
jsIPList = new List<string>();

var varDevices = CaptureDeviceList.Instance;

if(varDevices.Count<1) { Console.WriteLine("No devices were found on this machine"); return; } Console.WriteLine("The following devices are available on this machine:"); Console.WriteLine("----------------------------------------------------"); Console.WriteLine(); int i = 0; foreach(var varDec in varDevices) { Console.WriteLine("{0}) {1}", i, varDec.Description); i++; } Console.WriteLine(); Console.Write("-- Please choose a device to capture: "); int varChoice = 0; if (!int.TryParse(Console.ReadLine(), out varChoice) || varChoice>=i)
Console.WriteLine("The device is not valid!");

ICaptureDevice varDevice =varDevices[varChoice];

varDevice.OnPacketArrival += Device_OnPacketArrival;

varDevice.Filter = "ip and tcp";
Console.WriteLine("-- Listening on {0}, hit 'Ctrl-C' to exit...",varDevice.Description);


varDevice.OnPacketArrival -=Device_OnPacketArrival;

private static void Device_OnPacketArrival(object sender, CaptureEventArgs e)
string varMIP = "BE Server IP Address";
if (e == null || e.Packet == null)

if (e.Packet.Data == null)

var varPacket = PacketDotNet.Packet.ParsePacket(e.Packet.LinkLayerType, e.Packet.Data);
if (varPacket == null)

if (varPacket.GetType()!=typeof(PacketDotNet.EthernetPacket))

var varIP = (PacketDotNet.IpPacket)varPacket.Extract(typeof(PacketDotNet.IpPacket));
if (varIP == null)

string varDIP = varIP.DestinationAddress.ToString();
string varSIP = varIP.SourceAddress.ToString();

if (varSIP != varMIP)

var varTCP = (PacketDotNet.TcpPacket)varPacket.Extract(typeof(PacketDotNet.TcpPacket));
if (varTCP == null)

if (varTCP.PayloadData == null)

var varData = Encoding.UTF8.GetString(varTCP.PayloadData);

if (varData == null)

string varDPort = varTCP.DestinationPort.ToString();
string varSPort = varTCP.SourcePort.ToString();

bool varHTTPS = varSPort == "443";
bool varHTTP = varSPort.Contains("19005") && varData.Contains("text/html") && varData.Contains("gzip");
if ((varHTTPS || varHTTP) && !jsIPList.Contains(varDIP))

string varWay = varHTTP ? "HTTP" : "HTTPS";
string varM1 = "----------------------------------------------------";
string varM2 = string.Format("{0}, {1}, {2}", DateTime.Now, varDIP, varWay);
string varM3 = "Original IP packet: " + varIP.ToString();
string varM4 = "Original TCP packet: " + varTCP.ToString();
string varM5 = "Original TCP Header: " + varData;

if (varDIP != "IP to Exclude")
using (var varProcess = new Process())
varProcess.StartInfo.FileName = "cmd.exe";
varProcess.StartInfo.UseShellExecute = false;
varProcess.StartInfo.RedirectStandardInput = true;
varProcess.StartInfo.RedirectStandardOutput = true;
varProcess.StartInfo.RedirectStandardError = true;
varProcess.StartInfo.CreateNoWindow = true;

string varCommand = "netsh ipsec static add filter filterlist=\"IP_Filter_Grid\" srcaddr=" + varDIP + " dstaddr=me protocol=TCP mirrored=No";
varProcess.StandardInput.AutoFlush = true;


using (var varSMTP = new SmtpClient("Mail Forwarder IP Address"))
using (var varMail = new MailMessage())
varMail.From = new MailAddress("from address");
varMail.To.Add("my e-mail address");
varMail.Subject = "Unauthorised Access to Infor Grid Management Pages";
varMail.Body = varM1 + "\r\n" + varM2 + "\r\n" + "\r\n" + varM3 + "\r\n" + "\r\n" + varM4 + "\r\n" + "\r\n" + varM5;
catch (Exception ex)

SharpPcap can be downloaded from GitHub. It has two Dlls, SharpPcap for capturing packets and Packet.Net for packet analysis. WinPcap needs to be downloaded and installed into the BE server. There is no need to restart the server after installation.

The console application is running in an asynchronous mode, so there is trivial impact on the M3 performance.

The script starts with detecting all the devices first. Then it asks for a device number to listen to. Each device could be a network adapter. A filter is applied to the device for IP and TCP packets. An event to capture the packets is attached to the device. Finally the listening starts.

The event handler has the key logic.

1. Two patterns to find the visit to the grid management pages.

(1) HTTPS: The source port would be 443.

(2) HTTP: The packet contains text/html and gzip.

HTTPS communication is encrypted, so we cannot analyze the packet content. Fortunately LSO never uses the port of 443.

2. If the destination IP address is not on the white list, then it would be added to the IPSec filter list. We need to manually create a IPSec policy and a IPSec filter & Action beforehand.

3. Console would output the captured information.

4. An e-mail alert would be sent with the captured information.

5. A global variable of jsIPList is used to keep the IP addresses already captured to avoid repeated alerts.

Then it works. There were three IT users from local division, who still tried to access to the grid management pages on Monday as usual. Then they found they could not visit it any more, as well as LSO. So far there are no normal users to be blocked, no matter whether they run M3 programs, or download LSO from the installation web page. All of sudden the two-year headache is gone.

If you have the similar concerns to me, I hope the above solution would give you a ride. If you have got any issues using the solution, please reply to this post or send me an e-mail at

Finally my heartfelt appreciations to all the authors on this website, as well as the author of SharpPcap and Packet.Net.

Infor e-Commerce XML Gateway

Here is my first test of the Infor e-Commerce XML Gateway.

It is something like


The XML Gateway is an API in Infor e-Commerce, for third-party software to make requests to e-Commerce, e.g. to create an order, to get an invoice, or to delete an item. The requests are XML documents, in the proprietary IdealXML schema, sent to e-Commerce over HTTP, targeting the e-Commerce Business Objects and methods.


The XML Gateway has existed since the early days of Ideal Seller and e-Sales about 20 years ago:
9 3___ 8


The current part number is M3C-SGX Infor e-Commerce B2B XML Application Adapter:

Is MEC required? No.

Despite what the Infor sales and documentation say, Infor ION, Infor M3 Enterprise Collaborator (MEC), and the e-Commerce Extension for MEC, are NOT required to use the XML Gateway; the XML Gateway is built-in e-Commerce. MEC is suggested for it provides useful features such as development tools, transaction management, persistence, XML transformation, connection pooling, logging, monitoring, management, etc. Apart from that, you can use any other software that does XML over HTTP. Besides, if you were to use MEC, it would have to be the ancient version which is probably not compatible with the MEC you already have for M3:


There is some documentation available. The greatest amount of information is located in the Infor e-Commerce Development Studio User’s Guide, and there is some in the Developer’s Guide, Administration Guide, and Configuration Guide for Infor ION:
5__ 6__ 7 14

Business Objects

The business objects and methods of the XML Gateway are listed in the Business Center at Gateway > Requests:

The code is automatically generated from the e-Commerce Development Studio, e.g. Business Object Item and method GatewayDetails to get the details of an item by input parameter ItemID:
40 41 42 43 44

Source code

For the curious of us, we can peak at the source code.

The source code starts at /infor-ecom/src/common/gateway.jsp and includes the automatically generated JSP fragment Gateway.jspf:

And the e-Commerce Java library common-10.0.0.jar includes the class com.intentia.iec.businessobject.input.XMLRequest which parses the XML input:

That is sufficient to start peaking at source code.

Furthermore, the e-Commerce Extension for MEC ecom-extension-9.0.0.jar includes the class com.intentia.iec.meci.http.HttpRequester which sends the HTTP request:

And the ION Connector’s MEC Custom Channel iecprotocol-2.0.0.jar includes the class which also sends an HTTP request:


There are sample XML requests in the proprietary IdealXML schema located at C:\Program Files (x86)\Infor\Infor e-Commerce\XML Sample Documents\IdealXML 2.0\:
16 17


The XML requests are validated with the proprietary IdealXML Schema located at Infor e-Commerce Development Studio\Infor e-Commerce Extension for Enterprise Collaborator\dist\e-Commerce\request.xsd:

The Development Studio User’s Guide has a chapter The iXML document format.


The latest version of the XML Gateway does NOT provide XSL Transformation (XSLT); it may have been included in the early versions when it was ASP, not anymore. You can easily develop a proxy JSP that does XSLT and that forwards the request to gateway.jsp. I will explore this in a future post. Otherwise, if you use MEC and the e-Commerce Extension for MEC, you can do XSLT in MEC as usual.


To setup the XML Gateway:

Enable the desired Business Object Method (they are all enabled by default), e.g. Item.GatewayDetails:

In the desired Role (e.g. I created role Third-party software), select the Feature Element Gateway User:

In the desired User B2B, select that role:

Still, I am not able to reproduce the setup for another user, and I do not know why.

HTTP request

The HTTP request is of the form:

Content-Type: application/x-www-form-urlencoded
Content-Length: 123



  • I recommend HTTPS (secure), not HTTP (insecure).
  • The scheme, hostname and port number are those of your e-Commerce, e.g.
  • The method can be either GET (with the parameters in the URL) or POST (with the parameters in the request body), but I advise against GET because the user and password would be in the URL, and nodes along the way may store the URL in clear text in the logs; I recommend POST instead.
  • The URL path is /infor-ecom/common/gateway.jsp
  • The media type is application/x-www-form-urlencoded
  • The input parameters user and password are for authentication. Note: the XML Gateway does not accept HTTP Basic authentication.
  • The input parameters object and method are for the business object.
  • The input parameter request is the entire <IdealXML> content.
  • All parameters must be URL-encoded.


For my test, I will call Item.GatewayDetails to get the details of item 9412-0111:

Here is the corresponding IdealXML that I created from the sample XML:

<?xml version="1.0" encoding="UTF-8"?>
<idealXML version="2.0" id="Thibaud test">
               <param name="@LanguageCode">en</param>
               <bindings operand="or">
                  <bindings operand="and">
                     <binding attribute="ItemID" value="9412-0111" operator="eq"/>


  • I removed the <login> and <password> from the <credential> as they are ignored.
  • I removed the <command>’s name and method attributes as they are ignored.


Here is the result in raw and parsed view:

The XML response is the following, successful, with the requested item details:

<?xml version="1.0" encoding="UTF-8"?>
<resultset object="Item">
   <row Description="For ITRAN GE BLACK INKJET CART 10/CTN" GroupCode="OE" GroupName="Impact Inking" IsActive="Y" IsDangerous="0" IsEmphasized="N" ItemCode="normal" ItemCodeID="normalItemCode" ItemField1="WELLS FARG" ItemField2="201502861.00" ItemField3="" ItemField4="12/99" ItemField5="Y" ItemID="9412-0111" Key="8685" MainCategoryID="59052" MinimumQty="0.0000" ModularQty="0.0000" Name=" INK JET EQUIPMENT" SupplierID="" UnitCodeID="CTItemUnit" Weight="2.4940">
      <Category CategoryID="59052" CategoryName=" INK JET EQUIPMENT" InternalName=" INK JET EQUIPMENT (59052)"/>
      <Text Description="For ITRAN GE BLACK INKJET CART 10/CTN" LanguageID="de" Name=" INK JET EQUIPMENT"/>
      <Text Description="For ITRAN GE BLACK INKJET CART 10/CTN" LanguageID="en" Name=" INK JET EQUIPMENT"/>
      <Text Description="For ITRAN GE BLACK INKJET CART 10/CTN" LanguageID="fr" Name=" INK JET EQUIPMENT"/>
      <Text Description="For ITRAN GE BLACK INKJET CART 10/CTN" LanguageID="it" Name=" INK JET EQUIPMENT"/>


For troubleshooting:

Inspect the HTTP response headers that indicate either success:

XMLGatewayStatusCode: 200
XMLGatewayMessage: OK

Or an error:

XMLGatewayStatusCode: 401
XMLGatewayMessage: Login failed
XMLGatewayStatusCode: 403
XMLGatewayMessage: Access to requested object or method not allowed
XMLGatewayStatusCode: 500
XMLGatewayMessage: Internal error while executing Gateway method

The Development Studio User’s Guide has a chapter Gateway error messages, with codes, but the codes do not match this.

It is better to look in the logs at C:\IBM\WebSphere\AppServer\profiles\AppSrv01\logs\server1\SystemOut.log:


  • The user and password are echoed in clear text in the logs, it is insecure:
  • The XML Gateway accepts requests over plain HTTP (instead of HTTPS) even though the request contains the user and password and other private data in clear text, it is insecure.

Future work

  • Force HTTPS (secure) by default, disable HTTP (insecure).
  • Do XSL transformation (XSLT).
  • Finish reproducing the setup.
  • Try the e-Commerce Extension for MEC.
  • Try the WSDL and the Infor e-Commerce Web Service Specifications for Synchronous Calls.
  • Try other Business Objects and methods.
  • Try custom Business Objects and methods.
  • Understand more about the bindings.


That was my first test of the XML Gateway in Infor e-Commerce, for third-party software to make requests to e-Commerce, e.g. to place an order or get the details of an item. I have more work to do if I want to master the XML Gateway.

That’s it!

Please like, comment, subscribe, share, participate.

Subversion in Infor e-Commerce Development Studio

Here is an illustration of how to setup Apache Subversion for source control in Infor e-Commerce Development Studio, such that multiple developers can work on the same e-Commerce project at the same time, for team development.


The problem is that by design an Eclipse workspace cannot be shared, i.e. there can only be one developer using a workspace at a time, others will get the message “Workspace in use or cannot be created, choose a different one”:

Small teams can setup multiple workspaces, one per team member, share the same source code, and mutually agree on which non-overlapping files to work on, being careful to not touch each other’s files. This is workable in small teams, but is not scalable for large teams or inexperienced team members as there is risk of data loss.

The correct solution is to setup source control software to manage that.


Supposing there a N team members doing e-Commerce development, we will setup one Subversion server & repository, and N e-Commerce Development Studios & workspaces all using the same Subversion repository. In my case, there are three developers, Thibaud, Chris, and Madan, thus I will setup three workspaces to use the same Subversion respository.


There is a dedicated chapter in the Infor e-Commerce Development Studio User’s Guide:

Even better, there is a dedicated document in the M3 Adaptation Kit Version Control Guide, not for e-Commerce, but similar setup:

What about Git?

I wish I could use Git, instead of Subversion. I believe Git would work for e-Commerce just as well as Subversion does. The e-Commerce Development Studio requires Subclipse during installation; I could install Subclipse just to surpass that, then ignore it, and install Git. However, I asked Infor Support if Git would work with e-Commerce, and they responded it has not been tested and certified to completely work, and should problems arise due to an effect from using Git, they cannot provide support for it. So I will skip Git for now, and I will try it another time.

1. Subversion server

Install a Subversion server of your choice (e.g. Apache Subversion, TortoiseSVNVisualSVN):

Create the users (e.g. THIBAUD, CHRIS, MADAN):

Create a new repository, and save the Repository URL in your notes:
5_ 5__

Schedule a regular backup of the repository, e.g.:

The Subversion repository is now ready to host the e-Commerce projects.

2. Bootstrap

Choose one user (e.g. Thibaud) to bootstrap the e-Commerce projects (e.g. B2C and B2B) to the Subversion repository for the rest of the team (e.g. Chris, Madan).

I make the assumption that the Eclipse workspace is private (non-shared), e.g. C:\Users\THIBAUD\workspace\ , that it already has the e-Commerce Development Studio fully setup, and that the e-Commerce projects (e.g. B2C, B2B) are fully setup (see previous post):

Note 1: If the projects are in a shared workspace, e.g. C:\e-Commerce\workspace\, and you want to move them to the private workspace, simply cut and paste the project folder from the shared workspace to the private workspace.

Note 2: Don’t make a duplicate (copy) of a project, because after we bootstrap the project to the Subversion repository, any duplicate of that project would be out of reach of Subversion and deprecated.

Go to Eclipse > Window > Open Perspective > SVN Repository Exploring, create new Repository Location, and enter the URL of the Subversion repository created earlier, with the username and password of the workspace’s user (e.g. THIBAUD):

For each project (e.g. B2C, and B2B), do the following:

Select > Team > Share Project:

Select repository type SVN:

Use existing repository location:

Change folder to trunk:

Enter a commit comment, e.g. Initial import:

Wait for the synchronization to finish:

Select Team > Commit:

Select everything except the following files and folders, and enter a commit comment, e.g. Initial commit:

Wait for the SVN Commit to finish:
8 8_

Each file now has a revision number, date, and author:

Verify in Team > Show history:

Verify the repository in the Subversion server:

The project is now ready for the rest of the team to checkout.

Repeat for each project (e.g. B2C, B2B).

3. Other team members

Now we can setup the Eclipse workspaces and projects for the rest of the team (e.g. Chris, Madan).

Regarding the Eclipse IDE itself, you can choose to use a private install for each user, a shared install for all users, or a shared configuration, see the Eclipse multi-user installs.

I make the assumption that each user has the e-Commerce Development Studio fully setup, with a private workspace, e.g. C:\Users\CHRIS\workspace\ , and with no e-Commerce project (e.g. no B2C, B2B), like so:

Setup the SVN Repository for this user and password (e.g. CHRIS):

Expand the trunk, and checkout the projects (e.g. B2C, B2B):

Leave the default values and click Next:

Leave the default workspace and click Finish:

Wait for the SVN Checkout to finish:

Verify the result:

Select the Active project:

Go to Business Objects tab, click Generate Stub Codes, and wait for it to finish:
10__ 10___

That will create the files:


If not, you may have to clean, re-build, and/or refresh the project.

This team member’s environment is now all set.

Repeat for each remaining team member.

4. Everyday development

For everyday development:

Set the Active Project as usual:

Select Team > Update to HEAD to update the project with the latest changes of everyone else:

Make the changes you need to any of the files (e.g. JSP, CSS, HTML), and save your changes:

Deploy the application or presentation as needed:

Test your changes in e-Commerce as usual:

Repeat as needed: make changes, deploy, test.

When done, select the files you modified, select Team > Commit, and enter a comment of your changes; ensure you select only the files you changed, nothing else:
11__ 11____

Verify in the SVN Repository > Show History.

Now, when the other team members select Team > Update to HEAD, they will see your changes in their workspace.

Future work

Next time, I would like to try with Git instead of Subversion.


That was an illustration of how to setup Subversion in e-Commerce for a team to work on the same project at the same time. The first user bootstraps the project to the Subversion repository, and the other users checkout that project from the repository.

Special thanks to Wayne Liu of Infor and Marina Baldan of CAD IT for the help.

That’s it!

Please like, comment, subscribe, share, author.

Relate articles

OCI PunchOut in Infor e-Commerce

Here is my first test of Open Catalog Interface (OCI) in Infor e-Commerce.

About OCI

OCI is a standard from SAP from around year 1999:

It competes with the cXML standard from Ariba also from around year 1999.

I will use OCI for PunchOut with e-Commerce, i.e. for a buyer to place an order in a seller’s e-Commerce, and retrieve the order in the buyer’s system (e.g. SAP, PeopleSoft).


Infor e-Commerce supports OCI out of the box. Unfortunately, the documentation is meager, and when Infor acquired Lawson they removed the examples and screenshots of all documentation:

Thankfully, the old Lawson documentation still has examples and screenshots:

If we are familiar with Infor e-Commerce and OCI, and if we have the old documentation, we can figure it out.

1. Configuration for seller

Let’s configure the seller’s e-Commerce B2B, with role, customers, and users.

One time only, go to Business Center > Roles, select the desired role (e.g. Reseller), enable the Feature Element OCI Capable, and click Save:

For each customer, go to Business Center > Customers B2B > select a customer (e.g. 66045), and in the Customer Details > OCI Agreement, enter the Agreement Name/Description, Valid From/To, and Contact Person Buyer/Seller, and click Save:

For each user of each customer, go to Business Center > Users B2B, select the user (e.g. Thibaud), and in User Details > User Roles, enable the OCI Capable role (e.g. Reseller), and click Save:

2. Configuration for buyer

Setup the buyer’s OCI software (e.g. SAP, PeopleSoft) to launch e-Commerce with the URL in the following format:


  • is the base URL to Infor e-Commerce B2B Customer Center (replace the host, port, and path as needed). I had tried the B2C URL, but the reqpage had no effect, it only worked with the B2B URL.
  • Default2.jsp is the e-Commerce OCI page
  • @user.userid is the e-Commerce userid
  • @user.password is the e-Commerce password
  • reqpage=ItemList.jsp is the e-Commerce parameter to request the Item List landing page
  • HOOK_URL is the buyer’s OCI URL that will receive the e-Commerce order (ask the buyer for that URL), e.g.

As usual, the parameter values must be URL-encoded in the URL.

That URL will launch e-Commerce, will authenticate the user, and will land the user in the items page, ready for the user to place an order.

3. Place an order

The user launches e-Commerce using the URL configured above (e.g. from SAP, PeopleSoft), the URL will authenticate the user to e-Commerce, and land directly in the e-Commerce items list:

Add items to the shopping cart as usual, go to View cart & checkout. Then, click Retrieve Order, it is a new button for the OCI Capable role:

At that moment, e-Commerce will logout, and will send the order to the buyer’s sytem by making an HTTP POST request to the specified HOOK_URL with the order details as x-www-form-urlencoded name/value parameters in the body:

Verify the order on the buyer’s system (e.g. SAP, PeopleSoft). That completes the process flow.


There is a page OciTestPage.jsp that you can use in HOOK_URL for testing purposes:

But it seems to have a few problems in my environment, and I kept getting an HTTP 302 re-direct to the home page, so I had to fix a few things:

  • The parameter NEW_ITEM-VENDORMAT had an incorrect index, I had to correct it manually from [2] to [0].
  • It did not work with my User B2B Thibaud, it says “You are currently not authorized to see the requested page. Please login and try again.” I had to switch to admin, I must be missing a Role.
  • I had to force the parameter retrieveorder to any non-null value.
  • There is a parameter ocirul which I do not know how to use.

Future work

  • OCI does not support edit and cancel operations of requisition orders, unlike cXML, so I must find a workaround.
  • Most OCI implementations have customized tweaks, deviating from the standard, so I have to find the source code for OCI in e-Commerce, and see if I can modify it accordingly.


That was my first test of OCI in Infor e-Commerce for a buyer to PunchOut to a seller.

Special thanks to Wayne Liu and Karl Bonne at Infor for the help.

That’s it!

Please like, comment, subscribe, share, author.

How to install Infor e-Commerce Development Studio

Here is an illustrated guide on how to install Infor e-Commerce Development Studio.


Infor e-Commerce is the B2C and B2B solution for Infor M3. Here is some history I found from the archives. The product was started by Danish-based Catalog-International in 1997, which was acquired by Swedish-based Intentia International in 2002, which was acquired by US-based Lawson Software in 2005, which was acquired by Infor in 2011. Over the years, it has survived many cycles of re-branding, refactoring, re-integration, and feature changes. Its various names have been: Ideal Commerce Suite (Ideal Seller & Ideal Procurement), Movex e-Sales, Lawson e-Sales, Infor e-Commerce, and now Infor Rythm on Infor CloudSuite. The Development Studio is the current plugin for Eclipse to develop for e-Commerce. It is loosely inherited from the old Cat@log Builder and ide@l Design Center.


You can download the documentation from Infor Xtreme > Search > Browse Documentation > Show All Product Lines > Infor e-Commerce:

I will follow the Infor e-Commerce Development Studio Installation Guide and User’s Guide. They do not have screenshots, so I will show you screenshots here:

I will assume the Infor e-Commerce server is already installed and setup with the SQL Server database, IBM WebSphere Application Server (WAS), and IBM HTTP Server (IHS). I will install e-Commerce Development Studio version on a Windows x64. There are strict system requirements for ancient versions of software.

1. Java Development Kit

Install the Java SE Development Kit (JDK) version 1.6.0_45. Set the environment variables JAVA_HOME and PATH:

2. Eclipse IDE

Install Eclipse IDE for Java EE Developers version 3.7.1:

Note: I had used the lasted Eclipse version 4.6, but e-Commerce Development Studio threw an error during installation, and I resolved it by reverting to the old Eclipse version 3.7.1:
Missing requirement: DesignCenter Plug-in 1.0.0 (com.lawson.eap.designcenter 1.0.0) requires 'bundle org.eclipse.core.runtime.compatibility 3.2.100' but it could not be found

To install Eclipse, simply download and unzip, e.g. C:\e-Commerce\eclipse\ :

Then, launch Eclipse, and select a workspace, e.g. C:\Users\X\workspace\ :

You can verify the result in Eclipse > About:

Change the Eclipse > Preferences > Java > Compiler, to JDK compliance 1.6:

By default it uses default JDK compliance 1.2, but then e-Commerce will throw compilation errors:
The return type is incompatible with AbstractSelectComponent.getResultset

3. Subclipse plugin

Install the Subclipse plugin version 1.8.x for Eclipse, even if you will not use it:
4 4_

Note: If you do not install Subclipse – for instance if you want to install Git instead – e-Commerce Development Studio will throw an error during installation:
Missing requirement: DesignCenter Plug-in 1.0.0 (com.lawson.eap.designcenter 1.0.0) requires 'bundle org.tigris.subversion.subclipse.core 1.6.18' but it could not be found:

Note: I used the latest Subclipse version 4.2.x, but Eclipse threw an error, and I resolved it by reverting to the old Subclipse version 1.8.x:
Subclipse talks to Subversion via a Java API that requires access to native libraries. Those libraries were either not found or an incompatible version was loaded.

4. e-Commerce Development Studio plugin

Download the Infor e-Commerce Development Studio plugin from Infor Xtreme > Downloads > Products > Customer Relationship Management > Infor e-Commerce:

Unzip the download, and install the plugin:
0__ 6

Verify the installation details:

In Window > Open Perspectives, select the Infor e-Commerce Development Studio perspective:

e-Commerce Development Studio is ready to be used.

5. Infor Application Installer (IAI)

Install the Infor Application Installer (IAI):

Note: I had an error earlier because of the missing JDK in the PATH:

Select Install IAI:

Find the WAS folder on your e-Commerce server, e.g. C:\IBM\WebSphere\AppServer\ :

In IAI, click Browse, and select the WAS folder. IAI will automatically find the profile (e.g. AppSrv01), cell name (e.g. Node01Cell), node name (e.g. Node01), and internal server name (e.g. server1). Set the Admin login name and password, and click Start:
7____ 7______

You can verify the installation log in the temp folder, e.g. C:\Users\X\AppData\Local\Temp\Y\install-iai\ :

You can verify the resulting installation folder, e.g. C:\IBM\WebSphere\AppServer\profiles\AppSrv01\installedApps\WIN-70T65OKA2OJNode01Cell\Publish.ear\ :

You can verify the IAI About page, e.g. http://localhost:9080/publish/About :

The Application Installer is now ready to deploy e-Commerce applications.

6. New Application

Back in Eclipse, select File > New > New Registered Application:
8___ 8_

Enter a Project Name and Application Name, e.g. infor-ecom:

It will create the new project, and it will automatically build the workspace and generate the file businessobjectmethods.jar, wait for it to finish:

Whenever a timestamp changes in the project, e-Commerce Development Studio will re-build the project, and it can be time consuming and frustrating. To avoid waiting unnecessarily, un-check the Project > Build Automatically, and remember to manually Build Project before deploying:

Go to menu Infor e-Commerce Development Studio > Set Active Project, and select the project:

Go to menu Infor e-Commerce Development Studio > Deployment Settings, and enter the Deployment Target Properties, with Web Server Name as defined in WAS:
10 10_ 10__

Go to tab Data Sources > MS SQL Server > sqlserver > right-click > Connection, and add a new connection, with the e-Commerce database information:
11_ 11__ 11

The e-Commerce application is now ready to be deployed.

7. Deploy

Build the Project, and wait for the build to finish.

In the menu Infor e-Commerce Development Studio, select Deploy Application:
12 12_

The e-Commerce application is now deployed on WAS, and ready to use. There is no need to restart WAS.

8. Result

Test the resulting e-Commerce application.

Customer Center:

Busines Center:

We now have a working e-Commerce Development Studio, project, and website to develop with.

9. Everyday development

For everyday development:

We can now modify the JSP, CSS, HTML, and other files in the src folder, re-build the project, and re-deploy as needed:

It is quicker to deploy just the presentation, either bc, cc, or common, depending on where we modified the files, rather than re-deploying the entire application:

Remember to set the active project again after each time you exit Eclipse.

Future work

In future work, I would like to:

  • Setup a B2B application (it involves swApp.vbs), in addition to the default B2C
  • Setup a team environment with Subversion for multiple developers to collaborate on the same e-Commerce application at the same time without overriding each other.
  • Setup logging, troubleshooting, and Java debugging for e-Commerce.
  • Deploy multiple applications on the same WAS.
  • Develop JSP that call Business Objects.
  • Use the XML Gateway.
  • Use Git instead of Subversion.
  • Set the Active Project by default.


That was a guide on how to install Infor e-Commerce Development Studio, with lots of illustrations to compensate for the lack of screenshots from the Infor documentation. e-Commerce Development Studio relies on many standards (J2EE, Eclipse, Subversion, etc.), as such it is familiar territory to install. But it requires ancient versions of its software requirements that if not met will cause errors. And the mystery of the e-Commerce Development Studio’s automatic build, at unexpected times, and lengthy, is a known frustration.

That’s it!

Please like, comment, share, subscribe, and come author with us.

M3 Infor Enterprise Search – Search query examples V2

Infor published a new version of the Search query examples document for
M3 Infor Enterprise Search (IES) available on the Knowledge Base at KB 1687355.

IES is an important part of M3 to increase user productivity, like a Google Search for M3.

Here are the topics of the document:

  • Simple search
  • Advanced search
  • Search including reserved words
  • M3 IES usage through API calls
  • Multi level key search
  • Very advanced search queries
  • Lucene references

Here is a sample screenshot of the document:

See the document at KB 1687355.

Thank you Magnus.