Setting queueSize option on SEDA - queue

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);

Related

Quarkus: "no tenant identifier specified" in callback

I try to add multi-tenancy support for my Quarkus app, following Quarkus hibernate-orm doc (see last section).
I have my CustomTenantResolver class and configure in application.properties, with multiple data sources, but no named persistent unit, see below:
# Default data source
quarkus.hibernate-orm.datasource=master
quarkus.hibernate-orm.database.generation=none
quarkus.hibernate-orm.multitenant=DATABASE
# ----- Tenant 'master' (default) ---------------
quarkus.datasource."master".db-kind=postgresql
quarkus.datasource."master".username=postgres
quarkus.datasource."master".password=password
quarkus.datasource."master".jdbc.url=jdbc:postgresql://localhost:5432/db_master
# ----- Tenant 'test' ---------------------------
quarkus.datasource.test.db-kind=postgresql
quarkus.datasource.test.username=postgres
quarkus.datasource.test.password=password
quarkus.datasource.test.jdbc.url=jdbc:postgresql://localhost:5432/db_test
Everything works fine for Web Services APIs functions - based on incoming web service calls, I can extract and supply tenant identifier for DB access.
Problem is, my app also needs to use callback method to listen on messages coming from Apache Pulsar queue. When a message comes in and triggers this callback, any DB access in this method will give this exception:
SessionFactory configured for multi-tenancy, but no tenant identifier specified: org.hibernate.HibernateException: SessionFactory configured for multi-tenancy, but no tenant identifier specified
at org.hibernate.internal.AbstractSharedSessionContract.<init>(AbstractSharedSessionContract.java:172)
at org.hibernate.internal.AbstractSessionImpl.<init>(AbstractSessionImpl.java:29)
at org.hibernate.internal.SessionImpl.<init>(SessionImpl.java:221)
at org.hibernate.internal.SessionFactoryImpl$SessionBuilderImpl.openSession(SessionFactoryImpl.java:1282)
at org.hibernate.internal.SessionFactoryImpl.openSession(SessionFactoryImpl.java:472)
at io.quarkus.hibernate.orm.runtime.session.TransactionScopedSession.acquireSession(TransactionScopedSession.java:86)
at io.quarkus.hibernate.orm.runtime.session.TransactionScopedSession.persist(TransactionScopedSession.java:138)
at io.quarkus.hibernate.orm.runtime.session.ForwardingSession.persist(ForwardingSession.java:53)
... (snipped)
Apparently my CustomTenantResolver class was not called during this listener callback as the callback is another fresh thread, hence no tenant id is supplied.
Do I miss anything? How about the scheduler in Quarkus - how does it support multi-tenancy in scheduled jobs?
Thanks for helps.
I had a similar issue when pulling messages from JMS. The cause of the issue is that io.quarkus.hibernate.orm.runtime.tenant.HibernateCurrentTenantIdentifierResolver ( which implements CurrentTenantIdentifierResolver and as the doc says Maps from the Quarkus {#link TenantResolver} to the Hibernate {#link CurrentTenantIdentifierResolver} model ) expects a request context to be active before calling our implementation of TenantResolver, as shown here:
// Make sure that we're in a request
if (!Arc.container().requestContext().isActive()) {
return null;
}
TenantResolver resolver = tenantResolver(persistenceUnitName);
String tenantId = resolver.resolveTenantId();
I solved it on my app by, first, enabling the request context on the JMS consumer:
Arc.container().requestContext().activate();
and, second, using a ThreadLocal to "pass" the current tenant id to the TenantResolver that will be called later by Hibernate ( through the HibernateCurrentTenantIdentifierResolver instance):
CurrentTenantLocal.setCurrentTenantId("public");
On my TenantResolver ( the class that implements TenantResolver ) I resolve the tenant from either an injected JsonWebToken jwt when it comes from a WebRequest, or using the ThreadLocal when consuming from JMS:
if ( CurrentTenantLocal.getCurrentTenantId() != null ) {
return CurrentTenantLocal.getCurrentTenantId();
}
Caveats:
Note that I haven't done an exhaustive search of the possible side effects of activating the request context... but I have no problems so far.

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.

Spring WS remove flexible URL, Restricting WSDL URL and service URL

I'm trying to make a Spring Boot Soap WebService application, and was following the Get Started (https://spring.io/guides/gs/producing-web-service/) example to learn how to do this.
I've created what I want, but I have two URL problems with this setup and I could not find what configuration should I change to fix this :
WSDL URL basic is localhost:8080/ws/countries.wsdl but anything like localhost:8080/ws/whatever/countries.wsdl is correct
service URL for SoapUI request is localhost:8080/ws but anything like localhost:8080/ws/whatever is correct
I know that this is a feature for Spring WS, but I want a fixed URL (without 'whatever' in both cases) and could not find what to change for this
There is no straight forward way to restrict the way you want.
SOAP service is not URL based.
SOAP message body describe the endpoint.
The thing you wanted is possible following way.
Changing URL mapping in ServletRegistrationBean to restrict URL access
Existing /ws/* mapping is the reason why all the /ws/whatever url successfully responded.
Change as new ServletRegistrationBean(servlet, "/ws");
Effect will be you can not request other than /ws URL
Now the problem is, you can not get WSDL by this mapping.
Solution to get WSDL
The DefaultWsdl11Definition is actually generating WSDL from XSD on every request.
Save countries.wsdl to resource folder as static WSDL file.
Remove DefaultWsdl11Definition bean.
Create a new SimpleWsdl11Definition bean as like
#Bean(name = "countries")
public SimpleWsdl11Definition orders() {
SimpleWsdl11Definition wsdl11Definition = new SimpleWsdl11Definition();
wsdl11Definition.setWsdl(new ClassPathResource("countries.wsdl"));
return wsdl11Definition;
}
Now add another static URL mapping in ServletRegistrationBean. As it will be finally look like new ServletRegistrationBean(servlet, "/ws", "/ws/countries.wsdl");
This practice is good for development phase as you can publish easily the changed definition. But it is recommended to use static-wsdl for production environment. Details ** here
Just change
return new ServletRegistrationBean(servlet, "/ws/*");
for example to
return new ServletRegistrationBean(servlet, new String[]{
"/ws/v1/countries.wsdl",
"/ws/v2/countries.wsdl"
});

Can I configure a #FeignClient url using a properties/yml file?

My goal is to create a strategy of different steps to get from a point-to-point communication between 2 components to a "full blown netflix" style of communication using eureka, ribbon, hystrix. With each iteration I want to add more while I try to limit the amount of changes to the actual code. Feign is my preferred client side framework to make this happen. First step is to create a FeignClient to communicate to the server:
#FeignClient(url = "http://localhost:9000")
interface Client {
#RequestMapping(method = RequestMethod.GET, value = "/author/{author}/addedValue/{addedValue}")
Result addToTotal(#RequestParam(value="author") String author, #RequestParam(value="addedValue") long addedValue);
}
This works but I don't want the URL to be hardcoded in the annotation. I would like to have this: #FeignClient()
and have a properties construct like: client.url: http://localhost:9000
So far I couldn't find any clues on how to configure that and I couldn't find a solution in the spring-cloud sources.
Can it be done and if yes; how?
It can be done with a "serviceId" instead of a "url". E.g.
#FeignClient("foo")
interface Client { ... }
and
foo.ribbon.listOfServers: localhost:9000
e.g. see http://projects.spring.io/spring-cloud/spring-cloud.html#spring-cloud-ribbon-without-eureka for docs.
This can be done like this:
#FeignClient(name="fd-mobileapi-service",url="${fdmobile.ribbon.listOfServers}")
Where fdmobile.ribbon.listOfServers : value is a property in application.properties.
I have tested it and it is working.
I got a way to pass the environment variables in a very simple way interface FeignClient,
#FeignClient(url = "https://"+"\${url}")
interface Client {
#RequestMapping(method = RequestMethod.GET, value = "/author/{author}/addedValue/{addedValue}")
Result addToTotal(#RequestParam(value="author") String author, #RequestParam(value="addedValue") long addedValue);
properties
#URL
url.client=${URL}
.env
URL=https:localhost:9000

Can I add multiple servlets to a WebAppContext?

I have the following Scala code to setup a Jetty server with Scalatra.
val server = new Server(8080)
val context = new WebAppContext()
context.setResourceBase("visualization")
context.addServlet(new ServletHolder(new CallTreeServlet(dataProvider)), "/*")
context.addServlet(new ServletHolder(new DataLoadingServlet(dataProvider)), "/*")
server.setHandler(context)
My problem is that it seems to work only if I register a single servlet.
If I register more than one, like I do in the code I posted, it loads only one of them.
Is it possible to load multiple servlets? I guess it is, but I can't figure out how.
If I try to load a page from the first servlet I got this error message that references only pages belonging to the second servlet:
Requesting "GET /callTrees" on servlet "" but only have:
GET /components
POST /load
POST /searchCallTrees
POST /selectPlugIn
To troubleshoot this, you should verify the servlet lifecycle. One convenient way to do this is to peruse the servlet container's logs to see what it reports while starting up the web application. It should tell you about each web app ( servlet context ) and each servlet . . .
However, I think I see what your problem is. Your servlet path mappings are kind of funky. It looks to me that you are mapping both servlets to receive ALL requests. This can't work, from a practical point of view, and might not work in terms of the servlet rules. From the servlet specification:
SRV.11.2
Specification of Mappings
In the Web application deployment descriptor, the following syntax is used to define
mappings:
• A string beginning with a ‘/’ character and ending with a ‘/*’ suffix is used
for path mapping.
• A string beginning with a ‘*.’ prefix is used as an extension mapping.
• A string containing only the ’/’ character indicates the "default" servlet of
the application. In this case the servlet path is the request URI minus the con-
text path and the path info is null.
• All other strings are used for exact matches only.
I suggest you make them both unique. As it looks now, you have them both at "/*" which is kind of like the "default servlet", but not . . .
Why not try "/first/" and "/second/" as a sanity check. Then move from there toward getting the configuration how you like.