Monday, July 18, 2016

Creating Custom Core In SOLR for WebSphere Commerce


Solr is one of the highly reliable search engine which comes along with WebSphere Commerce Server. By default, Solr contain required configuration to support the search features used by WebSphere Commerce Server. But, during development, there can be some situation where we need to create an additional solr core and configuration to index additional details to Solr to improve the performance of certain functionalities.

Given below steps explains how to create a new Solr core in WebSphere Commerce Server.

Create a new Solr core

Step 1 - Navigate to C:\IBM\WCDE80\search\solr\home and edit solr.xml file. Create a new Solr core by adding the following lines (in bold) inside the <core> tag –

<cores>


<core instanceDir="MC_10001\en_US\CustomData\" name="CustomData_en_US"/>

</cores>


Step 2 – Create a folder structure to place the configuration and data files for indexing the Store Locator details

Navigate to C:\IBM\WCDE80\search\solr\home\MC_10001\en_US and create “CustomData” folder.
Now navigate to this folder and then create 2 sub folders:

1. conf – to hold the Solr configuration files
2. data – to store the indexes


Step 3 - Create configuration files to support the custom data

To speed up the configuration changes, let us copy the existing configuration files from C:\IBM\WCDE80\search\solr\home\MC_10001\en_US\CatalogEntry\conf to the newly created conf folder under CustomData.

a) Open schema.xml and navigate to the section starting with the text "Websphere Commerce text field naming convention". Below that, you can see the field definition created for CATENTRY information. Replace the field definition with the custom field details we need to index into Solr.


<field name="name" type="wc_text" indexed="true" stored="true"  multiValued="false"/>
<field name="description" type="string" indexed="false" stored="true"  multiValued="false"/>
<field name="brand" type="wc_text" indexed="true" stored="true"  multiValued="true"/>
<field name="brand_ntk" type="wc_keywordTextLowerCase" indexed="true" stored="true"  multiValued="true"/>
<copyField source="brand" dest="brand_ntk"/>

<!-- Field to use to determine and enforce document uniqueness.
      Unless this field is marked with required="false", it will be a required field
   -->
<uniqueKey>name</uniqueKey>

<!-- field for the QueryParser to use when an explicit fieldname is absent -->
<defaultSearchField>name</defaultSearchField>


b) update wc-data-config.xml file with the SQL queries and field definitions to load the data to Solr from database (if the source is present in database. It is also possible to load contents directly from files which I will explain in my next blog).

 After the changes, final wc-data-config.xml will look similar to the content given below.

<!-- WebSphere Commerce Solr Data Import Handler configuration -->
<dataConfig>

  <dataSource name="WC database"
              type="com.ibm.commerce.solr.handler.SchemaJdbcDataSource"
              jndiName="com.ibm.commerce.foundation.server.services.search.datasource"
              readOnly="true"
              autoCommit="true"
              transactionIsolation="TRANSACTION_READ_COMMITTED"
              holdability="CLOSE_CURSORS_AT_COMMIT"
              fullyMaterializeLobData="true"
              fullyMaterializeInputStreams="true"
              progressiveStreaming="2"
              progresssiveLocators="2"
              batchSize="1000"
 />

<document name="CustomData">
   
<entity name="CustomInfo"
dataSource="WC database"
transformer="ClobTransformer, RegexTransformer, com.ibm.commerce.solr.handler.NameValuePairTransformer"
query="SELECT TEST.NAME, TEST.DESCRIPTION, TEST.BRAND FROM TEST"
   >
<field column="NAME" name="name" />
<field column="DESCRIPTION" name="description" />
<field column="BRAND" name="brand" />

      </entity>

  </document>
</dataConfig>


Note: If the data to be indexed (eg. brand) is present in a different table and if "name" is the primary key of the second table, the following entry in wc-data-config.xml inside <entity> will help to include brand information in the same record.

<entity name="brand" query="SELECT brand FROM BRANDTEST where name = ${CustomInfo.NAME} ">
<field column="brand" name="BRAND"/>
</entity>


Step 4 - Restart the Solr server

Step 5 - Verify whether the core is created properly or not by hitting the following url

http://localhost:81/solr/CustomData_en_US/select?q=*.*

You should get a response XML with no data in it.



Registering the index in WebSphere Commerce Database:

To index the data from WCS DB to Solr, the following configuration entries need to be inserted in search configuration tables.

