Workflows stuck at AFX fulfilment or Provisioning command nodes as AFX fails to update the request state on RSA Identity Governance and Lifecycle 6.9.1 and above
2 years ago
Originally Published: 2016-08-24
Article Number
000043955
Applies To
RSA Product Set: Identity Management and Governance
RSA Product/Service Type: Access Fulfilment Express
RSA Version/Condition: 6.9.1, 7.0.0
Platform: Any
Issue
AFX requests which fail to fulfil at the target system (due to expected failures) get stuck and do not create manual activities (in case of AFX fulfilment workflows) or move to the next workflow node (in case of provisioning command nodes).

mule.AFX-MAIN.log
2016-05-16 16:50:35.204 [ERROR] org.mule.exception.DefaultMessagingExceptionStrategy:341 - 
********************************************************************************
Message               : Failed to invoke ScriptComponent{AFX_JMS_FULFILLMENT_STATE.component.459094127}. Component that caused exception is: ScriptComponent{AFX_JMS_FULFILLMENT_STATE.component.459094127}. Message payload is of type: String
Code                  : MULE_ERROR--2
--------------------------------------------------------------------------------
Exception stack is:
1. Fulfillment state F request for CR NA (message 34358392-dea5-43d5-a734-ea68e55e8524) resulted in a 500 HTTP status code - may retry later (java.lang.IllegalStateException)
  sun.reflect.NativeConstructorAccessorImpl:-2 (null)
