How to explicitely close Spring context in a Spring web application? - java

I have a Spring webapp running in Tomcat.
This app also needs to expose a service for remote access via RMI. I am using Spring's RmiServiceExporter to do this :
<bean class="org.springframework.remoting.rmi.RmiServiceExporter">
<property name="serviceName" value="${server.rmi.remoteServiceName}"/>
<property name="service" ref="remoteFacade"/>
<property name="serviceInterface" value="my.ServiceInterface"/>
<!-- defaults to 1099 -->
<property name="registryPort" value="${server.rmi.registryPort}"/>
</bean>
It works well, but when I shutdown Tomcat, it hangs and I have to kill it and then manually kill the Java process it has created for the RMI registry. It seems to be because I should explicitely close (i.e. call the close() method) on the context that created the RmiServiceExporter, in this case my application context (not the web context). (source : https://issues.springsource.org/browse/SPR-5601)
How to achieve this (call the close() method on the context when the application is being stopped) in a webapp, where the context is created by a ServletContextListener (org.springframework.web.context.ContextLoaderListener) ?
EDIT: My question was actually misleaded. The context is actually already being closed, and the RmiServiceExporter's destroy() method as well. The problem (tomcat unable to shutdown properly) seems to come from something else. May the users who spent time asnwering this question pardon my haste in posting it.

1)Add destroy method to your bean definition:
<bean class="org.springframework.remoting.rmi.RmiServiceExporter" destroy-method="destroy">
<property name="serviceName" value="${server.rmi.remoteServiceName}"/>
<property name="service" ref="remoteFacade"/>
<property name="serviceInterface" value="my.ServiceInterface"/>
<!-- defaults to 1099 -->
<property name="registryPort" value="${server.rmi.registryPort}"/>
</bean>
2)if you have link to context instance add shutdown hook
context.registerShutdownHook();

Try to start your application context by using ContextLoaderListener as described here. It should close the context automatically for you.

Related

Scope 'session' is not active for the current thread - multi-threading

I have a java-spring web application and I use some external libraries which I don't have access to.
At one of the flows, I create a new thread and use this external library. I get an exception:
Is there any possible way to overcome this exception?
Thanks!
Encountered the same problem as this, and came across with: https://bekce.github.io/replacing-session-scope-with-thread-scope-in-spring-framework/
"here is a problem with session scoped beans when your application also needs other integration points other than web servlets".
I then used the custom scope = "thread" from sping's SimpleThredScope.
In bean config, something like this:
<bean class="org.springframework.beans.factory.config.CustomScopeConfigurer">
<property name="scopes">
<map>
<entry key="thread">
<bean class="org.springframework.context.support.SimpleThreadScope"/>
</entry>
</map>
</property>
</bean>
<bean id="testA" class="com.concretepage.A" scope="thread" />

Getting IgniteCheckedException: Default Ignite instance has already been started exception when enabling Persistence on single Node

