0
votes

I'm trying to build a web service that accepts a number of variables used to build the path for Bing query API. For some reason, if I build the URI my flow recognizes that the new URI is assigned appropriately to the payload, but when I assign the payload to the out-bound HTTP endpoint, it fails.

<flow name="BingQuery" doc:name="BingQuery">
        <http:inbound-endpoint exchange-pattern="one-way" host="localhost" port="8082" doc:name="HTTP" />
       <set-variable variableName="query" doc:name="Variable" value="#[header:INBOUND:query]"/>
       <set-variable variableName="numResults" doc:name="Variable" value="#[header:INBOUND:top]"/>
       <set-variable variableName="offsetResults" doc:name="Variable" value="#[header:INBOUND:offset]"/>
       <scripting:component doc:name="Groovy">
           <scripting:script engine="Groovy">
               <scripting:text><![CDATA[def query = message.getInvocationProperty("query")
                def numResults = message.getInvocationProperty("numResults")
                def offsetResults = message.getInvocationProperty("offsetResults")
                def path = "Data.ashx/Bing/Search/v1/Web?Query=" + "$query" + "&amp;WebFileType=%27PDF%27&amp;\$top=" + "$numResults" + "&amp;\$skip=" + "$offsetResults" + "&amp;\$format=Json"
                    println "$path"
                    message.setProperty("pathVar","$path")
                    return null;]]></scripting:text>
           </scripting:script>
       </scripting:component> 
       <logger level="INFO" doc:name="Logger" message="#[header:OUTBOUND:pathVar]"/> 
        <https:outbound-endpoint exchange-pattern="request-response"
            host="api.datamarket.azure.com" port="443" path="#[header:OUTBOUND:pathVar]"
            user="*****" password="******"
            doc:name="Bing" /> ...

The exception I get is

ERROR 2012-10-25 14:14:26,250 [[poll_directory].BingQuery.stage1.02] org.mule.exception.DefaultMessagingExceptionStrategy: 
********************************************************************************
Message               : Failed to transform from "json" to "java.util.Map"
Code                  : MULE_ERROR-65110
--------------------------------------------------------------------------------
Exception stack is:
1. Unexpected character ('T' (code 84)): expected a valid value (number, String, array, object, 'true', 'false' or 'null')
at [Source: java.io.InputStreamReader@73b62d67; line: 1, column: 2] (org.codehaus.jackson.JsonParseException)
 org.codehaus.jackson.JsonParser:1291 (null)
