IBM Support

Fixing Display Options (Color) for Numeric Fields with Separator on Start Center Result Set Portlet

Technical Blog Post


Abstract

Fixing Display Options (Color) for Numeric Fields with Separator on Start Center Result Set Portlet

Body

On Start Center Result Set Portlets, expressions for color codes do not work as intended for numeric fields, i.e. integer or decimal data type. The root cause of this issue is the thousands separator (dot or comma) for the numeric fields. The expression value for comparison is alphanumeric. Changing the field type to alphanumeric is not a solution since it does string comparison, i.e. compares hexadecimal values.

Example:

Assume we have two display options for an integer field such as;

If field value < 1000, then color code = red

If field value >= 1000, then color code = green

When the field value is 300, the system colors the row in red as expected. But when the field value is 3000, the system colors the row in red again, although it is expected to be green.

Issue and Root Cause:

The comparison is realized in resultsetportlet.jsp which is located under maximo.ear/maximouiweb.war/webclient/components folder. The function responsible for the confusion is compareValues() method of psdi.webclient.controls.ResultSetPortlet bean class used in resultsetportlet.jsp. The following line should be searched in resultsetportlet.jsp.

style = portletControl.compareValues(conditionValue);

Later, we search for compareValues() method within psdi.webclient.controls.ResultSetPortlet bean class. The code piece below is the root cause for format confusion. psdi.mbo.MboValueData.getData() method fetches the data as string which causes an incorrect conversion.

String compareTo = mvd.getData();
...
double d1 = MXFormat.stringToDouble(compareTo);
double d2 = MXFormat.stringToDouble(value);

Resolution:

The custom class below (com.custom.beans.resultset.CustomResultSetPortlet) can be applied as a solution which will replace the psdi.webclient.controls.ResultSetPortlet.compareValues() method. The main difference is emphasized in bold font which basically fetches the data in its own type (integer, double, float, long) instead of fetching it as string. The rest of the logic is same as the original class.

package com.custom.beans.resultset;

import java.rmi.RemoteException;
import java.util.Date;
import java.util.HashSet;
import java.util.Hashtable;
import java.util.Iterator;

import psdi.app.rsconfig.RSConfigSetRemote;
import psdi.mbo.MboValueData;
import psdi.server.MXServer;
import psdi.util.MXException;
import psdi.util.MXFormat;
import psdi.util.MXSystemException;
import psdi.util.logging.MXLogger;
import psdi.util.logging.MXLoggerFactory;
import psdi.webclient.controls.ResultSetPortlet;

public class CustomResultSetPortlet {
    
    private static HashSet expressionConditions;
    static MXLogger myLogger = MXLoggerFactory.getLogger("maximo.application.STARTCNTR");
    private static ResultSetPortlet portletControl;

