Camel Salesforce - Multiple Components Configurations - apache-camel

I am trying to configure multiple Camel Salesforce components in the same camel context. As I need to connect two different salesforce instances.
I know in order to configure another instance, we can simply create a new bean with a different name and it can then be used in endpoint configurations.
I got one configured via standard properties configurations and the second one is configured using a bean with different properties.
But on startup my second bean configurations get overwritten by main components configurations in SalesforceComponentConfigurer class.
Is there any way to stop configurer to ignore the second component?
#Bean("salesforce-target")
public SalesforceComponent targetSalesforceComponent(#Autowired CamelContext camelContext) {
SalesforceComponent targetComponent = new SalesforceComponent(camelContext);
targetComponent.setClientId(clientId);
targetComponent.setClientSecret(clientSecret);
targetComponent.setUserName(userName);
targetComponent.setPassword(password);
targetComponent.setLoginUrl(loginUrl);
targetComponent.setLazyLogin(true);
targetComponent.setAuthenticationType(AuthenticationType.USERNAME_PASSWORD);
return targetComponent;
}

Related

#EnableJpaRepositories annotation disables data.sql initialization script

My Spring Boot (v2.3.4) based application uses my custom library containing core entities and business logic. To use entities and repositories from this library I had to use #EnableJpaRepositories and #EntityScan annotations with proper packages provided.
I also wanted to initialize database with some required data (let's say the configuration) during application startup. I found that Spring Boot allows to use data.sql or data-${platform}.sql files to achieve that.
Long story short when using #EnableJpaRepositories annotation the data.sql script is not executed.
I did some digging in the code and found that when #EnableJpaRepositories annotation is not used then entityManagerFactory bean is of org.springframework.orm.jpa.LocalContainerEntityManagerFactoryBean type. This bean uses org.springframework.boot.autoconfigure.orm.jpa.DataSourceInitializedPublisher bean post processor, which fires org.springframework.boot.autoconfigure.jdbc.DataSourceSchemaCreatedEvent event indicating the schema has been created. Class, which listens for this event is org.springframework.boot.autoconfigure.jdbc.DataSourceInitializerInvoker. This listener invokes initSchema() method from org.springframework.boot.autoconfigure.jdbc.DataSourceInitializer class. This method is responsible for whole initialization using data.sql script.
It looks like setting #EnableJpaRepositories annotation creates instance of different class for entityManagerFactory bean, which does not support this simple initialization.
My basic question is then how to make it all work with #EnableJpaRepositories annotation. I can always use Hibernate's import.sql file (which works fine) but I'm also trying to understand what exactly is going on under the hood I how can I control it.
UPDATE 1 28.09.2021
I did further investigation and #EnableJpaRepositories annotation does not change the instance type of entityManagerFactory but it causes silent exception (?) when creating org.springframework.scheduling.annotation.ProxyAsyncConfiguration bean (during creation of org.springframework.context.annotation.internalAsyncAnnotationProcessor bean). It looks like everything is related to #EnableAsync annotation, which I'm also using but didn't know it might be related. But it is - removing it makes the initialization work even with #EnableJpaRepositories.
UPDATE 2 28.09.2021
I've found full explanation for my issue. There are 4 conditions, which must be met to reproduce the issue:
#EnableJpaRepositories annotation in application configuration
#EnableAsync annotation in application configuration
Configuration implements AsyncConfigurer interface
Autowired any JpaRepository repository or any other bean which injects repository
Enabling asynchronous execution and implementing AsyncConfigurer makes the whole configuration to be instantiated before regular beans. Because Spring has to inject repository, it needs to instantiate entityManagerFactory bean too. Spring prints thenINFO level logs like below:
Bean 'entityManagerFactoryBuilder' of type [org.springframework.boot.orm.jpa.EntityManagerFactoryBuilder] is not eligible for getting processed by all BeanPostProcessors (for example: not eligible for auto-proxying)
One of not eligible BeanPostProcessors is DataSourceInitializedPublisher responsible for firing DataSourceSchemaCreatedEvent event. Without that event, data-${platform}.sql script won't be processed at all.
I'm not sure what is the role of #EnableJpaRepositories in that process but without it the problem does not occur.
Example
Minimal code to reproduce the issue (data.sql located in src/main/resources):
#Entity
public FileStore {
...
}
public interface FileStoreRepository extends extends JpaRepository<FileStore, Long> {
}
#Configuration
#EnableAsync
#EnableJpaRepositories
public class Configuration implements AsyncConfigurer {
#Autowired
private FileStoreRepository fileStoreRepository;
...
}
Solutions
There are two solutions I'm aware of:
Move AsyncConfigurer along with its overrided methods and #EnableAsync annotation to separate configuration class
Use #Lazy annotation on autowired bean like below:
#Lazy
#Autowired
private FileStoreRepository fileStoreRepository;
Similar problem was pointed by #Allen D. Ball and can be checked there.
This behavior had changed.
Take a look at the
how-to guide.
Add:
spring.jpa.defer-datasource-initialization: true

Adhoc execution of Apache Camel route

I have a couple of Apache Camel routes created using the Java DSL and Spring.
#Bean
public CamelContext camelContext() throws Exception {
CamelContext camelContext = new DefaultCamelContext();
camelContext.addRoutes(route1bean());
...
camelContext.start();
return camelContext;
}
These routes use quartz2 component for scheduling and everything works as expected.
The jobs can however have errors when running and there is a requirement to retry them manually. I'm looking for a way to make adhoc manual execution of the route using hawtio or in Java code.
Yes , use jconsole. There are many mbeans exposed by camel. You can use them to start and stop. Of course you can do the same using Hawtio as well.
Updated based on your comment:
I get what you mean, This is the approach I will take. Create 3 routes. 2 light weight routes - Route A with Simple File From endpoint, Route B with Cron and Route C with direct:bla From endpoint, which contains the actual business logic. This way, you can trigger Route A whenever you want, Route C is common, Irrespective of when Route B is triggered by the cron.

Difference between CamelContext and Registry in Camel

I'm new to Camel and bit confused between CamelContext and Registry.
As far as I know that CamelContext is the base object like ApplicationContext in Spring that is used for add routes and maintains the camel life cycle.
Also we got the Registry object from CamelContext but not sure what is the main purpose of this registry.
My intention is to add the component in the context/registry so that JNDIBind can look up the components.
CamelContext: Kind of Camel Runtime that keeps everything in Camel together, e.g.: Endpoints, TypeConverter, Routes, Components and Registry(!).
Registry: allows you to lookup beans, which by default will be JNDI beans. If you use the spring integration it will be Spring's ApplicationContext.
Generally camel when used with spring makes use of the ApplicationContextRegistry to lookup components, endpoints etc with the name of the bean defined in spring-bean.xml file. In places where we need to use JNDIRegistry we would have to add that registry when creating the CamelContext. This is used in places where JNDI objects are shared accross multiple JVMs where JNDI is the best solution.
Please see different types of registry implementation for camel: camel registries

Reconfiguring Apache Camel route parameters at runtime

I have aggregation configured in my code:
.aggregate(new BodyAggregationStrategy())
.constant(true)
.completionSize(1000) // Static value
.completionTimeout(300) // Static value
After I have started the Apache Camel context is it possible to change various parameters like completionSize and completionTimeout values?
When context is running a lot of data are transfering throught it and I want to increase some parameters like queue size and so on.
What you could do, is via the CameContext
stop the route
remove the route
add the route with new parameters
start the route
Have you tried to connect via JMX and see if those parameters can be configured?

Initialize Database connection in Jersey REST webapp

I want to make database queries in my Jersey REST webapp. The ideal situation would be to find a way where the database connection is initialised once at the first app run. Afterwards I only get the instance of DAOFactory object in my REST class and make the queries in the methods. I am using mysql connector. Is there a way to find a way to do it in Jersey? In JSF it was possible - I just used an application-scoped bean when I run the code. Moreover it would be good if I could access the ServletContext object inside this method cause I would like to use it's getResourceAsStream() method to read the database connection parameters from WEB-INF/dao.properties file. But the 'only once per app initialisation' is the crucial part here.

Resources