Technology Blogs by Members
Explore a vibrant mix of technical expertise, industry insights, and tech buzz in member blogs covering SAP products, technology, and events. Get in the mix!
cancel
Showing results for 
Search instead for 
Did you mean: 
former_member187673
Active Participant

Introduction

In this blog I demonstrate how to create an SAPUI5 frontend for SAPs Solution Sales Configuration system.

SAP Solution Sales Configuration is a system that helps customers to configure and sell solutions made of complex product combinations. It is integrated into both CRM and ECC.

See here for more details - https://help.sap.com/saphelp_ssc10/helpdata/en/f4/ee271973864f48ad502c070b50ef8a/frameset.htm

http://www.youtube.com/watch?v=Y3ogJzOtkVA

The UI will be dynamically generated at runtime creating the master lists and detail controls based on the instances and characteristics of the configuration.

In this application I am using the “sap.m.*” library controls to develop the UI for a mobile solution. For the layout I am using a splitApp control so that I have the master page on the left hand side that will contain a list of instances in the configuration and a detail page on the right hand side which will contain the characteristics of the instances. And of course when run on a mobile device the UI will be split so that you will see either the master page or the detail page. See here for more details on the SplitApp control - https://sapui5.netweaver.ondemand.com/sdk/#docs/guide/SplitApp.html

High Level Description

  • At a high level I have a js view which creates the splitApp control and a dummy master and detail page which are added to the splitApp (I will explain why I did this later on in the blog).
  • In my web.xml file I defined a servlet mapping for my servlet class SSCServlet which will be the gateway to the SSC engine.
  • In my controller I have an init function which makes a call to the SSCServlet class which in turn calls a java class called SSCClient.
  • The SSCClient will talk to the SSC configuration engine. Firstly it creates a configuration session and then a configuration instance for the knowledge base that I’m using. From this configuration it gets all the instances and instance characteristics.
  • This data is then formatted into a json object to send back to the controller init function via the servlet class.
  • Once the init function receives the json response, it parses out the json and builds out the master and detail pages for the configuration.
  • Each control on the details page will have a change or select event which will call either the onChange or onSelect controller functions.
  • These functions will again send a request to the SSCServlet class to indicate a selection has taken place. The SSCServlet class calls out to the SSCClient class again.
  • The SSCClient sets the new value for the characteristic in the configuration object and via the IDeltaBean object it captures all the configuration changes that have occurred as a result of the characteristic value change.
  • From this IDeltaBean data the class generates a json object with all the changed values and sends this back to the controller functions via the SSCServlet class.
  • In the controller it parses the json response and updates the UI page controls with new values and/or new instances.

Details

SSC_UI5_V2.view.js

In the view create the SplitApp control and add a dummy master and detail. The dummy pages are added so that the SplitApp control gets initialized properly. You may run into javascript errors on initialization if not added.

sap.ui.jsview("ssc_ui5_v2.SSC_UI5_V2", {
      getControllerName : function() {
         return "ssc_ui5_v2.SSC_UI5_V2";
      },
      createContent : function(oController) {
      
       jQuery.sap.require("jquery.sap.resources");
       var oSplit = new sap.m.SplitApp("splitApp");
      
       //Add dummy master and detail pages so that the splitApp gets initialized
       var oDummyMaster = new sap.m.Page("dummyMaster");
       var oDummyDetail = new sap.m.Page("dummyDetail");
         
          oSplit.addMasterPage(oDummyMaster);
          oSplit.addDetailPage(oDummyDetail);
          oSplit.setMode("ShowHideMode");
          return oSplit;
      }
});

web.xml

In the web.xml define the servlet mapping as follows:

