简体   繁体   中英

mule 4.4 community edition - parsing file read as stream

This question is a follow up to my earlier question [here][1] Thanks to @aled I am using 'set-payload' with expression.

Am reading a file and trying to parse and then validate each row. Edit2: added File details below: ( I need to validate that each row of the file has a price value, in below example line item 'Butter' has no price so should be flagged as an error while the other rows are good and they should be sent as a POST request to a third party api

d1|Milk|3.9|
d2|Butter||
g1|Bread|1.6|
g2|Biscuits|3.4|
d3|Yogurt|5.5|
d4|Flavored Yogurt|5.5|
m1|Toothbrush|12|

File reading is a repeatable-in-memory-stream
Now after reading the file, am setting the payload using 'set-payload'. Here is the complete code of this flow:

<flow name="get:shoppingProducts" >
    <logger level="INFO" doc:name="Logger" message="get list of products request received "/>
    <file:read doc:name="Read file"  config-ref="File_Config" path="/product_master/test.unl" outputMimeType='application/csv; header=false; separator=|' outputEncoding="utf-8">
        <repeatable-in-memory-stream />
    </file:read>
    <choice doc:name="is the file empty ?" >
        <when expression="sizeOf(payload) == 0">
            <logger level="ERROR" doc:name="Payload is empty " message="Empty payload from File read !"/>
            <raise-error doc:name="Raise error on empty file " type="XYZ:EMPTY" description="Empty file"/>
        </when>
        <otherwise >
            <logger level="INFO" doc:name="Payload not empty"  message="All good"/>
        </otherwise>
    </choice>

    <set-payload value="#[output application/json

    ---

    payload map (value,index)->
    {
      id:value.column_0,
      description:value.column_1,
      price:value.column_2

     }]" doc:name="Set Payload" mimeType="application/json" encoding="UTF-8"  />

    <foreach doc:name="For Each file record" collection="#[payload]">
        <logger level="DEBUG" doc:name="Log record" message="#[payload.description]"/>
        <scripting:execute doc:name="Validate data" engine="Groovy">
            <scripting:code ><![CDATA[println("hello world 001");
            println(payload);
            println("hello world 002");
            println(message.getPayload());
            println("hello world 003");
            println(payload.description);]]></scripting:code>
        </scripting:execute>
    </foreach>
    <logger level="INFO" doc:name="Logger"  message="after reading products file  "/>

This seems to work fine and I can see payload like below ( after calling set-payload ):

[
  {
    "id": "d1",
    "description": "Milk",
    "price": 3.9
  },
  {
    "id": "d2",
    "description": "Butter",
    "price": 4.5
  },
  ...
]

Now I am trying to iterate over the data in a for loop First component in the for loop is a 'Logger' which is logging the payloads description:

<logger level="DEBUG" doc:name="Log record" message="hello we are here #[payload.description]"/>

This is showing up fine in logs:

hello we are here "Milk"

( I am running code in debug mode ) and now the minute control reaches my groovy script inside the for loop, things go wrong... In debug the payload still shows up correctly as:

{
  "id": "d1",
  "description": "Milk",
  "price": "3.9"
}

However when I try and access one of its attributes in groovy script am getting this error:

"groovy.lang.MissingPropertyException: No such property: description for class: org.mule.runtime.core.internal.streaming.bytes.ManagedCursorStreamDecorator"

Could this be happening because I am using 'repeatable-in-memory-stream' which is causing for loop to again get the stream rather than json payload?

I also tried changing file read to: non-repeatable-stream but in this case my set-payload script is not able to handle:

org.mule.runtime.module.extension.internal.runtime.result.AbstractReturnDelegate$ConnectedInputStreamWrapper@70ee7444

What am I doing wrong and how to correct this please?

The problem is your groovy script. You are assuming the objects are a specific Java class and trying to access it directly. In some cases it may be true but you can not make assumptions. It also completely unneeded since Mule 4 & DataWeave provide a direct alternative to what you are trying to do (ir a logger component). Mule 4 is designed for users to avoid having to resort to Java or Groovy for normal tasks.

In your updated comments and question you made it clear that you need to validate that the price field is not null. That is a very basic validation and there is absolutely no need to go the Groovy/Java route for that. You can add a choice router inside the foreach loop with condition isEmpty(payload.price) to validate if the price is null, empty or spaces (since it is a string spaces is a valid check). Mule built-in components know to handle payloads that are contained in a stream transparently you don't even need to bother about handling streams.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM