How to set basic authentication with apache camel and http4 - apache-camel

I'm trying to use Apache Camel's Http4 component to connect to a HTTP URL that needs Basic authentication. I'm setting credentials from a camel processor through Exchange.HTTP_QUERY header. I configure my route like this:
<?xml version="1.0" encoding="UTF-8"?>
<blueprint ...>
<bean id="myProcessor"
class="com.myCompany.Bean"
factory-method="myProcessorBean">
</bean>
<camelContext id="myContext" xmlns="http://camel.apache.org/schema/blueprint">
<route id="myRoute>
<from uri="activemq:queue:myQueue" />
<process ref="myProcessor" />
<to uri="http4://oldhost"/>
</route>
</camelContext>
</blueprint>
and my processor looks like:
public void process(Exchange exchange) throws Exception {
String user = getUserFromDB();
String pwd = getPasswordFromDB();
String queryParameters = "authMethod=Basic&authPassword="+pwd+"authUsername="+user;
exchange.getIn().setHeader(Exchange.HTTP_QUERY, queryParameters);
exchange.getIn().setHeader(Exchange.HTTP_URI, "api.abc_company.com/service/to/consume");
....
}
It results in:
Error myContext: org.apache.camel.http.common.HttpOperationFailedException: HTTP operation failed invoking https://api.abc_company.com/service/to/consume?authMethod=Basic&authPassword=xxxxxx&authUsername=test with statusCode: 401
It seems that password was changed to xxxxxx but I'm not sure.
When I try hardcoding user and password in the URI it works well, however I need a way to set these values programmatically due to user and password are stored it the DB.

"authMethod=Basic&authPassword="+pwd+"authUsername="+user;
You'll need to at & between each uri parameter. You're missing one after password.
Try:
String queryParameters = "authMethod=Basic&authPassword="+pwd+"&authUsername="+user;
Also you should define credentials in producer endpoint URI http4://oldhost?authMethod=Basic&authPassword="+pwd+"&authUsername="+user instead of header: Exchange.HTTP_QUERY.
If you want to do this in your processor you can try to set Authorization header manually with value basic <credentials> where <credentials> is base64 encoded username:password.
Failed invoking https://api.abc_company.com/service/to/consume?
If you want to connect to https site use https4://

Related

Get Failed Node Endpoint URI in Camel route

I am developing a sample route
FROM: SOURCE ENDPOINT URI
TO: TRANS ENDPOINT URI // Error or Exception occurred at this TRANS endpoint
TO: TARGET ENDPOINT URI
Now I want to catch the Error Occured endpoint and pass it to my processor.
Could anyone please help me with this?
<route>
<from uri="file:C:/MINTS/Source/"/>
<to uri="file:C:/MINTS/TRANS/"/> <!-- EXCPECTION OCCURED -->
<to uri="file:C:/MINTS/TARGET/"/>
<onException>
<exception>java.lang.Exception</exception>
<handled>
<constant>true</constant>
</handled>
<!-- NEED TO CATCH FAILURE ENDPOINT URI AND PASS TO MY PROCESSOR BELOW-->
<process ref="MyExceptionProcessor" />
</onException>
</route>
You can use exchange properties:
CamelFailureEndpoint
example xml-dsl: <exchangeProperty>CamelFailureEndpoint</exchangeProperty>
example java: exchange.getProperty(Exchange.FAILURE_ENDPOINT, String.class);
CamelToEndpoint
example xml-dsl: <exchangeProperty>CamelToEndpoint</exchangeProperty>
example java: exchange.getProperty(Exchange.TO_ENDPOINT, String.class)
The first one should print uri for the consumer endpoint (from) that failed and the second one should show the previously called producer (to) endpoint.
One handy way to debug contexts of an failed exchange is to use:
<to uri="log:loggerName?showAll=true" />
This will log all exchange properties, headers, body and exception which can help to understand what information is available within exchange. Be careful where you use it as it might also log secrets and passwords if they're within the exchange so better use it only locally during development.
For more information you'd probably need to access CamelMessageHistory exchange property through processor, bean or something.

How to use properties with the SimpleRegistry in Apache Camel (Spring XML)

