How to dynamically change Spring JdbcTemplate DataSource? - java

I have a config file with default settings for JDBC connection.
Is there any option to edit this default connection details once application is running? After all beans has been created (edit connection details in the controller).
Scenario:
user starts the application, and can edit connection details by going to
localhost:8080/myapp/db/edit
fills in connection details and saves new database details
This should then find existing connections, update connection details and reinstantiate beans.

You can try removing beans from Spring Container and re initiating them.
Demo demo = getBean(context);
ConfigurableListableBeanFactory configurableListableBeanFactory = context
.getBeanFactory();
BeanDefinitionRegistry beanDefinitionRegistry = (BeanDefinitionRegistry) configurableListableBeanFactory;
// Removing the bean from container
beanDefinitionRegistry.removeBeanDefinition("demo");
// Trying to obtains bean again from container. This will throw a null
demo = getBean(context);
//demo object will be null here
// Creating and registering bean to the container
BeanDefinition beanDefinition = new RootBeanDefinition(Demo.class);
beanDefinition.setAttribute("name", "name");
beanDefinitionRegistry.registerBeanDefinition("demo", beanDefinition);
context.refresh();
//Obtaining from container again
demo = getBean(context);

Related

spring load dynamically beans from xml which use property injection

I need to load bean definitions from XML. The file is in a remote location (http) which is configured by properties. The properties should also be loaded from a remote location (a spring cloud config server)
constraints:
Spring 4.3.14 (not boot)
should be in runtime and after my properties already loaded
beans defined in xml are referencing properties in context
server URI (to fetch the xml from) should be in properties and not environment variable or profile depandant
The current setup I have works well when MY_XML_URI is passed as environment variable:
${SPRING_CONFIG_URI}/master/application-${spring.profiles.active}.properties
<import resource="${MY_XML_URI}/myBeans.xml"/>
And in the remote location, myBeans.xml with lots of beans e.g.
<bean name="mySpecialBean" class="com.example.MyGenericBean">
<constructor-arg value="mySpecialBean"/>
<constructor-arg value="${special.bean.config.expression}"/>
</bean>
However trouble starts when I want to get MY_XML_URI from the properties context, it doesn't resolve
…
I have tried several approaches e.g:
java configuration class with #ImportResource({"${xml.server.uri}"})
but the properties are not loaded yet so it not converting to real value of xml.server.uri .
#Configuration
#ImportResource({"${xml.server.uri:http://localhost:8888}/myBeans.xml"})
public class MyConfiguration {}
expose dummy bean which fetch xml as resource and load the beans to parent applicationcontext - i must have it available to other beans dependant on those beans defined in xml. This solution was not injecting the properties context to my beans so failed to init them.
#Configuration
public class RiskConfig {
#Value("${xml.server.uri}")
private String xmlUri;
#Autowired
#Bean
public Object myBean(ApplicationContext applicationContext) {
Resource resource = applicationContext.getResource(xmlUri + "myBeans.xml");
// not working since its not loading the beans to the main context
// GenericApplicationContext genericApplicationContext = new GenericApplicationContext(applicationContext);
// XmlBeanDefinitionReader reader = new XmlBeanDefinitionReader(genericApplicationContext);
// reader.loadBeanDefinitions(resource);
AutowireCapableBeanFactory factory = applicationContext.getAutowireCapableBeanFactory();
BeanDefinitionRegistry registry = (BeanDefinitionRegistry) factory;
XmlBeanDefinitionReader reader = new XmlBeanDefinitionReader(registry);
reader.loadBeanDefinitions(resource);
return new Object();
}
}
Finally - is there a way to load the beans from xml programmatically to parent application context (which is already exist) though they are injected with properties.

C3p0 connection pooling Tomcat Apache concept

1) Difference between the constructors of InitialContext.
public InitialContext(Hashtable<?,?> environment)
what does this constructor do and what will environment parameter do .
2)
Hashtable<Object, String> environment= new Hashtable<Object, String> (2);
--
--
Context ctx = new InitialContext( environment);
ComboPooledDataSource comboPooledDataSource = new ComboPooledDataSource();
comboPooledDataSource.setJdbcUrl(----);
comboPooledDataSource.setDriverClass(----);
ctx.bind (__);
please explain each line what does it do..
3)Why to create combopooldatasource object ,instead we can create datasource object..??
Answer for 3rd question : Datasource can not be created for ordinary domains,its only for JNDI domains.
For 1st : InitialContext is used to set the environment to create the pooled datasource by creating .bindings file
For 2nd : Context sets the environment.
ComboPooledDataSource object is created.
For that object the url and jdbc driver class wll be set to take the connections from DB to the Pool.
Above set things will be binded to the context and it will be wriiten in .bindings file in encoded format

