URL Encoding a Camel Exchange Body - activemq

I need help with this question.
I'm using the camel-http component as shown here but I'm having trouble because the body I'm sending has unescaped ampersands. This is causing the query string on the receiving server to break the post into multiple post parameters.
I know I could create compiled routes in java, but I must use the spring xml dialect so that new routes may be create/changed in the config files without a recompile.
So, in short, I'd like to URL Encode the ${body} property on my route using the spring dialect as shown in the (obviously invalid) pseudocode below.
<setBody inheritErrorHandler="true" id="setBody2">
<simple>name=<urlencode>${body}</urlencode></simple>
</setBody>

Ok, I bit the bullet. I created a java POJO
package com.wufoo.camel;
import java.io.UnsupportedEncodingException;
import java.net.URLEncoder;
import org.apache.log4j.Logger;
public class PayloadEncoder {
public String getEncodedBody(String body) throws UnsupportedEncodingException {
Logger mylogger = Logger.getLogger("log4j.logger.org.apache.camel");
mylogger.info("Appending payload and URL Encoding");
String encodedBody = new StringBuffer()
.append("payload=")
.append(URLEncoder.encode(body, "UTF-8")).toString();
return encodedBody;
}
}
Then injected it into the context
<bean id="payloadEncoder" class="com.wufoo.camel.PayloadEncoder" />
And finally used a transform to encode the body
<transform>
<method bean="payloadEncoder" method="getEncodedBody"/>
</transform>
That works. If anyone can tell me what's wrong with this approach, please let me know.

You can also use groovy language, like this:
<?xml version="1.0" encoding="UTF-8"?>
<blueprint
xmlns="http://www.osgi.org/xmlns/blueprint/v1.0.0"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="
http://www.osgi.org/xmlns/blueprint/v1.0.0
http://www.osgi.org/xmlns/blueprint/v1.0.0/blueprint.xsd">
<camelContext xmlns="http://camel.apache.org/schema/blueprint">
<route>
<from uri="file:camel/input"/>
<log message="Moving ${file:name} to the output directory"/>
<setBody>
<groovy>
"name=" + URLEncoder.encode(request.getBody(String.class));
</groovy>
</setBody>
<to uri="file:camel/output"/>
</route>
</camelContext>
</blueprint>

Related

Consume soap Service in Apache Camel

i want to consume soap web serivce in apache camel using Java DSL.Any way without CXF.i have already try using CXF with spring.
Here is a simple example that used only camel http without cxf. If you need to perform some modifications of SOAP request string you can just change "constant" to something like "spel".
<setBody><constant><![CDATA[<?xml version="1.0" encoding="UTF-8"?>
<soapenv:Envelope xmlns:soapenv="http://schemas.xmlsoap.org/soap/envelope/">
<soapenv:Header/>
<soapenv:Body>
<MyAction>
<myparam>ABC</myparam>
</MyAction>
</soapenv:Body>
</soapenv:Envelope>]]></constant></setBody>
<setHeader headerName="SOAPAction"><constant>MySOAPAction</constant></setHeader>
<setHeader headerName="CamelHttpMethod"><constant>POST</constant></setHeader>
<setHeader headerName="Content-Type"><constant>text/xml;charset=UTF-8</constant></setHeader>
<to uri="http://myserver:1234" />
Same with Java DSL
public class MyRouteBuilder extends RouteBuilder {
public void configure() {
from("direct:start")
.setBody(constant("")) // String SOAP content from XML example
.setHeader("SOAPAction", constant("MySOAPAction"))
.setHeader("CamelHttpMethod", constant("POST"))
.setHeader("Content-Type", constant("text/xml;charset=UTF-8"))
.to("http://myserver:1234")
.log("SOAP service called"); // Here you can process service response
}
}

Apache Camel - File Transfer on Particular Route Call

