SAP HR BuildMap error - Class nor found in namespace

Which IIQ version are you inquiring about?

Version 8.3

Share all details related to your problem, including any error messages you may have received.

Hi community,
We had an integration with SAP HR working in IIQ. Due to an update in SAP Basis, we needed to also update SailPoint IIW to use the new SAP HR connector since RFC_READ_TABLE is no longer supported. Now that we have updated and adjusted the BuildMap rule as per Sailpoint support recommendation, we are getting an strange error that maybe some of you have experienced before and can help me with.
The problem is that when running the aggregation task, it fails almost every time because there is a class that we import in the BuildMap Rule that at some point during aggregation stops finding in the namespace. Find the exact error below:
“Exception during aggregation. Reason: java.lang.RuntimeException: sailpoint.connector.ConnectorException: BeanShell script error: bsh.EvalError: Sourced file: inline evaluation of: ``import sailpoint.api.SailPointContext; import sailpoint.integration.JsonUtil; . . . ‘’ : Typed variable declaration : Typed variable declaration : Class: MultiFieldQueryForSPBAPI not found in namespace”

What is very relevant and surprising is that aggregation starts fine and runs smoothly for some accounts (it is random, sometimes 300, sometimes 4000), but usually at some points fails with this error. Once it fails, if we run aggregation again, it inmediately fails. Only way to make it work again is by restarting the tomcat (and therefore refreshing the classloaders).
From what we saw on the internet, seems to point out to something related with the beanshell / classloader cache, but don’t know how to solve it.
Has anyone experienced similar issue and knows how to solve it?

Update: Rule Pasted below (cleaned and only with one parameter - personal area-, but we are querying several parameters)

import sailpoint.api.SailPointContext;
import sailpoint.integration.JsonUtil;
import sailpoint.tools.Message;

import org.apache.log4j.Logger;
import org.apache.log4j.Level;

import java.util.HashMap;
import java.util.ArrayList;
import java.util.Collection;
import java.util.Iterator;
import java.util.Date;

import java.text.SimpleDateFormat;
import java.text.DateFormat;

import sailpoint.tools.GeneralException;
import sailpoint.object.Script;
import java.io.File;
import java.io.IOException;
import java.net.URI;
import java.net.URISyntaxException;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.lang.StringBuilder;

import sailpoint.object.ApprovalItem;
import sailpoint.object.Attributes;
import sailpoint.object.ApprovalSet;
import sailpoint.object.Application;
import sailpoint.object.Custom;
import sailpoint.object.Identity;
import sailpoint.object.ProvisioningPlan;
import sailpoint.object.Rule;
import sailpoint.object.Question;
import sailpoint.object.Workflow;
import sailpoint.object.Workflow.Variable;
import sailpoint.object.Workflow.Approval;
import sailpoint.object.Workflow.Arg;
import sailpoint.object.WorkItem;
import sailpoint.object.Script;
import sailpoint.api.SailPointContext;

import com.sap.conn.jco.AbapException;
import com.sap.conn.jco.JCoDestination;
import com.sap.conn.jco.JCoException;
import sailpoint.connector.ConnectorException; 
import sailpoint.connector.sap.tables.conditions.MultiFieldQueryForSPBAPI;
import sailpoint.connector.sap.tables.conditions.ConditionQueryStrategyForSPBAPI;

import com.sap.conn.jco.JCoFunction;
import com.sap.conn.jco.JCoParameterField;
import com.sap.conn.jco.JCoParameterFieldIterator;
import com.sap.conn.jco.JCoParameterList;
import com.sap.conn.jco.JCoStructure;
import com.sap.conn.jco.JCoTable;
import com.sap.conn.jco.JCoContext;