Dynamically select catalog for Tomcat mysql connection pool in a Spring application

I need to create a connection pool from a spring application running in a tomcat server.
This application has many catalogs, the main catalog (its is static) called 'db' has just one table with all existing catalog names and a boolean flag for the "active" one.
When the application starts I need to choose from the main catalogs the active one, then I have to select it as default catalog.
How can I accomplish this?
Until now I used a custom class DataSourceSelector extends DriverManagerDataSource but now I need to improve the db connection using a pool, then I thought about a tomcat dbcp pool.
I would suggest the following steps:
Extend BasicDataSourceFactory to produce customized BasicDataSources.
Those customized BasicDataSources would already know which catalog is active and have the defaultCatalog property set accordingly.
Use your extended BasicDataSourceFactory in the Tomcat configuration.
#Configuration
public class DataAccessConfiguration {
#Bean(destroyMethod = "close")
public javax.sql.DataSource dataSource() {
org.apache.tomcat.jdbc.pool.DataSource ds = new org.apache.tomcat.jdbc.pool.DataSource();
ds.setDriverClassName("com.mysql.jdbc.Driver");
ds.setUrl("jdbc:mysql://localhost/db");
ds.setUsername("javauser");
ds.setPassword("");
ds.setInitialSize(5);
ds.setMaxActive(10);
ds.setMaxIdle(5);
ds.setMinIdle(2);
ds.get
return ds;
}
}

ProgrammaticLogin

I use ProgrammaticLogin in Glassfish 3.1.2 with username,password and realm and it works good. Anyway when I call context.getCallerPrincipal() I get org.glassfish.security.common.PrincipalImpl with context.getCallerPrincipal().getName() which returns the username.
Is there any way that I can pass Principle via ProgrammaticLogin
so it is passed in my ejb and available from SessionContext - context.getCallerPrincipal()?
I guess you are in a context where resource-injection is not possible via annotations.
You can try to get an instance of the desired EJB via a manual JNDI lookup.
Example:
InitialContext init = new InitialContext();
YourBean bean = (YourBean) init.lookup(JNDI_NAME_OF_YOUR_BEAN);
Now you should be able to pass the Principal to your bean.

Where is the JNDI name in my code?

I have created a EJB2.0 using Eclipse 3.7 IDE, and deployed it in JBoss 5 application server (my bean name is product). I am doing normal context lookup (and other stuff to call ejb), and I am able to call EJB successfully. Now my question is what is JNDI name exactly, and where did it get used in all this. Is my bean name the JNDI name, or is this my JNDI name -> org.jnp.interfaces.NamingContextFactory. Where is the JNDI name in this?????
my code:-
// initial code.............
Context ctx = getContext();
Object obj=ctx.lookup("Product");
ProductHome home =(ProductHome) javax.rmi.PortableRemoteObject.narrow(obj,ProductHome.class);
ProductRemote remote=home.create();
Product prd = new rohit.Product("PRDCamera",001,50.50) ;
remote.addProduct(prd);
remote.updateProduct(prd);
remote.removeProduct(001);
remote.findProduct(001);
remote.findAllProduct();
// getContext Method
public static InitialContext getContext() throws Exception{
Properties pro = new Properties();
pro.put(javax.naming.InitialContext.INITIAL_CONTEXT_FACTORY,"org.jnp.interfaces.NamingContextFactory");
pro.put(javax.naming.InitialContext.PROVIDER_URL,"localhost:1099");
return new InitialContext(pro);
}
There is no JNDI name in your code.
This is how you look up EJBs in EJB 2.0:
Object ejbHome = initialContext.lookup("java:comp/env/com/mycorp/MyEJB");
MyHome myHome = (MyHome)javax.rmi.PortableRemoteObject.narrow(
(org.omg.CORBA.Object)ejbHome, MyHome.class);
The JNDI name is java:comp/env/com/mycorp/MyEJB in this case.
In the much saner EJB 3.0, you just do
MyEJB myEJB = initialContext.lookup("java:comp/env/com/mycorp/MyEJB")
and do away with the terrible home interface idea.

Categories