Camel-Guice and JNDi - apache-camel

Trying to integrate Camel+ Guice and JNDI. We have batch job which already uses Guice for Dependency Injection. We are Switching to Camel for Integration and decided to uses camel-guice component.
I have configured DataSource as provider binding in Guice Module. This module is bootstrapped through jndi.properties file in classpath
#Provides
#JndiBind("jdbc/dbName")
#Singleton
public DataSource congigureDataSource() {
//Actual code for creating DataSource
}
There is existing code which looks up the DataSource through JNDI api.
Context ctx = new InitialContext();
DateSource dx = (DataSource)ctx.lookup("jdbc/dbName");
//DB connection and query code goes here
The above code triggers an infinite recursion in GuiceInitialContextFactory in the method getInitialContext. i.e This method being called again and again
Just want to check if i'have configured everything correctly or something is missing. Is the approach correct.

Related

Camel Salesforce - Multiple Components Configurations

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

#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

How to configure Apache Camel's serviceCall to look for services in Eureka service discovery?

I am working on a project and I am forced to not using Spring Boot. I have a Eureka server running on localhost:8090 and some services already registered on it.
How can I force Apache Camel's serviceCall to look for services on the Eureka server?
I know that to make it work for Consul as the service discovery you should do something like following:
ConsulConfiguration config = new ConsulConfiguration();
config.setUrl("http://ip:port");
ConsulServiceDiscovery discovery = new ConsulServiceDiscovery(config);
// configure camel service call
ServiceCallConfigurationDefinition config = new ServiceCallConfigurationDefinition();
//config.setServiceDiscovery(servers);
// register configuration
camelContext.setServiceCallConfiguration(config);
How to make it work for Eureka server on localhost:8090??
there’s no direct support for eureka in camel so if you can’t use spring-boot, you need to build your own ServiceDiscovery implementation
As #Luca suggested and after some research I came to this conclusion that you should implement a custom service discovery to read from Eureka. In order to do that I did the following:
Extending my EurekaServiceDiscovery class from DefaultServiceDiscovery class of camel-core module
Overriding the method public List getServices(String name) of
DefaultServiceDiscovery class which is responsible to retrieve services from Eureka
Using Eureka REST API to get all the services in the overrided method. In order to do this you should convert the recieved JSON data from Eureka REST API to appropriate java classes. You need to define Application and InstanceInfo classes based on those JSON data.
For example after running Eureka on localhost:8090 and after registering a service named account-service on it, you can git information of account-service by sending a Http.GET request to localhost:8090/eureka/apps/account-service
For more info look at this Github repo: https://github.com/hamedmirzaei/service-gateway-bootless

Hangfire configuration for SQL Server

I am coding a MVC 5 internet application, and am wishing to use Hangfire for recurring tasks.
How can I setup Hangfire to use SQL Server storage without specifying this in the Startup.Auth ConfigureAuth(IAppBuilder app) function.
Here is a resource link for SQL Server configuration: http://docs.hangfire.io/en/latest/configuration/using-sql-server.html
This resource states that:
If you want to use Hangfire outside of web application, where OWIN
Startup class is not applicable, create an instance of the
SqlServerStorage manually and pass it to the JobStorage.Current static
property. Parameters are the same.
The example code is as follows:
JobStorage.Current = new SqlServerStorage("connection string or its name");
I have tried the following code (with my own connection string), yet the dashboard is not available. I have called the code above from a controller function.
Is there something that I have not done correct? How can I setup Hangfire to use SQL Server storage without using the Startup.Auth class?
Thanks in advance.
I think this is your problem:
I have called the code above from a controller function.
You should be setting this up once on application startup - either in the Configuration method of an OWIN Startup class (followed by an app.UseHangFireServer();), or in the Application_Start method of your Global.asax.cs if you really don't want to use OWIN. Either way, the line you're looking for is right there in the documentation you reference:
Hangfire.GlobalConfiguration.Configuration.UseSqlServerStorage(#"connection string or connection string name");
HOWEVER, as far as I know, if you want to use the dashboard you must configure that part via OWIN along with an authorization filter. See http://docs.hangfire.io/en/latest/configuration/using-dashboard.html
So really, I don't know if any downside of using the OWIN configuration for all of this. It's the more modern platform, and since you mention this is for an MVC5 app it's unlikely that you have legacy concerns.

Guice and JSF 2

I'm trying to use Guice to inject properties of a JSF managed bean. This is all running on Google App Engine (which may or may not be important)
I've followed the instructions here:
http://code.google.com/docreader/#p=google-guice&s=google-guice&t=GoogleAppEngine
One problem is in the first step. I can't subclass the Servlet module and setup my servlet mappings there because Faces is handled by the javax.faces.webapp.FacesServlet which subclasses Servlet, not HttpServlet. So, I tried leaving my servlet configuration in the web.xml file and simply instantiating a new ServletModel() along with my business module when creating the injector in the context listener described in the second step.
Having done all that, along with the web.xml configuration, my managed bean isn't getting any properties injected. The method is as follows
#ManagedBean
#ViewScoped
public class ViewTables implements Serializable
{
private DataService<Table> service;
#Inject
public void setService( DataService<Table> service )
{
this.service = service;
}
public List<Table> getTables()
{
return service.getAll();
}
}
So, I'm wondering if there is a trick to get Guice injecting into a JSF managed bean? I obviously can't use the constructor injection because JSF needs a no-arg constructor to create the bean.
Check the following JSF-Guice integration framework/advice:
http://code.google.com/p/jsf-sugar/
http://notdennisbyrne.blogspot.com/2007/09/integrating-guice-and-jsf.html
http://cagataycivici.wordpress.com/2007/03/26/integrating_guice_and_jsf/
http://snippets.dzone.com/posts/show/7171
You can also create an HTTP servlet that then simple delegates the request on to a FacesServlet (like a wrapper). This should give you the same effect using Guice Servlet.
How about this approach, works well for us:
http://uudashr.blogspot.com/2008/12/guicing-jsf-with-guice.html
being the developer of jsf sugar I really would like to know the problem you had using it. We are already using it in production here so there shouldn't be any "show stoppers", maybe something is just not well documented? Just drop me a mail: murbanek(at)gmx_net (replace the _ with a .) .
check out http://code.google.com/p/guice2jsf/, and website starchu.blogspot.com, it has excellent library that provides Guice and JSF 2.0 integration
As information in this post are getting out of date but the question is still relevant, I'd like to share my findings about this topic. I wrote a little tutorial including a runnable sample project on how to setup a fully guice powered web stack. You can find it here: https://github.com/skuzzle/guice-jsf

Resources