Accepting gzipped requests in CXF - cxf

I'm using Apache CXF to develop a JAX-RS service. My service is working, but I want to change it to accept compressed (gzipped) requests.
I've done some googling and added this to my beans.xml file:
<bean id="GZIPInInterceptor" class="org.apache.cxf.transport.common.gzip.GZIPInInterceptor"/>
<bean id="compressGZIPFeature" class="org.apache.cxf.transport.http.gzip.GZIPFeature"/>
<cxf:bus>
<cxf:inInterceptors>
<ref bean="GZIPInInterceptor"/>
</cxf:inInterceptors>
<cxf:features>
<ref bean="compressGZIPFeature"/>
<cxf:logging/>
</cxf:features>
</cxf:bus>
but when I call the service from my client application with a compressed request, I get the error Invalid UTF-8 start byte 0x8b and this in the log file:
28-May-2012 12:59:42 org.apache.cxf.interceptor.AbstractLoggingInterceptor log
INFO: Inbound Message
----------------------------
ID: 5
Address: http://localhost:8080/ ... /
Encoding: ISO-8859-1
Http-Method: POST
Content-Type: application/xml
Headers: {Accept=[application/xml], connection=[Keep-Alive], content-encoding=[g
zip], Content-Length=[246], content-type=[application/xml], expect=[100-continue
], host=[localhost:8080]}
Payload: ? ? ý¢`?I?%&/m-{¦J§JÎÓt?`?$Ï?#?ý-?-µ?ý?iG#)½*?-eVe]f?#¦Ý?+¸Ì{´¢¸Ì{´
¢¸¦;?N'¸¯ ?\fd?l÷+J++?!?¬+??~|??"? ?´?ez?ÎMQ-?¹hw+¾Q?/ºi¼X^|÷Ц=¯>°Þ¸8z|͵?ú4}|·
???¡-÷t+ÍÎgO?÷vv¸v÷w÷´¦ tg¦¸-/Õ+´Ý}¦¦w?¦+C¤/²®_·dþÚ¦²{;'??>³¶ßÚ+¦'¤?Ý|·õ¦±¦¦¦?O?
¯Ý>¥¦?·°.w
--------------------------------------
28-May-2012 12:59:43 org.apache.cxf.jaxrs.provider.AbstractJAXBProvider handleJA
XBException
WARNING: javax.xml.bind.UnmarshalException
- with linked exception:
[com.ctc.wstx.exc.WstxIOException: Invalid UTF-8 start byte 0x8b (at char #2, by
te #-1)]
at com.sun.xml.bind.v2.runtime.unmarshaller.UnmarshallerImpl.handleStrea
mException(UnmarshallerImpl.java:426)
...
28-May-2012 12:59:43 org.apache.cxf.interceptor.AbstractLoggingInterceptor log
INFO: Outbound Message
---------------------------
ID: 5
Response-Code: 400
Content-Type: text/plain
Headers: {Content-Type=[text/plain], Date=[Mon, 28 May 2012 11:59:43 GMT]}
Payload: JAXBException occurred : Invalid UTF-8 start byte 0x8b (at char #2, byt
e #-1). Invalid UTF-8 start byte 0x8b (at char #2, byte #-1).
--------------------------------------

In CXF, you can use
#GZIP
annotations for compressing the messages

The answer was that the interceptor was not getting picked up from the XML file. I tried adding this annotation above my service method and it started working:
#org.apache.cxf.interceptor.InInterceptors (interceptors = {"org.apache.cxf.transport.common.gzip.GZIPInInterceptor" })

Related

How to get AMQP Message properties in Apache Camel AMQP Component

I have a Springboot application using Apache Camel AMQP component to comsume messages from a Solace Queue. To send a message to the Queue I use Postman and the Solace REST API. In order to differentiate the message type I add Content-Type to the header of the Http request in Postman. I used SDKPerf to check the message header consumed from solace and the message header is found under "HTTP Content Type" along with other headers.
However, I can't seem to find a way to get this Content-Type from Camel Side. In the documentation it says
String header = exchange.getIn().getHeader(Exchange.CONTENT_TYPE, String.class);
However this always produces null. Any Ideas how to get the message properties in Camel?
EDIT: I think it's actually due to the fact that Camel is using QPid JMS, and there is no JMS API way of getting the Content Type, it's not in the spec. Even though AMQP 1.0 does support content-type as a property. But yeah, my suggestion of a custom property below is still probably the way I would go.
https://camel.apache.org/components/3.20.x/amqp-component.html
https://www.amqp.org/sites/amqp.org/files/amqp.pdf
Edited for clarity & corrections. TL/DR: use a custom user property header.
The SMF Content Type header in the original (REST) message is passed through to the consumed AMQP message as a property content-type, however the JMS API spec does not expose this; there is no way in standard JMS to retrieve this value. It is, however, used by the broker to set the type of message (e.g. TextMessage). Check "Content-Type Mapping to Solace Message Types" in the Solace docs.
Using Solace's SDKPerf AMQP JMS edition to dump the received message to console (note this uses QPid libraries):
./sdkperf_jmsamqp.sh -cip=amqp://localhost:5672 -stl=a/b/c
-md -q
curl http://localhost:9000/TOPIC/a/b/c -d 'hello' -H 'Content-Type: text'
^^^^^^^^^^^^^^^^^^ Start Message ^^^^^^^^^^^^^^^^^^^^^^^^^^^
JMSDeliveryMode: PERSISTENT
JMSDestination: a/b/c
JMSExpiration: 0
JMSPriority: 4
JMSTimestamp: 0
JMSRedelivered: false
JMSCorrelationID: null
JMSMessageID: null
JMSReplyTo: null
JMSType: null
JMSProperties: {JMSXDeliveryCount:1;}
Object Type: TextMessage
Text: len=5
hello
The header does not get mapped through, but does get used to set the message type. If I remove that HTTP header, the received AMQP message is binary. But since other types of Content-Types also map to TextMessages (e.g. application/json, application/xml, etc.), the fact you're receiving a TextMessage is not enough to infer exactly what Content-Type you published your REST message with.
For completeness, I used WireShark with an AMQP decoder, and you can see the header present on the received AMQP message:
Frame 3: 218 bytes on wire (1744 bits), 218 bytes captured (1744 bits) on interface \Device\NPF_Loopback, id 0
Null/Loopback
Internet Protocol Version 4, Src: 127.0.0.1, Dst: 127.0.0.1
Transmission Control Protocol, Src Port: 5672, Dst Port: 60662, Seq: 2, Ack: 1, Len: 174
Advanced Message Queueing Protocol
Length: 174
Doff: 2
Type: AMQP (0)
Channel: 2
Performative: transfer (20)
Arguments (5)
Message-Header
Durable: True
Message-Annotations (map of 1 element)
x-opt-jms-dest (byte): 1
Message-Properties
To: a/b/c
Content-Type: text <----------
Application-Properties (map of 1 element)
AaronEncoding (str8-utf8): CustomText
AMQP-Value (str32-utf8): hello
So my suggestion is this:
Set an additional custom header, a User Property, which will get passed through to the AMQP message:
curl http://localhost:9000/TOPIC/a/b/c -d 'hello' -H 'Solace-User-Property-AaronEncoding: CustomText' -H 'Content-Type: text'
JMSDestination: a/b/c
JMSProperties: {AaronEncoding:CustomText;JMSXDeliveryCount:1;}
Object Type: TextMessage
Text: len=5
hello
My always-goto guide for Solace REST interactions: https://docs.solace.com/API/RESTMessagingPrtl/Solace-REST-Message-Encoding.htm
Hope that helps!
It may have a different name in Camel. Try either printing all the headers or stop it in the debugger and examine the incoming message.

Apache Camel AS2 component cannot not process application/xml message

I tested to send a message with content-type set to application/xml to a Camel/AS2 server connection. However, I got 500 response. Does Camel/AS2 support application/xml content-typed messages?
Here comes the stack trace:
2022-01-16 11:44:23,725 [AS2Hdlr-6405] INFO .AS2ServerConnection [] - Processing new AS2 request
2022-01-16 11:44:23,725 [AS2Hdlr-6405] WARN nent.as2.AS2Consumer [] - Failed to process AS2 message
org.apache.http.HttpException: Failed to extract EDI message: invalid content type 'application/xml' for AS2 request message
at org.apache.camel.component.as2.api.util.HttpMessageUtils.extractEdiPayload(HttpMessageUtils.java:169) ~[camel-as2-api-3.13.0.jar!/:3.13.0]
at org.apache.camel.component.as2.AS2Consumer.handle(AS2Consumer.java:124) [camel-as2-3.13.0.jar!/:3.13.0]
at org.apache.http.protocol.HttpService.doService(HttpService.java:437) [wildfly-elytron-1.18.1.Final.jar!/:1.18.1.Final]
at org.apache.http.protocol.HttpService.handleRequest(HttpService.java:342) [wildfly-elytron-1.18.1.Final.jar!/:1.18.1.Final]
at org.apache.camel.component.as2.api.AS2ServerConnection$RequestHandlerThread.run(AS2ServerConnection.java:147) [camel-as2-api-3.13.0.jar!/:3.13.0]
2022-01-16 11:44:23,725 [AS2Hdlr-6405] INFO .AS2ServerConnection [] - Client closed connection

Apache Camel Azure queue: Message body is empty while sending message

I am trying to send a message to Azure Queue using Apache Camel, route code is:
from("direct:testMessage")
.process(exchange -> {
exchange.getIn().setBody("test message");
})
.to("azure-storage-queue://azureaccount/test-queue?operation=sendMessage");
The code to initiate Azure service client bean is:
#Bean
public QueueServiceClient queueServiceClient() {
StorageSharedKeyCredential credential = new StorageSharedKeyCredential(ACCOUNT, ACCESS_KEY);
return new QueueServiceClientBuilder().endpoint(QUEUE_URL).credential(credential).buildClient();
}
I am getting the below error:
com.azure.storage.queue.models.QueueStorageException: Status code 400, "<?xml version="1.0" encoding="utf-8"?><Error><Code>InvalidXmlDocument</Code><Message>XML specified is not syntactically valid.
RequestId:e3496af3-f003-001a-0d2e-a38636000000
Time:2020-10-15T20:08:26.5431469Z</Message><LineNumber>0</LineNumber><LinePosition>0</LinePosition><Reason /></Error>"
Tried enabling HTTP logs and looks like the Message body is empty:
2020-10-16 01:38:25 INFO c.a.s.q.i.M.enqueue - --> POST https://azureaccount.queue.core.windows.net/blob-backup-queue/messages
53-byte body:
<?xml version='1.0' encoding='UTF-8'?><QueueMessage/>
--> END POST
2020-10-16 01:38:25 INFO c.a.s.q.i.M.enqueue - <-- 400 https://azureaccount.queue.core.windows.net/blob-backup-queue/messages (163 ms, 294-byte body)
Response body:
<?xml version="1.0" encoding="utf-8"?><Error><Code>InvalidXmlDocument</Code><Message>XML specified is not syntactically valid.
RequestId:e3496af3-f003-001a-0d2e-a38636000000
Time:2020-10-15T20:08:26.5431469Z</Message><LineNumber>0</LineNumber><LinePosition>0</LinePosition><Reason /></Error>
<-- END HTTP
Going through the source code of camel-azure component, figured out the right way to send message is as follows:
exchange.getIn().getHeaders().put(QueueConstants.MESSAGE_TEXT, "test message");

Invalid parameter value on GetMyFeesEstimate

I am trying to send a request to GetMyFeesEstimate using the Amazon MWS service (doc):
POST /Products/2011-10-01/?FeesEstimateRequestList.FeesEstimateRequest.1.MarketplaceId=XXXXXXXXXXXXXX&FeesEstimateRequestList.FeesEstimateRequest.1.IdType=EAN&FeesEstimateRequestList.FeesEstimateRequest.1.IdValue=6950029002582&FeesEstimateRequestList.FeesEstimateRequest.1.IsAmazonFulfilled=true&FeesEstimateRequestList.FeesEstimateRequest.1.Identifier=request1&FeesEstimateRequestList.FeesEstimateRequest.1.PriceToEstimateFees.ListingPrice.CurrencyCode=USD&FeesEstimateRequestList.FeesEstimateRequest.1.PriceToEstimateFees.ListingPrice.Amount=30.00&FeesEstimateRequestList.FeesEstimateRequest.1.PriceToEstimateFees.Shipping.CurrencyCode=USD&FeesEstimateRequestList.FeesEstimateRequest.1.PriceToEstimateFees.Shipping.Amount=3.99&FeesEstimateRequestList.FeesEstimateRequest.1.PriceToEstimateFees.Points.PointsNumber=0&AWSAccessKeyId=XXXXXXXXXXXXXXXXXXXX&Action=GetMyFeesEstimate&MWSAuthToken=123&SellerId=XXXXXXXXXXXXXX&SignatureMethod=HmacSHA256&SignatureVersion=2&Timestamp=2016-06-23T14:58:28Z&Version=2011-10-01&Signature=cPG3pcI0OT9b0GzkfTVPuBJ+fKo= HTTP/1.1
Host: mws.amazonservices.es
Cache-Control: no-cache
Postman-Token: 953f5ba5-d6c3-481a-5e7d-7bfa6ba2adcd
Content-Type: application/x-www-form-urlencoded
But I am receiving this response:
<?xml version="1.0"?>
<ErrorResponse xmlns="https://mws.amazonservices.com/">
<Error>
<Type>Sender</Type>
<Code>InvalidParameterValue</Code>
<Message>Invalid query string provided - FeesEstimateRequestList.FeesEstimateRequest.1.MarketplaceId=XXXXXXXXXXXXXX&FeesEstimateRequestList.FeesEstimateRequest.1.IdType=EAN&FeesEstimateRequestList.FeesEstimateRequest.1.IdValue=6950029002582&FeesEstimateRequestList.FeesEstimateRequest.1.IsAmazonFulfilled=true&FeesEstimateRequestList.FeesEstimateRequest.1.Identifier=request1&FeesEstimateRequestList.FeesEstimateRequest.1.PriceToEstimateFees.ListingPrice.CurrencyCode=USD&FeesEstimateRequestList.FeesEstimateRequest.1.PriceToEstimateFees.ListingPrice.Amount=30.00&FeesEstimateRequestList.FeesEstimateRequest.1.PriceToEstimateFees.Shipping.CurrencyCode=USD&FeesEstimateRequestList.FeesEstimateRequest.1.PriceToEstimateFees.Shipping.Amount=3.99&FeesEstimateRequestList.FeesEstimateRequest.1.PriceToEstimateFees.Points.PointsNumber=0&AWSAccessKeyId=XXXXXXXXXXXXXXXXXXXX&Action=GetMyFeesEstimate&MWSAuthToken=123&SellerId=XXXXXXXXXXXXXX&SignatureMethod=HmacSHA256&SignatureVersion=2&Timestamp=2016-06-23T14:58:28Z&Version=2011-10-01&Signature=cPG3pcI0OT9a0GzkfTVPuBJ+fKo= is not valid; the value of a query string parameter may not contain a &apos;=&apos; delimiter</Message>
</Error>
<RequestID>506e7ce6-1f5f-4e4f-afc1-e2defa175a4d</RequestID>
</ErrorResponse>
As Jad said, the IdType can only be ASIN and SellerSKU, this needs to be changed.
But the exception here is the query string is invalid, as you can see in the error message. There should not be '=' in the query string. I see it in your signature, that may be the problem.

How to get instance of current message bein processed in cxf?

I want to get the ID of the Inbound message in my implemented service end point which has following parameters available:
Custom JAXB Request
#Context HttpServletRequest
e.g. From below inbound message i want to retrieve ID: 1 in my service endpoint.
INFO: Inbound Message
ID: 1
Address:
Encoding: ISO-8859-1
Http-Method: POST
Content-Type: application/xml
Headers:
Payload:
Can anyone please tell me if there is a way to get that ID ?
You can get the current CXF Message using PhaseInterceptorChain.getCurrentMessage(). The logging ID used by the logging interceptors is stored in the Message Map, and can be retrieved with its key, e.g.
String loggingId = (String) PhaseInterceptorChain.getCurrentMessage().get(LoggingMessage.ID_KEY);

Resources