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.FileInputStream;
17  import java.io.FileOutputStream;
18  import java.io.IOException;
19  import java.io.UnsupportedEncodingException;
20  import java.net.MalformedURLException;
21  import java.net.URL;
22  import java.security.GeneralSecurityException;
23  import java.util.TimerTask;
24  
25  import javax.swing.JLabel;
26  import javax.swing.JOptionPane;
27  import javax.swing.JPasswordField;
28  
29  import org.apache.commons.ssl.OpenSSL;
30  import org.apache.log4j.Logger;
31  import org.apache.log4j.xml.DOMConfigurator;
32  
33  import com.eviware.soapui.config.SoapuiSettingsDocumentConfig;
34  import com.eviware.soapui.impl.settings.XmlBeansSettingsImpl;
35  import com.eviware.soapui.impl.wsdl.support.http.HttpClientSupport;
36  import com.eviware.soapui.impl.wsdl.support.soap.SoapVersion;
37  import com.eviware.soapui.model.settings.Settings;
38  import com.eviware.soapui.monitor.JettyMockEngine;
39  import com.eviware.soapui.monitor.MockEngine;
40  import com.eviware.soapui.settings.HttpSettings;
41  import com.eviware.soapui.settings.ProxySettings;
42  import com.eviware.soapui.settings.SecuritySettings;
43  import com.eviware.soapui.settings.UISettings;
44  import com.eviware.soapui.settings.WSISettings;
45  import com.eviware.soapui.settings.WebRecordingSettings;
46  import com.eviware.soapui.settings.WsaSettings;
47  import com.eviware.soapui.settings.WsdlSettings;
48  import com.eviware.soapui.support.StringUtils;
49  import com.eviware.soapui.support.action.SoapUIActionRegistry;
50  import com.eviware.soapui.support.listener.SoapUIListenerRegistry;
51  import com.eviware.soapui.support.types.StringList;
52  
53  /***
54   * Initializes core objects. Transform to a Spring "ApplicationContext"?
55   * 
56   * @author ole.matzura
57   */
58  
59  public class DefaultSoapUICore implements SoapUICore
60  {
61  	public static Logger log;
62  
63  	private boolean logIsInitialized;
64  	private String root;
65  	protected SoapuiSettingsDocumentConfig settingsDocument;
66  	private MockEngine mockEngine;
67  	private XmlBeansSettingsImpl settings;
68  	private SoapUIListenerRegistry listenerRegistry;
69  	private SoapUIActionRegistry actionRegistry;
70  	private long lastSettingsLoad = 0;
71  
72  	private String settingsFile;
73  	private String password;
74  	protected boolean initialImport;
75  	private TimerTask settingsWatcher;
76  	private SoapUIExtensionClassLoader extClassLoader;
77  
78  	public boolean isSavingSettings;
79  
80  	public boolean getInitialImport()
81  	{
82  		return initialImport;
83  	}
84  
85  	public void setInitialImport( boolean initialImport )
86  	{
87  		this.initialImport = initialImport;
88  	}
89  
90  	public static DefaultSoapUICore createDefault()
91  	{
92  		return new DefaultSoapUICore( null, DEFAULT_SETTINGS_FILE );
93  	}
94  
95  	public DefaultSoapUICore()
96  	{
97  	}
98  
99  	/*
100 	 * this method is added for enabling settings password (like in core) all the
101 	 * way down in hierarchy boolean setingPassword is a dummy parameter, because
102 	 * the constructor with only one string parameter already existed
103 	 */
104 	public DefaultSoapUICore( boolean settingPassword, String soapUISettingsPassword )
105 	{
106 		this.password = soapUISettingsPassword;
107 	}
108 
109 	public DefaultSoapUICore( String root )
110 	{
111 		this.root = root;
112 	}
113 
114 	public DefaultSoapUICore( String root, String settingsFile )
115 	{
116 		this( root );
117 		init( settingsFile );
118 	}
119 
120 	public DefaultSoapUICore( String root, String settingsFile, String password )
121 	{
122 		this( root );
123 		this.password = password;
124 		init( settingsFile );
125 	}
126 
127 	public void init( String settingsFile )
128 	{
129 		initLog();
130 
131 		SoapUI.setSoapUICore( this );
132 
133 		loadExternalLibraries();
134 		initSettings( settingsFile == null ? DEFAULT_SETTINGS_FILE : settingsFile );
135 
136 		initCoreComponents();
137 		initExtensions( getExtensionClassLoader() );
138 
139 		SoapVersion.Soap11.equals( SoapVersion.Soap12 );
140 
141 	}
142 
143 	protected void initExtensions( ClassLoader extensionClassLoader )
144 	{
145 		String extDir = System.getProperty( "soapui.ext.listeners" );
146 		addExternalListeners( extDir != null ? extDir : root == null ? "listeners" : root + File.separatorChar
147 				+ "listeners", extensionClassLoader );
148 	}
149 
150 	protected void initCoreComponents()
151 	{
152 	}
153 
154 	public String getRoot()
155 	{
156 		if( root == null || root.length() == 0 )
157 			root = System.getProperty( "soapui.home", new File( "." ).getAbsolutePath() );
158 		return root;
159 	}
160 
161 	protected Settings initSettings( String fileName )
162 	{
163 		// TODO Why try to load settings from current directory before using root?
164 		// This caused a bug in Eclipse:
165 		// https://sourceforge.net/tracker/?func=detail&atid=737763&aid=2620284&group_id=136013
166 		File settingsFile = new File( fileName ).exists() ? new File( fileName ) : null;
167 
168 		try
169 		{
170 			if( settingsFile == null )
171 			{
172 				settingsFile = new File( new File( getRoot() ), DEFAULT_SETTINGS_FILE );
173 				if( !settingsFile.exists() )
174 				{
175 					settingsFile = new File( new File( System.getProperty( "user.home", "." ) ), DEFAULT_SETTINGS_FILE );
176 					lastSettingsLoad = 0;
177 				}
178 			}
179 			else
180 			{
181 				settingsFile = new File( fileName );
182 				if( !settingsFile.getAbsolutePath().equals( this.settingsFile ) )
183 					lastSettingsLoad = 0;
184 			}
185 
186 			if( !settingsFile.exists() )
187 			{
188 				if( settingsDocument == null )
189 				{
190 					log.info( "Creating new settings at [" + settingsFile.getAbsolutePath() + "]" );
191 					settingsDocument = SoapuiSettingsDocumentConfig.Factory.newInstance();
192 					setInitialImport( true );
193 				}
194 
195 				lastSettingsLoad = System.currentTimeMillis();
196 			}
197 			else if( settingsFile.lastModified() > lastSettingsLoad )
198 			{
199 				settingsDocument = SoapuiSettingsDocumentConfig.Factory.parse( settingsFile );
200 
201 				byte[] encryptedContent = settingsDocument.getSoapuiSettings().getEncryptedContent();
202 				if( encryptedContent != null )
203 				{
204 					char[] password = null;
205 					if( this.password == null )
206 					{
207 						// swing element -!! uh!
208 						JPasswordField passwordField = new JPasswordField();
209 						JLabel qLabel = new JLabel( "Password" );
210 						JOptionPane.showConfirmDialog( null, new Object[] { qLabel, passwordField }, "Global Settings",
211 								JOptionPane.OK_CANCEL_OPTION );
212 						password = passwordField.getPassword();
213 					}
214 					else
215 					{
216 						password = this.password.toCharArray();
217 					}
218 
219 					byte[] data = OpenSSL.decrypt( "des3", password, encryptedContent );
220 					try
221 					{
222 						settingsDocument = SoapuiSettingsDocumentConfig.Factory.parse( new String( data, "UTF-8" ) );
223 					}
224 					catch( Exception e )
225 					{
226 						log.warn( "Wrong password." );
227 						JOptionPane.showMessageDialog( null, "Wrong password, creating backup settings file [ "
228 								+ settingsFile.getAbsolutePath() + ".bak.xml. ]\nSwitch to default settings.",
229 								"Error - Wrong Password", JOptionPane.ERROR_MESSAGE );
230 						settingsDocument.save( new File( settingsFile.getAbsolutePath() + ".bak.xml" ) );
231 						throw e;
232 					}
233 				}
234 
235 				log.info( "initialized soapui-settings from [" + settingsFile.getAbsolutePath() + "]" );
236 				lastSettingsLoad = settingsFile.lastModified();
237 
238 				if( settingsWatcher == null )
239 				{
240 					settingsWatcher = new SettingsWatcher();
241 					SoapUI.getSoapUITimer().scheduleAtFixedRate( settingsWatcher, 10000, 10000 );
242 				}
243 			}
244 		}
245 		catch( Exception e )
246 		{
247 			log.warn( "Failed to load settings from [" + e.getMessage() + "], creating new" );
248 			settingsDocument = SoapuiSettingsDocumentConfig.Factory.newInstance();
249 			lastSettingsLoad = 0;
250 		}
251 
252 		if( settingsDocument.getSoapuiSettings() == null )
253 		{
254 			settingsDocument.addNewSoapuiSettings();
255 			settings = new XmlBeansSettingsImpl( null, null, settingsDocument.getSoapuiSettings() );
256 
257 			initDefaultSettings( settings );
258 		}
259 		else
260 		{
261 			settings = new XmlBeansSettingsImpl( null, null, settingsDocument.getSoapuiSettings() );
262 		}
263 
264 		this.settingsFile = settingsFile.getAbsolutePath();
265 
266 		if( !settings.isSet( WsdlSettings.EXCLUDED_TYPES ) )
267 		{
268 			StringList list = new StringList();
269 			list.add( "schema@http://www.w3.org/2001/XMLSchema" );
270 			settings.setString( WsdlSettings.EXCLUDED_TYPES, list.toXml() );
271 		}
272 
273 		if( !settings.isSet( WebRecordingSettings.EXCLUDED_HEADERS ) )
274 		{
275 			StringList list = new StringList();
276 			list.add( "Cookie" );
277 			list.add( "Set-Cookie" );
278 			list.add( "Referer" );
279 			list.add( "Keep-Alive" );
280 			list.add( "Connection" );
281 			list.add( "Proxy-Connection" );
282 			list.add( "Pragma" );
283 			list.add( "Cache-Control" );
284 			list.add( "Transfer-Encoding" );
285 			list.add( "Date" );
286 			settings.setString( WebRecordingSettings.EXCLUDED_HEADERS, list.toXml() );
287 		}
288 
289 		if( settings.getString( HttpSettings.HTTP_VERSION, HttpSettings.HTTP_VERSION_1_1 ).equals(
290 				HttpSettings.HTTP_VERSION_0_9 ) )
291 		{
292 			settings.setString( HttpSettings.HTTP_VERSION, HttpSettings.HTTP_VERSION_1_1 );
293 		}
294 
295 		setIfNotSet( WsdlSettings.NAME_WITH_BINDING, true );
296 		setIfNotSet( WsdlSettings.NAME_WITH_BINDING, 500 );
297 		setIfNotSet( HttpSettings.HTTP_VERSION, HttpSettings.HTTP_VERSION_1_1 );
298 		setIfNotSet( HttpSettings.MAX_TOTAL_CONNECTIONS, 2000 );
299 		setIfNotSet( HttpSettings.RESPONSE_COMPRESSION, true );
300 		setIfNotSet( HttpSettings.LEAVE_MOCKENGINE, true );
301 		setIfNotSet( UISettings.AUTO_SAVE_PROJECTS_ON_EXIT, true );
302 		setIfNotSet( UISettings.SHOW_DESCRIPTIONS, true );
303 		setIfNotSet( WsdlSettings.XML_GENERATION_ALWAYS_INCLUDE_OPTIONAL_ELEMENTS, true );
304 		setIfNotSet( WsaSettings.USE_DEFAULT_RELATES_TO, true );
305 		setIfNotSet( WsaSettings.USE_DEFAULT_RELATIONSHIP_TYPE, true );
306 		setIfNotSet( UISettings.SHOW_STARTUP_PAGE, true );
307 		setIfNotSet( UISettings.GC_INTERVAL, "60" );
308 		setIfNotSet( WsdlSettings.CACHE_WSDLS, true );
309 		setIfNotSet( WsdlSettings.PRETTY_PRINT_RESPONSE_MESSAGES, true );
310 		setIfNotSet( HttpSettings.RESPONSE_COMPRESSION, true );
311 		setIfNotSet( HttpSettings.INCLUDE_REQUEST_IN_TIME_TAKEN, true );
312 		setIfNotSet( HttpSettings.INCLUDE_RESPONSE_IN_TIME_TAKEN, true );
313 		setIfNotSet( HttpSettings.LEAVE_MOCKENGINE, true );
314 		setIfNotSet( UISettings.AUTO_SAVE_INTERVAL, "0" );
315 		setIfNotSet( UISettings.GC_INTERVAL, "60" );
316 		setIfNotSet( UISettings.SHOW_STARTUP_PAGE, true );
317 		setIfNotSet( WsaSettings.SOAP_ACTION_OVERRIDES_WSA_ACTION, false );
318 		setIfNotSet( WsaSettings.USE_DEFAULT_RELATIONSHIP_TYPE, true );
319 		setIfNotSet( WsaSettings.USE_DEFAULT_RELATES_TO, true );
320 		setIfNotSet( WsaSettings.OVERRIDE_EXISTING_HEADERS, false );
321 		setIfNotSet( WsaSettings.ENABLE_FOR_OPTIONAL, false );
322 
323 		boolean setWsiDir = false;
324 		String wsiLocationString = settings.getString( WSISettings.WSI_LOCATION, null );
325 		if( StringUtils.isNullOrEmpty( wsiLocationString ) )
326 		{
327 			setWsiDir = true;
328 		}
329 		else
330 		{
331 			File wsiFile = new File( wsiLocationString );
332 			if( !wsiFile.exists() )
333 			{
334 				setWsiDir = true;
335 			}
336 		}
337 		if( setWsiDir )
338 		{
339 			String wsiDir = System.getProperty( "wsi.dir", new File( "." ).getAbsolutePath() );
340 			settings.setString( WSISettings.WSI_LOCATION, wsiDir );
341 		}
342 		HttpClientSupport.addSSLListener( settings );
343 
344 		return settings;
345 	}
346 
347 	private void setIfNotSet( String id, boolean value )
348 	{
349 		if( !settings.isSet( id ) )
350 			settings.setBoolean( id, true );
351 	}
352 
353 	private void setIfNotSet( String id, String value )
354 	{
355 		if( !settings.isSet( id ) )
356 			settings.setString( id, value );
357 	}
358 
359 	private void setIfNotSet( String id, long value )
360 	{
361 		if( !settings.isSet( id ) )
362 			settings.setLong( id, value );
363 	}
364 
365 	/*
366 	 * (non-Javadoc)
367 	 * 
368 	 * @see com.eviware.soapui.SoapUICore#importSettings(java.io.File)
369 	 */
370 	public Settings importSettings( File file ) throws Exception
371 	{
372 		if( file != null )
373 		{
374 			log.info( "Importing preferences from [" + file.getAbsolutePath() + "]" );
375 			return initSettings( file.getAbsolutePath() );
376 		}
377 		return null;
378 	}
379 
380 	/*
381 	 * (non-Javadoc)
382 	 * 
383 	 * @see com.eviware.soapui.SoapUICore#getSettings()
384 	 */
385 	public Settings getSettings()
386 	{
387 		if( settings == null )
388 		{
389 			initSettings( DEFAULT_SETTINGS_FILE );
390 		}
391 
392 		return settings;
393 	}
394 
395 	protected void initDefaultSettings( Settings settings2 )
396 	{
397 
398 	}
399 
400 	/*
401 	 * (non-Javadoc)
402 	 * 
403 	 * @see com.eviware.soapui.SoapUICore#saveSettings()
404 	 */
405 	public String saveSettings() throws Exception
406 	{
407 		isSavingSettings = true;
408 		try
409 		{
410 			if( settingsFile == null )
411 				settingsFile = getRoot() + File.separatorChar + DEFAULT_SETTINGS_FILE;
412 
413 			// Save settings to root or user.home
414 			File file = new File( settingsFile );
415 			if( !file.canWrite() )
416 			{
417 				file = new File( new File( System.getProperty( "user.home", "." ) ), DEFAULT_SETTINGS_FILE );
418 			}
419 
420 			SoapuiSettingsDocumentConfig settingsDocument = ( SoapuiSettingsDocumentConfig )this.settingsDocument.copy();
421 			String password = settings.getString( SecuritySettings.SHADOW_PASSWORD, null );
422 
423 			if( password != null && password.length() > 0 )
424 			{
425 				try
426 				{
427 					byte[] data = settingsDocument.xmlText().getBytes();
428 					byte[] encryptedData = OpenSSL.encrypt( "des3", password.toCharArray(), data );
429 					settingsDocument.setSoapuiSettings( null );
430 					settingsDocument.getSoapuiSettings().setEncryptedContent( encryptedData );
431 				}
432 				catch( UnsupportedEncodingException e )
433 				{
434 					log.error( "Encryption error", e );
435 				}
436 				catch( IOException e )
437 				{
438 					log.error( "Encryption error", e );
439 				}
440 				catch( GeneralSecurityException e )
441 				{
442 					log.error( "Encryption error", e );
443 				}
444 			}
445 
446 			FileOutputStream out = new FileOutputStream( file );
447 			settingsDocument.save( out );
448 			out.flush();
449 			out.close();
450 			log.info( "Settings saved to [" + file.getAbsolutePath() + "]" );
451 			lastSettingsLoad = file.lastModified();
452 			return file.getAbsolutePath();
453 		}
454 		finally
455 		{
456 			isSavingSettings = false;
457 		}
458 	}
459 
460 	public String getSettingsFile()
461 	{
462 		return settingsFile;
463 	}
464 
465 	public void setSettingsFile( String settingsFile )
466 	{
467 		this.settingsFile = settingsFile;
468 	}
469 
470 	protected void initLog()
471 	{
472 		if( !logIsInitialized )
473 		{
474 			File log4jconfig = root == null ? new File( "soapui-log4j.xml" ) : new File( new File( getRoot() ),
475 					"soapui-log4j.xml" );
476 			if( log4jconfig.exists() )
477 			{
478 				System.out.println( "Configuring log4j from [" + log4jconfig.getAbsolutePath() + "]" );
479 				DOMConfigurator.configureAndWatch( log4jconfig.getAbsolutePath(), 5000 );
480 			}
481 			else
482 			{
483 				URL url = SoapUI.class.getResource( "/com/eviware/soapui/resources/conf/soapui-log4j.xml" );
484 				if( url != null )
485 				{
486 					DOMConfigurator.configure( url );
487 				}
488 				else
489 					System.err.println( "Missing soapui-log4j.xml configuration" );
490 			}
491 
492 			logIsInitialized = true;
493 
494 			log = Logger.getLogger( DefaultSoapUICore.class );
495 		}
496 	}
497 
498 	public synchronized void loadExternalLibraries()
499 	{
500 		if( extClassLoader == null )
501 		{
502 			try
503 			{
504 				extClassLoader = SoapUIExtensionClassLoader.create( getRoot(), getExtensionClassLoaderParent() );
505 			}
506 			catch( MalformedURLException e )
507 			{
508 				SoapUI.logError( e );
509 			}
510 		}
511 	}
512 
513 	protected ClassLoader getExtensionClassLoaderParent()
514 	{
515 		return SoapUI.class.getClassLoader();
516 	}
517 
518 	public SoapUIExtensionClassLoader getExtensionClassLoader()
519 	{
520 		if( extClassLoader == null )
521 			loadExternalLibraries();
522 
523 		return extClassLoader;
524 	}
525 
526 	/*
527 	 * (non-Javadoc)
528 	 * 
529 	 * @see com.eviware.soapui.SoapUICore#getMockEngine()
530 	 */
531 	public MockEngine getMockEngine()
532 	{
533 		if( mockEngine == null )
534 			mockEngine = buildMockEngine();
535 
536 		return mockEngine;
537 	}
538 
539 	protected MockEngine buildMockEngine()
540 	{
541 		return new JettyMockEngine();
542 	}
543 
544 	/*
545 	 * (non-Javadoc)
546 	 * 
547 	 * @see com.eviware.soapui.SoapUICore#getListenerRegistry()
548 	 */
549 	public SoapUIListenerRegistry getListenerRegistry()
550 	{
551 		if( listenerRegistry == null )
552 			initListenerRegistry();
553 
554 		return listenerRegistry;
555 	}
556 
557 	protected void initListenerRegistry()
558 	{
559 		listenerRegistry = new SoapUIListenerRegistry( null );
560 	}
561 
562 	/*
563 	 * (non-Javadoc)
564 	 * 
565 	 * @see com.eviware.soapui.SoapUICore#getActionRegistry()
566 	 */
567 	public SoapUIActionRegistry getActionRegistry()
568 	{
569 		if( actionRegistry == null )
570 			actionRegistry = initActionRegistry();
571 
572 		return actionRegistry;
573 	}
574 
575 	protected SoapUIActionRegistry initActionRegistry()
576 	{
577 		return new SoapUIActionRegistry(
578 				DefaultSoapUICore.class.getResourceAsStream( "/com/eviware/soapui/resources/conf/soapui-actions.xml" ) );
579 	}
580 
581 	protected void addExternalListeners( String folder, ClassLoader classLoader )
582 	{
583 		File[] actionFiles = new File( folder ).listFiles();
584 		if( actionFiles != null )
585 		{
586 			for( File actionFile : actionFiles )
587 			{
588 				if( actionFile.isDirectory() )
589 				{
590 					addExternalListeners( actionFile.getAbsolutePath(), classLoader );
591 					continue;
592 				}
593 
594 				if( !actionFile.getName().toLowerCase().endsWith( "-listeners.xml" ) )
595 					continue;
596 
597 				try
598 				{
599 					log.info( "Adding listeners from [" + actionFile.getAbsolutePath() + "]" );
600 
601 					SoapUI.getListenerRegistry().addConfig( new FileInputStream( actionFile ), classLoader );
602 				}
603 				catch( Exception e )
604 				{
605 					SoapUI.logError( e );
606 				}
607 			}
608 		}
609 	}
610 
611 	private class SettingsWatcher extends TimerTask
612 	{
613 		@Override
614 		public void run()
615 		{
616 			if( settingsFile != null && !isSavingSettings )
617 			{
618 				File file = new File( settingsFile );
619 				if( file.exists() && file.lastModified() > lastSettingsLoad )
620 				{
621 					log.info( "Reloading updated settings file" );
622 					initSettings( settingsFile );
623 					SoapUI.setProxyEnabled( getSettings().getBoolean( ProxySettings.ENABLE_PROXY ) );
624 				}
625 			}
626 		}
627 	}
628 }