<!-- ============================================================== -->
  <!-- SSCServlet servlet                                              -->
  <!-- ============================================================== -->
 
  <servlet>
    <servlet-name>SSCServlet</servlet-name>
    <servlet-class>com.ssc.ui.demo.SSCServlet</servlet-class>
  </servlet>
  <servlet-mapping>
    <servlet-name>SSCServlet</servlet-name>
    <url-pattern>/SSCServlet/*</url-pattern>
  </servlet-mapping>

SSC_UI5_V2.controller.js (init function)

On initialization of a SAPUI5 application the onInit function is called. Here we send a request to the SSCServlet URL which was defined in the previous step in the web.xml file. If the call is successful then we should receive a Json response object with the details of what instances and characteristics we need to display in the UI. This Json object is passed to the createUIControls function which will create the controls for the UI.

onInit : function() {
  $.ajax({
   type : "POST",
   url : "SSCServlet",
   data : {
    command: "initialize"
   },
   success : function(data) {
    sap.ui.controller("ssc_ui5_v2.SSC_UI5_V2").createUIControls(data);
   },
   error : function(data) {
    alert("Failed:" + data);
   }
  });
},

SSCServlet.java

As stated above the controller init function sends a request to the SSCServlet object and the doGet method is called. The doGet method specifies a json response content type and processes the request. For initialize it calls the getUIElements method of the SSCClient object, and writes the output to the response object.

public class SSCServlet extends HttpServlet {
private static final long serialVersionUID = 1L;
protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
    }
/**
* @see HttpServlet#doPost(HttpServletRequest request, HttpServletResponse response)
*/
protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
 
  JsonObjectBuilder objectBuilderOut = Json.createObjectBuilder();
 
  String action = request.getParameter("action");
 
  response.setContentType("application/json");
 
  if (action.equals("initialize"))
  {
   SSCClient client = new SSCClient();
     
   JsonObject resp = client.getUIElements();

   response.getWriter().print(resp);
  }
  else if (action.equals("change"))
  {
.
.
.

SSCClient.java

When the getUIElements method of the SSCClient is called it calls a number of methods in the SSCClient object to talk to the SSC engine and pull out the instance and characteristic data of the configuration. Here are some of the main features of this code:

  • Create a new configuration session:
IConfigSession cnfgSession = new ConfigSessionLocalImpl();
cnfgSession.createSession("true", sessionId, dataSourceName, false,
    useOnlyLocalDatasource, languageISOCode);

  • Create a new configuration from the above session
String configId = cnfgSession.createConfig(rfcConfigId, productId,
      productType, kbLogSys, kbName, kbVersion, kbProfile,
      kbIdInt, kbDateStr, kbBuild, useTraceStr, context,
      setRichConfigId, useLocalDeltaBean);

  • Get the instance data from the configuration session
IInstanceData[] instData = cnfgSession.getInstances(configId, getMimeObjStr);

  • For each instance from the above array we can get the characteristics by calling the getCstics method passing in the config id and the instance id
ICsticData[] allCstics = cnfgSession.getCstics(configId, instId);

  • Using the JsonObjectBuilder we can build up the json objects for the configuration. The properties of the characteristic determine whether the characteristic is to be displayed and what type of control should be used for the characteristic e.g. if you are allowed choose multiple values for a characteristic then create a sap.m.List control with multiSelect mode. Or if it’s single select and there are more than 4 selection values then use a sap.m.Select control, etc…here is an example of this:
.
.
if (csticDat.getCsticVisible())
{
labelID = csticDat.getCsticHeader().getCsticName() + "Lab"+ inst;
objectBuilderLabel.add("id", labelID);
objectBuilderLabel.add("text", csticDat.getCsticHeader().getCsticLname());
objectBuilderLabel.add("design", "sap.ui.commons.LabelDesign.Bold"); 
formEleID = csticDat.getCsticHeader().getCsticName() + "FE"+ inst;
objectBuilderFormElemProps.add("id", formEleID);
objectBuilderFormElem.add("properties", objectBuilderFormElemProps);
objectBuilderFormElem.add("Label", objectBuilderLabel.build());
objectBuilderFormElem.add("ResponsiveFlowLayoutData", objectBuilderRfld.build());
ICsticValueData[] csticVal = csticDat.getCsticValues();
String val = null;
if (csticVal != null && csticVal.length > 1 && !csticDat.getCsticDomainIsInterval())
{
  if(csticDat.getCsticHeader().getCsticMulti())
  {
   objectBuilderFormElem.add("List", buildMListJson(csticDat, "sap.m.ListMode.MultiSelect", inst, formEleVarName));
   objectBuilderFormElem.add("type", "sap.m.List");
  }
  else
  {
   if (csticVal.length>4)
   {
    objectBuilderFormElem.add("Select", buildMSelectJson(csticDat, true, inst, formEleVarName));
    objectBuilderFormElem.add("type", "sap.m.Select");
   }
.
.
.

  • Once we have built out the Json object for all the instances and characteristics we pass it back to the servlet object which in turns sends the json response back to the calling init function.

SSC_UI5_V2.controller.js (createUIControls function)

The createUIControls function will parse the Json object sent back from the SSCServlet response and build out the UI controls. e.g. - for each object in the "detailPages" json attribute it will create a new Page

if (object == "detailPages")
{
detailPages = data[object];
for ( var page in detailPages)
{
  newDPage = new sap.m.Page(detailPages[page].properties);

For each form element we get the control type and build out the control as specified:

  controlType = formElems[elem].type;
  switch (controlType)
  {
   case "sap.m.List":
    oCtrlList = new sap.m.List(formElems[elem].List.properties);
    switch (formElems[elem].List.mode)
    {
     case "sap.m.ListMode.MultiSelect":
      oCtrlList.setMode(sap.m.ListMode.MultiSelect);
      break;
     case "sap.m.ListMode.SingleSelect":
      oCtrlList.setMode(sap.m.ListMode.SingleSelect);
      break;
    }
    oCtrlListItems = formElems[elem].List.StandardListItem;
    for (var listItem in oCtrlListItems)
    {
     oCtrlList.addItem(new sap.m.StandardListItem(oCtrlListItems[listItem].properties));
    }
    oCtrlList.attachSelect(sap.ui.controller("ssc_ui5_v2.SSC_UI5_V2").onSelect);
    oFormElement.addField(oCtrlList);
    break;
   case "sap.m.Select":
    oCtrlSelect = new sap.m.Select(formElems[elem].Select.properties);
    oCtrlSelectItems = formElems[elem].Select.Item;
    for (var selectItem in oCtrlSelectItems)
    {
     oSelectItem = new sap.ui.core.Item(oCtrlSelectItems[selectItem].properties);
     oCtrlSelect.addItem(oSelectItem);
     if (oSelectItem.getText()== formElems[elem].Select.selectedVal)
     {
      oCtrlSelect.setSelectedItem(oSelectItem);
     }
    }
    oCtrlSelect.attachChange(sap.ui.controller("ssc_ui5_v2.SSC_UI5_V2").onChange);
    oFormElement.addField(oCtrlSelect);
    break;

All the form elements are added to a FormContainer. The form container is added to the Form, which is added to the new Page and finally the new page is added to the SplitApp control.

 oForm.addFormContainer(oFormContainer);
newDPage.addContent(oForm);
oSplit.addDetailPage(newDPage);

The master pages are built up in a similar fashion.

At this point the UI is built out with master pages and detail pages. The master pages control the navigation in the UI and are based on the instances of the config and the detail pages contain all the characteristics for each instance.

The next step was to handle UI events, e.g. a radio button is selected or a list item is selected from a List.

Each control (sap.m.Select, sap.m.List, sap.m.Input, etc...) will have a change or select event attached to it. These events will send a request to the SSCServlet again passing the change action along with the control that was changed and it's new value.

SSC_UI5_V2.controller.js (onSelect function)

onSelect : function(oEvent) {
  var control = oEvent.getParameters().id;
 
  var controlValue = oEvent.getParameters().listItem.getTitle();
  $.ajax({
   type : "POST",
   url : "SSCServlet",
   data : {
    action: "change",
    controlKey : control,
    controlValueKey : controlValue
   },
   success : function(data) {
    sap.ui.controller("ssc_ui5_v2.SSC_UI5_V2").updateUIControls(data);
   },
   error : function(data) {
    alert("Failed:" + data);
   }
  });
},

Again the SSCServlet doGet method processes this request and passes the control and control value to the SSCClient uiChangeEvent method:

SSCClient (uiChangeEvent method)

Some of the main features of this are as follows:

  • We define an ICsticData and IDeltaBean object.

ICsticData csticDat = null;
IDeltaBean csticBean = null;

  • The IDeltaBean object is the key here. Once the setCsticsValues method is called then the IDeltaBean object will contain all the changed characteristics and instances that have been generated in the SSC engine as a result of the change in the UI control value.

csticDat.setCsticValues(newCsticVal);
csticBean = setCsticsValues(instId,cnfgSession.getRichConfigId(), false,new ICsticData[] { csticDat }, null, null,0);

  • Using the IDeltaBean getChangedCsticsAndValues and getNewInstances methods we can get all the changed characteristics and new instances.

HashMap<String, ICsticData[]> changedData = csticBean.getChangedCsticsAndValues();
ArrayList<IInstanceData> newInstances = csticBean.getNewInstances();

Similarly like we did when generating the json for the intial UI controls we can do the same with the new instances and the changed characteristics. This gets sent back to the onChange or onSelect functions of the controller js via the servlet response. The updateUIControls function is called which parses the json and sets the new values and/or creates the new instance pages and controls.

SSC_UI5_V2.controller.js (updateUIControls function)

The below demonstrates how the new values are set.

for ( var cstic in csticData)
{   
control = sap.ui.getCore().byId(csticData[cstic].CsticName);
var controlType = control.getMetadata().getName();
switch (controlType)
{
  case "sap.m.List":
   var allItems = control.getItems();
   var newCsticValues = csticData[cstic].csticValues;
     
   var newCsticValue = null;
   var newCsticValueAssigned = null;
   for ( var csticVal in newCsticValues)
   {
      
    newCsticValue = newCsticValues[csticVal].CsticValue;
    newCsticValueAssigned = newCsticValues[csticVal].CsticValueAssigned;
      
    for ( var item in allItems)
    {
     if (allItems[item].getTitle() == newCsticValue)
     {
      if (newCsticValueAssigned)
      {
       // check if already selected. if not already selected then select it 
       if (!allItems[item].getSelected())
       {
        allItems[item].setSelected(true);
       }
      }
      else
      {
       // check if already selected. if already selected then deselect it
       if (allItems[item].getSelected())
       {
        allItems[item].setSelected(false);
       }
      }
     }
    }
   }
   break;
     
    
  case "sap.m.Select":
   var allItems = control.getItems();
     
   var newCsticValues = csticData[cstic].csticValues;
   var newCsticValue = null;
   var newCsticValueAssigned = null;
   for ( var csticVal in newCsticValues)
   {
      
    newCsticValue = newCsticValues[csticVal].CsticValue;
    newCsticValueAssigned = newCsticValues[csticVal].CsticValueAssigned;
    
    for ( var item in allItems)
    {
       
     if (allItems[item].getText() == newCsticValue && newCsticValueAssigned)
     {
      control.setSelectedItem(allItems[item]);
      break;
     }
    }
   }
   break;

To give a flavor of what the knowledge base looks like I have included a few screenshots from the SSC Testing tool:

Note: once the Base Model VNX5200 is selected the engine defaults the Platform configuration and the Rack Selection characteristics. It also creates a new Drive Line instance.

And here are the screenshots of the UI5 frontend. Notice the master page on the left with the list of instances and the details on the right with the characteristics of the instances.

When Summary Page is selected it navigates to a new master page with a list of all the child instances under the Summary page instance. The navigation button at the top left allows navigation back to the initial master page.

In the VNX Series Solution select VNX5200 for the Base Model

The Platform Configuration and Rack Selection are defaulted as indicated below

A new Drive Line instance is added to the Storage Components. As Storage Components previously did not have any child instances a new master page is created.

Conclusion

To conclude, the hardest part of the above was figuring out the SSC APIs. Once I was able to pull out the instances and instance characteristics it was relatively straight forward to build up the json object, send it back the UI5 controller and build out the UI from that. The above is just a basic demo and is executed on a local Tomcat instance but gives an idea of what can be done with SAPUI5 as a frontend for SAP Solution Sales Configuration.

4 Comments
Labels in this area