import sailpoint.object.EmailOptions;
import sailpoint.object.EmailTemplate;

  // Get current aggregated account details
  String PERNR = (String) object.get("Personal Number");
  Boolean positionChange = false;
  List dateConditions = new ArrayList();
  DateFormat format = new SimpleDateFormat("yyyyMMdd");
  String currentDate = "";
  String futureDate="";
  String stat2Next = object.get("STAT2_Next");
  String stat2Current = object.get("STAT2_Current");
  if(stat2Next != null && stat2Next.equalsIgnoreCase("Active") && stat2Current.equalsIgnoreCase("Inactive")){
    String stat2NextStartDate = object.get("STAT2_Next_Start_Date");
    currentDate = stat2NextStartDate != null ? stat2NextStartDate.replace("-","") : format.format(new Date());
    futureDate = stat2NextStartDate != null ? stat2NextStartDate.replace("-","") : format.format(new Date());
  }else{
    currentDate = format.format(new Date());
  }

 public List retrieveSAPvalue(String tableName, String field, String identifier, String keyIdentifier, List additionalConditions){
    List listFieldToGet = new ArrayList();//Campo que queremos obtener de la tabla
    List listQueryFieldValues = new ArrayList(); //Lista de valores de los campos que vamos a incluir como filtro
    String stringQuery = ""; //String de la query que vamos a hacer en formato ?? EQ && AND ?? EQ &&. && son los fieldvalue, ?? son los queryfield
    String stringQueryField = ""; //String de los campos en los que vamos a buscar, en orden
    
    List conditions = new ArrayList();
    
    listFieldToGet.add(field); 
    separator = "|"; //Separador por defecto
    fieldsSeparator = "/";
    conditions.add(keyIdentifier + " = '" + identifier + "'");
    conditions.addAll(additionalConditions);
    
    //Bucle for para recorrer todas las condiciones de la lista y sacar los 3 valores que necesitamos
    for (String condition : conditions){
        //Separamos la string por espacio
        String[] values = condition.split(" ");
      //logger.debug("Valores tras split: " + values);
        //comprobamos que tras separar la string por espacio nos devuelve 3 valores
        if (null != values && values.length == 3){
            //El primer valor es el StringQueryField, si stringQueryfiled es igual a "", concatenamos
            //si stringQueryfiled es disntinto de "" concatenamos fieldsSeparator + el valor
            if (stringQueryField != null && !stringQueryField.equals("")){
                stringQueryField = stringQueryField + fieldsSeparator + values[0];
            } else{
                stringQueryField = stringQueryField + values[0];
            }
            //El segundo valor es el stringQuery, si es igual a "=", y stringQuery es igual a "", concatenamos "?? " + "EQ" + " &&"
            //Si stringQuery es distinto de "", concatenamos " AND ?? " + "EQ" + " &&"
            //Si el valor es ">=", mismo procedimiento pero "ge" en lugar de "eq", si es "<=" "le"
            if (stringQuery.equals("")){
                if (values[1].equals("=")){
                    stringQuery = stringQuery + "?? EQ &&";
                }else if (values[1].equals(">=")){
                    stringQuery = stringQuery + "?? GE &&";
                }else if (values[1].equals("<=")){
                    stringQuery = stringQuery + "?? LE &&";
                }else{
                    stringQuery = stringQuery + "?? EQ &&";
                    logger.debug("Excepcion de query no controlada");
                }
                
            } else{
                if (values[1].equals("=")){
                    stringQuery = stringQuery + " AND ?? EQ &&";
                }else if (values[1].equals(">=")){
                    stringQuery = stringQuery + " AND ?? GE &&";
                }else if (values[1].equals("<=")){
                    stringQuery = stringQuery + " AND ?? LE &&";
                }else{
                    stringQuery = stringQuery + " AND ?? EQ &&";
                    logger.debug("Excepcion de query no controlada");
                }
            }
            //El tercer valor es el listQuertFieldValue, debemos añadirlo a la lista listQueryFieldValues quitando los caracteres ''
        String fieldvalue = values[2].replace("'","");
            listQueryFieldValues.add(Collections.singletonList(fieldvalue));
            
        }
    }   
    
     MultiFieldQueryForSPBAPI mfq = new MultiFieldQueryForSPBAPI();
    

    
     result = connector.querySAPTableWithSPBAPI(destination, tableName, listQueryFieldValues, listFieldToGet, separator, connector.getSpBapiName(), stringQuery, stringQueryField, mfq);
   
    return result;

  }

  public void setProperty(String propertyName, Object value, Map object){
    //logger.debug("Property: " + propertyName + " | Value: " + value);
    if (value != null && !value.isEmpty()){
      if(value instanceof List){
        object.put(propertyName, value.get(0));
        //logger.debug("not string: " + propertyName);
      }else{
        object.put(propertyName, value);
        //logger.debug("string: " + propertyName);
      }
    }
    //logger.debug("Successfully added property " + propertyName + " to object with value " + value);
  }
    
  // GET PERSONAL AREA DESCRIPTION
  try {
    List conditions = new ArrayList();
    String personalArea = object.get("Personal Area");
    List value = retrieveSAPvalue("T500P", "NAME1", personalArea, "PERSA", conditions);
    setProperty("Personal Area Description", value, object);
  } catch (Exception e) { 
    //logger.debug("Personal Area Description field exception: " + e);
  }

Thanks a lot and best regards,
David

3 Likes

Can you show the rule?

Hello David!

Can you paste the rule?

Hi, I have just updated the code with the rule, a little bit cleaned since we are querying much more than one parameter

Hello David,

I have the exact same issue in a client. The funny thing is that if we do a single account aggregation the logic of the rule works fine, there is no Class Not Found error. It only happens randomly when doing aggregations, both full and delta, partitioned or not.

In our case we have a higher number of accounts (around 50K) but we also see that sometimes if fails after aggregating 30K, other times it fails immediately and others it works.

try to put this code below the methods .

best!

Hi Ivan,

Changed and aggregation is running now, let’s see for how long. Will let you know with the updates.

Kind regards,
David

1 Like

Hi, I have tried but after 2 successful aggregations it then crashed again with same error :frowning:

Any other alternatives any one can suggest?

By Any chance are you using partition and the server does not have the library?

Best!

Hi Ivan,

We have tried both ways, using partition and without it. Same behaviour, sometimes it works, sometimes it fails in the middle of the aggregation, no matter if using partition or not
 It is like the aggregation ruke stops finding the class at some point.

We have seen something related with cache, any idea on that?

Kind regards,
David

@drodriguezacevedo
Is all your servers restarted and still facing this issue?
Also all you servers does have the library , did you check on that?

Hi Satish,
Yes we have restarded the servers and facing the issue still. Initially after restart usually aggregation starts fine and even works once, but then it fails and until it is not until we restart the tomcat that the aggregation is able to start again without inmediately failing.

Yes all the servers have the library.