2. java.lang.IllegalStateException: Fulfillment state F request for CR NA (message 34358392-dea5-43d5-a734-ea68e55e8524) resulted in a 500 HTTP status code - may retry later (javax.script.ScriptException)
  org.codehaus.groovy.jsr223.GroovyScriptEngineImpl:323 (http://java.sun.com/j2ee/sdk_1.3/techdocs/api/javax/script/ScriptException.html)
3. Failed to invoke ScriptComponent{AFX_JMS_FULFILLMENT_STATE.component.459094127}. Component that caused exception is: ScriptComponent{AFX_JMS_FULFILLMENT_STATE.component.459094127}. Message payload is of type: String (org.mule.component.ComponentException)
  org.mule.component.AbstractComponent:148 (http://www.mulesoft.org/docs/site/current3/apidocs/org/mule/component/ComponentException.html)
--------------------------------------------------------------------------------
Root Exception stack trace:
java.lang.IllegalStateException: Fulfillment state F request for CR NA (message 34358392-dea5-43d5-a734-ea68e55e8524) resulted in a 500 HTTP status code - may retry later
	at sun.reflect.NativeConstructorAccessorImpl.newInstance0(Native Method)
	at sun.reflect.NativeConstructorAccessorImpl.newInstance(NativeConstructorAccessorImpl.java:57)
	at sun.reflect.DelegatingConstructorAccessorImpl.newInstance(DelegatingConstructorAccessorImpl.java:45)
    + 3 more (set debug level logging or '-Dmule.verbose.exceptions=true' for everything)
********************************************************************************

2016-05-16 16:50:35.205 [INFO] org.mule.api.processor.LoggerMessageProcessor:197 - Failed initial fulfillment state request for CR NA (message 34358392-dea5-43d5-a734-ea68e55e8524)

aveksaServer.log
 
05/08/2016 10:44:07.832 ERROR (http-0.0.0.0-8444-8) [com.aveksa.afx.common.service.AFXBaseService] Exception during AFX SQL execution
java.sql.SQLException: ORA-01461: can bind a LONG value only for insert into a LONG column

	at oracle.jdbc.driver.T4CTTIoer.processError(T4CTTIoer.java:440)
	at oracle.jdbc.driver.T4CTTIoer.processError(T4CTTIoer.java:396)
	at oracle.jdbc.driver.T4C8Oall.processError(T4C8Oall.java:837)
	...

05/08/2016 10:44:07.847 WARN  (http-0.0.0.0-8444-8) [com.aveksa.afx.server.service.handler.AFXFulfillmentStateRequestHandler] Error handling AFX fulfillment state request
com.aveksa.server.db.PersistenceException: java.sql.SQLException: ORA-01461: can bind a LONG value only for insert into a LONG column

	at com.aveksa.afx.common.service.AFXBaseService.executeStatement(AFXBaseService.java:84)
	...
 
Cause
Unicode truncate discrepancies done by AFX for none ASCII characters in the request payload.
Resolution
Apply 6.9.1 P16 or 7.0.0 P04 and above should fix the issue.
Workaround
  1. Stop AFX
  2. Backup $AFX_HOME/mule/apps/15_AFX-MAIN/fulfillment-state-components.xml
  3. Edit $AFX_HOME/mule/apps/15_AFX-MAIN/fulfillment-state-components.xml
    1. Directly after the following code:
          <flow name="AFX_FULFILLMENT_STATE">
              <!-- XML payload parsing to extract _AFX variables -->
              <script:component script-ref="xml-in-groovy" />
              <script:component script-ref="xml-out-groovy" />
      
    2. Add the following block:
              <script:component>
              <script:script engine="groovy">
              <![CDATA[
                  import java.nio.ByteBuffer
                  import java.nio.CharBuffer
                  import java.nio.charset.Charset
                  import java.nio.charset.CharsetDecoder
                  import java.nio.charset.CodingErrorAction
      
                  import com.aveksa.afx.common.messages.primary.Envelope
                  import com.aveksa.afx.common.messages.primary.EnvelopeConverter
      
                  public String byteLimitTruncate(String input, int maxBytes, String truncateIndicator) {
                      Charset utf8 = Charset.forName("UTF-8")
      
                      if (input == null) {
                              return null
                      } else {
                              byte[] inputBytes = input.getBytes(utf8)
      
                              if (maxBytes < 0) {
                                      return input
                              } else if (maxBytes == 0) {
                                      return ""
                              } else if (inputBytes.length > maxBytes) {
                                      int inputTruncateLength = maxBytes
                                      boolean useTruncateIndicator = false
      
                                      if (truncateIndicator != null) {
                                              int truncateIndicatorLength = truncateIndicator.getBytes(utf8).length
      
                                              if (truncateIndicatorLength < maxBytes) {
                                                      useTruncateIndicator = true
                                                      inputTruncateLength = maxBytes - truncateIndicatorLength
                                              }
                                      }
      
                                      CharsetDecoder cd = utf8.newDecoder()
                                      // length in bytes
                                      ByteBuffer bb = ByteBuffer.wrap(inputBytes, 0, inputTruncateLength)
                                      // length in characters <= length in bytes
                                      CharBuffer cb = CharBuffer.allocate(inputTruncateLength)
                                      // Ignore an incomplete character
                                      cd.onMalformedInput(CodingErrorAction.IGNORE)
                                      cd.decode(bb, cb, true)
                                      cd.flush(cb)
                                      return new String(cb.array(), 0, cb.position()) + (useTruncateIndicator ? truncateIndicator : "")
                              } else {
                                      return input
                              }
                      }
                  }
      
                  Envelope envelope = EnvelopeConverter.instance.unmarshal(payload) 
      
                  if (envelope?.body?.request != null && envelope.body.request.size() > 0 && envelope.body.request[0]?.response?.status != null) {
                      log.debug "Brief before: " + envelope.body.request[0].response.status.brief
                      log.debug "Detailed before: " + envelope.body.request[0].response.status.detailed
      
                      String brief = envelope.body.request[0].response.status.brief
                      String detailed = envelope.body.request[0].response.status.detailed
      
                      envelope.body.request[0].response.status.brief = byteLimitTruncate(brief, 512, "")
                      envelope.body.request[0].response.status.detailed = byteLimitTruncate(detailed, 4000, "...")
      
                      log.debug "Brief after: " + envelope.body.request[0].response.status.brief
                      log.debug "Detailed after: " + envelope.body.request[0].response.status.detailed
                  }
      
                  String output = EnvelopeConverter.instance.marshal(envelope)
      
                  log.debug "Output: " + output
      
                  return output
      
              ]]>
              </script:script>
              </script:component>
      
    3. Ensure that this is in the correct location by verifying that it's followed by this code:
      <logger level="INFO" message="returning: #[header:_AFX_ERROR_CODE] -> #[header:_AFX_ERROR_MESSAGE]" />
      
  4. Start AFX