Apache Camel HMAC implemenation - java

I am working with a legacy repo which has code written in Apache Camel, I personally have never worked with Java or Camel before and am looking for some assistance.
Problem
We are using sftp to get some data from an external endpoint, this data is then sent over to another endpoint (/process-data) residing in a different service. The consumer endpoint /process-data will have an HMAC guard implemented on top off it. I need to figure out a way to calculate the hmac (using private key) and pass it as part of a the header to /process-data
For the hmac, i am looking at an encoding type of "sha256" and output format of "base64"
Existing Code
#Override
public void configure() throws Exception {
from(sftp("{{sftp.host}}:{{sftp.port}}/{{sftp.path}}")
.username("{{sftp.user}}")
.password("{{sftp.password}}")
.recursive(false)
.useUserKnownHostsFile(false)
.delay("{{sftp.delay}}")
.delete(false)
.idempotent(true)
.idempotentRepository(idempotentRepository)
.advanced()
.stepwise(false)
.localWorkDirectory("{{sftp.tmp-directory}}"))
.setHeader(Exchange.HTTP_METHOD, constant("POST"))
.setHeader(Exchange.CONTENT_TYPE, constant("application/json"))
.to("..../...../process-data");
}

Related

apache camel for jira

I want to build an Apache camel application to download a Jira
issue report, parse it, and store it into a .csv file.
I'm new at Apache camel, I do believe the jira here should be an endpoint, how to setup this configuration, I want to set is as from:("Jira") to (csv file).
I believe it could be something like this:
public void configure() throws Exception {
from("jira://pullRequestComment?ProjectKey=CAMEL-0000&IssueTypeId=1&IssueSummary=title")
.process(new MyLogProcessor())
.bean(new MyTransformer(),"transformContent")
.to("file:D:/camel/output");
}
I tried the above code, I got an exception for java conversion type.
Exception:
The JIRA component returns Java objects from the JIRA REST API. You need to either:
Support passing in the object type to your processor class as a method argument
Convert the JIRA Java Object to something else, then pass into your processor
BTW- The JIRA component caches "seen" data to know what is "new" to pass into the route. For really busy JIRA servers, this looks and acts like a memory leak so you'll need to be mindful to manage that scenario
The pullRequestComment endpoint is for a producer endpoint (i.e. it can only go in to("jira:pullRequestComment?..."). Since you want to poll for new comments, you should use the newComment endpoint. So your route would look something like:
from("jira:newComment?serverUrl={host}&username={username}password={password}")
.process(new MyLogProcessor())
.bean(new MyTransformer(),"transformContent")
.to("file:D:/camel/output");
Note that this endpoint returns an object of type com.atlassian.jira.rest.client.domain.Comment, so in MyLogProcessor if you do exchange.getIn().getBody(), it will return an object of type Comment (or maybe a List if there are multiple objects, you'll have to test this).
If you want to post a pull request comment, then you can use the pullRequestComment endpoint like the following:
from("direct://some/uri/name")
.header("ProjectKey", "CAMEL-0000")
.header("IssueTypeId", 1L)
.header("IssueSummary", "title")
.to("jira:pullRequestComment?serverUrl={host}&username={username}password={password}")
.... // More processing here
Then if you invoke the route from("direct://some/uri/name"), it should post the comment that's in the exchange body.

Camel With Cxf and Routing

I was doing some research on Camel - CXf integration and am confused about the below scenario.
So i implemented a Rest Endpoint
#Path("/authenticate")
public interface Sample {
#GET
#Path("/handshake")
#Produces(MediaType.TEXT_PLAIN)
public Response handshake();
#POST
#Path("/login")
#Consumes({MediaType.APPLICATION_JSON,MediaType.APPLICATION_XML})
#Produces(MediaType.APPLICATION_JSON)
public Response login(LoginRequest request) throws JsonGenerationException, JsonMappingException, IOException;
}
And the implementation as below
public class SampleImpl implements Sample{
#Context
private HttpHeaders headers;
#Autowired
CamelContext context;
public Response handshake()
{
System.out.println("HandShake Executed Successfully");
return Response.status(Status.OK).entity("This is a Message after Routing").build();
}
public Response login(LoginRequest request) throws JsonGenerationException, JsonMappingException, IOException {
System.out.println("The Rquest objecr is Received "+request);
return Response.status(Status.OK).entity(mapper.writeValueAsString(request)).build();
}
}
The Route
<camel:from uri="cxfrs:bean:SampleRestEndPoint?bindingStyle=SimpleConsumer"></camel:from>
routes it into the implementation. But since the implementation returns a response object am confused how to build the routes around this.
Once the call comes into the implementation how can I execute the
other routes and sent a response back?.In this case the implementation returns a custom object.
How are the other routes attached to a CXF route?.
Should my CXF Implemenation always return a void type?. As i see
that, to get access to Exchange object camel need the return type to
be void
Do I completely ignore the implementation and go with the "to" steps
and modify it in exchange body for the required response?.
Any pointers will be appreciated.
Dude, take a look at this - http://bushorn.com/camel-cxf-geocoder-example/
The above example is not REST though, but usage of CXF with Camel route is same.
I will do these mandatory steps:
Avoid beans/custom classes - try to use the camel framework capabilities.
Use XML - Spring/Blueprint DSL
Please look at the following thread.
Apache Camel and web services
I have successfully implemented web service consumption using camel and Apache CXF. If you have doubts, I can help you out.
Thanks,
Gautham
#GauthamHonnavara - that is an implementation of a JS webservice with an assosiated processor however it doesnt assosiate any direct route to the endpoint.Also my question was specific to JAX-RS where you cannot generate a service class from wsdl.
Assume this use case that u need a customer to invoke the endpoint and then go through say another 5 steps, reach out to another webservice etc and then sent a response back. The above implementation sents a response back in the webservice implementation bean itself.
So to avoid this create a simple interface with the producer consumer etc, just like in my question and then make each method void if you want to inject the Exchange( if needed. ) and use below configuration
<!-- Created the CXF End Point For the Calls to Come IN -->
<cxf:rsServer id="RestEndPoint" address="/rest"
serviceClass="com.poc.camel.cxf.service.incoming.xxx"
loggingFeatureEnabled="true" loggingSizeLimit="20">
<cxf:providers>
<bean class="org.codehaus.jackson.jaxrs.JacksonJsonProvider" >
<!-- <constructor-arg ref="customObjectMapper" type="org.codehaus.jackson.map.ObjectMapper"/> -->
</bean>
</cxf:providers>
</cxf:rsServer>
Trick is to use the service class tag. If the interface is provided there then it doesn't need a concrete implementation from CXF.
Hope this helps. Let me know

Apache-Camel: How to control the scope of the exchange headers?

I'm using the exchange headers to store any variables in the route. But, looks like these headers will be carried on to the other routes which are called from this route.
In the below sample, I'm calling a getContact route which will call a http endpoint. But, it will also send the headers, variable1 & variable2, it got from the initial route, direct:start.
from("direct:start")
.setHeader("variable1", constant("value1"))
.setHeader("variable2", constant("value2"))
.to("direct:getContact");
from("direct:getContact")
.setHeader("Content-Type", constant("application/json"))
.setHeader("Accept", constant("application/json"))
.setHeader(Exchange.HTTP_METHOD, constant("GET"))
.to("http://<host>:<port>/contact/3")
.unmarshal().json(JsonLibrary.Jackson);
Is there a way to avoid this? In contrast, a method call in java will hide all the existing variables by context switch.
I've run into the problem before when sending a webservice call using http4. Tt's rather annoying that Camel seems to send send the entire exchange when you're using the http4/http endpoint. I got around this by using a content enricher. I placed the actual call using http4 in the enrich route and had an simple aggregation strategy combine the two messages afterwards.
Alternatively, you can make the call in a bean. This way you lose some of the benefits of camel but you have complete control over the call body.
There is no direct way to avoid this. If you are setting the headers to a hard-coded value then you might be able to move the header to a URI property on your endpoint. If not then you only really have 2 other options. The first option is to remove all of the headers using a remove header call after your HTTP call so they don't go downstream. The second is to set all of the headers in the same route as the http call and have a different route call that endpoint with an enrich statement and in the aggregation back to the main route you can customize the returned exchange.
Here is an camel http reference page for all of the allowed headers to see if you can put it in the URI http://camel.apache.org/http4.html
Sample of a route removing headers
from("direct:start")
.setHeader("variable1", constant("value1"))
.setHeader("variable2", constant("value2"))
.setHeader("Content-Type", constant("application/json"))
.setHeader("Accept", constant("application/json"))
.setHeader(Exchange.HTTP_METHOD, constant("GET"))
.to("http://<host>:<port>/contact/3")
.unmarshal().json(JsonLibrary.Jackson)
.removeHeaders("variable*")
.to("Anything I call now won't have the variable headers");
enrichment call
AggregationStrategy aggregationStrategy = new ExampleAggregationStrategy();
from("direct:start")
.enrich("direct:getContact", aggregationStrategy)
.to("You can have no additional headers here");
public class ExampleAggregationStrategy implements AggregationStrategy {
public Exchange aggregate(Exchange original, Exchange resource) {
Object originalBody = original.getIn().getBody();
Object resourceResponse = resource.getIn().getBody();
Object mergeResult = //TODO implement this however you want. You can remove any headers here you like
if (original.getPattern().isOutCapable()) {
original.getOut().setBody(mergeResult);
} else {
original.getIn().setBody(mergeResult);
}
return original;
}
}
Actually 1 more option came to mind when going through the camel documentation I found an interesting property. Disclaimer I have never tried this property myself since I am still running camel 2.15 atm, but feel free to test it really quick it might just be what you need.
copyHeaders
default: true
Camel 2.16: If this option is true then IN exchange headers will be copied to OUT exchange headers according to copy strategy. Setting this to false, allows to only include the headers from the HTTP response (not propagating IN headers).
Just use:
.removeHeaders("variable*")
to remove headers of any pattern.

restlet content type, versioning with restlet

I am exposing a rest service by using restlet with camel.
I have exposed a rest service as one end, and at another end I have overridden process method.
The code looks like below,
from("restlet:/service/serviceName/{serviceId}?restletMethod=PUT").process(new Processor() {
#Override
public void process(Exchange exchange) throws Exception {
//Implementation goes here.
}
}
I have two issues here.
I am not able to set the content type for the request
I am not able
to achieve versioning of content type
I tried with the following options.
setHeader(Exchange.CONTENT_TYPE, simple("application/json"))
setHeader(Exchange.ACCEPT_CONTENT_TYPE, simple("application/json"))
Still the issue is not solved. Is there any other option?
So your route is a from. This means you send a request to it.
Send a request to it from fiddler, chrome or somewhere else with the headers you want.
Add logging to the route that prints out the entire exchange including the headers. Here you will find Content-Type, and all the other HTTP headers as well.
To access them you need to access the header on the Exchange like any other header.
I don't understand why you are setting headers there.
For example in your process code you can do like this:
String contentType=(String) exchange.getIn().getHeader("Content-Type");
if (contentType.equals("application/json")) {
//do something
}
Note, you need to verify that the header is called Content-Type and not content-type or something similar since RESTLET is case sensitive. That is why you need to add the logging to see the name of the header on the exchange.

How to distinguish what format a client requests back to my REST webservice?

I have a Java WebService setup which consumes an xml file and want to be able to produce either xml or json based on what the client requests. I know that this is possible through reading up on Jersey REST methods but it does not show how to extract this information. I have also looked on google all over but can't seem to find any examples of this.
http://wikis.sun.com/display/Jersey/Overview+of+JAX-RS+1.0+Features is the site that I was initially referencing which shows that it is possible, I was just wondering if anyone would be able to help me find out how to actually distinguish the client's request. Is it in the html header? body? And if so what is the proper way to extract it?
This is what my method currently looks like, I do not have any issues with connection, just finding out what the client requests as a return type.
#POST
#Path("getStatisticData")
#Produces ({"application/xml","application/json"})
#Consumes ("application/xml")
public String getStatisticData(#FormParam("xmlCoords") String xmlFile) throws Exception{
Thanks in advance.
You can extract it using the #HeaderParam annotation:
...
public String getStatisticData(#HeaderParam("Accept") String accept,
#FormParam("xmlCoords") String xmlFile) throws Exception {
...
}
The Accept header in the request is used for the client to indicate to the server what methods it supports.
If the client can set HTTP headers, the proper way to do it is to use the Accept header:
http://www.w3.org/Protocols/rfc2616/rfc2616-sec14.html
IF this is not possible, the type requested could be passed in as an argument.
Alternatively, expose two different web services: one that returns XML, one that returns JSON. Each web service would call the same code but with a parameter specifying which format to use.

Categories