S3 Upload Part Couldnt Find a Transformer in Mule
Hello Coder,
As before long equally we start writing Mule flows nosotros need to practice the conversion of information from i class to another and that is how a message (request-response) menstruum in any application works. For instance if we are writing endpoints for a mobile awarding, our server receives a request in some specified format say XML and it demand to give response in other format say JSON. So what we will practice in this case is to kickoff parse the request XML to a String and then to a Coffee object or volition use some 3rd party library which volition do this transformation for us. Same applies to the response also. The work seems reasonable if the endpoints are less but what if we need to provide thou endpoints to a mobile application ? Are we going to do this repeated procedure of transformation ? NO. That's where Mule wins the race considering it provides inbuilt transformers which will do the conversion. In this tutorial nosotros volition focus on Mule Custom Transformers. Beginning we volition understand what are transformers in Mule and why we demand them. And then we will attempt to write our ain custom transformer and add it in our existing Mule menstruum.
1) What is a Mule Transformer ?
A transformer is a joint point between two components in a Mule Flow. A Transformer enhances and or modifies the incoming mule message and prepares such a mule message which volition be processed by the adjacent available component in the Mule flow. Message transformation is done via payloads in the Mule Message. In other words a transformer is nothing but a uncomplicated java form which transforms the message from one format to another. There are many default transformers shipped with Mule ESB, some of them are Object-to-String, Object-to-Json, JAXB-Object-to-Xml, Object-to-xml etc. Every bit their name suggests these transformers are used to transform the incoming message from i form to another. The incoming message comes as a payload to the transformer, the transformer applies the transformation to the bulletin and sets the transformed bulletin again in the payload.
ii) Why are transformers needed in a Mule application ?
Transformers are the backbone of any ESB application because no ESB tin live without transformers. 1 of the ESB's major function is to connect two systems without changing the source and destination system. In that location is very less possibility that both the systems produces/consumes the data in aforementioned format and also live as an contained arrangement. Here the transformers come into picture show in a Mule awarding flow. Transformers are needed when the next component in the menstruation expects the message in other format than the current component have. For example, the mule message that initiates the mule flow receives data in XML format, merely a downstream message processor requires data in JSON format. In this case the transformers positioned betwixt the message source and the message processor can achieve this translation. By default no XML-to-JSON transformer exists in Mule, hence in this detail tutorial we will write a custom transformer which converts a XML message to JSON message and pass the JSON to next component.
iii) How to write a custom transformer
In the above case if the incoming message to a component is in XML format (as we used in our concluding post here) and suppose we want to pass this XML message to some other flow or an outbound endpoint (outbound endpoints are used to make http requests outside of Mule ESB) for further processing which expects the message in JSON format then we need to write custom transformer and practice the transformation of message in the transformer. To write a custom transformer y'all need to write a custom java class which extends org.mule.transformer.AbstractMessageTransformer
from mule-core module. AbstractMessageTransformer
is an abstract grade with an abstruse method :
public abstract Object transformMessage(MuleMessage message, String outputEncoding) throws TransformerException;
From the documentation of AbstractMessageTransformer
class:
AbstractMessageTransformer
is a transformer that has a reference to the current bulletin. This message tin can be used to obtain backdrop associated with the current message which are useful to the transform. Note that when part of a transform chain, the MuleMessage payload reflects the pre-transform message state, unless there is no electric current outcome for this thread, then the message will exist a new DefaultMuleMessage with the src as its payload. Transformers should e'er piece of work on the src object not the message payload.
In our custom transformer class we need to override the transformMessage
method from AbstractMessageTransformer
and provide the implementation of this method. The implementation is responsible to read the incoming bulletin to the transformer, transform it to another format and pass it to side by side component or catamenia or outbound endpoint. The MuleMessage
parameter is the message which mule populates, wraps the request inside information technology and passes it to this transformer. In our example the XML bulletin will be received in the MuleMessage
object. We need to employ this message object to pull the requested xml object out of it and utilize the desired conversion.
We will update the mule menstruum divers here to add 2 more components after the Soap component. We will add 2 JAVA transformers by dragging and dropping the Coffee transformer component from right pane to the flow. Our period volition look similar this after this (Ignore the "JSON request to xml response" transformer for now.):
Soap webservice Mule flow
Likewise in gild to completely visualize the object transformation we will update the original wsdl to transport and receive the custom objects instead of primitive types. We are doing this and so that we tin get a Java object in our transformer and we can typeCast information technology from MuleMessage
. Here is the updated wsdl for previous post :
<?xml version="1.0" encoding="UTF-8"?> <wsdl:definitions name="DoubleIt" xmlns:xsd="http://world wide web.w3.org/2001/XMLSchema" xmlns:wsdl="http://schemas.xmlsoap.org/wsdl/" xmlns:soap="http://schemas.xmlsoap.org/wsdl/soap/" xmlns:di="http://www.example.org/schema/DoubleIt" xmlns:tns="http://www.example.org/contract/DoubleIt" targetNamespace="http://www.example.org/contract/DoubleIt"> <wsdl:types> <xsd:schema targetNamespace="http://world wide web.example.org/schema/DoubleIt"> <xsd:element name="DoubleIt"> <xsd:complexType> <xsd:sequence> <xsd:element minOccurs="1" maxOccurs="1" proper noun="requestItem" type="di:ItemsToProcess"/> </xsd:sequence> </xsd:complexType> </xsd:element> <xsd:complexType proper noun="ItemsToProcess"> <xsd:sequence> <xsd:element minOccurs="one" maxOccurs="i" proper name="numberToDouble" type="xsd:int"/> <xsd:element minOccurs="1" maxOccurs="1" proper noun="numberToHalf" type="xsd:int"/> </xsd:sequence> </xsd:complexType> <xsd:element name="DoubleItResponse"> <xsd:complexType> <xsd:sequence> <xsd:element minOccurs="one" maxOccurs="1" name="responseItem" type="di:ItemsToResponse"/> </xsd:sequence> </xsd:complexType> </xsd:element> <xsd:complexType proper noun="ItemsToResponse"> <xsd:sequence> <xsd:element minOccurs="1" maxOccurs="one" name="numberToDouble" type="xsd:int"/> <xsd:element minOccurs="i" maxOccurs="1" name="numberToHalf" type="xsd:int"/> </xsd:sequence> </xsd:complexType> </xsd:schema> </wsdl:types> <wsdl:bulletin name="DoubleItRequest"> <wsdl:role element="di:DoubleIt" name="parameters" /> </wsdl:message> <wsdl:message name="DoubleItResponse"> <wsdl:part element="di:DoubleItResponse" name="parameters" /> </wsdl:bulletin> <wsdl:portType proper noun="DoubleItPortType"> <wsdl:operation name="DoubleIt"> <wsdl:input message="tns:DoubleItRequest" /> <wsdl:output message="tns:DoubleItResponse" /> </wsdl:functioning> </wsdl:portType> <wsdl:binding name="DoubleItBinding" type="tns:DoubleItPortType"> <lather:binding style="document" transport="http://schemas.xmlsoap.org/soap/http" /> <wsdl:operation name="DoubleIt"> <soap:operation soapAction=""/> <wsdl:input><soap:body utilize="literal"/></wsdl:input> <wsdl:output><soap:body employ="literal"/></wsdl:output> </wsdl:operation> </wsdl:binding> <wsdl:service name="DoubleItService"> <wsdl:port proper noun="DoubleItPort" bounden="tns:DoubleItBinding"> <!-- Default accost for Tomcat deployment (CXF/Metro) --> <soap:address location="http://localhost:8090/mulesvc/sample/soapws/DoubleIt.svc"/> <!-- Default address for Karaf deployment (CXF only) --> <!--soap:address location="http://localhost:8181/cxf/doubleit"/--> </wsdl:port> </wsdl:service> </wsdl:definitions>
Yous need to generate the JAXB classes once more from this updated wsdl. You lot can apply the Anypoint Studio to generate the classes this time or else you demand to again perform the Footstep 10 of this post.
Now, we will write two transformers in this example every bit the flow shows above. Nosotros are writing two transformers so that we can larn the transformer chaning also and view the transformed message from first transformer in 2nd transformer :
1) XML to JSON Transformer and
2) JSON to XML Transformer
1) XML to JSON transformer
This transformer will receive the XML request (JAXB objects) from SOAP component as Message Payload. In this transformer we will transform the incoming XML asking to side by side transformer's understandable JSON Cord format. Beneath is the full code for this transformer.
bundle com.sample.mule.impl; import org.mule.api.MuleMessage; import org.mule.api.transformer.TransformerException; import org.mule.transformer.AbstractMessageTransformer; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import com.fasterxml.jackson.core.JsonProcessingException; import com.fasterxml.jackson.databind.DeserializationFeature; import com.fasterxml.jackson.databind.ObjectMapper; import com.fasterxml.jackson.databind.SerializationFeature; import com.sample.mule.ItemsToProcess; public grade XmlToJsonTransformer extends AbstractMessageTransformer { private static final Logger LOGGER = LoggerFactory.getLogger(XmlToJsonTransformer.class.getName()); @Override public Object transformMessage(MuleMessage message, Cord outputEncoding) throws TransformerException { // Incoming request xml object ItemsToProcess request = (ItemsToProcess) bulletin.getPayload(); JsonMessage transformed = new JsonMessage(); transformed.setNumberToDouble(String.valueOf(request.getNumberToDouble())); transformed.setNumberToHalf(Cord.valueOf(request.getNumberToHalf())); try { // Parse the java object to a json string String jsonString = getObjectMapper().writeValueAsString(transformed); // Set up the json string for next component/outbound-endpoint/sub-catamenia message.setPayload(jsonString); } catch (JsonProcessingException e) { LOGGER.fault("Cannot catechumen into json"); } return message; } individual static ObjectMapper getObjectMapper() { final ObjectMapper result = new ObjectMapper(); consequence.configure(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES, false); event.configure(SerializationFeature.INDENT_OUTPUT, true); return result; } }
The render blazon of message.getPayload()
is Object
. This is then that information technology tin can be typecasted to the incoming Java object. Since in our example, as per updated wsdl file, the requested JAXB object would be ItemsToProcess
hence we can safely typecast the payload to ItemsToProcess
. Now nosotros tin create our custom JsonMessage
and set its fields from the ItemsToProcess
object. Next nosotros will use the jackson library to catechumen the coffee object to a String json. We will exit the jacson details upto the reader until nosotros write a separate mail for Jackson.
One time we congenital the Cord JSON in the overridden transformMessage()
method nosotros demand to pass it to outside of this component. We can easily practice information technology past setting it to the payload again then the original payload (XML) will be updated by new payload (JSON). Once the payload is updated nosotros need to return it dorsum to Mule so that it can take the updated payload and pass it to side by side transformer (Json To Xml Transformer). Mule will take care that the adjacent transformer receives the updated payload.
two) JSON to XML Transformer
This is the transformer which receives the JSON request from its previous component. It transforms the incoming JSON message to an XML response and passes it further to to Soap component. This is the same as defined in XML-to-JSON transformer, just with reversed process. Here is the full code of this transformer:
package com.sample.mule.impl; import org.mule.api.MuleMessage; import org.mule.api.transformer.TransformerException; import org.mule.transformer.AbstractMessageTransformer; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import com.fasterxml.jackson.databind.DeserializationFeature; import com.fasterxml.jackson.databind.ObjectMapper; import com.fasterxml.jackson.databind.SerializationFeature; import com.sample.mule.ItemsToResponse; public class JsonToXmlTransformer extends AbstractMessageTransformer { private static last Logger LOGGER = LoggerFactory.getLogger(JsonToXmlTransformer.course.getName()); @Override public Object transformMessage(MuleMessage message, String outputEncoding) throws TransformerException { // Incoming asking xml object endeavour {
String incomingJson = message.getPayloadAsString(); JsonMessage request = getObjectMapper().readValue(incomingJson, JsonMessage.class); ItemsToResponse response = new ItemsToResponse(); response.setNumberToDouble(Integer.valueOf(asking.getNumberToDouble())*two); response.setNumberToHalf(Integer.valueOf(asking.getNumberToHalf())/2); bulletin.setPayload(response); } grab (Exception due east) { LOGGER.error("Error transforming JSON to XML"); } return message; } private static ObjectMapper getObjectMapper() { concluding ObjectMapper result = new ObjectMapper(); result.configure(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES, false); result.configure(SerializationFeature.INDENT_OUTPUT, true); return result; } }
This transformer receives the JSON sent by previous transformer in a String format. Since we know the previous transformer had written a String in the payload hence hither we can safely use the getPayloadAsString()
method to get the incoming request. We will utilize jackson library again to convert the JSON Cord to Java object. After transformation to Java object we can apply the logic for our webservice, multiply by two and split up past ii, and create a ItemsToResponse
object.
Now we need to set this ItemsToResponse
object to payload and so information technology will be returned to SOAP component and and so it volition be returned to the Soap service caller via http endpoint.
To accept a working menses you need to provide the fully qualified transformer class proper noun to each of these component's properties department in the "Transformer class" tag. Run across the epitome from Anypoint studio below:
XML to Json Transformer
You need to do this for both the Transformers and relieve the mule flow xml. Now start the Mule application from Anypoint studio and transport a Lather asking from a tool similar SOAPUI. Below is the snapshot of this SOAP request-response from my machine.
Lather UI request response
Hither is the total mule flow xml
<?xml version="1.0" encoding="UTF-viii"?> <mule xmlns:cxf="http://www.mulesoft.org/schema/mule/cxf" xmlns:http="http://www.mulesoft.org/schema/mule/http" xmlns:tracking="http://www.mulesoft.org/schema/mule/ee/tracking" xmlns="http://world wide web.mulesoft.org/schema/mule/core" xmlns:medico="http://www.mulesoft.org/schema/mule/documentation" xmlns:spring="http://www.springframework.org/schema/beans" version="EE-3.6.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-electric current.xsd http://www.mulesoft.org/schema/mule/core http://www.mulesoft.org/schema/mule/core/current/mule.xsd http://www.mulesoft.org/schema/mule/http http://world wide web.mulesoft.org/schema/mule/http/current/mule-http.xsd http://world wide web.mulesoft.org/schema/mule/ee/tracking http://www.mulesoft.org/schema/mule/ee/tracking/current/mule-tracking-ee.xsd http://www.mulesoft.org/schema/mule/cxf http://www.mulesoft.org/schema/mule/cxf/electric current/mule-cxf.xsd"> <http:listener-config name="Connector_Config" host="localhost" port="8090" doc:name="HTTP Listener Configuration" basePath="mulesvc"/> <flow proper name="soap-webservice-muleFlow"> <http:listener config-ref="Connector_Config" path="sample/soapws/DoubleIt.svc" doc:name="HTTP"/> <object-to-string-transformer doc:name="Object to Cord"/> <logger message="#[payload]" level="INFO" medico:name="Logger"/> <cxf:jaxws-service service="DoubleIt.svc" serviceClass="com.sample.mule.DoubleItPortType" doc:name="CXF" wsdlLocation="C:\Mule-workspace\workspace\soap-ws-mule\src\principal\resources\example-soap-ws.wsdl"/> <!-- <component form="com.sample.mule.impl.DoubleItPortTypeImpl" doc:name="Java"/> --> <custom-transformer class="com.sample.mule.impl.XmlToJsonTransformer" doc:name="Xml Request To Json"/> <custom-transformer grade="com.sample.mule.impl.JsonToXmlTransformer" dr.:proper name="Json request to xml response"/> </menses> </mule>
Observe the highlighted lines in above flow xml which were added afterwards we kept these 2 chaining Java transformers. These custom-transformer tags contains our fully qualified grade names. So when, at runtime, mule flow execution reaches to these components, Mule will call transformMessage()
of each of them sequentially in the order they are defined in the flow XML.
Annotation: To go on the example simple we have used transformer chaining i.east joined two transformers. In more than circuitous scenarios the bulletin transformed from a transformer can be passed to a subflow or an entirely separate http out-bound endpoint.
I hope it will assist you lot.
Source: https://javacodinggeeks.blogspot.com/2015/05/writing-custom-transformers-in-mule.html
0 Response to "S3 Upload Part Couldnt Find a Transformer in Mule"
Post a Comment