1) INSERT INTO srchconf (indextype, indexscope,languages,config,optcounter) values ('CustomData',10001,'-1,-1001,-1002','IndexScopeTag=2,SearchServerPort=81,SearchServerName=localhost,PreProcessConfigDirectory=C:\IBM\WCDE80\search\pre-processConfig\MC_10001\DB2\CustomData',27);
2) INSERT INTO srchconfext (srchconfext_id,indextype,indexscope,language_id,indexsubtype,config) VALUES(101,'CustomData','10001',-1,'Structured','SearchServerName=localhost,SearchServerPort=81');
3) INSERT INTO srchconfext (srchconfext_id,indextype,indexscope,language_id,indexsubtype,config) VALUES(102,'CustomData','10001',-1,'Unstructured','SearchServerName=localhost,SearchServerPort=81');
4) INSERT INTO srchconfext (srchconfext_id,indextype,indexscope,language_id,indexsubtype,config) VALUES(103,'CustomData','10001',-1,'WebContent','SearchServerName=localhost,SearchServerPort=81');

Importing Data to Solr:


The data can be imported to Solr by hitting the below URL in browser.

http://localhost:81/solr/CustomData_en_US/dataimport?command=full-import

By default, wc-data-config.xml will be referenced by data import command. If data import is being executed in other environments, then the name of the config file can be specified as a parameter. For example: http://localhost:81/solr/CustomData_en_US/dataimport?command=full-import&config=wc-data-config.dev.xml












You can check whether indexing is completed or not by using the below URL.
http://localhost:81/solr/CustomData_en_US/dataimport?command=status

Once it is completed, hit the below URL again and you can see the result with the details indexed.

http://localhost:81/solr/CustomData_en_US/select?q=*.*



HTML/JSP Coding Guidelines

This blog explains some of the best practices to be followed for optimizing the web page for better performance. This mainly talks on the front end coding part which includes HTML, Style Sheet, JavaScript, images etc. 

   Every byte we save in a JSP/HTML attributes to few bytes per page and if you look at the number of pages delivered per day, this number would be a considerably huge number. By optimizing the page size we can reduce the bandwidth utilization on our infrastructure, thereby allowing other necessary process to utilize them.

 1. There should not be any unnecessary HTML comments in the JSP – Since the HTML comments are delivered in the response which in turn will increase the page size, we should stick to scriptlet comments in JSP pages.

2. Unnecessary whitespace characters in the JSP should be removed.

3. There should not be any inline scripts or styles in the JSP as this again can increase the page size. If it is part of the static content, make it part of the g-zip compressed resource.

4. If an HTML portion is not required, then we should not have the content present in the html as hidden. Instead we should put a condition in JSP in such a way that the HTML portion is not generated and included in the response.

5. All the JS and CSS should be imported or defined in a single place (if applicable).

6. We can also look at the option of removing line breaks in the JSP, instead we can use the return carriage between the HTML tags.

For example:
<body>
<div id=”myDiv”>
:
:
</div>

The above code can be indented as there by saving the return carriage space
<body><div
id = ”myDiv”>:
:
</div>

7. Optimal use of HTML hidden variables, only necessary attributes to be set.


8. No iFrames to be used unless it is absolutely necessary.

9. Minify JS/CSS files: Minification refers to the process of removing unnecessary data without affecting the functionality. This includes removing the comments, code formatting, unused code etc. This will result in reduced size and hence it will load faster. This applies to resources like JavaScript and CSS.

There are many tools available for JS/CSS minification. We can consider tools such as YUI Compressor for the same.

10. Combine JS/CSS files: Concatenating multiple resource files into one will help in improving the performance by reduced network calls. If there are many separate files getting loaded in a page, there will be multiple server calls happening from the browser and will impact the performance. Combining multiple files will reduce the server calls and hence improve the performance.

    We should take a look at the file size while combining the JavaScript/CSS files. The combined file should not be of large size, we should combine only the files which can be retained with in a range of 300~400 kb.

11. Avoid unwanted library usage: If we are using any library JS files, make sure we are loading only the required JS files in each page instead of including all the library files.

12. Leverage g-zip compression: GZIP compression is an effective way to save bandwidth and reduce download time. GZIP performs best on text-based assets: CSS, JavaScript, and HTML. All modern browsers support GZIP compression and will automatically request it. It usually provides 50~80% reduction in content size, in JS/CSS files. The combination of minified files, plus GZIP, offers more advantage. This can be configured in the web server level.

