Paging step based on response attribute containing @ symbol

We have a webservice connector configured which provides a paged result as part of the user get call. The link to the next page is available as part of the response attribute (@odata.nextLink). We have the following configured as paging step -

TERMINATE_IF [email protected]$ == NULL
$endpoint.fullUrl$ = [email protected]$

For some reason the terminate condition is triggering every time even though the response has the @odata.nextLink attribute. Any suggestion with regards to this is appreciated. Could this be because of the @ symbol on the header name? If so, is there a way to escape the @ character?

Hi @svenkitachalam,

Try using double quotes for your termination condition and paging setup.

TERMINATE_IF "${[email protected]}" == NULL
$endpoint.fullUrl$ = "${[email protected]}"

Using double quotes around the attribute name ("${[email protected]}" ) should allow IDN to correctly interpret and access the @odata.nextLink attribute.

Hope this helps!

1 Like

Thanks for your response. I tried giving double quotes but still seem to hit the terminate condition on the first run itself. This is what I see in the logs -
“message”:“PAGING: Termination triggered! Unable to evaluate paging step: $endpoint.fullUrl$ = "[email protected]$"”

Thanks,
Sreejith

I think you should remove the double quotes around the variable reference.
Try this,

$endpoint.fullUrl$ = ${[email protected]}

Now I get this -