I want to use a SimpleRegistry to store properties (as global variables). The property is changed with setProperty in a route with a jms endpoint. The camel documentation changed last week and has many dead links, also the Registry page. I did not found any samples that describe the use of the simpleRegistry.
I used the camel-example-servlet-tomcat as base. I do not use Fuse or the patched camel wildfly, because is to huge for our simple module.
<beans .... >
.
.
.
<bean id="simpleRegistry" class="org.apache.camel.support.SimpleRegistry" />
<camelContext xmlns="http://camel.apache.org/schema/spring">
<propertyPlaceholder id="properties" location="ref:simpleRegistry" />
<route id="storeConfig">
<from id="myTopic" uri="jms:topic:myTopic?selector=Configuration %3D 'xyz'" />
<log id="printHeader2" message="Received header: ${headers}" />
<log id="logToken" message="Received token: ${headers[myToken]}" />
<setProperty id="setMyToken" name="myProperty">
<simple>${headers[myToken]}</simple>
</setProperty>
</route>
<route id="externalIncomingDataRoute">
<from uri="servlet:hello" />
<transform>
<simple>The Token is: {{myProperty}}</simple>
</transform>
</route>
</camelContext>
</beans>
With the camel context deined like above, I got a java.io.FileNotFoundException Properties simpleRegistry not found in registry.
When I use <propertyPlaceholder id="properties" location="classpath:test.properties" /> and create a test.properties file, everything works fine but I cannot change the property. The operation in the setProperty tag is ignored.
The reason why I need a global variable is, I send a dynamic configuration (the myToken) via a jms topic to the camel context. A single route should store this configuration globaly. If an other route is called via an rest component, this route need the token to make a choice.
Alternatively you can achieve the same result following the below approach which uses the PropertiesComponent
<bean id="applicationProperties" class="java.util.Properties"/>
<bean id="properties" class="org.apache.camel.component.properties.PropertiesComponent">
<property name="location" value="classpath:application.properties"/>
<property name="overrideProperties" ref="applicationProperties" />
</bean>
Define the property place holder in the camel context:
<propertyPlaceholder id="propertiesRef" location="ref:applicationProperties" />
Set a property as shown below :
<bean ref="applicationProperties" method="setProperty(token, 'Test'})" />
And to fetch the property : ${properties:token}
OK, there are multiple subjects in your question.
You write you want to use Camel SimpleRegistry, but you obviously have a Spring application.
If you got Spring available, the Camel Registry automatically uses the Spring bean registry. The Camel Registry is just a thin wrapper or provider interface that uses whenever possible an available registry of another framework.
The Camel SimpleRegistry is only used when nothing else is available. This is basically an in-memory registry based on a Map.
You want to set an application property with <setProperty>.
<setProperty> sets an Exchange property, NOT an application property. With this you can save values in the Exchange of a message.
You want to use "global variables".
You could perhaps use a Spring singleton bean that is a Map. You could then autowire it where you need it, it would be like an application wide available map.
However, think twice why you need this kind of variable. This could also be a symptom of a design problem.

sending a response to client from camel cxf component

I am new to camel, i am trying to use camel cxf component to create a soap webservice. I started with a samples from camel in action. I have configured a route using cxf component and added a processor to process the request. I received the request in the bean i used to process the service but i cant able to send the response back to the client. Thanks in advance
This is the route i used :
<route>
<from uri="cxf:bean:orderEndpoint" />
<setExchangePattern pattern="InOut"/>
<to uri="bean:productService" />
</route>
This is the cxf endpoint i have configured,
<cxf:cxfEndpoint id="orderEndpoint"
address="/"
serviceClass="camelws.ws.ProductService"/>
This is the bean i used:
#Service("productService")
public class ProductServiceImpl {
public Product getProducts(){
System.out.println("Inside webservices method....");
Product product = new Product();
product.setName("test product");
product.setPrice("3242");
return product;
}
}
Sysout statement is printed on the console but i am getting a soap response with empty body.
below is my response when i hit http://localhost:9080// from browser:
<soap:Envelope xmlns:soap="http://schemas.xmlsoap.org/soap/envelope/">
<soap:Body/>
</soap:Envelope>
You should implement a Processor, intercept and process your message using something like that :
public class MyProcessor implements Processor {
public void process(Exchange exchange) throws Exception {
...
// Set your response here
exchange.getOut().setBody(product);
}
}
Then reference your processor in your route.
Your response is what you have in your route body after your rote ends, so you must create your massege response object before route ends.

Getting ClassCastException in Camel route while handling response containing java.util.List

