Announcement Announcement Module
Collapse
No announcement yet.
Multiple appliation contexts in Web application Page Title Module
Move Remove Collapse
X
Conversation Detail Module
Collapse
  • Filter
  • Time
  • Show
Clear All
new posts

  • Multiple appliation contexts in Web application

    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.

    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 PluginConfig is a simple bean hosting the context configuratio file name for the given plugin and list of paths to jars.

    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>
    Code:
    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;
    	}
    The PluginLoader creates the loads each plugin into its application context
    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);
    	}
    }
    For the sake of brevity I had shown two plugins but I have three. The third plugin context definition it the problematic one:

    Code:
        <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>
    
        ...
    When Tomcat starts I'm getting the following error

    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
    None of the placeholders are resolved. The two other contexts load fine and outside of the Tomcat environment all works perfectly well.

    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

  • #2
    i doubt this is right way to define absolute path to the properties file:
    Code:
     <value>file:c:/config/three-plugin.properties</value>
    My suggestion is to try using class path instead of absolute path to make sure above is not a problem, and then start from there.

    Comment

    Working...
    X