1
2
3
4
5
6
7
8
9
10
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
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
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
424
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
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
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
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
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
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
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
1211
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
1290
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 }