2. Failed to transform from "json" to "java.util.Map" (org.mule.api.transformer.TransformerException)
 org.mule.module.json.transformers.JsonToObject:136 (http://www.mulesoft.org/docs/site/current3/apidocs/org/mule/api/transformer/TransformerException.html)
--------------------------------------------------------------------------------
Root Exception stack trace:
org.codehaus.jackson.JsonParseException: Unexpected character ('T' (code 84)): expected a valid value (number, String, array, object, 'true', 'false' or 'null')
at [Source: java.io.InputStreamReader@73b62d67; line: 1, column: 2]
    at org.codehaus.jackson.JsonParser._constructError(JsonParser.java:1291)
    at org.codehaus.jackson.impl.JsonParserMinimalBase._reportError(JsonParserMinimalBase.java:385)
    at org.codehaus.jackson.impl.JsonParserMinimalBase._reportUnexpectedChar(JsonParserMinimalBase.java:306)
   + 3 more (set debug level logging or '-Dmule.verbose.exceptions=true' for everything)
********************************************************************************

There has to be a simple reason it isn't working and I'm sure it's just because I don't know the proper syntax yet in Mule. I also know there is probably a better way to do this using MEL versus Groovy, but I'm not familiar enough with MEL to do it yet.

SOLUTION

Turns out some of the characters of the User property and Password property were being encoded before being sent. Putting that key into a variable before passing to the User & Password property prevents that and led to success.

<?xml version="1.0" encoding="UTF-8"?>

<mule xmlns:scripting="http://www.mulesoft.org/schema/mule/scripting" xmlns="http://www.mulesoft.org/schema/mule/core" xmlns:json="http://www.mulesoft.org/schema/mule/json"
    xmlns:vm="http://www.mulesoft.org/schema/mule/vm" xmlns:http="http://www.mulesoft.org/schema/mule/http"
    xmlns:https="http://www.mulesoft.org/schema/mule/https" xmlns:file="http://www.mulesoft.org/schema/mule/file"
    xmlns:doc="http://www.mulesoft.org/schema/mule/documentation"
    xmlns:spring="http://www.springframework.org/schema/beans" xmlns:core="http://www.mulesoft.org/schema/mule/core"
    version="CE-3.3.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
    xsi:schemaLocation="
http://www.mulesoft.org/schema/mule/json http://www.mulesoft.org/schema/mule/json/current/mule-json.xsd 
http://www.mulesoft.org/schema/mule/vm http://www.mulesoft.org/schema/mule/vm/current/mule-vm.xsd 
http://www.mulesoft.org/schema/mule/http http://www.mulesoft.org/schema/mule/http/current/mule-http.xsd 
http://www.mulesoft.org/schema/mule/https http://www.mulesoft.org/schema/mule/https/current/mule-https.xsd 
http://www.mulesoft.org/schema/mule/file http://www.mulesoft.org/schema/mule/file/current/mule-file.xsd 
http://www.mulesoft.org/schema/mule/scripting http://www.mulesoft.org/schema/mule/scripting/current/mule-scripting.xsd 
http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-current.xsd 
http://www.mulesoft.org/schema/mule/core http://www.mulesoft.org/schema/mule/core/current/mule.xsd ">
    <configuration doc:name="Configuration">
        <expression-language>
            <import class="org.mule.util.StringUtils" />
        </expression-language>
    </configuration>
    <flow name="BingQuery" doc:name="BingQuery">
        <http:inbound-endpoint exchange-pattern="one-way" host="localhost" port="8082" doc:name="HTTP" />
       <set-variable variableName="query" doc:name="Variable" value="#[header:INBOUND:query]"/>
       <set-variable variableName="numResults" doc:name="Variable" value="#[header:INBOUND:top]"/>
       <set-variable variableName="offsetResults" doc:name="Variable" value="#[header:INBOUND:offset]"/>
        <scripting:component doc:name="Groovy">
          <scripting:script engine="Groovy">
              <scripting:text><![CDATA[def query = message.getInvocationProperty("query")
               def numResults = message.getInvocationProperty("numResults")
               def offsetResults = message.getInvocationProperty("offsetResults")
               def path = "Data.ashx/Bing/Search/v1/Web?Query=" + "$query" + "&WebFileType=%27PDF%27&\$top=" + "$numResults" + "&\$skip=" + "$offsetResults" + "&\$format=Json"
                   println "$path"
                   message.setProperty("pathVar","$path")
                   message.setProperty("APIIdentifier","*****")
                   return null;]]></scripting:text>
          </scripting:script>
      </scripting:component>
        <https:outbound-endpoint exchange-pattern="request-response"
            host="api.datamarket.azure.com" port="443" path="#[header:OUTBOUND:pathVar]"
            user="#[header:OUTBOUND:APIIdentifier]" password="#[header:OUTBOUND:APIIdentifier]"
            doc:name="Bing" />
        <json:json-to-object-transformer
            returnClass="java.util.Map" doc:name="JSON to Object" />
        <expression-transformer expression="#[message.payload.d.results]"
            doc:name="Expression" />
        <collection-splitter doc:name="Collection Splitter" />
        <vm:outbound-endpoint exchange-pattern="one-way"
            path="fileWriter" doc:name="VM" />
    </flow>
    <flow name="RestProcessor" doc:name="RestProcessor">
        <vm:inbound-endpoint exchange-pattern="one-way"
            path="fileWriter" doc:name="VM" />
        <set-variable variableName="fileName" value="#[message.payload.ID].pdf"
            doc:name="Variable" />
        <http:rest-service-component
            serviceUrl="#[joinChar=message.payload.Url.contains('?')?'&amp;':'?' ; StringUtils.join(new String[]{message.payload.Url,(String)joinChar,'followRedirects=true'})]"
            httpMethod="GET">
           <http:error-filter> 
               <expression-filter expression="#[Integer.valueOf(message.inboundProperties['http.status']) &gt;= 400]"></expression-filter> 
           </http:error-filter>
        </http:rest-service-component>
        <file:outbound-endpoint path="/home/administrator/Documents"
            outputPattern="#[flowVars.fileName]" responseTimeout="10000"
            mimeType="application/pdf" doc:name="File" />
    </flow>
</mule>
1

1 Answers

1
votes

Here is the beginning of the flow rewritten with MEL (which works for me, although I tested against a test endpoint not Bing).

Note that I also set the method to GET on the outbound HTTPS endpoint:

<flow name="BingQuery">
    <http:inbound-endpoint exchange-pattern="one-way"
        host="localhost" port="8082" />
    <set-variable variableName="query"
        value="#[message.inboundProperties.query]" />
    <set-variable variableName="numResults"
        value="#[message.inboundProperties.top]" />
    <set-variable variableName="offsetResults"
        value="#[message.inboundProperties.offset]" />
    <expression-component>
        flowVars['bingQuery'] =
            'Data.ashx/Bing/Search/v1/Web?Query=' + query
          + '&amp;WebFileType=%27PDF%27&amp;$top=' + numResults
          + '&amp;$skip=' + offsetResults
          + '&amp;$format=Json';
        payload = null;
    </expression-component>
    <logger level="ERROR" message="#[bingQuery]" />
    <http:outbound-endpoint exchange-pattern="request-response"
        method="GET"
        host="api.datamarket.azure.com" port="443" path="#[bingQuery]"
        user="*****" password="******" />

If the query, numResults and offsetResults variables are not used elsewhere in the flow, I suggest inlining the expressions used to create them right in the expression-component.