    public static String compareValues(MboValueData mvd, ResultSetPortlet rsp) {
        boolean isConditionTrue = false;
        int intType = mvd.getTypeAsInt();
        String compareTo = mvd.getData();
        String style = "";
        try {
            if (compareTo.equals("")) {
                return "";
            }
            expressionConditions = getConditions(rsp);
            Iterator expressions = expressionConditions.iterator();
            while (expressions.hasNext()) {
                Hashtable entry = (Hashtable) expressions.next();
                String expression = (String) entry.get("expression");
                String value = getReplacementValue((String) entry.get("expvalue"), rsp);
                String color = entry.get("color").toString();
                
                double d1, d2;
                
                switch (intType) {
                case 7:
                    d1 = (double) mvd.getDataAsInt();
                    d2 = MXFormat.stringToDouble(value);
                    isConditionTrue = compareDoubles(expression, d1, d2);
                    break;
                case 8:
                    d1 = (double) mvd.getDataAsFloat();
                    d2 = MXFormat.stringToDouble(value);
                    isConditionTrue = compareDoubles(expression, d1, d2);
                    break;
                case 9:
                case 10:
                case 11:
                    d1 = mvd.getDataAsDouble();
                    d2 = MXFormat.stringToDouble(value);
                    isConditionTrue = compareDoubles(expression, d1, d2);
                    break;
                case 6:
                case 19:
                    d1 = (double) mvd.getDataAsLong();
                    d2 = MXFormat.stringToDouble(value);
                    isConditionTrue = compareDoubles(expression, d1, d2);
                    break;
                case 12:
                    String dataYorN = MXFormat.convertToStoreYNValue(compareTo,
                            rsp.getWebClientSession().getUserInfo().getLocale());
                    String customerYorN = MXFormat.convertToStoreYNValue(value,
                            rsp.getWebClientSession().getUserInfo().getLocale());
                    if (expression.equals("=")) {
                        if (dataYorN.equalsIgnoreCase(customerYorN)) {
                            isConditionTrue = true;
                        }
                    } else if (expression.equals("<>")) {
                        if (!dataYorN.equalsIgnoreCase(customerYorN)) {
                            isConditionTrue = true;
                        }
                    }
                    break;
                case 0:
                case 1:
                case 2:
                case 13:
                case 14:
                case 15:
                case 17:
                case 18:
                    int iResult = value.compareTo(compareTo);
                    if (expression.equals(">")) {
                        if (iResult > 0) {
                            isConditionTrue = true;
                        }
                    } else if (expression.equals("<")) {
                        if (iResult < 0) {
                            isConditionTrue = true;
                        }
                    } else if (expression.equals("=")) {
                        if (iResult == 0) {
                            isConditionTrue = true;
                        }
                    } else if (expression.equals(">=")) {
                        if ((iResult > 0) || (iResult == 0)) {
                            isConditionTrue = true;
                        }
                    } else if (expression.equals("<=")) {
                        if ((iResult < 0) || (iResult == 0)) {
                            isConditionTrue = true;
                        }
                    } else if (expression.equals("<>")) {
                        if (!value.equals(compareTo)) {
                            isConditionTrue = true;
                        }
                    } else {
                        isConditionTrue = true;
                    }
                    break;
                case 3:
                case 4:
                case 5:
                    Date date1 = mvd.getDataAsDate();
                    Date date2 = MXFormat.stringToDate(value);
                    if (expression.equals(">")) {
                        if (date1.after(date2)) {
                            isConditionTrue = true;
                        }
                    } else if (expression.equals("<")) {
                        if (date1.before(date2)) {
                            isConditionTrue = true;
                        }
                    } else if (expression.equals("=")) {
                        if (date1.compareTo(date2) == 0) {
                            isConditionTrue = true;
                        }
                    } else if (expression.equals(">=")) {
                        if (date1.compareTo(date2) >= 0) {
                            isConditionTrue = true;
                        }
                    } else if (expression.equals("<=")) {
                        if (date1.compareTo(date2) <= 0) {
                            isConditionTrue = true;
                        }
                    } else if (expression.equals("<>")) {
                        if (date1.compareTo(date2) != 0) {
                            isConditionTrue = true;
                        }
                    } else {
                        isConditionTrue = false;
                    }
                    break;
                }
                if (isConditionTrue) {
                    style = "style=\"color:" + color + "\"";
                }
                isConditionTrue = false;
            }
        } catch (RemoteException e) {
            if (myLogger.isDebugEnabled()) {
                myLogger.debug("Remote in ResultSetPortlet");
            }
            e.printStackTrace();
        } catch (NumberFormatException e) {
            if (myLogger.isDebugEnabled()) {
                myLogger.debug("NumberFormatException in ResultSetPortlet");
            }
            e.printStackTrace();
        } catch (MXException e) {
            if (myLogger.isDebugEnabled()) {
                myLogger.debug("MXException in ResultSetPortlet");
            }
            e.printStackTrace();
        }
        return style;
    }

