Camel mid-route jpa consumer - jpa

I faced the following problem with JPA but it's maybe more like a conceptional question about Camel.
I need a cron based Quartz consumer. But if it's triggered, I'd like to make a selection as a 1st step with JPA component.
<from uri="quartz://myQuartz?cron=myCronExpression/>
<to uri="jpa://home.myEntity?consumer.query=select o from home.myEntity o"/>
But if I call the JPA component with "to", then it's used as a Producer, and not as a Consumer. Can I use somehow the JPA component to handle this, or I have to follow the Service Activator (bean-based) logic and leave the JPA component behind?
Thanks in advance,
Gergely

This is pretty much the Content-Enrichement pattern. You can use the
<pollEnrich uri="jpa://home.myEntity?consumer.query=select o from home.myEntity o"/>
instead to use a consumer mid-route. Keep in mind that you cannot use runtime data from the route (headers or the like) but need to keep the route URI static in this case. Seems your URI is static so that should be no issue.

Very good point Petter. I had a similar issue. I wanted to create a simple route that when called will retrieve data from the database. The solutions is simple.
from("direct:test")
.pollEnrich("jpa://" + User.class.getName() + "?consumer.query=select u from test.User u&consumeDelete=false")
Also check this Camel - content enricher: enrich() vs pollEnrich().

Related

Project Reactor and Server Side Events