I'm trying to create a webservice which, when called look into a local directory picks up files from there and upload to the ftp server.
I'm able to create a simple route which picks file from local directory and uploads to ftp server below is the code :
<route>
<from uri="file://D:\\FTPTest?noop=true&delay=2000" />
<to uri="ftp://user#host.in:21/public_html/EnterpriseProject?password=password123#"/>
<to uri="bean:myBean?method=test" />
</route>
But, I want to this file transfer to be called when a particular route is called via restlet webservice is called, I tried with the following code, but it didn't work :
<route>
<from uri="direct:fileTransferRoute" />
<to uri="file://D:\\FTPTest?noop=true&delay=2000" />
<to uri="ftp://user#host.in:21/public_html/EnterpriseProject?password=password123#"/>
</route>
The above route is called by restlet from following route :
<route>
<from
uri="restlet:http://0.0.0.0:9080/csitec/{serviceName}?restletMethod=post" />
<process ref="serviceRouteProcessor" />
<toD uri="direct:${in.header.nextRoute}" />
</route>
Here's the code of my serviceRouteProcessor :
public void process(Exchange exchange) throws Exception {
String body = exchange.getIn().getBody(String.class);
String serviceName = exchange.getIn().getHeader(Constants.SERVICE_NAME).toString();
String nextRoute = serviceName+Constants.NEXT_ROUTE_APPENDER;
exchange.getOut().setHeader(Constants.NEXT_ROUTE, nextRoute);
exchange.getOut().setBody(body);
}
Please help me and suggest the changes needs to be done to make it work like this.
You should try the pollEnrich feature of content-enricher
In the example section you can find a example regarding files.
Your route should look something like this(I work only with camel java dsl, so this a bit xml pseudo code):
<route>
<from uri="direct:fileTransferRoute" />
<pollEnrich uri="file://D:\\FTPTest?fileName=data.txt....." />
<to uri="ftp://user#host.in:21/public_html/EnterpriseProject?password=password123#"/>
</route>
Edited :
you must understand one thing first , to is producer not consumer <to uri="file://D:\\FTPTest?noop=true&delay=2000" />
What you can do is ,
#Autowired
private CamelContext context;// if you have more than one camel context use #Qualifier and wire by bean id
public void process(Exchange exchange) throws Exception {
String body = exchange.getIn().getBody(String.class);
String serviceName = exchange.getIn().getHeader(Constants.SERVICE_NAME).toString();
context.startRoute(serviceName+Constants.NEXT_ROUTE_APPENDER);// here in nextroute you must give the routeid
}
your route must look like
<route id = "<value of serviceName+Constants.NEXT_ROUTE_APPENDER>" autoStartup = "false">
<from uri="file://D:\\FTPTest..." />
<onCompletion onFailureOnly="true">
<choice>
<when>
<simple>${property.CamelBatchComplete}</simple>
<process ref="asyncSelfShutdownProcessor"/>
</when>
</choice>
</onCompletion>
<to uri="ftp://user#host.in:21..."/>
</route>
And add asyncSelfShutdownProcessor to spring context
#Component
public class AsyncSelfShutdownProcessor implements AsyncProcessor {
#Autowired
private CamelContext context
public boolean process(Exchange exchange, AsyncCallback callback){
new Thread(() -> context.stopRoute(exchange.getFromRouteId())).start();
}
}
##############################################################################
Old :
OK I understand your need as - you have a route that moves file from file system to ftp server, all you need is this route to get executed only when you trigger from a rest service. I would do it like this ,
*I will make the route autoStartup = "false" and assign as id = "fs-to-ftp" to the route
<route id = "fs-to-ftp" autoStartup = "false">
<from uri="file://D:\\FTPTest..." />
<onCompletion onFailureOnly="true">
<process ref="asyncSelfShutdownProcessor"/>
</onCompletion>
<to uri="ftp://user#host.in:21..."/>
</route>
**Add a self shutdown async process in onComplete to the route "fs-to-ftp". Async Processor
asyncSelfShutdownProcessor= AsyncProcessorConverterHelper.convert(exchange -> {
new Thread(() -> context.stopRoute("fs-to-ftp")).start();
});
***Add the camel context dependency to rest service and start the route by id in the rest service context.startRoute("fs-to-ftp")

Apache cxf Jax Rs encoding issue

I am using jaxrs with Apache cxf . Below is the xml config
<jaxrs:server id="accountrs" address="/rservice">
<jaxrs:serviceBeans>
<ref bean="accountService"/>
</jaxrs:serviceBeans>
<jaxrs:providers>
<ref bean='jsonProvider' />
</jaxrs:providers>
</jaxrs:server>
For some of my post methods i see that that the double byte charectors are getting distorted and appearing as garbled charectors and getting stored in the database .
I am reading the json body as string and not as any bean in my service implementation method . Below is the sample
#POST
#Path("/accounts/")
public Account getAccount(String jsonBody) {
//Business code goes here
}
I am stuck with this for a while now . Can some one help
Try adding #Consumes("application/json;charset=utf-8") to your getAccount resource. You may also need to specify a #Produces annotation too with a content type and a charset.

No such operation: HTTP GET PATH_INFO: /services/EchoUMO

