Camel-jetty component : use of available options - apache-camel

I am using the recipientList tag in my route as shown below. The bean findCallbackUrl will return a String which is my destination address. i.e i will be making a POST request to this endpoint . For example i may have a server listening at http://localhost:8080/acceptcallbacks .
<recipientList>
<method ref="findCallbackUrl"/>
</recipientList>
So when the String(destination) returned from the findCallbackUrl bean is jetty:http://localhost:8080/acceptcallback , the POST works fine.
However when some of the option mentioned in the Camel-jetty component are used so issues are seen. when the destination returned is jetty:http://localhost:8080/acceptcallbacks?enableJmx=false or jetty:http://localhost:8080/acceptcallbacks?disableStreamCache=false the POST works fine. However if the returned string is jetty:http://localhost:8080/acceptcallbacks?chunked=false , the call becomes a GET request .
Not sure what is happening here. If the Camel-jetty options are not to be used in the way they have been used above , for options enableJmx or disableStreamCache or some other options , the resulting destination URL should have been http://localhost:8080/acceptcallbacks?enableJmx=false which is a GET request.
Can chunked=false be used for producer as well as consumer endpoints or is it only for consumer endpoint?

Selection of http method in jetty depends on In Body of camel exchange, or on CamelHttpMethod header.
Look at source code of class org.apache.camel.component.http.helper.HttpHelper, method createMethod:
public static HttpMethods createMethod(Exchange exchange, HttpEndpoint endpoint, boolean hasPayload) throws URISyntaxException {
// compute what method to use either GET or POST
HttpMethods answer;
HttpMethods m = exchange.getIn().getHeader(Exchange.HTTP_METHOD, HttpMethods.class);
if (m != null) {
// always use what end-user provides in a header
answer = m;
} else if (hasPayload) {
// use POST if we have payload
answer = HttpMethods.POST;
} else {
// fallback to GET
answer = HttpMethods.GET;
}
return answer;
}
Now look at the call of this method in class org.apache.camel.component.jetty.JettyHttpProducer:
HttpMethods methodToUse = HttpHelper.createMethod(exchange, getEndpoint(), exchange.getIn().getBody() != null);
IMHO options don't matter. Check exchange.getIn().getBody() before request to HTTP, or you can reset header CamelHttpMethod.

Related

Optional response body for rest client using RESTEasy

