RmiProxyFactoryBean + Autowired(required=false) - java

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.

Related

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 explicitely close Spring context in a Spring web application?

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.

Different persistence.xml properies for test run / JPA Fixtures

I develop some Java EE/Spring web-app. I use JPA 2.0 - Hibernate. For integration tests I need to use different database. Those tests require Jetty to run application, but I managed to override web.xml for such run, there I can modify my Spring context files, it's ok.
But I need each time a clean database (and load some data into it).
As my database name and address are configured in sprig context I just switched them as I described above - but how can I change some of my persistence.xml properies for this tests only to have database drop and recreated?
I tried to make another persistence.xml in /src/test/resources/META-INF (and checked that test-classes are first in classpath) but it is not loaded and only the 'master' version is used (from /src/main/resources/META-INF). Any help?
With spring you usually define your data source as a spring bean. The database url and credentials are usually included form an external file, for example application.properties.
If you put a new applicaiton.properties in src/test/resources it will work. See also here.
You can define org.springframework.orm.jpa.persistenceunit.DefaultPersistenceUnitManager :
<bean id="pum" class="org.springframework.orm.jpa.persistenceunit.DefaultPersistenceUnitManager">
<property name="persistenceXmlLocations">
<list>
<value>/path/to/my/test-persistence.xml</value>
</list>
</property>
<property name="dataSources">
<map>
<entry key="dataSource" value-ref="dataSource"/>
</map>
</property>
<!-- if no datasource is specified, use this one -->
<property name="defaultDataSource" ref="dataSource"/>
</bean>
Then, link it to your entityManagerFactory :
<bean id="entityManagerFactory" class="org.springframework.orm.jpa.LocalContainerEntityManagerFactoryBean">
...
...
<property name="persistenceUnitManager" ref="pum"/>
</bean>
I used this to make my own persistence.xml linked to a HSQL in-memory db, preloaded with DBUnit (using hibernate.hbm2ddl.auto=create-drop).
It Works perfectly.

Transaction Manager don't assume the transaction

i'm facing a problem i really dunno how to catch the cat tail (if you hollow me the joke :o))
i have a webapp in war, deploy in tomcat. the war contains 4 Jars.
4 jars have 4 applicationContext, with 4 entityManager, and 4 TransactionManager.
declare like this (change the number 1..):
<bean id="entityManagerFactory1"
class="org.springframework.orm.jpa.LocalContainerEntityManagerFactoryBean"
p:dataSource-ref="dataSource1"
p:persistence-unit-name="com.xxxxxx.domain" >
<property name="jpaVendorAdapter">
<bean class="org.springframework.orm.jpa.vendor.HibernateJpaVendorAdapter"
p:databasePlatform="${ds1.dbdialect}" p:generate-ddl="false"
p:showSql="${ds1.showsql}" />
</property>
<property name="loadTimeWeaver">
<bean class="org.springframework.instrument.classloading.InstrumentationLoadTimeWeaver" />
</property>
</bean>
<bean id="transactionManager1" class="org.springframework.orm.jpa.JpaTransactionManager"
p:entityManagerFactory-ref="entityManagerFactory1">
depends-on="entityManagerFactory1" name="transactionManager1"/>
<tx:annotation-driven transaction-manager="transactionManager1" />
the context is load like this :
my problem i discover that when i'm using a BO of 3, the transaction is open with the datasource of 2.
moreover, if i do a persist i have the message :
AbstractSaveEventListener - delaying identity-insert due to no transaction in progress
BUT if i launch the jar 1 alone (for example), everything is working perfectly.
thanks a lot for your enlightement.
Let me guess:
in your servlet-context.xml, do you import the contexts? e.g.:
<import location="classpath:context1.xml" />
<import location="classpath:context2.xml" />
etc.
If you do, all bean definitions are copied from the imported context into the root context, which means that you have four different <tx:annotation-driven /> declarations, with different transaction managers. Probably the last one wins.
Possible solutions: Either use Qualifiers or use the XML style of transaction declaration.
What I'd do is probably to introduce a custom #Transactional annotation per context:
#Transactional("tx1")
#Inherited
#Retention(RetentionPolicy.RUNTIME)
#Target({ElementType.TYPE,ElementType.METHOD})
public #interface Transactional1 {}
Now annotate all methods in jar 1 with #Transactional1, in jar 2 with #Transactional2 etc. This mechanism is documented in the Section 10.5.6.3 Custom shortcut annotations

Categories

Resources