I have a Camel route exposed as a CXF web service. This is a bottom up web service and has an operation like so:
List<Book> getBooks();
The CXF endpoint is defined as:
<cxf:cxfEndpoint id="bookService"
address="http://localhost:9045/bookservice"
serviceClass="org.test.cxfws.service.BookDBService">
</cxf:cxfEndpoint>
The operation queries a list of books and returns it to the caller. The Camel route looks like this:
<camel:camelContext xmlns="http://camel.apache.org/schema/spring">
<route>
<from uri="cxf:bean:bookService"/>
<choice>
<when>
<simple>${header.operationName} == 'getBooks'</simple>
<to uri="bean:wsImplBean?method=getBooks"/>
</when>
<to uri="log:outboundSoapResponse"/>
<choice>
</route>
</camel:camelContext>
After running the route, I am getting the following exception:
org.apache.cxf.interceptor.Fault: org.test.cxfws.service.Book cannot be cast to java.util.List
at org.apache.cxf.jaxws.interceptors.WrapperClassOutInterceptor.handleMessage(WrapperClassOutInterceptor.java:117)
at org.apache.cxf.phase.PhaseInterceptorChain.doIntercept(PhaseInterceptorChain.java:272)
at org.apache.cxf.interceptor.OutgoingChainInterceptor.handleMessage(OutgoingChainInterceptor.java:77)
at org.apache.cxf.phase.PhaseInterceptorChain.doIntercept(PhaseInterceptorChain.java:272)
...
Caused by: java.lang.ClassCastException: org.test.cxfws.service.Book cannot be cast to java.util.List
at org.test.cxfws.service.GetBooksResponse_WrapperTypeHelper1.createWrapperObject(Unknown Source)
at org.apache.cxf.jaxws.interceptors.WrapperClassOutInterceptor.handleMessage(WrapperClassOutInterceptor.java:101)
I can see that the getBooks method from the bean wsImpBean is executed and the result being returned at the end of the choice block inside the route:
[ qtp1653072092-14] outboundSoapResponse INFO Exchange[ExchangePattern: InOut, BodyType: java.util.ArrayList, Body: [org.test.cxfws.service.Book#63f1858b, org.test.cxfws.service.Book#5769bf0, org.test.cxfws.service.Book#2df7ac5d, org.test.cxfws.service.Book#5f55253e, org.test.cxfws.service.Book#4f003a57]]
Can someone help me to understand why the ClassCastException.
Thanks.
As camel-cxf use list to hold the response for handling the InOut parameters. When you set the response result into the message body, you need to wrap the result into a List just like this
List<Book> books ...
List<Object> resultList = new ArrayList<Object>();
resultList.add(books);
exchange.getOut().setBody(resultList);

Want to build a route which will check contents of Soap request and pass the request to appropriate URI

I am Ashish from Mumbai and very new to Apache Camel.
Currently I am building a route in XML which will scan the SOAP request and will redirect the request to appropriate URI.
My Soap request isn as follows:
<service xmlns="http://ws.madcomum.comprova.com">
<request>
<keysValues>
<item>
<bytesValue
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:nil="true"/>
<dateValue
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:nil="true"/>
<doubleValue
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:nil="true"/>
<key>validatesOriginIntegrity</key>
<longValue
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:nil="true"/>
<stringValue>z4x/FOOR+EPQ0vD9+itPSCBeNR4=</stringValue>
</item>
</keysValues>
<actionId>1</actionId>
<clientId>ARGO</clientId>
</request>
</service>
From this SOAP envelope, I want to parse out value of actionId tag using Camel Route.
If actionId has value of 1 then route must be redirected to callService else to another service.
I developed logic of route as folows:
<route>
<from uri="cxf:bean:comprovaWS?dataFormat=MESSAGE" />
<when>
<xpath>//actionId=1</xpath>
<to uri="log:input" />
<to ref="callService" />
<to uri="log:output" />
</when>
<otherwise>
<to uri="log:input" />
<to ref="otherService"/>
<to uri="log:output" />
</otherwise>
</choice>
</route>
But this logic is not working.
Is there any error in my route?
Though I am Java guy, I don't want to use Java here. I want to rely on Camel itself.
Please help me ASAP.
Regards,
Ashish
When you use xpath then 95% of the times when people have trouble its often due to namespaces. Your SOAP message is defined using a namespace - "http://ws.madcomum.comprova.com". The xpath expression must use this namespace to make it work.
See more details at: http://camel.apache.org/xpath, there is an example at the section Using XML configuration
Also as you use CXF in MESSAGE mode, then read about stream caching as the message is stream based: http://camel.apache.org/stream-caching.html

Resources