13.    Optimize images: Optimize the images using techniques such as CSS spriting. By using this technique, portions of a single image can be used for displaying multiple images in the website.

14. Remove render-blocking JavaScripts

15. Remove duplicate imports


Block And Class Loading Order In Java


The below program will illustrate the loading order of different blocks  (Static and this block) and methods when main class is invoked in Java.

----------------------------------------------- Order Test Program -----------------------------

public class OrderTest {

                public static final int A =5;   // Static final Variables: These are constant ,
                public static final int B;  // need to  initialize, once initialized will not be able to change value
                public static final String s; //  If not initialized will be able to initialize only  from static block
                               
                {
System.out.println("This Block ....");   // This Block :  Execute Each time the when the
//  object of class  is created, after the super() call
                }
                static {
                                System.out.println(" First Static Block ..."); // static Block: Execute before main method,
                                                                                       // when the class is first loaded     
                           }
                public OrderTest() {
                                System.out.println("Constructor ...."); // Constructor: Execute during object creation
                }
               
                public static void print1() {
                                System.out.println("Static Method ...."); // Static method: Execute When it is explicitly called.
                }
               
                static {
                                if          (A==5)    { B=10; s = "ab"; } //  Initializing static final variables
                               
                                else        { B= 5; }

                                System.out.println("Second Static Block ...");
                                System.out.println("--------A ="+A);
                                System.out.println("--------B ="+B);
                }
                static {
                                System.out.println("Third Static Block ....");
                //             B =5; // Compilation error :  Final field B already have been assigned
                }
               
                public static void main(String[] args) {
                                System.out.println("Main Block .........");
                                print1();
                                OrderTest o = new OrderTest();
                                print1();
                }
}

------------------------------------ Output Of the above program ---------------------------------------------
First Static Block ...
Second Static Block ...
--------A =5
--------B =10
Third Static Block ....
Main Block .........
Static Method ....
This Block ....
Constructor ....
Static Method ....


---------------------------------End of output -------------------------------------------------------------------

Filters Vs Servlet

A filter is a web component on the web server that filters the request and response client and the business unit.
Filters are monitoring the request/response before it reaches its destination. So the filters are transparent to the client and Servlets
.
Filters Vs Servlet

Filters do not themselves create a response like servlet. It just modify header and information in the request/response before and after the servlet invocation. Filters are used for Logging and blocking the request-response. It is giving the customized version of the request and response.

Servlet is used to control the request and perform action on that particular request. Actions involves login, interaction with database and execution of business logic.

How filters are working:

Filters will process the request before sending to the servlet, and after processing the request filters can do the following:
  • ·        Filters can generate response and return it to the client.
  • ·        Filters will be able to modify the request and will send that modified/unmodified request to next filter (if there is filter changing) in the chain or to the correct resource.
  • ·        Filters can route the request to different resource other than the specified one.
  • ·        The response form the servlets are passing back to the client through the same set of filters (the request are send to servlet), but will be in reverse order.
  • ·        Filters will be able to modify the response before sending to the client.


How to use the filter:

A filter is a java class that implements javax.servlet.Filter

It defines three methods, these are declared in Filter Interface.

init()
doFilter()
destroy()

void init(FilterConfig config) throws ServletException
  • ·        It is used to initialize the filter.
  • ·        Called by the web container before the filter goes into service, and sets the filter's configuration object. It is invoked only once.

void doFilter(ServletRequest req, ServletResponse res, FilterChain chain) throws IOException, ServletException:

  • ·        Called by the web container each time a request/response pass through the filter chain. Performs the actual filtering tasks

void destroy()

  • ·        Called by the web container after the filter has been taken out of service.
  • ·         It is called only once.


chain.doFilter() : To  transfer control to the next filter.

public class TimerLogFilter implements Filter  {  // Implements Filter interface

private FilterConfig filterConfig;  