I'm looking for a solution that will have the backend publish an event to the frontend as soon as a modification is done on the server side. To be more concise I want to emit a new List of objects as soon as one item is modified.
I've tried implementing on a SpringBoot project, that uses Reactive Web, MongoDB which has a #Tailable cursor that publish an event as soon as the capped collection is modified. The problem is that the capped collection has some limitation and is not really compatible with what I want to do. The thing is I cannot update an existing element if the new one has a different size(as I understood this is illegal because you cannot make a rollback).
I honestly don't even know if it's doable, but maybe I'm lucky and I'll run into a rocket scientist right here that will prove otherwise.
Thanks in advance!!
*** EDIT:
Sorry for the vague question. Yes I'm more focused on the HOW, using the Spring Reactive framework.
When I had a similar need - to inform frontend that something is done on the backend side - I have used a message queue.
I have published a message to the queue from the backend and the frontend consumed the message.
But I am not sure if that is what you're looking for.
if you are using webflux with spring reactor, I think you can simply have a client request with content-type as 'text/event-stream' or 'application/stream+json' and You shall have API that can produce those content-type. This gives you SSE model without too much effort.
#GetMapping(value = "/stream", produces = {MediaType.TEXT_EVENT_STREAM_VALUE, MediaType.APPLICATION_STREAM_JSON_VALUE, MediaType.APPLICATION_JSON_UTF8_VALUE})
public Flux<Message> get(HttpServletRequest request) {
Just as an idea - maybe you need to use a web socket technology here:
The frontend side (I assume its a client side application that runs in a browser, written in react, angular or something like that) can establish a web-socket communication with the backend server.
When the process on backend finishes, the message from backend to frontend can be sent.
You can do emitting changes by hand. For example:
endpoint:
public final Sinks.Many<SimpleInfoEvent> infoEventSink = Sinks.many().multicast().onBackpressureBuffer();
#RequestMapping(path = "/sseApproach", produces = MediaType.TEXT_EVENT_STREAM_VALUE)
public Flux<ServerSentEvent<SimpleInfoEvent>> sse() {
return infoEventSink.asFlux()
.map(e -> ServerSentEvent.builder(e)
.id(counter.incrementAndGet() + "")
.event(e.getClass().getName())
.build());
}
Code anywhere for emitting data:
infoEventSink.tryEmitNext(new SimpleInfoEvent("any custom event"));
Watch out of threads and things like "subscribeOn", "publishOn", but basically (when not using any third party code), this should work good enough.

Setting Scenario Endpoints

I am having problems setting an endpoint URI in a scenario for the Citrus Simulator. Here is how I am trying to build my scenario:
#Override
public void run(ScenarioDesigner scenario) {
scenario
.soap()
.receive().endpoint("{http://www.sikorsoftware.com/lov/schemas}LOVRequest")
.payload("<ns2:LOVRequest xmlns:ns2=\"http://www.sikorsoftware.com/lov/schemas\"><ns2:id>123456</ns2:id></ns2:LOVRequest>");
scenario
.soap()
.send()
.payload("<LOVResponse xmlns=\"http://www.sikorsoftware.com/lov/schemas\">" +
"Hi there!" +
"</LOVResponse>");
}
But I keep getting this message when I try to send a soap message:
o.s.ws.server.EndpointNotFound : No endpoint mapping found
for [SaajSoapMessage
{http://www.sikorsoftware.com/lov/schemas}LOVRequest]
What am I doing wrong. Should I be setting up my endpoints a different way?
Thanks,
Michael
The endpoint is always a reference to a Citrus Spring bean component, in particular the component id that is used to add the component to the Spring application context.
In addition to that the scenario endpoint is automatically referenced when using the scenario designer instance. So in case you want to receive the scenario triggering message you do not need any endpoint reference.
When your scenario is not called this is because of some other issue in your setup. Maybe the incoming request does not map to your scenario definition.

Setting queueSize option on SEDA

I have a seda queue where i set queueSize option according to the camel documentation
The route i have looks like:
from("seda:someQueue?concurrentConsumers=10&queueSize=10")
.process(someProcessor);
I'm getting the following error due to the queueSize option:
org.apache.camel.FailedToCreateRouteException: Failed to create route....bla bla bla..
There are 1 parameters that couldn't be set on the endpoint. Check the uri if the parameters are spelt correctly and that they are properties of the endpoint. Unknown parameters=[{queueSize=10}].....
[stacktrace continues here]
Can anyone point out what's wrong?
I'm using Java 8, Camel 2.9.13
Notice that the documentation says that the option queueSize is component only, which mean you need to configure it on the SedaComponent instead. In other words you cannot configure it on the endpoint as you do in your route above.
For up to date documentation and better docs on Camel components, then browse github pages at: https://github.com/apache/camel/blob/master/components/camel-seda/src/main/docs/seda-component.adoc
Those docs are up to date and show both component vs endpoint options in different tables, so its easier to know the difference.
For those who have the same question, this is how i use the queueSize now
Initialize a new seda component,
SedaComponent sedaComponent = new SedaComponent();
sedaComponent.setQueueSize(3);
context.addComponent("sedaComponent", sedaComponent);
then use this component at the route like,
from("seda:someEndPoint?concurrentConsumers=5")
.to("sedaComponent:someOtherSedaEndPoint?blockWhenFull=true");
Create a specific queue . it is quarkus example replace Named as bean and ApplicationScoped to Configuration for Spring boot
#ApplicationScoped
public class ConnectionConf {
#Named("NonLimitQueue")
#Produces
public BlockingQueue arrayDeque(){
return new ArrayBlockingQueue(30000);
}
}
camel side
from("seda:queue=#NonLimitQueue")
.convertBodyTo(String.class).log("${body}")
Replace queueSize
with
size(query param in apache document)
from("seda:someQueue?concurrentConsumers=10&queueSize=10")
.process(someProcessor);

JAX-RS(CXF) JSONProvider

I am new to JAX-RS, I am just starting with apache CXF, I am struck at "No message body writer has been found for response class" while trying to return "application/jason". I know, I can set the JSONProvider using spring context loader file, but I dont want to use spring. Is there any way to set JSONProvider to the application directly?
I made a mistake in my code, instead "application/json" I wrote "application/jason", I corrected it, and it is working. And I found that no need to set JSON Provider explicitly.

Performing Sticky load balancing in Camel

Hi I would like to perform sticky load balncing in apache camel based on the SOAP session, whcih is embedded in ServiceGroupID node of the first response.
I wrote a small route as follow:
from(uri)
.loadBalance().sticky(xpath(query).namespaces(env).namespaces(wsa).namespaces(ax))
.to(BE1,BE2);
Where URI is the string to which the requests are passed and BE1 and BE2 are the two backend servers.
And my query is
String query = "/soapenv:Envelope/soapenv:Header/wsa:ReplyTo/wsa:ReferenceParameters/axis2:ServiceGroupId/text()";
If i am not wrong this query would extract the servicegroupID from my SOAP header.
But when I try to perform the balancing, due to some reason whatsoever, the requets are not being passed to the same backend server.
and my env, wsa and ax are the namespaces, which are :
Namespaces env = new Namespaces("soapenv", "http://schemas.xmlsoap.org/soap/envelope/");
Namespaces wsa = new Namespaces("wsa", "http://www.w3.org/2005/08/addressing");
Namespaces ax = new Namespaces("axis2", "http://ws.apache.org/namespaces/axis2");
Am I doing something wrong here?
If so what? I would appreciate any help.
Also being discussed at the mailing list
http://camel.465427.n5.nabble.com/Performing-Sticky-load-balancing-in-Camel-tp5719170.html
Please dont start the same topic in multiple places at the same time. And if you do, then at least tell us, so we would know this.
People get upset when they spend time to help you, when its already been answered in another place!