Camel-Cdi not injecting CamelContext with Registery - apache-camel

I am using camel-cdi and it is injecting the CamelContext, detecting all the routes in project.
But I want a CamelContext with a registry because I have some components that I use in camel routes like shown below.
SimpleRegistry registry = new SimpleRegistry();
registry.put("actionProcessor", actionProcessor);
registry.put("jpa", jpaComponent);
registry.put("jtaTransactionManager", platformTransactionManager);
CamelContext camelContext = new DefaultCamelContext(registry);
When I inject CamelContext the components like actionProcess, jpa are not recognized. when in my Route I have
.to("bean:actionProcessor?method=myMethod(${body})")
but my bean does not get executed.
I documentation I read use # before components name which are in registry but still it is not working.
Please suggest how can I achieve this using camel-cdi.

Did you already try with creating a CdiCamelContext (a subclass of DefaultCamelContext) ?
Otherwise, a more elegant would be to annotate your various classes, eg:
#Named("actionProcessor")
public class MyActionProcessor{
...
}

We have been using this for years without any problem
public class ContextFactory {
#Produces
#ApplicationScoped
#ContextName("Demo")
static final CamelContext createContext() {
CdiCamelContext context = new CdiCamelContext();
context.setStreamCaching(true);
context.disableJMX();
return context;
}
}
#ContextName("Demo")
public class MyRouteBuilder extends RouteBuilder {
from("...")
.to("bean:actionProcessor?method=myMethod")
}
#Named("actionProcessor")
public class MyActionProcessor{
public void myMethod(#Body String body) {}
}
Of course, in order to work, you need to activate the JEE bean discovery (=add a "beans.xml" file in META-INF or WEB-INF) !

Related

Explicitly define Camel Routes in Quarkus

Current behaviour: When I'm running a Quarkus App with Camel it automatically starts all the RouteBuilder Extensions as Routes.
What I want to achieve: On startup only the Routes that I configured are started.
What I tried:
With the following snippet it's possible to explicitly start the CamelMainApplication but I dont know how to get control over e.g. the CamelContext at this point where I would be able to configure my routes.
#QuarkusMain
public class Main {
public static void main(String[] args) throws Exception {
Quarkus.run(CamelMainApplication.class, args);
}
}
On the Route I can use .noAutoStartup() to disable the route on startup. But this means that it's not the default for all routes to be disabled at first and second I don't know where to activate them as I don't know where in a Quarkus App I can get a hand on the Camel Context to activate the route.
With the following in my application.yml I can disable the automatic route discovery but then the remaining question is how I can manually start the route, e.g. in my QuarkusMain class.
quarkus:
camel:
routes-discovery:
enabled: false
I think it is best way. Quarkus has properties for include and exclude route as pattern. this properties is List You can add one to N
quarkus.camel.routes-discovery.exclude-patterns=tes.Comp,tes.package.MyRoute
quarkus.camel.routes-discovery.include-patterns=test.mypackage.XX
I had this same problem I ended up doing something like the following:
#QuarkusMain
public class Main implements QuarkusApplication {
#Inject
OrderService orderService;
#Override
public int run(String... args) throws Exception {
CamelRuntime runtime = Arc.container().instance(CamelRuntime.class).get();
runtime.start(new String[]{});
orderService.handleOrders(args[0]); //this would inject the camelContext and start the route.
return 0;
}

Using Project Reactor with Apache Camel

I'd like to know if it is possible to use Project Reactor with Apache Camel, so applications be fully reactive and non-blocking IO. I'd like to know how does the Project Reactor support works when integrating other Apache Camel's components.
Can I read for example from S3 reactively (therefore I'll need to use the Async S3 client behind the scenes)? Or will I block when reading from S3 and then just create a Flux out of what has been returned?
Where reactiveness is needed, you should use the relevant spring and reactor libraries. there are pseudo camel code also u can db call in camel bean or processors etc
#RestController
#RequestMapping(value = "/api/books")
#RequiredArgsContructor
public class HomeController {
private final BookRepository bookRepository;
private final ProducerTemplate template
#GetMapping("")
public Flux<Book> getHome() {
List <Book> books=bookRepository.findAll();
X ret = template.requestBody("direct:something", books, X.class);
}
}
#Component
public class SomeRoute extends RouteBuilder {
#Override
public void configure() throws Exception {
from("direct:something")
.process(e-> {
List<Book> books = e.getIn.getBody(List.class)
// some logic
e.getIn.setBody(new X( ))
})
}

Camel Properties file load from Junit Integration Test

I have a Camel Route which uses CDI to load a properties file from the JBoss configuration directory ...works perfect.
What I need to do is load one of the properties that are loaded in
an Arquillian integration test I am writing.
Example:
Content of Fiddler.properties file in the JBoss configuration directory
silly.value = Laughing
serious.value = politics
Example Producer class to load properties
/**
* Create the Camel properties component using CDI #Produces
*/
#Produces
#Named("properties")
PropertiesComponent propertiesComponent() {
final PropertiesComponent component = new PropertiesComponent();
// load JBoss properties file
component.setLocation(
"file:${jboss.server.config.dir}/fiddler.properties"
);
return component;
}
A given property from the Fiddler.properties file is now available in the main Camel route as {{silly.value}} or {{serious.value}}
Problem:
What I would like to do is load/reference one of these property values from my Arquillian Integration Test … probably in the #BeforeClass method …something like below:
#RunWith(Arquillian.class)
public class MainRouteIT {
.
.
Boolean allOK = false;
#BeforeClass
public static void setupTest() throws Exception {
allOK = new testCheck(
{{silly.value}}, {{serious.value}}
);
.
.
Any idea if something like this is possible in Camel within an Arquillian test ?
Here is the solution we are using (but without Arquillian):
First define a CDI alternative for the Camel "properties" component, which will use testing property values.
Then annotate your unit test in order to use the alternate producers of Camel components.
#Alternative
public class CamelAlternatives {
#Produces
#ApplicationScoped
#Named("properties")
public PropertiesComponent propertiesComponent() {
PropertiesComponent component = new PropertiesComponent();
component.setLocations( Arrays.asList("classpath:common.properties", "classpath:testing.properties") );
return component;
}
#RunWith(CamelCdiRunner.class)
#Beans(alternatives = {CamelAlternatives.class})
public class MyUnitTest {
...
}

Get the CamelContext for standalone Apache Camel instance

I'm using the Main class from Apache Camel to run it as standalone.
I need to use the JMS component so I have to add it to the CamelContext instance used by the Main class.
Of course I need to do that before calling main.run(args) method.
The problem is the following ...
Using main.getCamelContexts().get(0) returns an index out of bounds exception.
Using main.getOrCreateCamelContext() returns a valid CamelContext instance named "camel-1" to which I'm able to add my JMS component but .... when I execute main.run(args), another CamelContext named "camel-2" is used !
The only way I found to add my JMS component is to use :
main.bind("jms", JmsComponent.jmsComponentAutoAcknowledge(connectionFactory));
Is this the only way or the CamelContext way should work ?
Thanks,
Paolo.
You can provide completely own camel context to be used. To achieve that you can inherit org.apache.camel.main.Main and override only one method
protected Map<String, CamelContext> getCamelContextMap()
Here is the example of inherited body:
#Override
protected Map<String, CamelContext> getCamelContextMap() {
Map<String, CamelContext> camelContextMap = new HashMap<>();
DefaultCamelContext camelContext = new DefaultCamelContext();
camelContext.setName("MyContext");
// Add your context configuration here
camelContextMap.put("connectorContext", camelContext);
return camelContextMap;
}
In general it is better to create context map not in the "getCamelContextMap()" inherited method but somewhere in the constructor.
Old Question, but was able to figure it out - tried with camel 2.17.x version
private void runMyExample() {
//Add a Main Listener
main.addMainListener(new MyMainListener);
main.run();
}
public static class MyMainListener extends MainListenerSupport {
#Override
public void afterStart(MainSupport main) {
System.out.println("MainExample with Camel is now started!");
//This is the right instance
CamelContext context = main.getCamelContexts().get(0);
}
#Override
public void beforeStop(MainSupport main) {
System.out.println("MainExample with Camel is now being stopped!");
}
}
Regards,
R.

#EnableAspectJAutoProxy not work with proxyTargetClass=false

I am learning about Spring AOP at first time.
I am reading about in this sites:
Site2 and
Site1
Following this I have made the next classes
Main class:
public class App {
public static void main(String[] args) {
AnnotationConfigApplicationContext context = new AnnotationConfigApplicationContext();
context.register(AppConfig.class);
context.refresh();
MessagePrinter printer = context.getBean(MessagePrinter.class);
System.out.println(printer.getMessage());
}
}
App config class:
#Configuration
#ComponentScan("com.pjcom.springaop")
#EnableAspectJAutoProxy(proxyTargetClass=true)
public class AppConfig {
#PostConstruct
public void doAlert() {
System.out.println("Application done.");
}
}
Aspect class:
#Component
#Aspect
public class AspectMonitor {
#Before("execution(* com.pjcom.springaop.message.impl.MessagePrinter.getMessage(..))")
public void beforeMessagePointCut(JoinPoint joinPoint) {
System.out.println("Monitorizando Mensaje.");
}
}
And others...
Just like that app work nice, but if I put proxyTargetClass to false. Then I get the error below.
Exception in thread "main" org.springframework.beans.factory.NoSuchBeanDefinitionException: No qualifying bean of type [com.pjcom.springaop.message.impl.MessagePrinter] is defined
at org.springframework.beans.factory.support.DefaultListableBeanFactory.getBean(DefaultListableBeanFactory.java:318)
at org.springframework.context.support.AbstractApplicationContext.getBean(AbstractApplicationContext.java:985)
at com.pjcom.springaop.App.main(App.java:18)
Why?
#EnableAspectJAutoProxy(proxyTargetClass=false)
Indicates that JDK dynamic proxy will be created to support aspect execution on the object. And therefore as this type of proxy requires a class to implement an interface your MessagePrinter must implement some interface which declares method getMessage.
#EnableAspectJAutoProxy(proxyTargetClass=true)
On the opposite instruct to use CGLIB proxy which is able to create proxy for a class without an interface.
1> Message Printer has to be defined as a component i.e :
`
package com.pjcom.springaop.message.impl;
#Component
public class MessagePrinter{
public void getMessage(){
System.out.println("getMessage() called");
}
}`
in the same package as configuration java file if no #ComponentScan is not defined for some other packages.
2> If same type of bean class has many other dependencies then to resolve dependencies in spring Config use #Qualifier annotation.

Resources