View Javadoc

1   /*
2    *  soapUI, copyright (C) 2004-2007 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.awt.BorderLayout;
16  import java.awt.Color;
17  import java.awt.Component;
18  import java.awt.Dimension;
19  import java.awt.Insets;
20  import java.awt.Toolkit;
21  import java.awt.event.ActionEvent;
22  import java.awt.event.KeyEvent;
23  import java.awt.event.MouseAdapter;
24  import java.awt.event.MouseEvent;
25  import java.awt.event.WindowAdapter;
26  import java.awt.event.WindowEvent;
27  import java.io.File;
28  import java.io.IOException;
29  import java.net.URI;
30  import java.net.URISyntaxException;
31  import java.net.URL;
32  import java.util.ArrayList;
33  import java.util.Collection;
34  import java.util.Collections;
35  import java.util.List;
36  import java.util.Properties;
37  
38  import javax.swing.AbstractAction;
39  import javax.swing.Action;
40  import javax.swing.BorderFactory;
41  import javax.swing.ImageIcon;
42  import javax.swing.JComponent;
43  import javax.swing.JFrame;
44  import javax.swing.JLabel;
45  import javax.swing.JMenu;
46  import javax.swing.JMenuBar;
47  import javax.swing.JOptionPane;
48  import javax.swing.JPanel;
49  import javax.swing.JScrollPane;
50  import javax.swing.JSplitPane;
51  import javax.swing.JTabbedPane;
52  import javax.swing.JWindow;
53  import javax.swing.SwingUtilities;
54  import javax.swing.ToolTipManager;
55  import javax.swing.UIManager;
56  import javax.swing.plaf.ColorUIResource;
57  import javax.xml.namespace.QName;
58  import javax.xml.parsers.FactoryConfigurationError;
59  
60  import org.apache.log4j.Level;
61  import org.apache.log4j.Logger;
62  import org.apache.log4j.xml.DOMConfigurator;
63  
64  import com.eviware.soapui.actions.SoapUIPreferencesAction;
65  import com.eviware.soapui.config.SoapuiSettingsDocumentConfig;
66  import com.eviware.soapui.impl.settings.XmlBeansSettingsImpl;
67  import com.eviware.soapui.impl.wsdl.actions.iface.tools.axis1.Axis1XWSDL2JavaAction;
68  import com.eviware.soapui.impl.wsdl.actions.iface.tools.axis2.Axis2WSDL2CodeAction;
69  import com.eviware.soapui.impl.wsdl.actions.iface.tools.dotnet.DotNetWsdlAction;
70  import com.eviware.soapui.impl.wsdl.actions.iface.tools.gsoap.GSoapAction;
71  import com.eviware.soapui.impl.wsdl.actions.iface.tools.jaxb.JaxbXjcAction;
72  import com.eviware.soapui.impl.wsdl.actions.iface.tools.jbossws.JBossWSConsumeAction;
73  import com.eviware.soapui.impl.wsdl.actions.iface.tools.jbossws.WSToolsWsdl2JavaAction;
74  import com.eviware.soapui.impl.wsdl.actions.iface.tools.oracle.OracleWsaGenProxyAction;
75  import com.eviware.soapui.impl.wsdl.actions.iface.tools.support.SwingToolHost;
76  import com.eviware.soapui.impl.wsdl.actions.iface.tools.tcpmon.TcpMonAction;
77  import com.eviware.soapui.impl.wsdl.actions.iface.tools.wscompile.WSCompileAction;
78  import com.eviware.soapui.impl.wsdl.actions.iface.tools.wsimport.WSImportAction;
79  import com.eviware.soapui.impl.wsdl.actions.iface.tools.xfire.XFireAction;
80  import com.eviware.soapui.impl.wsdl.actions.iface.tools.xmlbeans.XmlBeans2Action;
81  import com.eviware.soapui.impl.wsdl.actions.support.OpenUrlAction;
82  import com.eviware.soapui.impl.wsdl.actions.support.ShowOnlineHelpAction;
83  import com.eviware.soapui.impl.wsdl.support.HelpUrls;
84  import com.eviware.soapui.impl.wsdl.support.soap.SoapVersion;
85  import com.eviware.soapui.model.ModelItem;
86  import com.eviware.soapui.model.PanelBuilder;
87  import com.eviware.soapui.model.settings.Settings;
88  import com.eviware.soapui.model.settings.SettingsListener;
89  import com.eviware.soapui.model.tree.SoapUITreeNode;
90  import com.eviware.soapui.model.util.PanelBuilderRegistry;
91  import com.eviware.soapui.model.workspace.Workspace;
92  import com.eviware.soapui.model.workspace.WorkspaceFactory;
93  import com.eviware.soapui.monitor.MockEngine;
94  import com.eviware.soapui.monitor.TestMonitor;
95  import com.eviware.soapui.settings.HttpSettings;
96  import com.eviware.soapui.settings.UISettings;
97  import com.eviware.soapui.settings.WsdlSettings;
98  import com.eviware.soapui.support.ClasspathHacker;
99  import com.eviware.soapui.support.SoapUIException;
100 import com.eviware.soapui.support.UISupport;
101 import com.eviware.soapui.support.action.SoapUIActionRegistry;
102 import com.eviware.soapui.support.action.swing.ActionList;
103 import com.eviware.soapui.support.action.swing.ActionListBuilder;
104 import com.eviware.soapui.support.action.swing.ActionSupport;
105 import com.eviware.soapui.support.action.swing.SwingActionDelegate;
106 import com.eviware.soapui.support.log.Log4JMonitor;
107 import com.eviware.soapui.support.log.LogDisablingTestMonitorListener;
108 import com.eviware.soapui.support.types.StringList;
109 import com.eviware.soapui.ui.JDesktopPanelsList;
110 import com.eviware.soapui.ui.Navigator;
111 import com.eviware.soapui.ui.NavigatorListener;
112 import com.eviware.soapui.ui.desktop.DesktopPanel;
113 import com.eviware.soapui.ui.desktop.DesktopRegistry;
114 import com.eviware.soapui.ui.desktop.SoapUIDesktop;
115 import com.eviware.soapui.ui.desktop.standalone.StandaloneDesktop;
116 import com.eviware.soapui.ui.desktop.standalone.StandaloneDesktopFactory;
117 import com.eviware.soapui.ui.support.DesktopListenerAdapter;
118 import com.eviware.x.form.XFormFactory;
119 import com.eviware.x.impl.swing.SwingFileDialogs;
120 import com.eviware.x.impl.swing.SwingFormFactory;
121 import com.jgoodies.looks.HeaderStyle;
122 import com.jgoodies.looks.Options;
123 import com.jgoodies.looks.plastic.PlasticXPLookAndFeel;
124 import com.jgoodies.looks.plastic.theme.SkyBluer;
125 
126 /***
127  * Main SoapUI entry point.
128  * 
129  * @author Ole.Matzura
130  * 
131  * For version 0.6
132  * @todo improve error assertion reporting +
133  * @todo find/search/replace +
134  * @todo undo +
135  * @todo recreate request and keep values +
136  * @todo dont create optional elements +
137  * @todo option to create requests when importing +
138  * @todo show soapaction +
139  * @todo save response +
140  * @todo color-coding +
141  * @todo rapportera fel vid null-svar +
142  * @todo fixa bugg vid update interface +
143  * @todo xmlbeans2 +
144  * @todo httpclient rc3 +
145  * @todo refactor request panels +
146  * @todo refactor project/interface/testsuite listeners +
147  * @todo create properties table +
148  * 
149  * For version 0.7
150  * @todo workspace in home folder +
151  * @todo allow renaming of operation names in tree +
152  * @todo add functionality for copying values from test response to following
153  *       test request +
154  * @todo fix relative xsd imports when loading from file system +
155  * @todo fix cancelling of request when closing request window -> introduce
156  *       DesktopPanel interface +
157  * @todo refactor panel creation / listener handling/release +
158  * @todo fix update of testcase window when adding test steps +
159  * @todo add delete-line action in xml-editor (Ctrl-D) +
160  * @todo add submit action to xml request editor (Ctrl Enter) +
161  * @todo add mousewheel support to xml editor +
162  * @todo add mousewheel + C support to xml editor (move cursor) +
163  * @todo fix revalidation problems +
164  * @todo add validation to xmleditors +
165  * @todo check localisation of schema errors +
166  * @todo add possibility to reload schema (neccessary?) +
167  * @todo fix cloning of assertions when cloning test steps +
168  * @todo ask for creation of optional elements when (re)creating new request +
169  * @todo add action to add existing namespaces to xpath in xpathassertion +
170  * 
171  * For version 0.8
172  * @todo fix default values when creating requests +
173  * @todo bug-fixes - creation of namespace declarations creates multiple with
174  *       same name + - check defintion update + - deletion of endpoint always
175  *       deletes first + - deleted assertions result in error during save/exit? + -
176  *       disable submit when missing endpoint + - clone request null-pointer + -
177  *       fix value transfer element <> attribute + - fix cancelling of test
178  *       requests +
179  * @todo create assertion events / listeners +
180  * @todo ask to add testcase if missing +
181  * @todo add alt-enter to response area +
182  * @todo allow url config of SchemaCompliance assertion +
183  * @todo add accelerators for common actions +
184  * @todo fix positions of dialogs +
185  * @todo add possibility to specify testsuite/testcase in maven-plugin +
186  * @todo refactoring: replaced SoapUIAction with standard swing Action +
187  * @todo refactoring: checked all JOptionPanes for correct title, etc. +
188  * @todo add filename-filters to filechoosers +
189  * @todo add shortcut for cancel request to editor +
190  * 
191  * For version 0.9
192  * @todo initial class/code comments +
193  * @todo bug-fixes - fix cancelling of test runs + - fix removal of request
194  *       test-steps when associated operations / interfaces are removed + -
195  *       update of request-step status in testcase panel + - focus on find-field
196  *       in find/replace dialog + - fix filters to not remove directories.. + -
197  *       change wsdl file filter to *.wsdl + - disable declare in transfer panel
198  *       when no transfer is selected + - declare in transfer panel declares
199  *       target from target response (should be request) + - ask to cancel when
200  *       closing running testcase + - fix pretty-printing of large xml-documents + -
201  *       fix find and replace + - fix node insert error on multiple clone
202  *       teststep + - fix log-messages from canceled requests + - disable
203  *       replace-related options in find/replace if editor is not editable +
204  * @todo add possibility to move teststeps within testcase +
205  * @todo improve/disable disabling of request-editor +
206  * @todo add addAssertion button to testrequest panel +
207  * @todo add copy/pase actions to editor popup +
208  * @todo model-items tests
209  * @todo improve wsdl/xsd viewer +
210  * @todo improve line-number reporting in validations +
211  * @todo added shift-tab to move focus between request/response editors +
212  * @todo refactorings - SoapUIException + - UIFacade for JOptionPane +
213  *       (partially)
214  * 
215  * For version 1.0b
216  * @todo initial user documentation / samples +
217  * @todo bug-fixes +
218  * @todo more tests / testing!
219  * @todo beta release +
220  * 
221  * For version 1.0
222  * @todo official release
223  * 
224  * For version 1.5
225  * @todo finish LoadTest panels - fix UI + - color legend + - reset action + -
226  *       interactive thread-count change + - error-log + - see responses + -
227  *       assertions + - command-line/maven-plugin + - export results +
228  * @todo loadtest fixes - resizing/scaling of graphs + - autoreset on restart +
229  * @todo fix disabling of relevant actions during test-runs + - Add to testcase,
230  *       delete testcase, etc +
231  * @todo allow TransferValues between any requests/responses +
232  * @todo fix "global values" in testcases + - properties +
233  * @todo improve endpoint editing + - add "edit.." to combobox +
234  * @todo remove xpath/xquery tester.. +
235  * @todo improve testcase properties dialog +
236  * @todo fix icons for all tree nodes +
237  * @todo fix updating of desktop panel titles +
238  * @todo global settings; + - proxy + - close connections + - user-agent header + -
239  *       preemptive authentication + - editor font + - socket timeout + - ?
240  * @todo add loop-functionality for testcases +
241  * @todo support one-way operations +
242  * @todo fix wsdlcontext initialization in loadtests +
243  * @todo create testrun summary in commandline
244  * @todo create loadtest summary in commandline
245  * @todo add maven.soapui.test.host commandline property +
246  * @todo add test-suite runner panel +
247  * @todo option to abort testcase on error +
248  * @todo ensure unique test-step names +
249  * @todo grooy-teststep +
250  * @todo onewayop tree icon +
251  * @todo fix desktoppanels list +
252  * 
253  * For version 1.6
254  * @todo finish SOAP 1.2 request generation +
255  * @todo finish gsoap integration +
256  * @todo bugfixes!
257  * @todo swa-attachments support +
258  * 
259  * Improvements
260  * @todo make modifications of response content "alive"
261  * @todo animated tree icons for testcase/loadtest runs
262  * @todo add run-testcase action in teststep/testcase editors
263  * @todo implement testsuite/testcase generation
264  * @todo refactor XmlObject configurables
265  * @todo workspace management
266  * @todo add reload-project!?
267  * @todo option to reload schemas on run testcase
268  * @todo option to select visible steps in loadtest statistics
269  * @todo generate testcase/testsuite actions
270  * @todo form-based input
271  */
272 
273 public class SoapUI
274 {
275 	public static final String CURRENT_SOAPUI_WORKSPACE = SoapUI.class.getName() + "@workspace";
276 	public final static Logger log = Logger.getLogger( SoapUI.class );
277 	public final static String SOAPUI_VERSION = "1.7.5";
278 	public static final String DEFAULT_WORKSPACE_FILE = "default-soapui-workspace.xml";
279 	private final static String DEFAULT_SETTINGS_FILE = "soapui-settings.xml";
280 	public static final String SOAPUI_SPLASH_GIF = "soapui-splash.gif";
281 
282 	// ------------------------------ FIELDS ------------------------------
283 
284 	private static SoapUI instance;
285 	private static SoapuiSettingsDocumentConfig settingsDocument;
286 	private static List<Object> logCache = new ArrayList<Object>();
287 	private static Settings settings;
288 
289 	private static JFrame frame;
290 
291 	private Navigator navigator;
292 	private SoapUIDesktop desktop;
293 	private static TestMonitor testMonitor;
294 	static Workspace workspace;
295 	private JDesktopPanelsList desktopPanelsList;
296 	private Log4JMonitor logMonitor;
297 
298 	private JMenu desktopMenu;
299 	private JMenu helpMenu;
300 	private JMenu fileMenu;
301 	private JMenuBar menuBar;
302 
303 	public static boolean checkedGroovyLogMonitor;
304 	
305 	private JPanel overviewPanel;
306 	private JMenu toolsMenu;
307 	private boolean saveOnExit = true;
308 	private static MockEngine mockEngine;
309 	private static boolean loadedExtLibs;
310 	private static boolean isStandalone;
311 	private JSplitPane contentSplit;
312 	private InternalDesktopListener internalDesktopListener = new InternalDesktopListener();
313 	private static SoapUIActionRegistry actionRegistry;
314 	private static Logger errorLog = Logger.getLogger( "soapui.errorlog" );
315 	private static boolean logIsInitialized;
316 
317 	// --------------------------- CONSTRUCTORS ---------------------------
318 
319 	public SoapUI()
320 	{
321 		instance = this;
322 		testMonitor = new TestMonitor();
323 		actionRegistry = new SoapUIActionRegistry( SoapUI.class.getResourceAsStream( "/soapui-actions.xml" ));
324 	}
325 
326 	private void buildUI()
327 	{
328 		frame.addWindowListener( new MainFrameWindowListener() );
329 		UISupport.setMainFrame( frame );
330 
331 		navigator = new Navigator( workspace );
332 		navigator.addNavigatorListener( new InternalNavigatorListener() );
333 
334 		desktopPanelsList = new JDesktopPanelsList( desktop );
335 
336 		JSplitPane splitPane = UISupport
337 					.createHorizontalSplit( buildMainPanel(), buildContentPanel() );
338 
339 		frame.setJMenuBar( buildMainMenu() );
340 		frame.getContentPane().add( splitPane, BorderLayout.CENTER );
341 		frame.setDefaultCloseOperation( JFrame.DO_NOTHING_ON_CLOSE );
342 		frame.setSize( 1000, 750 );
343 
344 		splitPane.setDividerLocation( 250 );
345 
346 		navigator.selectModelItem( workspace );
347 
348 		desktop.addDesktopListener( internalDesktopListener );
349 
350 		ToolTipManager.sharedInstance().setInitialDelay( 200 );
351 	}
352 
353 	private JMenuBar buildMainMenu()
354 	{
355 		menuBar = new JMenuBar();
356 		menuBar.putClientProperty( Options.HEADER_STYLE_KEY, HeaderStyle.BOTH );
357 
358 		menuBar.add( buildFileMenu() );
359 		menuBar.add( buildToolsMenu() );
360 		menuBar.add( buildDesktopMenu() );
361 		menuBar.add( buildHelpMenu() );
362 
363 		return menuBar;
364 	}
365 
366 	public static Workspace getWorkspace()
367 	{
368 		return workspace;
369 	}
370 
371 	private JMenu buildDesktopMenu()
372 	{
373 		desktopMenu = new JMenu( "Desktop" );
374 		desktopMenu.setMnemonic( KeyEvent.VK_D );
375 
376 		ActionSupport.addActions( desktop.getActions(), desktopMenu );
377 
378 		return desktopMenu;
379 	}
380 
381 	private JMenu buildHelpMenu()
382 	{
383 		helpMenu = new JMenu( "Help" );
384 		helpMenu.setMnemonic( KeyEvent.VK_H );
385 
386 		helpMenu.add( new ShowOnlineHelpAction( "User Guide", HelpUrls.USERGUIDE_HELP_URL ) );
387 		helpMenu.add( new ShowOnlineHelpAction( "Getting Started",
388 					HelpUrls.GETTINGSTARTED_HELP_URL ) );
389 		helpMenu.addSeparator();
390 		
391 		helpMenu.add( new ShowSystemPropertiesAction());
392 		
393 		helpMenu.addSeparator();
394 		helpMenu.add( new OpenUrlAction( "soapui.org", "http://www.soapui.org" ) );
395 		helpMenu.add( new AboutAction() );
396 		return helpMenu;
397 	}
398 
399 	@SuppressWarnings("unchecked")
400 	private JMenu buildToolsMenu()
401 	{
402 		toolsMenu = new JMenu( "Tools" );
403 		toolsMenu.setMnemonic( KeyEvent.VK_T );
404 
405 		toolsMenu.add( SwingActionDelegate.createDelegate( WSToolsWsdl2JavaAction.SOAPUI_ACTION_ID ));
406 		toolsMenu.add( SwingActionDelegate.createDelegate( JBossWSConsumeAction.SOAPUI_ACTION_ID ));
407 		toolsMenu.addSeparator();
408 		toolsMenu.add( SwingActionDelegate.createDelegate( WSCompileAction.SOAPUI_ACTION_ID ));
409 		toolsMenu.add( SwingActionDelegate.createDelegate( WSImportAction.SOAPUI_ACTION_ID ));
410 		toolsMenu.addSeparator();
411 		toolsMenu.add( SwingActionDelegate.createDelegate( Axis1XWSDL2JavaAction.SOAPUI_ACTION_ID ));
412 		toolsMenu.add( SwingActionDelegate.createDelegate( Axis2WSDL2CodeAction.SOAPUI_ACTION_ID ));
413 		toolsMenu.add( SwingActionDelegate.createDelegate( XFireAction.SOAPUI_ACTION_ID ));
414 		toolsMenu.add( SwingActionDelegate.createDelegate( OracleWsaGenProxyAction.SOAPUI_ACTION_ID ));
415 		toolsMenu.addSeparator();
416 		toolsMenu.add( SwingActionDelegate.createDelegate( XmlBeans2Action.SOAPUI_ACTION_ID ));
417 		toolsMenu.add( SwingActionDelegate.createDelegate( JaxbXjcAction.SOAPUI_ACTION_ID ));
418 		toolsMenu.addSeparator();
419 		toolsMenu.add( SwingActionDelegate.createDelegate( DotNetWsdlAction.SOAPUI_ACTION_ID ));
420 		toolsMenu.add( SwingActionDelegate.createDelegate( GSoapAction.SOAPUI_ACTION_ID ));
421 		toolsMenu.addSeparator();
422 		toolsMenu.add( SwingActionDelegate.createDelegate( TcpMonAction.SOAPUI_ACTION_ID ));
423 		// toolsMenu.addSeparator();
424 		// toolsMenu.add( new XQueryXPathTesterAction());
425 
426 		return toolsMenu;
427 	}
428 
429 	private JMenu buildFileMenu()
430 	{
431 		fileMenu = new JMenu( "File" );
432 		fileMenu.setMnemonic( KeyEvent.VK_F );
433 
434 		ActionList actions = ActionListBuilder.buildActions( workspace );
435 		actions.removeAction( actions.getActionCount()-1 );
436 
437 		ActionSupport.addActions( actions, fileMenu );
438 
439 		fileMenu.add( SoapUIPreferencesAction.getInstance() );
440 		fileMenu.add( new SavePreferencesAction() );
441 		fileMenu.add( new ImportPreferencesAction() );
442 
443 		fileMenu.addSeparator();
444 		fileMenu.add( new ExitAction() );
445 		fileMenu.add( new ExitWithoutSavingAction() );
446 		fileMenu.addSeparator();
447 		fileMenu.add( new ShowOnlineHelpAction( HelpUrls.OVERVIEW_HELP_URL ));
448 
449 		return fileMenu;
450 	}
451 
452 	public JFrame getFrame()
453 	{
454 		return frame;
455 	}
456 
457 	private JComponent buildMainPanel()
458 	{
459 		JSplitPane splitPane = UISupport.createVerticalSplit();
460 
461 		splitPane.setBorder( BorderFactory.createEmptyBorder( 2, 2, 2, 2 ) );
462 
463 		splitPane.setTopComponent( navigator );
464 		splitPane.setBottomComponent( buildOverviewPanel() );
465 		splitPane.setDividerLocation( 500 );
466 		splitPane.setResizeWeight( 0.6 );
467 		return splitPane;
468 	}
469 
470 	private Component buildOverviewPanel()
471 	{
472 		JTabbedPane detailTabs = new JTabbedPane( JTabbedPane.BOTTOM );
473 
474 		overviewPanel = new JPanel( new BorderLayout() );
475 		detailTabs.addTab( "Details", overviewPanel );
476 		detailTabs.addTab( "Windows", new JScrollPane( desktopPanelsList ) );
477 
478 		return UISupport.createTabPanel( detailTabs, true );
479 	}
480 
481 	private void setOverviewPanel( Component panel )
482 	{
483 		if( overviewPanel.getComponentCount() == 0 && panel == null )
484 			return;
485 
486 		overviewPanel.removeAll();
487 		if( panel != null )
488 			overviewPanel.add( panel, BorderLayout.CENTER );
489 		overviewPanel.revalidate();
490 		overviewPanel.repaint();
491 	}
492 
493 	private Component buildContentPanel()
494 	{
495 		contentSplit = UISupport.createVerticalSplit();
496 		contentSplit.setBorder( BorderFactory.createEmptyBorder( 2, 2, 2, 2 ) );
497 
498 		contentSplit.setTopComponent( desktop.getDesktopComponent() );
499 		contentSplit.setBottomComponent( buildLogPanel( true, "soapUI log" ) );
500 		contentSplit.setDividerLocation( 550 );
501 		contentSplit.setResizeWeight( 1 );
502 		return contentSplit;
503 	}
504 
505 	public Component buildLogPanel( boolean hasDefault, String defaultName )
506 	{
507 		logMonitor = new Log4JMonitor();
508 		logMonitor.addLogArea( defaultName, "com.eviware.soapui", hasDefault ).setLevel( Level.DEBUG );
509 		logMonitor.addLogArea( "http log", "httpclient.wire", false ).setLevel( Level.DEBUG );
510 		logMonitor.addLogArea( "jetty log", "jetty", false ).setLevel( Level.INFO );
511 		logMonitor.addLogArea( "error log", "soapui.errorlog", false ).setLevel( Level.DEBUG );
512 
513 		for( Object message : logCache )
514 		{
515 			logMonitor.logEvent( message );
516 		}
517 
518 		return UISupport.createTabPanel( logMonitor, true );
519 	}
520 
521 	// -------------------------- OTHER METHODS --------------------------
522 
523 	public static synchronized void log( final Object msg )
524 	{
525 		if( instance == null || instance.logMonitor == null )
526 		{
527 			logCache.add( msg );
528 			return;
529 		}
530 
531 		if( SwingUtilities.isEventDispatchThread() )
532 		{
533 			instance.logMonitor.logEvent( msg );
534 		}
535 		else
536 		{
537 			SwingUtilities.invokeLater( new Runnable()
538 			{
539 				public void run()
540 				{
541 					instance.logMonitor.logEvent( msg );
542 				}
543 			} );
544 		}
545 	}
546 
547 	// -------------------------- INNER CLASSES --------------------------
548 
549 	private final class InternalDesktopListener extends DesktopListenerAdapter
550 	{
551 		public void desktopPanelSelected( DesktopPanel desktopPanel )
552 		{
553 			ModelItem modelItem = desktopPanel.getModelItem();
554 			if( modelItem != null )
555 				navigator.selectModelItem( modelItem );
556 		}
557 	}
558 
559 	private final class MainFrameWindowListener extends WindowAdapter
560 	{
561 		public void windowClosing( WindowEvent e )
562 		{
563 			if( saveOnExit )
564 			{
565 				String question = "Exit SoapUI?";
566 				
567 				if( getTestMonitor().hasRunningTests() )
568 					question += "\n(Projects with running tests will not be saved)";
569 				
570 				if( !UISupport.confirm( question, "Question" ) )
571 					return;
572 
573 				try
574 				{
575 					saveSettings();
576 					workspace.onClose();
577 				}
578 				catch( IOException e1 )
579 				{
580 					SoapUI.logError( e1 );
581 				}
582 			}
583 			else
584 			{
585 				if( !UISupport.confirm( "Exit SoapUI without saving?", "Question" ) )
586 				{
587 					saveOnExit = true;
588 					return;
589 				}
590 			}
591 
592 			frame.dispose();
593 		}
594 
595 		public void windowClosed( WindowEvent e )
596 		{
597 			System.out.println( "exiting.." );
598 			System.exit( 0 );
599 		}
600 	}
601 
602 	/***
603 	 * Adapted theme for soapUI Look and Feel
604 	 * 
605 	 * @author ole.matzura
606 	 */
607 	
608 	public static class SoapUITheme extends SkyBluer
609 	{
610 		public static final Color BACKGROUND_COLOR = new Color( 240, 240, 240 );
611 
612 		public ColorUIResource getControl()
613 		{
614 			return new ColorUIResource( BACKGROUND_COLOR );
615 		}
616 
617 		public ColorUIResource getMenuBackground()
618 		{
619 			return getControl();
620 		}
621 
622 		public ColorUIResource getMenuItemBackground()
623 		{
624 			return new ColorUIResource( new Color( 248, 248, 248 ) );
625 		}
626 	}
627 
628 	// --------------------------- main() method ---------------------------
629 
630 	public static void main( String[] args ) throws Exception
631 	{
632 		String title = "soapUI " + SOAPUI_VERSION;
633 		String splashImage = "soapui-splash.gif";
634 		
635 		startSoapUI( args, title, findSplash( splashImage ));
636 	}
637 
638 	public static URL findSplash( String filename )
639 	{
640 		File file = new File( filename );
641 		URL url = null;
642 		
643 		try
644 		{
645 			if( !file.exists() )
646 				url = SoapUI.class.getResource( "/" + filename );
647 			else
648 				url = file.toURL();
649 		}
650 		catch( Exception e1 )
651 		{
652 		}
653 		
654 		try
655 		{
656 			if( url == null )
657 				url = new URL( "http://www.soapui.org/images/" + filename );
658 		}
659 		catch( Exception e2 )
660 		{
661 			SoapUI.logError( e2 );
662 		}
663 		
664 		return url;
665 	}
666 	
667 	public static SoapUI startSoapUI( String[] args, String title, URL splashImage ) throws FactoryConfigurationError, SoapUIException
668 	{
669 		isStandalone = true;
670 
671 		// force loading of SoapVersion 
672 		SoapVersion.Soap11.equals( SoapVersion.Soap12 );
673 		
674 		initSoapUILog();
675 		
676 		frame = new JFrame( title );
677 		new SoapUISplash( splashImage );
678 		
679 		initSoapUILookAndFeel();
680 		prepareSwingUI();
681 		loadExtLibs();
682 		
683 		DesktopRegistry.getInstance().addDesktop( "Default", new StandaloneDesktopFactory() );
684 		
685 		// Run with the currently installed license.
686 		SoapUI soapUI = new SoapUI();
687 
688 		Workspace workspace = null;
689 
690 		if( args.length > 0 )
691 		{
692 			workspace = WorkspaceFactory.getInstance().openWorkspace( args );
693 			getSettings().setString( CURRENT_SOAPUI_WORKSPACE, args[0] );
694 		}
695 		else
696 		{
697 			String wsfile = getSettings().getString( CURRENT_SOAPUI_WORKSPACE, System.getProperty( "user.home" ) + File.separatorChar
698 						+ DEFAULT_WORKSPACE_FILE );
699 			workspace = WorkspaceFactory.getInstance().openWorkspace( new String[] { wsfile } );
700 		}
701 		
702 		soapUI.show( workspace );
703 		return soapUI;
704 	}
705 	
706 	public static boolean isStandalone()
707 	{
708 		return isStandalone;
709 	}
710 
711 	public static void loadExtLibs()
712 	{
713 		if( loadedExtLibs )
714 			return;
715 		
716 		try
717 		{
718 			File dir = new File( "ext" );
719 			
720 			if( dir.exists() && dir.isDirectory() )
721 			{
722 				File[] files = dir.listFiles();
723 				for( File file : files )
724 				{
725 					if( file.getName().toLowerCase().endsWith( ".jar" ))
726 					{
727 						ClasspathHacker.addFile( file );
728 					}
729 				}
730 			}
731 			else
732 			{
733 				log.info( "Missing folder [" + dir.getAbsolutePath() + "] for external libraries" );
734 			}
735 			
736 			loadedExtLibs = true;
737 		}
738 		catch( IOException e )
739 		{
740 			SoapUI.logError( e );
741 		}
742 	}
743 
744 	public static void prepareSwingUI()
745 	{
746 		UISupport.setToolHost( new SwingToolHost() );
747       XFormFactory.Factory.instance = new SwingFormFactory();
748 	}
749 
750 	public static void initSoapUILookAndFeel()
751 	{
752 		try
753 		{
754 			if( getSettings().getBoolean( UISettings.NATIVE_LAF ))
755 			{
756 				javax.swing.UIManager.setLookAndFeel(UIManager.getSystemLookAndFeelClassName());
757 			}
758 			else
759 			{
760 				SoapUITheme theme = new SoapUITheme();
761 
762 				PlasticXPLookAndFeel.setCurrentTheme( theme );
763 				PlasticXPLookAndFeel.setTabStyle( "Metal" );
764 
765 				UIManager.setLookAndFeel( new PlasticXPLookAndFeel() );
766 				UIManager.put( "TabbedPane.tabAreaInsets", new Insets( 3, 2, 0, 0 ) );
767 				UIManager.put( "TabbedPane.unselectedBackground", new Color( 220, 220, 220 ) );
768 				UIManager.put( "TabbedPane.selected", new Color( 240, 240, 240 ) );
769 				
770 				PlasticXPLookAndFeel.setPlasticTheme( theme );
771 			}
772 		}
773 		catch( Throwable e )
774 		{
775 			System.err.println( "Error initializing PlasticXPLookAndFeel; " + e.getMessage() );
776 		}
777 	}
778 
779 	public static JMenuBar getMenuBar()
780 	{
781 		return instance == null ? null : instance.menuBar;
782 	}
783 	
784 	public static void initSoapUILog() throws FactoryConfigurationError
785 	{
786 		if( !logIsInitialized )
787 		{
788 			File log4jconfig = new File( "soapui-log4j.xml" );
789 			if( log4jconfig.exists() )
790 			{
791 				System.out.println( "Configuring log4j from [" + log4jconfig + "]" );
792 				DOMConfigurator.configureAndWatch( log4jconfig.getAbsolutePath(), 5000 );
793 			}
794 			else
795 			{
796 				URL log4jUrl = SoapUI.class.getResource( "/soapui-log4j.xml" );
797 				System.out.println( "Configuring log4j from [" + log4jUrl + "]" );
798 				DOMConfigurator.configure( log4jUrl );
799 			}
800 			
801 			logIsInitialized = true;
802 		}
803 	}
804 
805 	private void show( Workspace workspace )
806 	{
807 		SoapUI.workspace = workspace;
808 
809 		String desktopType = getSettings().getString( UISettings.DESKTOP_TYPE, "Default");
810 		desktop = DesktopRegistry.getInstance().createDesktop( desktopType, workspace );
811 		
812 		if( desktop == null ) 
813 			desktop = new StandaloneDesktop( workspace );
814 
815 		getSettings().addSettingsListener( new SettingsListener() {
816 
817 			public void settingChanged( String name, String newValue, String oldValue )
818 			{
819 				if( name.equals( UISettings.DESKTOP_TYPE ))
820 				{
821 					changeDesktop( DesktopRegistry.getInstance().createDesktop( newValue, SoapUI.workspace ));
822 				}
823 			}
824 		} );
825 		
826 		buildUI();
827 		testMonitor.addTestMonitorListener( new LogDisablingTestMonitorListener() );
828 		testMonitor.init( workspace );
829 		frame.setVisible( true );
830 	}
831 	
832 	private void changeDesktop(SoapUIDesktop newDesktop )
833 	{
834 		desktopPanelsList.setDesktop( newDesktop );
835 		desktop.removeDesktopListener( internalDesktopListener );
836 		
837 		desktop.transferTo( newDesktop );
838 		desktop.release();
839 		
840 		desktop = newDesktop;
841 		contentSplit.setTopComponent( desktop.getDesktopComponent() );
842 		
843 		desktop.addDesktopListener( internalDesktopListener );
844 		
845 		desktopMenu.removeAll();
846 		ActionSupport.addActions( desktop.getActions(), desktopMenu );
847 	}
848 
849 	public static void logError( Throwable e )
850 	{
851 		String msg = e.getMessage();
852 		if( msg == null )
853 			msg = e.toString();
854 		
855 		log.error( "An error occured [" + msg + "], see error log for details" );
856 		errorLog.error(e.toString(), e );
857 	}
858 
859 	public static synchronized Logger ensureGroovyLog()
860 	{
861 		if( !checkedGroovyLogMonitor )
862 		{
863 			Log4JMonitor logMonitor = getLogMonitor();
864 			if( logMonitor != null && !logMonitor.hasLogArea( "groovy.log" ))
865 				logMonitor.addLogArea( "groovy log", "groovy.log", false );
866 			
867 			checkedGroovyLogMonitor = true;
868 		}
869 		
870 		return Logger.getLogger( "groovy.log" );
871 	}
872 
873 	public class InternalNavigatorListener implements NavigatorListener
874 	{
875 		public void nodeSelected( SoapUITreeNode treeNode )
876 		{
877 			if( treeNode == null )
878 			{
879 				setOverviewPanel( null );
880 			}
881 			else
882 			{
883 				PanelBuilder<ModelItem> panelBuilder = PanelBuilderRegistry.getPanelBuilder( treeNode.getModelItem() );
884 				if( panelBuilder != null && panelBuilder.hasOverviewPanel() )
885 				{
886 					setOverviewPanel( panelBuilder.buildOverviewPanel( treeNode.getModelItem() ) );
887 				}
888 				else
889 				{
890 					setOverviewPanel( null );
891 				}
892 			}
893 		}
894 	}
895 
896 	private class ExitAction extends AbstractAction
897 	{
898 		public ExitAction()
899 		{
900 			super( "Exit" );
901 			putValue( Action.SHORT_DESCRIPTION, "Saves all projects and exits SoapUI" );
902 			putValue( Action.ACCELERATOR_KEY, UISupport.getKeyStroke( "menu Q" ) );
903 		}
904 
905 		public void actionPerformed( ActionEvent e )
906 		{
907 			saveOnExit = true;
908 			WindowEvent windowEvent = new WindowEvent( frame, WindowEvent.WINDOW_CLOSING );
909 			frame.dispatchEvent( windowEvent );
910 		}
911 	}
912 
913 	private class ShowSystemPropertiesAction extends AbstractAction
914 	{
915 		public ShowSystemPropertiesAction()
916 		{
917 			super( "System Properties" );
918 			putValue( Action.SHORT_DESCRIPTION, "Shows the current systems properties" );
919 		}
920 
921 		public void actionPerformed( ActionEvent e )
922 		{
923 			StringBuffer buffer = new StringBuffer();
924 			Properties properties = System.getProperties();
925 			
926 			List<String> keys = new ArrayList<String>();
927 			for( Object key : properties.keySet() )
928 				keys.add( key.toString() );
929 			
930 			Collections.sort( keys );
931 			
932 			String lastKey = null;
933 			
934 			for( String key : keys )
935 			{
936 				if( lastKey != null )
937 				{
938 					if( !key.startsWith( lastKey ))
939 						buffer.append(  "\r\n" );
940 				}
941 
942 				int ix = key.indexOf( '.' );
943 				lastKey = ix == -1 ? key : key.substring( 0, ix );
944 				
945 				buffer.append( key ).append( '=' ).append( properties.get( key )).append( "\r\n" );
946 			}
947 			
948 			UISupport.showExtendedInfo( "System Properties", "Current system properties", 
949 						"<html><body><pre><font size=-1>" + buffer.toString() + "</font></pre></body></html>", 
950 						new Dimension( 600, 400 ));
951 		}
952 	}
953 	
954 	private class AboutAction extends AbstractAction
955 	{
956 		public AboutAction()
957 		{
958 			super( "About soapUI" );
959 			putValue( Action.SHORT_DESCRIPTION, "Shows information on soapUI" );
960 		}
961 
962 		public void actionPerformed( ActionEvent e )
963 		{
964 			URI splashURI = null;
965 			try
966 			{
967 				splashURI = SoapUI.findSplash( SoapUI.SOAPUI_SPLASH_GIF ).toURI();
968 			}
969 			catch( URISyntaxException e1 )
970 			{
971 				SoapUI.logError( e1 );
972 			}
973 			
974 			Properties props = new Properties();
975 			try
976 			{
977 				props.load( SoapUI.class.getResourceAsStream( "/buildinfo.txt" ) );
978 			}
979 			catch( Exception e1 )
980 			{
981 				SoapUI.logError( e1 );
982 			}
983 			
984 			
985 			UISupport.showExtendedInfo( "About soapUI", null, 
986 						"<html><body><p align=center><img src=\"" + splashURI + "\"><br>soapUI " +
987 						SOAPUI_VERSION + ", copyright (C) 2004-2007 eviware.com<br>" +
988 						"<a href=\"http://www.soapui.org\">http://www.soapui.org</a> | " +
989 						"<a href=\"http://www.eviware.com\">http://www.eviware.com</a><br>" +
990 									"Build " + props.getProperty( "build.number" ) + ", Build Date " +
991 									props.getProperty( "build.date" ) + "</p></body></html>",
992 									
993 						new Dimension( 470, 350 ));
994 		}
995 	}
996 	
997 	
998 	private class ExitWithoutSavingAction extends AbstractAction
999 	{
1000 		public ExitWithoutSavingAction()
1001 		{
1002 			super( "Exit without saving" );
1003 			putValue( Action.SHORT_DESCRIPTION, "Saves all projects and exits SoapUI" );
1004 			putValue( Action.ACCELERATOR_KEY, UISupport.getKeyStroke( "ctrl alt Q" ) );
1005 		}
1006 
1007 		public void actionPerformed( ActionEvent e )
1008 		{
1009 			saveOnExit = false;
1010 			WindowEvent windowEvent = new WindowEvent( frame, WindowEvent.WINDOW_CLOSING );
1011 			frame.dispatchEvent( windowEvent );
1012 		}
1013 	}
1014 
1015 	private class SavePreferencesAction extends AbstractAction
1016 	{
1017 		public SavePreferencesAction()
1018 		{
1019 			super( "Save Preferences" );
1020 			putValue( Action.SHORT_DESCRIPTION, "Saves all global preferences" );
1021 		}
1022 
1023 		public void actionPerformed( ActionEvent e )
1024 		{
1025 			try
1026 			{
1027 				saveSettings();
1028 			}
1029 			catch( IOException e1 )
1030 			{
1031 				UISupport.showErrorMessage( e1 );
1032 			}
1033 		}
1034 	}
1035 	
1036 	private class ImportPreferencesAction extends AbstractAction
1037 	{
1038 		public ImportPreferencesAction()
1039 		{
1040 			super( "Import Preferences" );
1041 			putValue( Action.SHORT_DESCRIPTION, "Imports soapUI Settings from another settings-file" );
1042 		}
1043 
1044 		public void actionPerformed( ActionEvent e )
1045 		{
1046 			try
1047 			{
1048 				// prompt for import
1049 				File file = UISupport.getFileDialogs().open( null, "Import Preferences", ".xml", "soapUI Settings XML (*.xml)", null );
1050 				if( file != null )
1051 				{
1052 					SoapuiSettingsDocumentConfig doc = SoapuiSettingsDocumentConfig.Factory.parse( file );
1053 					settingsDocument.set( doc );
1054 				}
1055 			}
1056 			catch( Exception e1 )
1057 			{
1058 				UISupport.showErrorMessage( e1 );
1059 			}
1060 		}
1061 	}
1062 
1063 	public static TestMonitor getTestMonitor()
1064 	{
1065 		return testMonitor;
1066 	}
1067 
1068 	public static void setTestMonitor( TestMonitor monitor )
1069 	{
1070 		testMonitor = monitor;
1071 	}
1072 
1073 	public static Log4JMonitor getLogMonitor()
1074 	{
1075 		return instance == null ? null : instance.logMonitor;
1076 	}
1077 
1078 	public static void setLogMonitor( Log4JMonitor monitor )
1079 	{
1080 		if( instance != null )
1081 			instance.logMonitor = monitor;
1082 	}
1083 
1084 	public static Settings getSettings()
1085 	{
1086 		if( settings == null )
1087 		{
1088 			if( settingsDocument == null )
1089 				initSettings( DEFAULT_SETTINGS_FILE );
1090 
1091 			if( settingsDocument.getSoapuiSettings() == null )
1092 			{
1093 				settingsDocument.addNewSoapuiSettings();
1094 				settings = new XmlBeansSettingsImpl( null, null, settingsDocument.getSoapuiSettings() );
1095 
1096 				settings.setBoolean( WsdlSettings.CACHE_WSDLS, true );
1097 				settings.setBoolean( WsdlSettings.PRETTY_PRINT_RESPONSE_MESSAGES, true );
1098 				
1099 				settings.setBoolean( HttpSettings.INCLUDE_REQUEST_IN_TIME_TAKEN, true );
1100 				settings.setBoolean( HttpSettings.INCLUDE_RESPONSE_IN_TIME_TAKEN, true );
1101 			}
1102 			else
1103 			{
1104 				settings = new XmlBeansSettingsImpl( null, null, settingsDocument.getSoapuiSettings() );
1105 			}
1106 			
1107 			if( !settings.isSet( WsdlSettings.EXCLUDED_TYPES ))
1108 			{
1109 				StringList list = new StringList();
1110 				list.add( "schema@http://www.w3.org/2001/XMLSchema");
1111 				settings.setString( WsdlSettings.EXCLUDED_TYPES, list.toXml() );
1112 			}
1113 
1114 			if( !settings.isSet( WsdlSettings.NAME_WITH_BINDING ))
1115 			{
1116 				settings.setBoolean( WsdlSettings.NAME_WITH_BINDING, true );
1117 			}
1118 			
1119 			if( !settings.isSet(  HttpSettings.MAX_CONNECTIONS_PER_HOST ))
1120 			{
1121 				settings.setLong( HttpSettings.MAX_CONNECTIONS_PER_HOST, 500 );
1122 			}
1123 
1124 			if( !settings.isSet(  HttpSettings.MAX_TOTAL_CONNECTIONS ))
1125 			{
1126 				settings.setLong( HttpSettings.MAX_TOTAL_CONNECTIONS, 2000 );
1127 			}
1128 		}
1129 
1130 		return settings;
1131 	}
1132 
1133 	public static void saveSettings() throws IOException
1134 	{
1135 		File file = new File( DEFAULT_SETTINGS_FILE );
1136 		settingsDocument.save( file );
1137 		log.info( "Saved global preferences to [" + file.getAbsolutePath() + "]" );
1138 	}
1139 
1140 	/***
1141 	 * Initializes the soapui settings from the specified file. Must be called on
1142 	 * startup before any model items are created.
1143 	 * 
1144 	 * @param fileName
1145 	 */
1146 
1147 	public static void initSettings( String fileName )
1148 	{
1149 		try
1150 		{
1151 			File settingsFile = new File( fileName );
1152 			if( !settingsFile.exists() )
1153 			{
1154 				if( isStandalone )
1155 				{
1156 					settingsFile = importSettingsOnStartup( settingsFile );
1157 				}
1158 				
1159 				if( settingsDocument == null )
1160 				{
1161 					log.info( "Creating new settings at [" + settingsFile.getAbsolutePath() + "]" );
1162 					settingsDocument = SoapuiSettingsDocumentConfig.Factory.newInstance();
1163 				}
1164 			}
1165 			else
1166 			{
1167 				settingsDocument = SoapuiSettingsDocumentConfig.Factory.parse( settingsFile );
1168 				log.info( "initialized soapui-settings from [" + settingsFile.getAbsolutePath() + "]" );
1169 			}
1170 		}
1171 		catch( Exception e )
1172 		{
1173 			log.warn( "Failed to load settings from [" + e.getMessage() + "], creating new" );
1174 			settingsDocument = SoapuiSettingsDocumentConfig.Factory.newInstance();
1175 		}
1176 	}
1177 
1178 	private static File importSettingsOnStartup( File settingsFile ) throws Exception
1179 	{
1180 		javax.swing.UIManager.setLookAndFeel(UIManager.getSystemLookAndFeelClassName());
1181 		if( JOptionPane.showConfirmDialog( null, "Missing soapUI Settings, import from existing installation?", 
1182 					"Import Preferences", JOptionPane.YES_NO_OPTION ) == JOptionPane.YES_OPTION )
1183 		{
1184 			while( true )
1185 			{
1186 				settingsFile = SwingFileDialogs.openFile( null, "Import Preferences", ".xml", "soapUI settings XML", settingsFile.getAbsolutePath() );
1187 				if( settingsFile != null )
1188 				{
1189 					try
1190 					{
1191 						settingsDocument = SoapuiSettingsDocumentConfig.Factory.parse( settingsFile );
1192 						log.info( "imported soapui-settings from [" + settingsFile.getAbsolutePath() + "]" );
1193 						break;
1194 					}
1195 					catch( Exception e )
1196 					{
1197 						if( JOptionPane.showConfirmDialog( null, "Error loading settings from [" + settingsFile.getAbsolutePath() + "]\r\nspecify another?", 
1198 									"Error Importing", JOptionPane.OK_CANCEL_OPTION, JOptionPane.ERROR_MESSAGE ) == JOptionPane.CANCEL_OPTION )
1199 						{
1200 							break;
1201 						}
1202 					}
1203 				}
1204 			}
1205 		}
1206 		
1207 		return settingsFile;
1208 	}
1209 
1210 	// instance is null in Eclipse. /Lars
1211 	// eclipse-version(s) should provide SoapUIDesktop implementation
1212 	public static SoapUIDesktop getDesktop()
1213 	{
1214 		return instance != null ? instance.desktop : null;
1215 	}
1216 
1217 	public static void setDesktop( SoapUIDesktop desktop )
1218 	{
1219 		if( instance != null )
1220 			instance.desktop = desktop;
1221 	}
1222 
1223 	public static Navigator getNavigator()
1224 	{
1225 		return instance != null ? instance.navigator : null;
1226 	}
1227 	
1228 	public static SoapUIActionRegistry getActionRegistry()
1229 	{
1230 		return actionRegistry;
1231 	}
1232 
1233 	public static void setNavigator( Navigator navigator )
1234 	{
1235 		if( instance != null )
1236 			instance.navigator = navigator;
1237 	}
1238 
1239 	static class SoapUISplash extends JWindow
1240 	{
1241 		public SoapUISplash( URL splashImage )
1242 		{
1243 			super( frame );
1244 			JLabel l = new JLabel( new ImageIcon( splashImage ) );
1245 			getContentPane().add( l, BorderLayout.CENTER );
1246 			pack();
1247 			Dimension screenSize = Toolkit.getDefaultToolkit().getScreenSize();
1248 			Dimension labelSize = l.getPreferredSize();
1249 			setLocation( screenSize.width / 2 - ( labelSize.width / 2 ), screenSize.height / 2
1250 						- ( labelSize.height / 2 ) );
1251 			addMouseListener( new MouseAdapter()
1252 			{
1253 				public void mousePressed( MouseEvent e )
1254 				{
1255 					if( frame.isVisible())
1256 					{
1257 						setVisible( false );
1258 						dispose();
1259 					}
1260 				}
1261 			} );
1262 			final int pause = 1000;
1263 			final Runnable closerRunner = new Runnable()
1264 			{
1265 				public void run()
1266 				{
1267 					setVisible( false );
1268 					dispose();
1269 				}
1270 			};
1271 			
1272 			Runnable waitRunner = new Runnable()
1273 			{
1274 				public void run()
1275 				{
1276 					try
1277 					{
1278 						do
1279 						{
1280 							Thread.sleep( pause );
1281 						}
1282 						while( !frame.isVisible() );
1283 						
1284 						SwingUtilities.invokeAndWait( closerRunner );
1285 					}
1286 					catch( Exception e )
1287 					{
1288 						SoapUI.logError( e );
1289 						// can catch InvocationTargetException
1290 						// can catch InterruptedException
1291 					}
1292 				}
1293 			};
1294 			setVisible( true );
1295 			Thread splashThread = new Thread( waitRunner, "SplashThread" );
1296 			splashThread.start();
1297 		}
1298 	}
1299 
1300 	public static MockEngine getMockEngine()
1301 	{
1302 		if( mockEngine == null )
1303 			mockEngine = new MockEngine();
1304 			
1305 		return mockEngine;
1306 	}
1307 
1308 	public static String getSchemaDirectory()
1309 	{
1310 		return SoapUI.getSettings().getString( WsdlSettings.SCHEMA_DIRECTORY, null );
1311 	}
1312 
1313 	public static Collection<? extends QName> getExcludedTypes()
1314 	{
1315 		List<QName> result = new ArrayList<QName>();
1316 		
1317 		String excluded = SoapUI.getSettings().getString( WsdlSettings.EXCLUDED_TYPES, null );
1318       if( excluded != null && excluded.trim().length() > 0 )
1319       {
1320     	  	try
1321 			{
1322 			   StringList names = StringList.fromXml( excluded );
1323 			   for( String name : names )
1324 			   {
1325 			   	int ix = name.indexOf( '@' );
1326 			   	result.add( new QName( name.substring( ix+1 ), name.substring( 0, ix )));
1327 			   }
1328 		 	}
1329 			catch( Exception e )
1330 			{
1331 				SoapUI.logError( e );
1332 			}
1333       }
1334       
1335 		return result;
1336 	}
1337 
1338 	public static void setStandalone( boolean b )
1339 	{
1340 		SoapUI.isStandalone = b;
1341 	}
1342 }