View Javadoc

1   /*
2    *  soapUI, copyright (C) 2004-2010 eviware.com 
3    *
4    *  soapUI is free software; you can redistribute it and/or modify it under the 
5    *  terms of version 2.1 of the GNU Lesser General Public License as published by 
6    *  the Free Software Foundation.
7    *
8    *  soapUI is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without 
9    *  even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. 
10   *  See the GNU Lesser General Public License for more details at gnu.org.
11   */
12  
13  package com.eviware.soapui;
14  
15  import java.io.File;
16  import java.io.IOException;
17  import java.lang.reflect.Method;
18  import java.net.MalformedURLException;
19  import java.net.URL;
20  import java.net.URLClassLoader;
21  import java.util.ArrayList;
22  import java.util.HashMap;
23  import java.util.List;
24  import java.util.Map;
25  
26  /***
27   * ClassLoader that loads external jars
28   * 
29   * @author Ole
30   */
31  
32  public class SoapUIExtensionClassLoader extends URLClassLoader
33  {
34  	public SoapUIExtensionClassLoader( URL[] urls, ClassLoader parent )
35  	{
36  		super( urls, parent );
37  	}
38  
39  	@Override
40  	public void addURL( URL url )
41  	{
42  		super.addURL( url );
43  	}
44  
45  	public void addFile( File file ) throws MalformedURLException
46  	{
47  		addURL( file.toURI().toURL() );
48  	}
49  
50  	private static Map<ClassLoader, SoapUIClassLoaderState> clStates = new HashMap<ClassLoader, SoapUIClassLoaderState>();
51  
52  	public static SoapUIClassLoaderState ensure()
53  	{
54  		ClassLoader contextClassLoader = Thread.currentThread().getContextClassLoader();
55  		SoapUIClassLoaderState state = clStates.get( contextClassLoader );
56  
57  		if( state == null )
58  		{
59  			ClassLoader cl = contextClassLoader;
60  
61  			while( cl != null && !( cl instanceof SoapUIExtensionClassLoader ) )
62  			{
63  				cl = cl.getParent();
64  			}
65  
66  			state = new SoapUIClassLoaderState( cl == null ? contextClassLoader : null );
67  			clStates.put( contextClassLoader, state );
68  		}
69  
70  		return state.activate();
71  	}
72  
73  	public static class SoapUIClassLoaderState
74  	{
75  		private ClassLoader cl;
76  
77  		private SoapUIClassLoaderState( ClassLoader cl )
78  		{
79  			this.cl = cl;
80  		}
81  
82  		private SoapUIClassLoaderState activate()
83  		{
84  			if( cl != null && SoapUI.getSoapUICore() != null )
85  				Thread.currentThread().setContextClassLoader( SoapUI.getSoapUICore().getExtensionClassLoader() );
86  
87  			return this;
88  		}
89  
90  		public void restore()
91  		{
92  			if( cl != null )
93  				Thread.currentThread().setContextClassLoader( cl );
94  		}
95  	}
96  
97  	public static SoapUIExtensionClassLoader create( String root, ClassLoader parent ) throws MalformedURLException
98  	{
99  		String extDir = System.getProperty( "soapui.ext.libraries" );
100 
101 		File dir = extDir != null ? new File( extDir ) : new File( new File( root ), "ext" );
102 		List<URL> urls = new ArrayList<URL>();
103 
104 		if( dir.exists() && dir.isDirectory() )
105 		{
106 			File[] files = dir.listFiles();
107 			for( File file : files )
108 			{
109 				if( file.getName().toLowerCase().endsWith( ".jar" ) )
110 				{
111 					urls.add( file.toURI().toURL() );
112 					SoapUI.log.info( "Adding [" + file.getAbsolutePath() + "] to extensions classpath" );
113 				}
114 			}
115 		}
116 		else
117 		{
118 			SoapUI.log.warn( "Missing folder [" + dir.getAbsolutePath() + "] for external libraries" );
119 		}
120 
121 		return new SoapUIExtensionClassLoader( urls.toArray( new URL[urls.size()] ), parent );
122 	}
123 	
124 	/***
125 	 * method used for hermes classloading
126 	 * @param u
127 	 * @param classLoader
128 	 * @throws IOException
129 	 */
130 	public static void addUrlToClassLoader( URL u, ClassLoader classLoader ) throws IOException
131 	{
132 		try
133 		{
134 			Method method = classLoader.getClass().getDeclaredMethod( "addURL", new Class[] { java.net.URL.class } );
135 			method.setAccessible( true );
136 			method.invoke( classLoader, new Object[] { u } );
137 
138 			SoapUI.log.info( "Added [" + u.toString() + "] to classpath" );
139 		}
140 		catch( NoSuchMethodException e )
141 		{
142 			try
143 			{
144 				Method method = classLoader.getClass().getSuperclass().getDeclaredMethod( "addURL",
145 						new Class[] { java.net.URL.class } );
146 				method.setAccessible( true );
147 				method.invoke( classLoader, new Object[] { u } );
148 
149 				SoapUI.log.info( "Added [" + u.toString() + "] to classpath" );
150 			}
151 			catch( NoSuchMethodException ex )
152 			{
153 				try
154 				{
155 					Method method = classLoader.getClass().getSuperclass().getSuperclass().getDeclaredMethod( "addURL",
156 							new Class[] { java.net.URL.class } );
157 					method.setAccessible( true );
158 					method.invoke( classLoader, new Object[] { u } );
159 
160 					SoapUI.log.info( "Added [" + u.toString() + "] to classpath" );
161 				}
162 				catch( Throwable t )
163 				{
164 					try
165 					{
166 						if( classLoader.getParent() != null )
167 						{
168 							SoapUI.log.info( "Failed to add jar to " + classLoader.getClass().getName() + ", trying parent" );
169 							addUrlToClassLoader( u, classLoader.getParent() );
170 						}
171 						else
172 							throw new IOException( "Error, could not add URL to classloader "
173 									+ classLoader.getClass().getName() );
174 					}
175 					catch( IOException e3 )
176 					{
177 						SoapUI.logError( t );
178 						throw e3;
179 					}
180 				}// end try catch
181 			}
182 			catch( Throwable t )
183 			{
184 				SoapUI.logError( t );
185 				throw new IOException( "Error, could not add URL to system classloader " + classLoader.getClass().getName() );
186 			}// end try catch
187 		}
188 		catch( Throwable t )
189 		{
190 			SoapUI.logError( t );
191 			throw new IOException( "Error, could not add URL to system classloader " + classLoader.getClass().getName() );
192 		}// end try catch
193 	}
194 }