I have created this Camel routes
from("direct:pageExtraction")
.bean(PageManager.class, "setProperties(*, ${headers})")
.filter().method(PageManager.class, "exists").to("seda:pagePostProcessing").end()
.to("seda:pageImposition");
from("seda:pagePostProcessing")
.bean(PageManager.class, "extractThumbnail(*, ${headers})")
.bean(PageManager.class, "extractCMYKSeparation(*, ${headers})")
.bean(PageManager.class, "persist(*, ${headers})")
.bean(PageManager.class, "cleanUp(${headers})")
.to("seda:pageImposition");
from("seda:pageImposition")
.bean(PageManager.class, "extractImposition(*, ${headers})")
.to("seda:printQueue");
At the end, the seda:printQueue has no consumers, sending a message in a route like this apparently works fine. Now I want to introduce a new consumer after the routes have been initialized, I thought it would be possible to create a Spring bean programmatically and let Camel pick up the bean using the #Consume(uri="seda:printQueue") annotation, but as soon as I create the consumer Camel complains
org.apache.camel.RuntimeCamelException: org.springframework.beans.factory.NoSuchBeanDefinitionException: No bean named '4965d710-b5c7-41cf-97e9-a42bdfcea894' is defined]
Any thoughts?
[UPDATE]
I have traced back the error to the class where this new consumer is created, I'm instantiating the PrintQueue class and then integrating it to the Spring context using an AutowireCapableBeanFactory doing a factory.autowireBean(printQueueInstance) followed by factory.initializeBean(printQueueInstance, id) where id is the 4965d710-b5c7-41cf-97e9-a42bdfcea894 that appears in the exception above, so I think this has to be some kind of context scope problem, may be I am creating this bean in the main or web Spring context and it can't be access by the Camel context, is this possible?
Since this route is invoked synchronously via use of the "direct:" component, it does not appear to require "seda:" for asynchronous invocation of another bean. In this situation, it would appear simplest to invoke a bean with Camel's bean methods for the Java DSL. As an example shown in the Camel bean documentation at:
http://camel.apache.org/bean.html
I would simply do:
// Send message to the bean endpoint
// and invoke given method.
from("direct:start")
// do other stuff in your route
.beanRef("beanName", "methodName");
Related
I use Java WebSocket API to declare client (Java class annotated by #ClientEndpoint):
#ClientEndpoint
public class MySock {
MySock(ExecutorService exec){}
...
}
Instance is created via constructor:
webSocket = new MySock(exec);
session = wsContainer.connectToServer(webSocket, url);
And I have error during the build via quarkus-maven-plugin:
[error]: Build step ...ArcProcessor#validate threw an exception:
javax.enterprise.inject.UnsatisfiedResolutionException:
Unsatisfied dependency for type ...ExecutorService and qualifiers [#Default]
- java member: edu.MySock#<init>()
- declared on CLASS bean [types=[edu.MySock, java.lang.Object], qualifiers=[#Default, #Any], target=edu.MySock]
Pay attention: there is no #Inject annotation
Should have it been validated, if it can be passed to #connectToServer as a class and as instance too?
So, Is it ok if validation processes a pessimistic case, where validation is useful, but it brokes an optimistic case?
Pessimistic case, where dependencies may not be declared:
session = wsContainer.connectToServer(MySock.class, url);
In the following case, validation is harmful because it brokes build phase:
session = wsContainer.connectToServer(webSocket, url);
Maybe ClientEndpoint should not be validated at all?
And before you ask me...
We are not going to inject something into WebSocket and we would not like to use programmatic EndPoints. But we want to create an instance for the annotated class. Why not? WebSocket incapsulates complex logic inside itself and this variant we used multiple times (e. g. in applications on WildFly).
The best solution for me would be to disable validation for my bean only, but I cannot find an idea of how to do it.
This article has not helped me https://quarkus.io/guides/cdi-reference. The fact that beans.xml is ignored cannot help me too.
The second-way, for the future, is to disable validation if there is no one class member with #Inject annotation. It can be not correct, but here there is some explanation:
First, the container calls the bean constructor (the default constructor or the one annotated #Inject), to obtain an instance of the bean.
So, my constructor is not "default" and I did not use #Inject annotation.
Work around is so simple: #javax.enterprise.inject.Vetoed annotation disables bean for validation.
I'am trying to send a simple message using "spring cloud stream" to the rabbitmq. Basically code looks like this:
#EnableBinding(Source.class)
#SpringBootApplication
public class SourceApplication {
public static void main(String[] args) {
SpringApplication.run(SourceApplication.class, args);
}
#Autowired Source source;
#PostConstruct
public void init() {
source.send(MessageBuilder.withPayload("payload").build());
}
}
then I get this error message:
org.springframework.messaging.MessageDeliveryException: Dispatcher has no subscribers for channel 'unknown.channel.name'.; nested exception is org.springframework.integration.MessageDispatchingException: Dispatcher has no subscribers, failedMessage=GenericMessage [payload=******, headers={id=c60dd5be-6576-99d5-fd1b-b1cb94c191c1, timestamp=1488651422892}]
at org.springframework.integration.channel.AbstractSubscribableChannel.doSend(AbstractSubscribableChannel.java:93)
at org.springframework.integration.channel.AbstractMessageChannel.send(AbstractMessageChannel.java:423)
at org.springframework.integration.channel.AbstractMessageChannel.send(AbstractMessageChannel.java:373)
However, if I add some delay, before sending a message (just second or few), it works ok. My question is: how can I wait before spring completely initialize message channels and then send a message?
#PostConstruct is triggered too early (when the configuration bean is created, but before the context is started and the binding takes place). What you want is to trigger the sending of the message once the context is completely initialized, or at least after the output channels are bound.
You have a few options, all relying on the creation of an additional bean:
To use the SmartLifecycle support from Spring (make sure that isAutoStartup returns true by default and the phase is zero - the default - so that the bean is started after outputs are bound).
Use an ApplicationListener for ContextRefreshedEvent.
Since this is a Spring Boot application you can use an ApplicationRunner bean (which gets invoked after the context has been created).
You might look into Spring's Task Execution and Scheduling features.
In particular, it sounds like you want something like what section 34.4 covers.
Also, I spotted this answer to a similar question.
Is it possible to define a prototype bean, using XML config or annotation-based config such that I can get an instance of the bean with a custom parameter value? My use case is a message queue handler that makes API calls with different parameter values that are supplied in the inbound message.
In this case it seems I can do one of two things:
Get an instance of my prototype-scope bean and then call setters to customize it to be specific to the inbound message.
Construct a new instance of the bean class using a plain new MyPrototypeBean() and then call setters to customize the instance.
Perhaps a different way of wording my question is: What is the benefit of using a prototype-scope bean vs. using a simple Java constructor?
To get a prototype bean from another bean while passing arguments to constructor you can use <lookup-method> (XML Configuration) or #Lookup (annotation-based configuration).
If you want to get the prototype instance from "unmanaged" code (not from a bean) or you don't want to use the lookup methods, you can achieve the same using org.springframework.beans.factory.BeanFactory.getBean(String beanName, Object...).
Answering your second question, difference between a prototype-scope bean and using a simple Java constructor is that the prototype-scope bean still have access to Spring container's features. This includes, but it's not limited to the following: it can have collaborators provided in XML configuration (<property name="someCollaborator" ref="..."/>) or with annotations (#Resource, #Autowired, ...), t can implement Spring-aware interfaces (like ApplicationContextAware so that the prototype bean itself has access to the container).
I have a request-scoped bean which are used in app. Now I need to implement some predefined configuration beans. I tried both ways:
as a InitializingBean implementation
as a spring's ApplicationListener<ApplicationReadyEvent> listener
but the problem is that code within this config beans uses erquest-scoped bean and everytime I get a:
Caused by: java.lang.IllegalStateException: No thread-bound request found: Are you referring to request attributes outside of an actual web request, or processing a request outside of the originally receiving thread?
is there any way of simulating request?
I configured a spring boot based application to use remoting with activemq/jms. The listening part is running fine but I have problems implementing the sending part.
For the sender I went back to "classic" camel and spring because I found more working examples for this but still receive an error:
org.springframework.beans.factory.BeanNotOfRequiredTypeException:
Bean named 'myProxy' must be of type [foo.bar.YouNameIt],
but was actually of type [com.sun.proxy.$Proxy83]
This is the way I try to load the proxy definition:
ApplicationContext context = new ClassPathXmlApplicationContext("config/spring.xml");
YouNameIt youNameIt = context.getBean("myProxy", YouNameIt.class);
And this is the entry in the spring.xml:
<camel:proxy id="myProxy"
serviceInterface="foo.bar.IYouNameIt"
serviceUrl="activemq:queue:site12345" />
What am I doing wrong ?
Access the interface IYouNameIt and not the implementation class YouNameIt:
IYouNameIt youNameIt = context.getBean("myProxy", IYouNameIt.class);
See here for a full Spring remoting example.