I downloaded the echo sample for mule from internet. I have 1 java class
package org.mule.example.echo;
public class Echo
{
public Echo()
{
}
public String echo(String string)
{
return string;
}
}
And an xml file
<?xml version="1.0" encoding="UTF-8"?>
<mule>
<flow name="EchoFlow">
<inbound-endpoint address=":65082/services/EchoUMO" exchange-pattern="request-response"/>
<cxf:jaxws-service serviceClass="org.mule.example.echo.Echo"/>
<component>
<singleton-object class="org.mule.example.echo.Echo" />
</component>
</flow>
</mule>
When I write :65082/services/EchoUMO in my browser I don't get any good result. In my console i see this error:
WARN 2013-03-04 12:08:10,713 [[sample-echo].connector.http.mule.default.receiver.02] org.apache.cxf.phase.PhaseInterceptorChain: Interceptor for {http://echo.example.mule.org/}EchoService has thrown exception, unwinding now
org.apache.cxf.interceptor.Fault: No such operation: (HTTP GET PATH_INFO: /services/EchoUMO)
at org.apache.cxf.interceptor.URIMappingInterceptor.handleMessage(URIMappingInterceptor.java:88)
at org.apache.cxf.phase.PhaseInterceptorChain.doIntercept(PhaseInterceptorChain.java:263)
at org.apache.cxf.transport.ChainInitiationObserver.onMessage(ChainInitiationObserver.java:123)
Can you explain what is going on for me?
When I write :65082/services/EchoUMO in my browser, my browser shows this page:
<soap:Envelope>
<soap:Body><soap:Fault>
<faultcode>soap:Server</faultcode>
<faultstring>No such operation: (HTTP GET PATH_INFO: /services/EchoUMO)</faultstring>
</soap:Fault></soap:Body>
</soap:Envelope>
Your class does not use JAX-WS annotation therefor you get the error.
You have 2 choices:
Keep the current class and use simple service, i.e <cxf:simple-service serviceClass="org.mule.example.echo.Echo"/>
Add JAX-WS annotation to your POJO as explained here

Why is my WCF Data Services method not appearing in the OData collections list?

When I view the root of my WCF Data Services service (http://localhost/MyService.svc/) in a browser I see this:
<?xml version="1.0" encoding="utf-8" standalone="yes" ?>
<service xml:base="http://localhost/MyService.svc/" xmlns:atom="http://www.w3.org/2005/Atom" xmlns:app="http://www.w3.org/2007/app" xmlns="http://www.w3.org/2007/app">
<workspace>
<atom:title>Default</atom:title>
</workspace>
</service>
I would expect to see a list of collections.
When I go to the $metadata URL I see this:
<?xml version="1.0" encoding="iso-8859-1" standalone="yes"?>
<edmx:Edmx Version="1.0" xmlns:edmx="http://schemas.microsoft.com/ado/2007/06/edmx">
<edmx:DataServices xmlns:m="http://schemas.microsoft.com/ado/2007/08/dataservices/metadata" m:DataServiceVersion="1.0">
<Schema Namespace="MyApp" xmlns:d="http://schemas.microsoft.com/ado/2007/08/dataservices" xmlns:m="http://schemas.microsoft.com/ado/2007/08/dataservices/metadata" xmlns="http://schemas.microsoft.com/ado/2007/05/edm">
<ComplexType Name="Package">
<Property Name="Id" Type="Edm.String" Nullable="true" />
</ComplexType>
</Schema>
<Schema Namespace="MyApp" xmlns:d="http://schemas.microsoft.com/ado/2007/08/dataservices" xmlns:m="http://schemas.microsoft.com/ado/2007/08/dataservices/metadata" xmlns="http://schemas.microsoft.com/ado/2007/05/edm">
<EntityContainer Name="PackageService" m:IsDefaultEntityContainer="true">
<FunctionImport Name="GetQueryablePackages" ReturnType="Collection(MyApp.Package)" m:HttpMethod="GET" />
</EntityContainer>
</Schema>
</edmx:DataServices>
</edmx:Edmx>
Why might my GetQueryablePackages collection not be appearing?
I'm using these access settings:
config.SetEntitySetAccessRule("*", EntitySetRights.AllRead);
config.SetServiceOperationAccessRule("*", ServiceOperationRights.All);
Service operations (the function import in the EDM) is not exposed in the service document. Only entity sets are exposed there.
If you want your data to be exposed in the service document make an entity set out of it. Depending on the provider model this differs. Typically it means exposing a property of type IQueryable on your context class. Note that T has to be an entity type (must have a key).
Can you share the context definition where you have defined the IQueryable <> properties. There are 2 things that come to my mind: First the properties must be of type IQueryable<> or some type that derives from it. Second, the element type refered by the IQueryable<> must be an entity type i.e. they must have key properties declared in them.
Hope this helps.
Thanks
Pratik
Or you can create an extension method like this:
public static class TestEntitiesExtensions
{
public static IEnumerable<Package> GetQueryablePackages(this TestEntities context)
{
var uri = new Uri(context.BaseUri, "GetQueryablePackages");
return context.Execute<Package>(uri);
}
}