I am deploying an application where I need to maintain some data in Ignite cache. I used in memory Ignite cache. Here is the Ignite configuration I have used:
<property name="cacheConfiguration">
<list>
<bean
class="org.apache.ignite.configuration.CacheConfiguration">
<property name="name" value="IGNITE_DATA" />
<property name="cacheMode" value="PARTITIONED" />
<property name="atomicityMode" value="ATOMIC" />
<property name="writeSync"
value="PRIMARY_SYNC" />
<property name="backups"
value="${IGNITE_CACHE_BACKUPS}" />
</bean>
</list>
</property>
Now when I deployed multiple instances of my application and stored data in Ignite cache. Its shared among all the application instances.
Even if any any instance goes down and comes up after sometime it has the latest data via Ignite cache sync.
But issue occurs when all the application instances go down. When they come up data is gone since it was not persisted. For persistence I used dataStorageConfiguration property and enabled the persistence. Here is the change I added to Ignite configuration:
<property name="dataStorageConfiguration">
<bean
class="org.apache.ignite.configuration.DataStorageConfiguration">
<!-- Enabling Apache Ignite Persistent Store. -->
<property name="defaultDataRegionConfiguration">
<bean
class="org.apache.ignite.configuration.DataRegionConfiguration">
<property name="persistenceEnabled" value="true" />
</bean>
</property>
<!-- Changing Write Ahead Log Mode. -->
<property name="storagePath" value="${IGNITE_BC_STORE_PATH}"/>
<property name="walMode" value="LOG_ONLY" />
</bean>
</property>
Now when I deploy my application and I try and start Ignite from Java code as mentioned below:
log.info("Initializing IGNITE...");
ignite = Ignition.start(getClass().getResource(CONF_FILE));
I get an exception every time stating the default instance has already started.Tried several things but didn't work. Even if I remove the CacheConfiguration from Ignite Configuration and just keep dataStorageConfiguration I still getting the same error. Error is :
Caused by: class org.apache.ignite.IgniteCheckedException: Default Ignite instance has already been started.
at org.apache.ignite.internal.IgnitionEx.start0(IgnitionEx.java:1141)
at org.apache.ignite.internal.IgnitionEx.startConfigurations(IgnitionEx.java:1076)
at org.apache.ignite.internal.IgnitionEx.start(IgnitionEx.java:962)
at org.apache.ignite.internal.IgnitionEx.start(IgnitionEx.java:881)
at org.apache.ignite.Ignition.start(Ignition.java:373)
Normally this error comes when we try and run multiple Ignite nodes under same JVM but here I am running single node per JVM. Then also getting the error.
Please do correct me if I am wrong.
Any help here will be appreciated.
Most probably, you have more than one IgniteConfiguration bean in your config file. If one configuration bean extends another one, then make sure, that the parent is abstract.
I have resolved the issue. Seems like the issue was not woth the Ignite configuration but was with Spring Framework configuration.
I was creating the bean for the Ignite class using the lazy-init=true. I switched that to the eager-init and that resolved my issue.
Not sure how exactly it solved this but it worked at least in my case.

Switch LDAP connection at runtime in Spring

I am new to spring. Admins of my spring based web app want to configure settings from the web interface, so users can authenticate against LDAP server with their company username and password.
Change in LDAP settings should be possible without restarting the application. This might happen during a 'migration' or whatever reason. I have a couple beans, which need to be refreshed after the admin saves new settings for the LDAP server:
<bean id="ldapServer" class="org.springframework.security.ldap.DefaultSpringSecurityContextSource">
<constructor-arg>
<list>
<value>${ldap.url1}</value>
...
</list>
</constructor-arg>
<constructor-arg value="${ldap.basedn}"</constructor-arg>
<property name="referral" value="${ldap.referral}" />
<property name="baseEnvironmentProperties">...</property>
<property name="userDn" value="${ldap.username}" />
<property name="password" value="${ldap.password}" />
</bean>
I am using Springframework 3.1.2. The problem is, there are constructor arguments, which I want to change and not affect other running jobs. I tried playing with Scoped proxy, but not to much success yet:
<bean id="ldapServer" scope="prototype" ...>
<aop:scoped-proxy/>
I was successful though to get ldapServer to reinstantiate, when using prototype scope by running this piece of code:
#Controller
public class LDAPSettingsController implements ApplicationContextAware {
public ModelAndView handleRequest(...) {
DefaultSpringSecurityContextSource ldap;
ldap = context.getParentBeanFactor().getBean("ldapServer");
System.out.println(ldap.hashCode());
return new ModelAndView(new RedirectView('login.jsp'));
}
...
}
Are scopes and proxies here the way to go, or is the another mechanism in Spring to reflect configuration changes into a running program instance?
UPDATE: Clear up the question.
UPDATE: The root problem with the AOP proxies was following root exception:
java.lang.IllegalArgumentException: Superclass has no null constructors but no arguments were given
What worked was adding proxy-target-class="false" attribute to the <aop:scoped-proxy/> tag. I created a new scope, which works better than prototype - It destroys beans on settings update. Now I have this in my beans.xml:
<bean class="org.springframework.beans.factory.config.CustomScopeConfigurer">
<property name="scopes">
<map>
<entry key="ldap">
<ref bean="ldapScope" />
</entry>
</map>
</property>
</bean>
<bean id="ldapScope" class="com.myapp.SettingsScope" />
<bean id="ldapServer" scope="ldap" ...>
<aop:scoped-proxy proxy-target-class="false"/>
<constructor-args>
<list><value>${ldap.url1}</value> .. </list>
</constructor-args>
...
</bean>
I also have a controller for LDAP settings into which I inject ldapScope and I call a method which destroys current life-cycle objects and starts a new life-cycle every time, user presses the apply button.
PS: Not sure if I handle the life-cycle "re-start" in the right way - people my way to look for auto-start beans and start them after such event happens (i.e.: Setting -> Apply)