I'm writing a POC for Quarkus. I'm using this quick start guide to build a REST client. The REST service I'll be integrating with is third party. Here is a simple example of my current implementation:
#Path("/v1")
#RegisterRestClient
public class EmployeeApi {
#POST
#Path("/employees")
ApiResponse createEmployee(#RequestBody Employee employee)
}
This works fine. The issue I'm having is that the third party API will, depending on success / failure, return a response body. In the scenario it does fail, it provides details in the response body (ApiResponse) on why it was unsuccessful. When it succeeds, it returns nothing. This causes Quarkus to throw the following exception:
javax.ws.rs.ProcessingException: RESTEASY003145: Unable to find a MessageBodyReader of content-type application/octet-stream and type com.test.app.ApiResponse
I've tried to wrap ApiResponse in an Optional type but does not solve the problem. I see absolutely nothing in Quarkus / RESTEasy documentation that would indicate a work-around.
I'm wondering if I should be using javax.ws.rs.core.Response instead.
The problem is JaxRS tries to fit ApiResponse to a default return type being application/octet-stream
You should make sure to specify explicitly that you're returning application/json
This is possible using #Produces(APPLICATION_JSON) on top of your service.
Here is the correct code snippet
#Path("/v1")
#RegisterRestClient
public class EmployeeApi {
#POST
#Path("/employees")
#Produces(APPLICATION_JSON)
ApiResponse createEmployee(#RequestBody Employee employee)
}

Component vert.x does not propagate headers

I'm using the Camel component Vertx: http://camel.apache.org/vertx.html
The headers set in Camel are not sent into the eventBus address:
from("direct:inbound")
.setHeader("myHeader").constant("myHeaderValue")
.to("vertx:inboundAddress");
inboundAddress does not receive the header "myHeader".
I've checked the code of the VertxProducer in Vertx Component and it actually only send the body.Is there any reason why the headers are not sent to the eventBus?
Btw, the documentation on GitHub is much more up to date: https://github.com/apache/camel/blob/master/components/camel-vertx/src/main/docs/vertx-component.adoc
I agree that the vertx headers should be accessible via camel. If someone sees an official way it is supported I would love to know. Until then there is an easy workaround though. Instead of passing just the body in the message pass both the headers and the body as the message body and both will be accessible.
JsonObject message = new JsonObject();
message.put("body", routingContext.getBodyAsJson());
DeliveryOptions d = new DeliveryOptions()
.addHeader("myheader", "myheadervalue")
.addHeader("h2", "h2value");
message.put("deliveryOptions", d.toJson());
vertx.eventBus().send("myVertxEndpoint",
message,...
Later in Camel, you could call a method similar to the following as part of your route to have the Vertx headers put inside the camel headers.
public void setVertxHeaders(#Body JsonObject jsonObject, Exchange exchange ) {
exchange.getIn().getHeaders()
.putAll(jsonObject.getJsonObject("deliveryOptions").getJsonObject("headers")
.getMap());
}
You're setting the headers incorrectly.
Instead of
.setHeader("myHeader").constant("myHeaderValue")
Do
.setHeader("myHeader", constant("myHeaderValue"))
See their test suite for more references:
https://github.com/apache/camel/blob/3505e718db48cc0d8be5b47f6c4030c958d93a5f/camel-core/src/test/java/org/apache/camel/component/bean/BeanWithAnnotationInheritedTest.java

How to add a filter in in the "middle of the URL" using Restlet?

I have the following routes:
/projects/{projectName}
and
/projects/{projectName}/Wall/{wallName}
Now I'd like to have that all GETs be allowed but PUT, POST, DELETE should only be allowed by project members i.e. users members of that project. I have a special class that given a user id and project name I can get the status of the user's membership - something like MyEnroler.getRole(userId, projectName) - where the userId is part of the request header and the projectName is taken from the URI.
I've tried a number of things but doesn't work. Here's the idea:
public class RoleMethodAuthorizer extends Authorizer {
#Override
protected boolean authorize(Request req, Response resp) {
//If it's a get request then no need for further authorization.
if(req.getMethod().equals(Method.GET))
return true;
else
{
String authorEmail = req.getClientInfo().getUser().getIdentifier();
String projectName = req.getAttributes().get("project").toString();
Role userRole = MyEnroler.getRole(authorEmail, projectName);
//forbid updates to resources if done by non-members of project
if(userRole.equals(MyEnroler.NON_MEMBER))
return false;
//for everybody else, return true
return true;
}
}
}
Now simply doing the following completely fails when creating inbound root in the Application:
Router projectRouter = new Router(getContext());
RoleMethodAuthorizer rma = new RoleMethodAuthorizer();
//Guard declaration here. Then setNext Restlet
guard.setNext(projectRouter);
projectRouter.attach("/projects/{project}",rma);
Router wallRouter = new Router(getContext());
wallRouter.attach("/Wall/{wallName}", WallResource.class);
rma.setNext(wallRouter);
//return guard;
So a request to /projects/stackoverflow/Wall/restlet fails. The URL is never found. I'm guessing since it's trying to match it with the projectRouter. Well I tried the various modes (MODE_BEST_MATCH or MODE_FIRST/NEXT_MATCH) to no avail.
Nothing seems to work. Conceptually this should work. I'm only intercepting a call and just being transparent to the request, but don't know how things are working on the inside.
I could move the authorizer just after the guard, but I'd lose access to the request attribute of projectName - I don't wish to parse the URL myself to search for the projectName since the URL pattern could change and would break the functionality - i.e. require 2 changes instead of one.
Any ideas how to achieve this?
I would use the standard RoleAuthorizer class to supply the list of allowed roles, along with your custom enroller probably split into two I would then add a custom Filter class that does something like this to call your Enrolers.
protected int beforeHandle(final Request request, final Response response) throws ResourceException {
final String projectName = (String) request.getAttributes().get("projectName");
// Check that a projectName is supplied, should not have got this far otherwise but lets check.
if (projectName == null || projectName.isEmpty()) {
throw new ResourceException(Status.CLIENT_ERROR_NOT_FOUND);
}
if (Method.GET.equals(request.getMethod())){
new ReadEnroler(projectName).enrole(request.getClientInfo());
}else{
new MutateEnroler(projectName).enrole(request.getClientInfo());
}
return super.beforeHandle(request, response);
}
the enrolers would then set the appropriate values in the clientInfo.getRoles() Collection when enrole was called.

RPC call to external server

I am a new bie on GWT, I wrote an application on abc.com, I have another application i.e. xyz.com, xyz.com?id=1 provides me a data in json format, I was thinking to find a way that how to get that json file in abc.com via RPC call, because I have seen tutorials in which RPC calls are used to get data from its server. any help will be appreciated.
EDIT
I am trying to implement this in this StockWatcher tutorial
I changed my code slightly change to this
private static final String JSON_URL = "http://localhost/stockPrices.php?q=";
AND
private void refreshWatchList() {
if (stocks.size() == 0) {
return;
}
String url = JSON_URL;
// Append watch list stock symbols to query URL.
Iterator iter = stocks.iterator();
while (iter.hasNext()) {
url += iter.next();
if (iter.hasNext()) {
url += "+";
}
}
url = URL.encode(url);
MyJSONUtility.makeJSONRequest(url, new JSONHandler() {
#Override
public void handleJSON(JavaScriptObject obj) {
if (obj == null) {
displayError("Couldn't retrieve JSON");
return;
}
updateTable(asArrayOfStockData(obj));
}
});
}
before when I was requesting my url via RequestBuilder it was giving me an exception Couldn't retrieve JSON but now JSON is fetched and status code is 200 as I saw that in firebug but it is not updating on table. Kindly help me regarding this.
First, you need to understand the Same Origin Policy which explains how browsers implement a security model where JavaScript code running on a web page may not interact with any resource not originating from the same web site.
While GWT's HTTP client and RPC call can only fetch data from the same site where your application was loaded, you can get data from another server if it returns json in the right format. You must be interacting with a JSON service that can invoke user defined callback functions with the JSON data as argument.
Second, see How to Fetch JSON DATA

How to know if a Kohana request is an internal one?

I'm writing an API using Kohana. Each external request must be signed by the client to be accepted.
However, I also sometime need to do internal requests by building a Request object and calling execute(). In these cases, the signature is unnecessary since I know the request is safe. So I need to know that the request was internal so that I can skip the signature check.
So is there any way to find out if the request was manually created using a Request object?
Can you use the is_initial() method of the request object? Using this method, you can determine if a request is a sub request.
Kohana 3.2 API, Request - is_initial()
It sounds like you could easily solve this issue by setting some sort of static variable your app can check. If it's not FALSE, then you know it's internal.
This is how I ended up doing it: I've overridden the Request object and added a is_server_side property to it. Now, when I create the request, I just set this to true so that I know it's been created server-side:
$request = Request::factory($url);
$request->is_server_side(true);
$response = $request->execute();
Then later in the controller receiving the request:
if ($this->request->is_server_side()) {
// Skip signature check
} else {
// Do signature check
}
And here is the overridden request class in application/classes/request.php:
<?php defined('SYSPATH') or die('No direct script access.');
class Request extends Kohana_Request {
protected $is_server_side_ = false;
public function is_server_side($v = null) {
if ($v === null) return $this->is_server_side_;
$this->is_server_side_ = $v;
}
}
Looking through Request it looks like your new request would be considered an internal request but does not have any special flags it sets to tell you this. Look at 782 to 832 in Kohana_Request...nothing to help you.
With that, I'd suggest extending the Kohana_Request_Internal to add a flag that shows it as internal and pulling that in your app when you need to check if it is internal/all others.
Maybe you are looking for is_external method:
http://kohanaframework.org/3.2/guide/api/Request#is_external
Kohana 3.3 in the controller :
$this->request->is_initial()
http://kohanaframework.org/3.3/guide-api/Request#is_initial

Resources