   public void  init(FilterConfig config) throws ServletException  {

   this.filterConfig = filterConfig;                // creating filter config object
   }
   public void  doFilter(ServletRequest request, ServletResponse response,
                 FilterChain chain) throws java.io.IOException, ServletException {

     long start = System.currentTimeMillis();
    System.out.println("Milliseconds start: " + start);
    chain.doFilter(request, response);      //Pass request back down the filter chain
    long end = System.currentTimeMillis();
    System.out.println("Milliseconds end: " + end);
   }
   public void destroy( ){

      /* Called before the Filter instance is removed from service by the web container*/
                       filterConfig = null;

   }
Servlet Filter Mapping in Web.xml:

-- Mapping filter class to a filter name
<filter>
    <filter-name>timerLog</filter-name>  
    <filter-class>filter.TimerLogFilter </filter-class>
</filter>
-- Mapping a filter name to servlet name or URL pattern
-- Servlet name , to have the filter invoked whenever the servlet of name myservlet is invoked:
<filter-mapping>
    <filter-name> timerLog </filter-name>
    <servlet-name>myservlet</servlet-name>
</filter-mapping>
-- OR URL pattern ,invoke for all servlet.
<filter-mapping>
   <filter-name> timerLog </filter-name>
   <url-pattern>/*</url-pattern>
</filter-mapping>

Sunday, November 29, 2015

Updating SOLR REST configuration

If you need to change the port used by Solr REST calls in WCS7 FEP8, please follow the below steps.

1. Start the test server in RAD.
2. Launch admin console.
3. In admin console, navigate to Environment -> Naming -> Name space bindings
4. Update the values of the  following resources to use the new port rather than default port 80.
             com.ibm.commerce.foundation.server.services.search.port
             com.ibm.commerce.foundation.server.services.search.url
5. Restart the server for changes to take effect.

Wednesday, November 25, 2015

Limiting Number Of Items in Shopping Cart (FEP 8)

If there is a business requirement to limit the number of items to be added in cart, no need to go with customizing the code. This can be achieved by modifying the configurations in wc-admin-component.xml inside WC/xml/config/com.ibm.commerce.order folder.

The following attributes inside the grouping ShoppingCartThreshold can be modified for this.
  • size for maximum allowed items in an cart.
  • quantity for maximum quantity of an item in cart.


<_config:configgrouping name="ShoppingCartThreshold">
            <_config:property name="size" value="10"/>
            <_config:property name="quantity" value="5"/>
            <_config:property name="defaultPageSize" value="100"/>
            <_config:property name="maximumPageSize" value="100"/>
        </_config:configgrouping>


Changing formatter configuration in RAD

While coding, as a best practice, we need to ensure the quality of the code. There are multiple criteria based on which the code quality is evaluated. One of them is formatting. RAD has in-built support for formatting, which can be modified as per the project needs.

The steps to change the settings of the formatter in RAD are given below.

1. Open RAD, go to Windows -> Preferences option.
2. In Preferences window, navigate to Java -> Code Style -> Formatter.




3. One profile name will be displayed by default as the active profile.
4.     Click "New" and provide a custom profile name. If a custom profile already exists and you want to edit it, click on "Edit" button
5.     Make changes in the following window as required and save it.


Creating a new Commerce Composer Widget


From feature pack 7 of WCS 7 onwards, a new feature called commence composer is introduced which will help the business to change the layout & alignment of widgets without much involvement from IT team. Widgets are independent components which can be plugged anywhere and will perform the pre-defined functionalities.

WCS feature pack 7 and later versions are coming with a set of pre-defined layouts and widgets which can be applied on the browse pages. Even we can define our own custom layouts & widgets, if the ones provided by WCS doesn’t fit into our requirement.

Given below are the steps to be followed for creating a new widget. 

1. Generating commerce composer widget source

We use a Java Emitter Template (JET) Transformation to generate the source code files that are required to create a Commerce composer widget.

  •  Create a new project in the Websphere commerce workspace.
  • Inside this project folder, create a pattern input file for JET Transformation. Contents of the input XML file should be as follows:


<pageLayout vendor="TestCompany">
  <Widget>
    <widgetDef identifier="Test"
     UIObjectName="TestWidget"
      displayName="Sample widget"
   description="This widget is for learning purpose" >
</widgetDef>
 </widget>
</pageLayout>

            Where
           
Property
Values
Vendor
The name of your company
Identifier
The external reference name for the widget or container definition. This must be unique.
UIObjectName
The name that identifies the Management Center object and object definition of this widget.
DisplayName
The language-specific display name of the widget
Description
The language-specific description for the widget.



  • Right click the pattern input file and run JET Transformation.
  • The JET Transformation generates a set of file directories and files that can be used to create the custom widget. The generated file directories contain three main folders: LOBTools, Stores and DataLoad.

2. Defining the Storefront assets for a site-level widget


  • Copy the generated source code files for your widget storefront assets from your project folder to the appropriate location within the default Stores project.
  • Modify the source files to suit the functionality of the widget.
  • All the JSPs, JSPFs, images and property files required by the widget should be moved to this location.

3. Testing the widget in the store


  •  Import the base JSP of the widget in any of the available pages of your store. Suppose, Test.jsp corresponds to the base JSP of the custom widget. This file can be imported in TopCategoriesDisplay.jsp which is the base JSP of default Home page.
  •  Navigate to the Home Page in the site and debug the widget source files in case of errors.


 4. Loading widget into the database by using data load utility

In this step, Data load utility is used to register the custom widget and to make the store to subscribe to the widget.

  • Open the new project folder created for the custom widget.
  • Open the registerWidgetdef.csv for editing. This input file is used to load widget definition into PLWIDGETDEF and PLWIDGETDEFDESC database tables. This file is also used to register the custom widget within the Commerce composer framework. The file should contain the following property definitions:


Property
Value
WidgetDefIdentifier
The external reference name for the widget definition. This value should be unique.
WidgetDisplayName
The name that displays within the Commerce Composer tool in Management Center to help business users identify the widget.

WidgetUIObjectName
The name that identifies the Management Center object and definition of the widget.
WidgetVendor
The name of the company or vendor that created the widget.
WidgetType
The type of the widget.
The possible values for the property are:
1 - Widget
2 - Container

Ensure that the specified value is 1.
WidgetPath
The relative path to the entry point top-level JSP file for the widget.
WidgetDefinitionxml
The XML definition for the dynamic properties of the widget.
WidgetState
The state of the widget registration. The possible values for the property are:
·         1-Active
·         2-Inactive
Set the value as 1.
WidgetStoreUniqueID
The unique reference number of the store in which you are registering the widget.
Possible values are:
·          0 – Site Level Widget
·         Store Identifier – Store Level Widget
WidgetDescription
The description that displays for the widget within the Commerce Composer tool in Management Center to help business users identify the widget
Delete
A flag that indicates whether to delete the widget definition. Possible values are 0 and 1.

·         Specify 1 to delete the widget.
·         The default value is 0, which indicates that the Data Load utility is to load the information for the row into the database.


  • Open the subscribeWidgetdef.csv file for editing. The subscribeWidgetdef.csv input file loads data into the PLSTOREWIDGET database table. This input file is used to subscribe additional stores to the widget. This CSV input file can also be used to override the definition xml of the widget for a store. The file should contain the following property definitions:

Property
Value
WidgetDefIdentifier
The external reference name for the widget definition
WidgetDefinitionxml
The XML definition for the dynamic properties of the widget
WidgetState
The state of the widget registration. The possible values for the property are:
          1 – Active
          2 - Inactive
Delete
A flag that indicates whether to delete the widget definition. Possible values are 0 and 1.

Specify 1 to delete the widget.
The default value is 0, which indicates that the Data Load utility is to load the information for the row into the database.


  • In the DataLoad directory within the new project directory, open the wc-dataload-env.xml file for editing. The wc-dataload-env.xml file is the data load environment configuration file that is generated to help to configure and run the Data Load utility. Update the file to match your database and environment settings.
  • Stop the WCS Test server. Run the following command to load the input CSV files to register the  widget and to have a store subscribe to the widget:
Dataload.bat workspace_dir\NewWidgetProject\DataLoad\widget\wc-dataload-widget.xml

5. Extending resource bundle and properties files


  • Copy the generated resource bundle and properties file into your default directory workspace structure. I.e. Copy the ‘Testcompany’ directory from workspace_dir\NewWidgetProject\LOBTools\src\com and paste it in the path workspace_dir\LOBTools\Java Resources\src directory. Refresh the LOBTools directory within default workspace. Ensure that com.mycompany.commerce.pagelayout.client.lobtools.properties package exists in the LOBTools\Java Resources\src directory.
  • Expand the com.mycompany.commerce.pagelayout.client.lobtools.properties package in LOBTools\Java Resources\src directory. Open the PageLayoutLOB.properties and PageLayoutLOB_en_US.properties files for editing. Define any additional translatable text for the new widget by adding code into both these files.
  • Copy the generated resource bundle extension into your default workspace directory structure and register the new widget specific properties files. I.e. copy the mycompany directory from NewWidgetProject\LOBTools\WebContent\WEB-INF\src\lzx and paste it in the location LOBTools\WebContent\WEB-INF\src\lzx directory.
  • Update the default Commerce Composer resource bundle library to include the new resource bundle extension. Copy the generated code that includes the new widget resource bundle from NewWidgetProject\LOBTools\WebContent\WEB-INF\src\lzx\commerce\pagelayout\PageLayoutExtensionsLibrary.lzx and paste it in the file LOBTools\WebContent\WEB-INF\src\lzx\commerce\pagelayout\ PageLayoutExtensionsLibrary.lzx The generated code can resemble the following:

<library>
<! -- Include the file to add any custom libraries. -->
  <include href="../../mycompany/pagelayout/mycompanyPageLayoutResourceBundle.lzx"/>
</library>



6. Define the object definition for widget

  • The object definition adds support for the widget object within the Management Center framework.
  •  Copy the generated object definition files for the custom widget into the default workspace directory structure. i.e. Copy the testcompany directory from NewWidgetProject\LOBTools\WebContent\config and paste it in the location LOBTools\WebContent\config
  • Go to the directory LOBTools\WebContent\config\mycompany\pagelayout\widgetDefinitions\testWidget and open the file WidgetObjectDefinition.def for editing. By default, a sample code will be generated for the widget object definition.

<? Xml version="1.0" encoding="UTF-8"?>
<! -- The following code is created as example. Modify the generated code and add any additional required code.  -->
<Definitions>
  <WidgetObjectDefinition package="plm"
    definitionName="plmLayoutWidget_TestWidget"
    parentDefinitionName="plmBasePageLayoutPrimaryObjectDefinition"
    baseDefinitionName="plmBaseLayoutWidget"
    objectType="TestWidget"
    gridPropertiesDefinitionName="plmWidgetProperties_TestWidget"
    iconPath="/images/pagelayouts/widgetIcons/Test.png">
   
    <CreateService baseDefinitionName="plmBaseCreateLayoutWidget" />
    <UpdateService baseDefinitionName="plmBaseUpdateLayoutWidget" />
   
    <Xml name="template">
      <sequence>0</sequence>
    </Xml>                     
  </WidgetObjectDefinition>  
</Definitions>

Where

Property
Values
iconPath
The file path to the icon that displays for the custom widget within the Add Widgets to Slots window in the Commerce Composer tool.
objectType
The widget object type and the name of the properties definition for the custom widget.
parentDefinitionName
The widget definition name for the parent widget definitions. The definition name must be included so that the object definition can be retrieved for use in Management Center for the custom widget.
plmLayoutWidget_HomePageDetailWidget
The definition name for the object definition of the custom widget, which must be unique in your workspace.

7. Define the properties view definition for widget
  • The properties view definition file specifies how to render the Management Center properties view for a widget. It contains the configurable properties that business users can set when the widget is included in a page layout.
  • Go to the location LOBTools\WebContent\config\mycompany\pagelayout\widgetDefinitions\TestWidget directory within the default workspace directory structure and open the WidgetPropertiesView.def file for editing.
  • The default code generated for this file can resemble the following:
<? Xml version="1.0" encoding="UTF-8"?>
<! -- The following code is created as example. Modify the generated code and add any additional required code. -->
<Definitions>
<GridObjectProperties definitionName="plmWidgetProperties_TestWidget">
  <PropertyPane>
    <PropertyGroup name="widgetProperties" collapsable="false" groupTitle="${plmPageLayoutResources.widgetPropertiesPrompt}">
      <PropertyInputText name="${plmPageLayoutResources.widgetNamePrompt}" propertyName="widgetName"
      promptText="${plmPageLayoutResources.widgetNamePrompt}" />
    </PropertyGroup>
    <PropertyGroup name="contentProperties" collapsable="false" groupTitle="${plmPageLayoutResources.widgetContentPrompt}">
      <PropertyStaticText text="${mycompanyPageLayoutResources.TestWidgetContent}" />
    </PropertyGroup>
  </PropertyPane>
</GridObjectProperties>
</Definitions>

8. Test the new widget in management center

  • Open Commerce Composer Tool in Management center.
  • Select any layout from Layouts folder.
  • In the ‘manage layout’ section assign a page to the layout selected.
  • In the ‘Design layout’ section click on any of the slots of the wireframe.
  • A popup with the title ‘Add widgets to slots’ appears. It contains the list of all widgets available in the store. Check if the newly created widget is available in the list.
  • If yes, click on the widget and select OK.
  • Click on save and launch preview to see the widget.

If you are developing widget for the first time and looking for simple steps to achieve this in WCS 8, refer my latest post http://myjavakitchentime.blogspot.com/2016/09/in-one-of-my-earlier-post-i.html .