How to configure Connection Pool for Java Web Project?

I've been doing a research on connection pool with JDBC api and classes. But still I don't know how to configure a Connection Pool class for a java web project. As you may know, the Connection Pool is a Singleton Class that encapsulates the JDBC apis. But the Connection Class is started once when the web project is deployed on Tomcat Server, I wonder if there's something needed to be done with Web.xml configuration file, to let Tomcat Server load the Connection Pool Class.
Thank you very much for your time!
There a many ways of doing this. JNDI is one way - but it is not so "user friendly" in tomcat. The datasource also can be configured in Spring. For e.g.:
<bean id="dataSource"
class="org.springframework.jdbc.datasource.DriverManagerDataSource">
<property name="driverClassName" value="${jdbc.driverClassName}"/>
<property name="url" value="${jdbc.url}"/>
<property name="username" value="${jdbc.username}"/>
<property name="password" value="${jdbc.password}"/>
</bean>
The most simplest way of doing this is to create a ServletContextListener class, create your datasource and put it into ServletContext so that the same instance could be retrieved from ServletContext in your project.
See my answer here how to create ServletContextListener.
See also:
How to use JNDI DataSource provided by Tomcat in Spring?

RmiProxyFactoryBean + Autowired(required=false)

I have 5 projects - 4 of which are run on the console (say A,B,C and D) with java -jar A.jar etc and 1 web application (E). The web application is deployed on a number of isolated servers some of which also have a combination of A, B, C and D running.
In the spring config file for the web application I have 4 RmiProxyFactoryBean declarations, one for each of the projects A, B, C and D where each of these projects have 1 RmiServiceExporter.
My problem is that the web application throws an exception on startup if one of the projects (A-D) is not running. I've tried using #Autowired(required=false) in the controllers using these services to no avail. To make it work I'm having to go edit the web app spring file to comment out the RmiProxyFactoryBean for projects that aren't running. Is there a way of telling an RmiProxyFactoryBean to attempt to retrieve the bean and if it fails then don't worry - in much a similar way as required=false with the autowire?
My config currently looks like this:
<bean class="org.springframework.remoting.rmi.RmiServiceExporter">
<property name="service" ref="diagramAssociationService" />
<property name="serviceName" value="diagramAssociationService"/>
<property name="serviceInterface" value="com.act.xv.service.IDiagramAssociationService"/>
</bean>
and
<bean id="diagramAssociationService" class="org.springframework.remoting.rmi.RmiProxyFactoryBean">
<property name="serviceUrl" value="rmi://${xv.deploy.location}/diagramAssociationService"/>
<property name="serviceInterface" value="com.act.xv.service.IDiagramAssociationService"/>
<property name="refreshStubOnConnectFailure" value="true" />
</bean>
In your RmiProxyFactoryBean also set the lookupStubOnStartup property to "false". This should prevent the client proxy from throwing an exception on startup.

Categories

Resources