{“exception”:{“stacktrace”:"java.lang.RuntimeException: sailpoint.connector.ConnectorException: Error: class java.lang.String cannot be cast to class java.lang.Boolean (java.lang.String and java.lang.Boolean are in module java.base of loader ‘bootstrap’)\n\tat sailpoint.connector.webservices.v2.WebServiceFacadeV2$WebServiceIterator.hasNext(WebServiceFacadeV2.java:2071)\n\tat sailpoint.connector.ConnectorProxy$CustomizingIterator.peek(ConnectorProxy.java:1331)\n

Here’s the paging step I have -

TERMINATE_IF ${response.@odata.nextLink} == NULL
$endpoint.fullUrl$ = ${response.@odata.nextLink}

Thanks,
Sreejith

You should still use the double-quoted syntax "${[email protected]}" for the termination condition.

TERMINATE_IF "${[email protected]}" == NULL
$endpoint.fullUrl$ = ${[email protected]}

Hope this works!

Getting this exception -
sailpoint.connector.ConnectorException: Url: ${response.@odata.nextLink}, Message: 0 : java.net.MalformedURLException: no protocol: ${response.@odata.nextLink}, HTTP Error Code: 0

Thanks,
Sreejith

It looks like an issue with URL formatting. Make sure that the value being assigned to $endpoint.fullUrl$ is a properly formatted URL. What I mean is that it should include the protocol (e.g., http:// or https:// ).
For example.

TERMINATE_IF "${[email protected]}" == NULL

$endpoint.fullUrl$ = "https://your-base-url.com/${[email protected]}"

Please replace "https://your-base-url.com/" with the actual base URL or endpoint URL for your specific web service connector.

Hope this helps!

Hi Sachin,

The value of @odata.nextLink includes the complete URL including the protocol. Here’s a sample value -
@odata.nextLink”: “https://graph.microsoft.com/v1.0/users/?$skiptoken=RFNwdAIAAQAAADk6YWFuZ290X3JlY

It looks like in when the value is assigned to full url, it is not substituting the response value but taking it as a ${response.@odata.nextLink} string.

Thanks,
Sreejith

Okay, at this point I think you should print or log the value of [email protected] just before assigning it to $endpoint.fullUrl$ to verify whether the value is being retrieved correctly and whether it’s a string.

Initially I thought you could add this,

$endpoint.fullUrl$ = ${[email protected]}.toString()

But if its indeed a string and you will still encounter issues with variable substitution

Okay. Do you know what syntax this is using? Is it velocity?
If I knew, I thought I could check that documentation.

Thanks,
Sreejith

Yes, its velocity. Try this,

#set($nextLink = $response.@odata.nextLink)
$log.info(“Next Link: $nextLink”)
$endpoint.fullUrl = $nextLink

Getting this -
sailpoint.connector.ConnectorException: Error: null

I think you should try this,

TERMINATE_IF “${response.@odata.nextLink}” == NULL
#set($nextLink = $response.@odata.nextLink)
$log.info(“Next Link: $nextLink”)
$endpoint.fullUrl = $nextLink

Same error - sailpoint.connector.ConnectorException: Error: null

I tried to fetch another attribute from response that does not contain @ in the name and it is fetching correctly. I feel if we can somehow escape @, that should work.

Okay, lets try this then,

#set($nextLink = $response?.@odata?.nextLink)
$log.info(“Next Link: $nextLink”)
TERMINATE_IF “$nextLink” == NULL
$endpoint.fullUrl = $nextLink

(?. ) is the safe navigation operator to access properties (@odata and nextLink ) of the $response object.

saw your message late,

Here’s how you can modify the code to escape the @ character:

#set($nextLink = $response[“@odata”].nextLink)
$log.info(“Next Link: $nextLink”)
TERMINATE_IF “$nextLink” == NULL
$endpoint.fullUrl = $nextLink

Same null exception. Here’s the stacktrace:

{“exception”:{“stacktrace”:"java.lang.RuntimeException: sailpoint.connector.ConnectorException: Error: null\n\tat sailpoint.connector.webservices.v2.WebServiceFacadeV2$WebServiceIterator.hasNext(WebServiceFacadeV2.java:2071)\n\tat sailpoint.connector.ConnectorProxy$CustomizingIterator.peek(ConnectorProxy.java:1331)\n\tat sailpoint.connector.ConnectorProxy$CustomizingIterator.hasNext(ConnectorProxy.java:1358)\n\tat com.sailpoint.ccg.aggregation.util.CisSourceIterator.hasNext(CisSourceIterator.java:46)\n\tat com.sailpoint.aggregation.server.service.extract.BaseExtractor.extract(BaseExtractor.java:237)\n\tat com.sailpoint.aggregation.server.service.extract.BaseExtractor.extractObjects(BaseExtractor.java:120)\n\tat com.sailpoint.aggregation.server.service.extract.AccountExtractor.extractObjects(AccountExtractor.java:16)\n\tat com.sailpoint.aggregation.server.service.SourceAggregator.aggregateAccounts(SourceAggregator.java:72)\n\tat com.sailpoint.ccg.handler.StreamingAggregationHandler.invoke(StreamingAggregationHandler.java:180)\n\tat sailpoint.gateway.accessiq.CcgPipelineMessageHandler.handleMessage_aroundBody0(CcgPipelineMessageHandler.java:47)\n\tat sailpoint.gateway.accessiq.CcgPipelineMessageHandler$AjcClosure1.run(CcgPipelineMessageHandler.java:1)\n\tat org.aspectj.runtime.reflect.JoinPointImpl.proceed(JoinPointImpl.java:167)\n\tat com.sailpoint.tracing.otel.TracedAspect.lambda$traceExecution$0(TracedAspect.java:34)\n\tat com.sailpoint.tracing.otel.GlobalTracer.trace(GlobalTracer.java:157)\n\tat com.sailpoint.tracing.otel.GlobalTracer.trace(GlobalTracer.java:136)\n\tat com.sailpoint.tracing.otel.GlobalTracer.trace(GlobalTracer.java:124)\n\tat com.sailpoint.tracing.otel.TracedAspect.traceExecution(TracedAspect.java:36)\n\tat sailpoint.gateway.accessiq.CcgPipelineMessageHandler.handleMessage(CcgPipelineMessageHandler.java:36)\n\tat com.sailpoint.pipeline.server.PipelineServer$InboundQueueListener$MessageHandler.run(PipelineServer.java:369)\n\tat java.base/java.util.concurrent.Executors$RunnableAdapter.call(Executors.java:515)\n\tat java.base/java.util.concurrent.FutureTask.run(FutureTask.jav