Hello,
I have a web application using the Stripes framework, Spring 3.1 and and Axis2 web service client. I need to integrate into it several web service clients, each of which uses different SOAP frameworks - Axis 1.4, Axis2 1.6, Axis CXF.
Trying straightforward approach injection these clients did not work because of jar conflicts, so I decided to load each web service client using using its own application context.
The PluginConfig is a simple bean hosting the context configuratio file name for the given plugin and list of paths to jars.Code:<util:list id="oneClasspath"> <value>webapps/SSP/WEB-INF/lib/clientOne.jar/</value> <value>webapps/SSP/WEB-INF/lib/axis.jar</value> <value>webapps/SSP/WEB-INF/lib/org.springframework.asm-3.1.0.RELEASE.jar</value> ... </util:list> <util:list id="twoClasspath"> <value>webapps/SSP/WEB-INF/lib/clientTwo.jar/</value> <value>webapps/SSP/WEB-INF/lib/cxf-2.5.2.jar</value> <value>webapps/SSP/WEB-INF/lib/org.springframework.asm-3.1.0.RELEASE.jar</value> ... </util:list> <bean id="onePluginConfig" class="com.rsa.pso.selfservice.plugins.PluginConfig"> <property name="pluginConfigXml" value="${config.path}/one-context.xml"/> <property name="classpath" ref="oneClasspath"/> </bean> <bean id="twoPluginConfig" class="com.abc.plugins.PluginConfig"> <property name="pluginConfigXml" value="${config.path}/two-context.xml"/> <property name="classpath" ref="twoClasspath"/> </bean> <util:list id="pluginConfigs"> <ref bean="onePluginConfig"/> <ref bean="twoPluginConfig"/> </util:list> <bean id="pluginLoader" class="com.abc.plugins.PluginLoader"> <property name="pluginConfigs" ref="pluginConfigs"/> </bean>
The PluginFactory creates the parent application context for the plugin appliation contexts and is defined in the top
spring-context.xml:
Code:<bean id="pluginFactory" class="com.abc.plugins.PluginFactory"> <property name="configXml"><value>${plugin.manager.config}</value></property> </bean>The PluginLoader creates the loads each plugin into its application contextCode:public class PluginFactory implements ApplicationContextAware { private FileSystemXmlApplicationContext context; private ApplicationContext parentContext; private String configXml; private PluginLoader pluginLoader; public void initialise() { context = new FileSystemXmlApplicationContext(new String[]{configXml}, parentContext); context.refresh(); for (String name: context.getBeanDefinitionNames()) { System.out.println("--- " + name); } pluginLoader = context.getBean(PluginLoader.class); } public Plugin getPlugin(String beanName, Class beanClass) { Object o = pluginLoader.gePlugin(beanName, beanClass); return (Plugin) o; }
For the sake of brevity I had shown two plugins but I have three. The third plugin context definition it the problematic one:Code:public class PluginLoader implements ApplicationContextAware { private ApplicationContext parentContext; private List<AbstractRefreshableApplicationContext> pluginContexts; private List<PluginConfig> pluginConfigs; private boolean initialised = false; public List<PluginConfig> getPluginConfigs() { return pluginConfigs; } public void setPluginConfigs(List<PluginConfig> pluginConfigs) { this.pluginConfigs = pluginConfigs; } @Override public void setApplicationContext(ApplicationContext parentContext) throws BeansException { this.parentContext = parentContext; } private void initialise() { pluginContexts = new ArrayList<AbstractRefreshableApplicationContext>(); for (PluginConfig pc : pluginConfigs) { ClassLoader classloader = createClassloader(pc.getClasspath()); FileSystemXmlApplicationContext context = new FileSystemXmlApplicationContext(); context.setClassLoader(classloader); context.setParent(parentContext); context.setConfigLocation(pc.getPluginConfigXml()); context.refresh(); pluginContexts.add(context); } initialised = true; } public Object getPlugin(Class beanClass) { if (!initialised) { initialise(); } for (AbstractRefreshableApplicationContext ctx: pluginContexts) { if (ctx.getBeanNamesForType(beanClass).length > 0) { return ctx.getBean(beanClass); } } return null; } private URLClassLoader createClassloader(List<String> pathelements) { URL[] urls = new URL[pathelements.size()]; for (int i = 0; i < urls.length; i++) { try { File f = new File(pathelements.get(i)); urls[i] = f.toURI().toURL(); } catch (MalformedURLException e) { e.printStackTrace(); } } return new URLClassLoader(urls); } }
When Tomcat starts I'm getting the following errorCode:<bean id="threeProperties" class="org.springframework.beans.factory.config.PropertyPlaceholderConfigurer"> <property name="location"> <value>file:c:/config/three-plugin.properties</value> </property> </bean> <bean id="threeServiceUrl" class="java.net.URL"> <constructor-arg type="java.lang.String"><value>${three.service.url}</value></constructor-arg> </bean> ...
None of the placeholders are resolved. The two other contexts load fine and outside of the Tomcat environment all works perfectly well.Code:Caused by: org.springframework.beans.BeanInstantiationException: Could not instantiate bean class [java.net.URL]: Constructor threw exception; nested exception is java.net.MalformedURLException: no protocol: ${three.service.url} at org.springframework.beans.BeanUtils.instantiateClass(BeanUtils.java:162) at org.springframework.beans.factory.support.SimpleInstantiationStrategy.instantiate(SimpleInstantiationStrategy.java:108) at org.springframework.beans.factory.support.ConstructorResolver.autowireConstructor(ConstructorResolver.java:280) ... 60 more Caused by: java.net.MalformedURLException: no protocol: ${three.service.url} at java.net.URL.<init>(Unknown Source) at java.net.URL.<init>(Unknown Source) at java.net.URL.<init>(Unknown Source) at sun.reflect.NativeConstructorAccessorImpl.newInstance0(Native Method) at sun.reflect.NativeConstructorAccessorImpl.newInstance(Unknown Source) at sun.reflect.DelegatingConstructorAccessorImpl.newInstance(Unknown Source) at java.lang.reflect.Constructor.newInstance(Unknown Source) at org.springframework.beans.BeanUtils.instantiateClass(BeanUtils.java:147) ... 62 more
Any advice on what be causing this error would be most welcome, as well as to the approach I've taken. Is there a better way of avoiding the plugins stepping on each other inside Tomcat?
TIA
-aaron


Reply With Quote