    private static String getReplacementValue(String value, ResultSetPortlet rsp) throws MXException {
        if ((value == null) || (!value.startsWith(":"))) {
            return value;
        }
        String variableName = value.substring(1);
        if (variableName.equalsIgnoreCase("YES")) {
            return MXFormat.getStoreYesValue();
        }
        if (variableName.equalsIgnoreCase("NO")) {
            return MXFormat.getStoreNoValue();
        }
        if ((variableName.equalsIgnoreCase("DATE")) || (variableName.equalsIgnoreCase("&DATE&"))) {
            return MXFormat.dateToString(new Date());
        }
        if ((variableName.equalsIgnoreCase("DATETIME")) || (variableName.equalsIgnoreCase("&DATETIME&"))) {
            return MXFormat.dateTimeToString(new Date());
        }
        if (variableName.equalsIgnoreCase("TIME")) {
            return MXFormat.timeToString(new Date());
        }
        if ((variableName.equalsIgnoreCase("&HOSTNAME&")) || (variableName.equalsIgnoreCase("HOSTNAME"))) {
            try {
                return MXServer.getMXServer().getProperty("mxe.hostname");
            } catch (RemoteException e) {
                throw new MXSystemException("system", "remote", e);
            }
        }
        if ((variableName.equalsIgnoreCase("USER")) || (variableName.equalsIgnoreCase("&USERNAME&"))) {
            return rsp.getWebClientSession().getUserInfo().getUserName();
        }
        if ((variableName.equalsIgnoreCase("PERSONID")) || (variableName.equalsIgnoreCase("&PERSONID&"))) {
            return rsp.getWebClientSession().getUserInfo().getPersonId();
        }
        return value;
    }

    private static HashSet getConditions(ResultSetPortlet rsp) throws RemoteException, MXException {
        String portletCacheId = rsp.getPortletCacheId() + "_rsconditions";
        HashSet conditions = null;
        if (rsp.getWebClientSession().hasStartCenterCache(portletCacheId)) {
            conditions = (HashSet) rsp.getWebClientSession().getStartCenterCache(portletCacheId);
        } else {
            RSConfigSetRemote rs = (RSConfigSetRemote) rsp.getDataBean().getMboSet();
            conditions = rs.getConditions();

            rsp.getWebClientSession().setStartCenterCache(portletCacheId, conditions);
        }
        return conditions;
    }
    
    private static boolean compareDoubles(String expression, double d1, double d2){
        boolean isConditionTrue = false;
        if (expression.equals(">")) {
            if (d1 > d2) {
                isConditionTrue = true;
            }
        } else if (expression.equals("<")) {
            if (d1 < d2) {
                isConditionTrue = true;
            }
        } else if (expression.equals("=")) {
            if (d1 == d2) {
                isConditionTrue = true;
            }
        } else if (expression.equals(">=")) {
            if (d1 >= d2) {
                isConditionTrue = true;
            }
        } else if (expression.equals("<=")) {
            if (d1 <= d2) {
                isConditionTrue = true;
            }
        } else if (expression.equals("<>")) {
            if (d1 != d2) {
                isConditionTrue = true;
            }
        }
        return isConditionTrue;
    }

}

The new custom class should be put into maximo.ear/maximouiweb.war/WEB-INF/classes/com/custom/beans/resultset folder. Since this is a brand new bean class, it needs application server to be restarted. Then, we inject our solution into the resultsetportlet.jsp as follows: First we add the import declaration at the end of the original declarations in jsp which can be seen in bold font below.

<%@ include file="../common/simpleheader.jsp"
%><%@page import="com.ibm.json.java.JSONArray"
%><%@page import="psdi.webclient.beans.startcntr.ResultSetGraph"
%><%@page import="psdi.webclient.beans.startcntr.ChartData"
%><%@page import="psdi.webclient.beans.startcntr.BarChartData"
%><%@page import="psdi.webclient.beans.startcntr.BarChartData.BarChartItem"
%><%@page import="psdi.webclient.beans.startcntr.PieChartData"
%><%@page import="psdi.webclient.beans.startcntr.PieChartData.PieChartItem"
%><%@page import="com.custom.beans.resultset.CustomResultSetPortlet"
%>

Secondly, we search for the following line which we will comment out and replace with our custom class and method.

style = portletControl.compareValues(conditionValue);

Here, how it looks after editing.

//  style = portletControl.compareValues(conditionValue); // original code
    style = CustomResultSetPortlet.compareValues(conditionValue, portletControl); // workaround for separator problem

That's all Folks!!!

[{"Business Unit":{"code":"BU059","label":"IBM Software w\/o TPS"},"Product":{"code":"SSLKT6","label":"IBM Maximo Asset Management"},"Component":"","Platform":[{"code":"PF025","label":"Platform Independent"}],"Version":"","Edition":"","Line of Business":{"code":"LOB59","label":"Sustainability Software"}}]

UID

ibm11130433