View Javadoc

1   /*
2    *  soapUI, copyright (C) 2004-2009 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.impl.wsdl.panels.iface;
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.event.ActionEvent;
20  import java.awt.event.MouseAdapter;
21  import java.awt.event.MouseEvent;
22  import java.io.File;
23  import java.io.StringWriter;
24  import java.util.ArrayList;
25  import java.util.Collections;
26  import java.util.Comparator;
27  import java.util.Enumeration;
28  import java.util.HashMap;
29  import java.util.List;
30  import java.util.Map;
31  
32  import javax.swing.AbstractAction;
33  import javax.swing.Action;
34  import javax.swing.BorderFactory;
35  import javax.swing.JButton;
36  import javax.swing.JComponent;
37  import javax.swing.JLabel;
38  import javax.swing.JPanel;
39  import javax.swing.JProgressBar;
40  import javax.swing.JScrollPane;
41  import javax.swing.JSplitPane;
42  import javax.swing.JTabbedPane;
43  import javax.swing.JTree;
44  import javax.swing.SwingUtilities;
45  import javax.swing.event.TreeSelectionEvent;
46  import javax.swing.event.TreeSelectionListener;
47  import javax.swing.table.AbstractTableModel;
48  import javax.swing.tree.DefaultMutableTreeNode;
49  import javax.swing.tree.DefaultTreeModel;
50  import javax.swing.tree.TreePath;
51  import javax.wsdl.BindingOperation;
52  
53  import org.apache.log4j.Logger;
54  import org.apache.xmlbeans.XmlCursor;
55  import org.apache.xmlbeans.XmlLineNumber;
56  import org.apache.xmlbeans.XmlObject;
57  import org.apache.xmlbeans.XmlOptions;
58  import org.jdesktop.swingx.JXTable;
59  import org.syntax.jedit.JEditTextArea;
60  import org.w3c.dom.Element;
61  
62  import com.eviware.soapui.SoapUI;
63  import com.eviware.soapui.actions.SoapUIPreferencesAction;
64  import com.eviware.soapui.impl.support.actions.ShowOnlineHelpAction;
65  import com.eviware.soapui.impl.support.definition.InterfaceDefinitionPart;
66  import com.eviware.soapui.impl.wsdl.WsdlInterface;
67  import com.eviware.soapui.impl.wsdl.WsdlOperation;
68  import com.eviware.soapui.impl.wsdl.actions.iface.CreateWsdlDocumentationAction;
69  import com.eviware.soapui.impl.wsdl.actions.iface.ExportDefinitionAction;
70  import com.eviware.soapui.impl.wsdl.actions.iface.UpdateInterfaceAction;
71  import com.eviware.soapui.impl.wsdl.actions.iface.tools.wsi.WSIAnalyzeAction;
72  import com.eviware.soapui.impl.wsdl.actions.iface.tools.wsi.WSIReportPanel;
73  import com.eviware.soapui.impl.wsdl.panels.teststeps.support.LineNumbersPanel;
74  import com.eviware.soapui.impl.wsdl.support.HelpUrls;
75  import com.eviware.soapui.impl.wsdl.support.wsdl.WsdlUtils;
76  import com.eviware.soapui.impl.wsdl.support.xsd.SchemaUtils;
77  import com.eviware.soapui.model.ModelItem;
78  import com.eviware.soapui.model.iface.Interface;
79  import com.eviware.soapui.model.support.ProjectListenerAdapter;
80  import com.eviware.soapui.support.UISupport;
81  import com.eviware.soapui.support.action.swing.SwingActionDelegate;
82  import com.eviware.soapui.support.components.JEditorStatusBar;
83  import com.eviware.soapui.support.components.JXToolBar;
84  import com.eviware.soapui.support.components.MetricsPanel;
85  import com.eviware.soapui.support.components.ProgressDialog;
86  import com.eviware.soapui.support.components.MetricsPanel.MetricType;
87  import com.eviware.soapui.support.components.MetricsPanel.MetricsSection;
88  import com.eviware.soapui.support.types.StringList;
89  import com.eviware.soapui.support.xml.JXEditTextArea;
90  import com.eviware.soapui.support.xml.XmlUtils;
91  import com.eviware.soapui.ui.support.ModelItemDesktopPanel;
92  import com.eviware.x.dialogs.Worker;
93  import com.eviware.x.dialogs.XProgressDialog;
94  import com.eviware.x.dialogs.XProgressMonitor;
95  import com.jgoodies.forms.builder.ButtonBarBuilder;
96  
97  /***
98   * DesktopPanel for WsdlInterface. Loads all referenced wsdls/xsds for the
99   * specified WsdlInterface and displays these in seperate tabs
100  * 
101  * @author Ole.Matzura
102  */
103 
104 public class WsdlInterfaceDesktopPanel extends ModelItemDesktopPanel<WsdlInterface>
105 {
106 	private final static Logger logger = Logger.getLogger( WsdlInterfaceDesktopPanel.class );
107 	private JTabbedPane partTabs;
108 	private List<JEditTextArea> editors = new ArrayList<JEditTextArea>();
109 	private JTree tree;
110 	private Map<String, DefaultMutableTreeNode> groupNodes = new HashMap<String, DefaultMutableTreeNode>();
111 	private Map<String, TreePath> pathMap = new HashMap<String, TreePath>();
112 	private List<TreePath> navigationHistory = new ArrayList<TreePath>();
113 	private StringList targetNamespaces = new StringList();
114 	private int historyIndex;
115 	private boolean navigating;
116 	private JEditorStatusBar statusBar;
117 	private DefaultMutableTreeNode rootNode;
118 	private DefaultTreeModel treeModel;
119 	private InternalProjectListener projectListener;
120 	private final WsdlInterface iface;
121 	private JPanel wsiPanel;
122 	private WSIReportPanel reportPanel;
123 	private SaveWsiReportAction saveWsiReportAction;
124 	private MetricsPanel metrics;
125 	private boolean updatingInterface;
126 	private OperationsTableModel operationsTableModel;
127 
128 	public WsdlInterfaceDesktopPanel( WsdlInterface iface )
129 	{
130 		super( iface );
131 		this.iface = iface;
132 
133 		try
134 		{
135 			iface.getWsdlContext().loadIfNecessary();
136 			buildUI();
137 		}
138 		catch( Exception e )
139 		{
140 			UISupport.showErrorMessage( e );
141 			SwingUtilities.invokeLater( new Runnable()
142 			{
143 
144 				public void run()
145 				{
146 					SoapUI.getDesktop().closeDesktopPanel( WsdlInterfaceDesktopPanel.this );
147 				}
148 			} );
149 		}
150 	}
151 
152 	private void buildUI()
153 	{
154 		JTabbedPane tabs = new JTabbedPane();
155 		tabs.addTab( "Overview", buildInterfaceOverviewTab() );
156 		tabs.addTab( "Service Endpoints", buildEndpointsTab() );
157 		tabs.addTab( "WSDL Content", buildWsdlContentTab() );
158 		tabs.addTab( "WS-I Compliance", buildWSITab() );
159 
160 		add( UISupport.createTabPanel( tabs, true ), BorderLayout.CENTER );
161 	}
162 
163 	private Component buildWSITab()
164 	{
165 		wsiPanel = new JPanel( new BorderLayout() );
166 		wsiPanel.setBackground( Color.WHITE );
167 		wsiPanel.setOpaque( true );
168 
169 		wsiPanel.add( builderWsiToolbar(), BorderLayout.NORTH );
170 
171 		return wsiPanel;
172 	}
173 
174 	private Component builderWsiToolbar()
175 	{
176 		JXToolBar toolbar = UISupport.createToolbar();
177 
178 		toolbar.addFixed( UISupport.createToolbarButton( new RunWSIAction() ) );
179 		toolbar.addFixed( UISupport.createToolbarButton( new WSIOptionsAction() ) );
180 		toolbar.addRelatedGap();
181 		saveWsiReportAction = new SaveWsiReportAction();
182 		toolbar.addFixed( UISupport.createToolbarButton( saveWsiReportAction ) );
183 
184 		toolbar.addGlue();
185 		toolbar.addFixed( UISupport.createToolbarButton( new ShowOnlineHelpAction( HelpUrls.WSI_COMPLIANCE_HELP_URL ) ) );
186 
187 		return toolbar;
188 	}
189 
190 	private Component buildInterfaceOverviewTab()
191 	{
192 		metrics = new MetricsPanel();
193 		JXToolBar toolbar = UISupport.createSmallToolbar();
194 		toolbar.addGlue();
195 		toolbar.addFixed( UISupport
196 				.createToolbarButton( new ShowOnlineHelpAction( HelpUrls.INTERFACE_OVERVIEW_HELP_URL ) ) );
197 		metrics.add( toolbar, BorderLayout.NORTH );
198 		MetricsSection section = metrics.addSection( "WSDL Definition" );
199 
200 		try
201 		{
202 			section.addMetric( "WSDL URL", MetricType.URL ).set( iface.getDefinition() );
203 			section.addMetric( "Namespace" ).set( iface.getBindingName().getNamespaceURI() );
204 			section.addMetric( "Binding" ).set( iface.getBindingName().getLocalPart() );
205 			section.addMetric( "SOAP Version" ).set( iface.getSoapVersion().toString() );
206 			section.addMetric( "Style" ).set( iface.getStyle() );
207 			section.addMetric( "WS-A version" ).set( iface.getWsaVersion() );
208 		}
209 		catch( Exception e )
210 		{
211 			UISupport.showErrorMessage( e );
212 		}
213 
214 		section.finish();
215 
216 		metrics.addSection( "Definition Parts" );
217 		section = metrics.addSection( "Operations" );
218 		operationsTableModel = new OperationsTableModel();
219 		JXTable table = section.addTable( operationsTableModel );
220 		table.getColumn( 1 ).setPreferredWidth( 60 );
221 		table.getColumn( 2 ).setPreferredWidth( 60 );
222 		section.finish();
223 
224 		table.packColumn( 3, 10 );
225 		if( table.getColumn( 3 ).getPreferredWidth() < 250 )
226 			table.getColumn( 3 ).setPreferredWidth( 250 );
227 
228 		return new JScrollPane( metrics );
229 	}
230 
231 	private Component buildEndpointsTab()
232 	{
233 		return iface.getProject().getEndpointStrategy().getConfigurationPanel( iface );
234 	}
235 
236 	private JComponent buildWsdlContentTab()
237 	{
238 		partTabs = new JTabbedPane();
239 		partTabs.setTabLayoutPolicy( JTabbedPane.SCROLL_TAB_LAYOUT );
240 
241 		rootNode = new DefaultMutableTreeNode( iface.getName() );
242 		treeModel = new DefaultTreeModel( rootNode );
243 		tree = new JTree( treeModel );
244 		tree.setBorder( BorderFactory.createEmptyBorder( 2, 2, 2, 2 ) );
245 		tree.setExpandsSelectedPaths( true );
246 		tree.addTreeSelectionListener( new InternalTreeSelectionListener() );
247 		tree.addMouseListener( new MouseAdapter()
248 		{
249 
250 			@Override
251 			public void mouseClicked( MouseEvent arg0 )
252 			{
253 				if( arg0.getClickCount() > 1 )
254 				{
255 					TreePath selectionPath = tree.getSelectionPath();
256 					if( selectionPath != null )
257 					{
258 						DefaultMutableTreeNode treeNode = ( DefaultMutableTreeNode )selectionPath.getLastPathComponent();
259 						Object userObject = treeNode.getUserObject();
260 						if( userObject instanceof InspectItem )
261 						{
262 							InspectItem item = ( InspectItem )userObject;
263 							if( item != null && item.selector != null )
264 							{
265 								item.selector.selectNode( item );
266 							}
267 						}
268 					}
269 				}
270 			}
271 		} );
272 
273 		JScrollPane scrollPane = new JScrollPane( tree );
274 		JSplitPane split = UISupport.createHorizontalSplit( scrollPane, UISupport.createTabPanel( partTabs, true ) );
275 
276 		split.setDividerLocation( 250 );
277 		split.setResizeWeight( 0.3 );
278 
279 		initTreeModel( iface );
280 
281 		JPanel panel = new JPanel( new BorderLayout() );
282 
283 		panel.add( split, BorderLayout.CENTER );
284 		panel.add( buildWsdlTabToolbar(), BorderLayout.PAGE_START );
285 		statusBar = new JEditorStatusBar();
286 		panel.add( statusBar, BorderLayout.PAGE_END );
287 		setPreferredSize( new Dimension( 600, 500 ) );
288 
289 		projectListener = new InternalProjectListener();
290 		iface.getProject().addProjectListener( projectListener );
291 
292 		return panel;
293 	}
294 
295 	private void initTreeModel( WsdlInterface iface )
296 	{
297 		try
298 		{
299 			if( iface.getWsdlContext().loadIfNecessary() )
300 			{
301 				XProgressDialog progressDialog = UISupport.getDialogs().createProgressDialog( "Loading Defintion", 3,
302 						"Initializing definition..", true );
303 				Loader loader = new Loader( iface );
304 
305 				if( progressDialog != null )
306 					progressDialog.setCancelLabel( "Run in background" );
307 
308 				progressDialog.run( loader );
309 				loader = null;
310 				treeModel.nodeStructureChanged( rootNode );
311 			}
312 		}
313 		catch( Exception e )
314 		{
315 			SoapUI.logError( e );
316 		}
317 	}
318 
319 	private Component buildWsdlTabToolbar()
320 	{
321 		JXToolBar toolbar = UISupport.createToolbar();
322 
323 		toolbar.addFixed( UISupport.createToolbarButton( new BackwardAction() ) );
324 		toolbar.addFixed( UISupport.createToolbarButton( new ForwardAction() ) );
325 		toolbar.addUnrelatedGap();
326 		JButton button = UISupport.createToolbarButton( SwingActionDelegate.createDelegate(
327 				UpdateInterfaceAction.SOAPUI_ACTION_ID, getModelItem(), null, "/updateDefinition.gif" ) );
328 		button.setText( null );
329 		toolbar.addFixed( button );
330 		button = UISupport.createToolbarButton( SwingActionDelegate.createDelegate(
331 				ExportDefinitionAction.SOAPUI_ACTION_ID, getModelItem(), null, "/exportDefinition.gif" ) );
332 		button.setText( null );
333 		toolbar.addFixed( UISupport.createToolbarButton( SwingActionDelegate.createDelegate(
334 				CreateWsdlDocumentationAction.SOAPUI_ACTION_ID, iface, null, "/export.gif" ) ) );
335 		toolbar.addFixed( button );
336 		toolbar.addGlue();
337 		button = UISupport.createToolbarButton( new ShowOnlineHelpAction( HelpUrls.WSDL_CONTENT_HELP_URL ) );
338 		button.setText( null );
339 		toolbar.addFixed( button );
340 
341 		return toolbar;
342 	}
343 
344 	private final class InternalProjectListener extends ProjectListenerAdapter
345 	{
346 		@Override
347 		public void interfaceUpdated( Interface iface )
348 		{
349 			if( iface == getModelItem() )
350 			{
351 				updatingInterface = true;
352 				partTabs.removeAll();
353 				tree.setSelectionRow( -1 );
354 				rootNode.removeAllChildren();
355 				editors.clear();
356 				groupNodes.clear();
357 				pathMap.clear();
358 				targetNamespaces.clear();
359 				initTreeModel( ( WsdlInterface )iface );
360 				operationsTableModel.fireTableDataChanged();
361 				updatingInterface = false;
362 			}
363 		}
364 	}
365 
366 	private final class InternalTreeSelectionListener implements TreeSelectionListener
367 	{
368 		public void valueChanged( TreeSelectionEvent e )
369 		{
370 			TreePath newLeadSelectionPath = e.getNewLeadSelectionPath();
371 			if( newLeadSelectionPath != null )
372 			{
373 				if( !navigating )
374 				{
375 					// if we have moved back in history.. reverse before adding
376 					while( historyIndex < navigationHistory.size() - 1 )
377 					{
378 						TreePath path = navigationHistory.remove( navigationHistory.size() - 1 );
379 						navigationHistory.add( historyIndex++ , path );
380 					}
381 
382 					navigationHistory.add( newLeadSelectionPath );
383 					historyIndex = navigationHistory.size() - 1;
384 				}
385 
386 				DefaultMutableTreeNode tn = ( DefaultMutableTreeNode )newLeadSelectionPath.getLastPathComponent();
387 				if( tn.getUserObject() instanceof InspectItem )
388 				{
389 					InspectItem item = ( InspectItem )tn.getUserObject();
390 
391 					partTabs.setSelectedIndex( item.getTabIndex() );
392 					statusBar.setInfo( item.getDescription() );
393 
394 					JEditTextArea editor = editors.get( item.getTabIndex() );
395 					int lineNumber = item.getLineNumber();
396 					if( lineNumber > 0 && editor.getLineStartOffset( lineNumber ) >= 0 )
397 					{
398 						editor.setCaretPosition( editor.getLineStartOffset( lineNumber ) );
399 					}
400 					else
401 					{
402 						editor.setCaretPosition( 0 );
403 					}
404 				}
405 
406 				tree.scrollPathToVisible( newLeadSelectionPath );
407 				tree.expandPath( newLeadSelectionPath );
408 			}
409 		}
410 	}
411 
412 	private class Loader implements Worker
413 	{
414 		private static final String DEFINITION_PARTS_SECTION = "Definition Parts";
415 		private ProgressDialog progressDialog;
416 		private final WsdlInterface iface;
417 		private JProgressBar progressBar;
418 
419 		public Loader( WsdlInterface iface )
420 		{
421 			this.iface = iface;
422 		}
423 
424 		public Object construct( XProgressMonitor monitor )
425 		{
426 			MetricsSection section = metrics.getSection( DEFINITION_PARTS_SECTION );
427 			section.clear();
428 
429 			try
430 			{
431 				List<InterfaceDefinitionPart> schemas = iface.getWsdlContext().getDefinitionParts();
432 				int tabCount = partTabs.getTabCount();
433 
434 				for( InterfaceDefinitionPart part : schemas )
435 				{
436 					addTab( part.getUrl(), part.getContent() );
437 				}
438 
439 				while( tabCount-- > 0 )
440 					partTabs.remove( 0 );
441 
442 				return null;
443 			}
444 			catch( Exception e )
445 			{
446 				logger.error( "Failed to load WSDL; " + e.getClass().getSimpleName() + "; " + e.getMessage() );
447 				add( new JLabel( "Failed to load WSDL; " + e.toString() ), BorderLayout.NORTH );
448 
449 				SoapUI.logError( e );
450 
451 				return e;
452 			}
453 			finally
454 			{
455 				section.finish();
456 			}
457 
458 		}
459 
460 		private void addTab( String url, String content ) throws Exception
461 		{
462 			int ix = url.startsWith( "file:" ) ? url.lastIndexOf( File.separatorChar ) : url.lastIndexOf( '/' );
463 			if( ix == -1 )
464 				ix = url.lastIndexOf( '/' );
465 
466 			String title = url.substring( ix + 1 );
467 
468 			metrics.getSection( DEFINITION_PARTS_SECTION ).addMetric( title, MetricType.URL ).set( url );
469 
470 			if( progressBar != null )
471 				progressBar.setString( title );
472 			else if( progressDialog != null )
473 				progressDialog.setProgress( 1, title );
474 
475 			JPanel panel = new JPanel( new BorderLayout() );
476 			JLabel label = new JLabel( url );
477 			label.setBorder( BorderFactory.createEmptyBorder( 3, 3, 3, 3 ) );
478 			panel.add( label, BorderLayout.NORTH );
479 
480 			JXEditTextArea inputArea = JXEditTextArea.createXmlEditor( false );
481 			StringWriter writer = new StringWriter();
482 			XmlUtils.serializePretty( XmlObject.Factory.parse( content ), writer );
483 			String xmlString = writer.toString();
484 
485 			// reparse so linenumbers are correct
486 			XmlObject xmlObject = XmlObject.Factory.parse( xmlString, new XmlOptions().setLoadLineNumbers() );
487 
488 			inputArea.setText( xmlString );
489 			inputArea.setEditable( false );
490 			inputArea.getPainter().setLineHighlightEnabled( true );
491 
492 			JPanel p = new JPanel( new BorderLayout() );
493 			p.add( inputArea, BorderLayout.CENTER );
494 			p.add( new LineNumbersPanel( inputArea ), BorderLayout.WEST );
495 
496 			panel.add( new JScrollPane( p ), BorderLayout.CENTER );
497 			partTabs.addTab( title, panel );
498 
499 			if( tree != null )
500 			{
501 				initInspectionTree( xmlObject, inputArea );
502 			}
503 		}
504 
505 		private void initInspectionTree( XmlObject xmlObject, JXEditTextArea inputArea )
506 		{
507 			DefaultMutableTreeNode treeRoot = rootNode;
508 
509 			targetNamespaces.add( SchemaUtils.getTargetNamespace( xmlObject ) );
510 
511 			int tabCount = partTabs.getTabCount() - 1;
512 			mapTreeItems( xmlObject, treeRoot, false, tabCount, "Complex Types",
513 					"declare namespace xs='http://www.w3.org/2001/XMLSchema';//xs:complexType[@name!='']", "@name", true,
514 					null );
515 
516 			mapTreeItems( xmlObject, treeRoot, false, tabCount, "Simple Types",
517 					"declare namespace xs='http://www.w3.org/2001/XMLSchema';//xs:simpleType[@name!='']", "@name", true,
518 					null );
519 
520 			mapTreeItems( xmlObject, treeRoot, false, tabCount, "Anonymous Complex Types",
521 					"declare namespace xs='http://www.w3.org/2001/XMLSchema';//xs:complexType[not(exists(@name))]",
522 					"parent::node()/@name", true, null );
523 
524 			mapTreeItems( xmlObject, treeRoot, false, tabCount, "Global Elements",
525 					"declare namespace xs='http://www.w3.org/2001/XMLSchema';//xs:schema/xs:element[@name!='']", "@name",
526 					true, new GlobalElementSelector() );
527 
528 			mapTreeItems( xmlObject, treeRoot, false, tabCount, "Schemas",
529 					"declare namespace xs='http://www.w3.org/2001/XMLSchema';//xs:schema", "@targetNamespace", true, null );
530 
531 			List<DefaultMutableTreeNode> messages = mapTreeItems( xmlObject, treeRoot, false, tabCount, "Messages",
532 					"declare namespace wsdl='http://schemas.xmlsoap.org/wsdl/';//wsdl:message", "@name", true, null );
533 
534 			for( DefaultMutableTreeNode treeNode : messages )
535 			{
536 				mapTreeItems(
537 						( ( InspectItem )treeNode.getUserObject() ).item,
538 						treeNode,
539 						false,
540 						tabCount,
541 						null,
542 						"declare namespace wsdl='http://schemas.xmlsoap.org/wsdl/';wsdl:part",
543 						"declare namespace wsdl='http://schemas.xmlsoap.org/wsdl/';concat('part: name=[', @name, '] type=[', @type, '] element=[', @element, ']' )",
544 						true, new PartSelector() );
545 			}
546 
547 			List<DefaultMutableTreeNode> portTypes = mapTreeItems( xmlObject, treeRoot, false, tabCount, "PortTypes",
548 					"declare namespace wsdl='http://schemas.xmlsoap.org/wsdl/';//wsdl:portType", "@name", true, null );
549 
550 			for( DefaultMutableTreeNode treeNode : portTypes )
551 			{
552 				List<DefaultMutableTreeNode> operationNodes = mapTreeItems(
553 						( ( InspectItem )treeNode.getUserObject() ).item, treeNode, false, tabCount, null,
554 						"declare namespace wsdl='http://schemas.xmlsoap.org/wsdl/';wsdl:operation", "@name", true, null );
555 
556 				for( DefaultMutableTreeNode treeNode2 : operationNodes )
557 				{
558 					mapTreeItems( ( ( InspectItem )treeNode2.getUserObject() ).item, treeNode2, false, tabCount, null,
559 							"declare namespace wsdl='http://schemas.xmlsoap.org/wsdl/';wsdl:*",
560 							"concat( @name, ' [', local-name(), '], message=[', @message, ']' )", false, new MessageSelector() );
561 				}
562 			}
563 
564 			List<DefaultMutableTreeNode> bindings = mapTreeItems(
565 					xmlObject,
566 					treeRoot,
567 					false,
568 					tabCount,
569 					"Bindings",
570 					"declare namespace wsdl='http://schemas.xmlsoap.org/wsdl/';//wsdl:binding",
571 					"declare namespace wsdlsoap='http://schemas.xmlsoap.org/wsdl/soap/';concat( @name, ' [style=', wsdlsoap:binding[1]/@style, ']' )",
572 					true, null );
573 
574 			for( DefaultMutableTreeNode treeNode : bindings )
575 			{
576 				List<DefaultMutableTreeNode> operationNodes = mapTreeItems(
577 						( ( InspectItem )treeNode.getUserObject() ).item,
578 						treeNode,
579 						false,
580 						tabCount,
581 						null,
582 						"declare namespace wsdl='http://schemas.xmlsoap.org/wsdl/';wsdl:operation",
583 						"declare namespace wsdlsoap='http://schemas.xmlsoap.org/wsdl/soap/';concat( @name, ' [soapAction=', wsdlsoap:operation/@soapAction, ']' )",
584 						true, null );
585 
586 				for( DefaultMutableTreeNode treeNode2 : operationNodes )
587 				{
588 					mapTreeItems( ( ( InspectItem )treeNode2.getUserObject() ).item, treeNode2, false, tabCount, null,
589 							"declare namespace wsdl='http://schemas.xmlsoap.org/wsdl/';wsdl:*",
590 							"concat( @name, ' [', local-name(), ']' )", false, new BindingOperationSelector() );
591 				}
592 			}
593 
594 			List<DefaultMutableTreeNode> services = mapTreeItems( xmlObject, treeRoot, false, tabCount, "Services",
595 					"declare namespace wsdl='http://schemas.xmlsoap.org/wsdl/';//wsdl:service", "@name", true, null );
596 
597 			for( DefaultMutableTreeNode treeNode : services )
598 			{
599 				mapTreeItems( ( ( InspectItem )treeNode.getUserObject() ).item, treeNode, false, tabCount, null,
600 						"declare namespace wsdl='http://schemas.xmlsoap.org/wsdl/';wsdl:port",
601 						"concat( 'port: name=[', @name, '] binding=[', @binding, ']' )", true, new PortSelector() );
602 			}
603 
604 			tree.expandRow( 0 );
605 			editors.add( inputArea );
606 		}
607 
608 		public void finished()
609 		{
610 			if( progressDialog != null )
611 				progressDialog.setVisible( false );
612 
613 			progressDialog = null;
614 		}
615 
616 		public boolean onCancel()
617 		{
618 			progressBar = new JProgressBar( 0, 1 );
619 			progressBar.setSize( new Dimension( 120, 20 ) );
620 			progressBar.setStringPainted( true );
621 			progressBar.setString( "Loading Definition.." );
622 			progressBar.setIndeterminate( true );
623 
624 			ButtonBarBuilder builder = ButtonBarBuilder.createLeftToRightBuilder();
625 			builder.addGlue();
626 			builder.addFixed( progressBar );
627 			builder.addGlue();
628 			builder.setBorder( BorderFactory.createEmptyBorder( 10, 10, 10, 10 ) );
629 
630 			partTabs.addTab( "Loading.. ", builder.getPanel() );
631 			return true;
632 		}
633 	}
634 
635 	public boolean dependsOn( ModelItem modelItem )
636 	{
637 		return modelItem == getModelItem() || modelItem == getModelItem().getProject();
638 	}
639 
640 	public List<DefaultMutableTreeNode> mapTreeItems( XmlObject xmlObject, DefaultMutableTreeNode treeRoot,
641 			boolean createEmpty, int tabIndex, String groupName, String query, String nameQuery, boolean sort,
642 			NodeSelector selector )
643 	{
644 		List<DefaultMutableTreeNode> resultNodes = new ArrayList<DefaultMutableTreeNode>();
645 
646 		try
647 		{
648 			XmlObject[] items = xmlObject.selectPath( query );
649 			List<DefaultMutableTreeNode> treeNodes = new ArrayList<DefaultMutableTreeNode>();
650 
651 			DefaultMutableTreeNode root = treeRoot;
652 			if( groupName != null )
653 			{
654 				String groupKey = new TreePath( root.getPath() ).toString() + "/" + groupName;
655 				root = groupNodes.get( groupKey );
656 				if( root == null && ( items.length > 0 || createEmpty ) )
657 				{
658 					root = new DefaultMutableTreeNode( groupName );
659 					treeRoot.add( root );
660 					groupNodes.put( groupKey, root );
661 				}
662 				else if( root != null )
663 				{
664 					Enumeration<?> children = root.children();
665 					while( children.hasMoreElements() )
666 						treeNodes.add( ( DefaultMutableTreeNode )children.nextElement() );
667 				}
668 			}
669 
670 			if( items.length == 0 )
671 				return resultNodes;
672 
673 			for( XmlObject item : items )
674 			{
675 				XmlObject[] selectPath = item.selectPath( nameQuery );
676 				if( selectPath.length > 0 )
677 				{
678 					DefaultMutableTreeNode treeNode = new DefaultMutableTreeNode( new InspectItem( item, selectPath[0],
679 							tabIndex, selector ) );
680 					treeNodes.add( treeNode );
681 					resultNodes.add( treeNode );
682 				}
683 			}
684 
685 			if( sort )
686 			{
687 				Collections.sort( treeNodes, new Comparator<DefaultMutableTreeNode>()
688 				{
689 
690 					public int compare( DefaultMutableTreeNode o1, DefaultMutableTreeNode o2 )
691 					{
692 						return o1.toString().compareTo( o2.toString() );
693 					}
694 				} );
695 			}
696 
697 			root.removeAllChildren();
698 
699 			for( DefaultMutableTreeNode treeNode : treeNodes )
700 			{
701 				root.add( treeNode );
702 
703 				String path = "/" + getTreeNodeName( treeNode );
704 				TreePath treePath = new TreePath( treeNode.getPath() );
705 				while( treeNode.getParent() != null )
706 				{
707 					treeNode = ( DefaultMutableTreeNode )treeNode.getParent();
708 					path = "/" + getTreeNodeName( treeNode ) + path;
709 				}
710 
711 				pathMap.put( path, treePath );
712 			}
713 		}
714 		catch( Throwable e )
715 		{
716 			SoapUI.log( "Failed to map items for query [" + query + "]:[" + nameQuery + "]" );
717 			SoapUI.logError( e );
718 		}
719 
720 		return resultNodes;
721 	}
722 
723 	private String getTreeNodeName( DefaultMutableTreeNode treeNode )
724 	{
725 		Object userObject = treeNode.getUserObject();
726 		if( userObject instanceof InspectItem )
727 			return ( ( InspectItem )userObject ).getName();
728 		else
729 			return treeNode.toString();
730 	}
731 
732 	private final class InspectItem
733 	{
734 		private final XmlObject item;
735 		private String name;
736 		private final int tabIndex;
737 		private XmlLineNumber lineNumber;
738 		private final NodeSelector selector;
739 
740 		public InspectItem( XmlObject item, XmlObject nameObj, int tabIndex, NodeSelector selector )
741 		{
742 			this.item = item;
743 			this.selector = selector;
744 			this.name = XmlUtils.getNodeValue( nameObj.getDomNode() );
745 			if( name == null )
746 				name = nameObj.toString();
747 			this.tabIndex = tabIndex;
748 
749 			ArrayList<?> list = new ArrayList<Object>();
750 			XmlCursor cursor = item.newCursor();
751 			cursor.getAllBookmarkRefs( list );
752 
753 			for( Object o : list )
754 				if( o instanceof XmlLineNumber )
755 					lineNumber = ( XmlLineNumber )o;
756 
757 			cursor.dispose();
758 		}
759 
760 		public String getDescription()
761 		{
762 			return getName() + "@" + targetNamespaces.get( tabIndex );
763 		}
764 
765 		public String getName()
766 		{
767 			int ix = name.indexOf( ' ' );
768 			return ix == -1 ? name : name.substring( 0, ix );
769 		}
770 
771 		public int getTabIndex()
772 		{
773 			return tabIndex;
774 		}
775 
776 		public int getLineNumber()
777 		{
778 			return lineNumber == null ? -1 : lineNumber.getLine() - 1;
779 		}
780 
781 		@Override
782 		public String toString()
783 		{
784 			return name;
785 		}
786 
787 		public NodeSelector getSelector()
788 		{
789 			return selector;
790 		}
791 
792 		public Element getElement()
793 		{
794 			return ( Element )item.getDomNode();
795 		}
796 	}
797 
798 	public boolean onClose( boolean canCancel )
799 	{
800 		if( projectListener != null )
801 			getModelItem().getProject().removeProjectListener( projectListener );
802 
803 		return release();
804 	}
805 
806 	private void simpleSelect( InspectItem item, String attribute, String targetGroup )
807 	{
808 		Element elm = item.getElement();
809 		String type = elm.getAttribute( attribute );
810 		if( type.length() > 0 )
811 		{
812 			int ix = type.indexOf( ':' );
813 			if( ix != -1 )
814 				type = type.substring( ix + 1 );
815 
816 			TreePath treePath = pathMap.get( "/" + getModelItem().getName() + "/" + targetGroup + "/" + type );
817 			if( treePath != null )
818 			{
819 				tree.setSelectionPath( treePath );
820 			}
821 		}
822 	}
823 
824 	protected interface NodeSelector
825 	{
826 		public void selectNode( InspectItem item );
827 	}
828 
829 	public class PartSelector implements NodeSelector
830 	{
831 		public void selectNode( InspectItem item )
832 		{
833 			Element elm = item.getElement();
834 			String type = elm.getAttribute( "type" );
835 			String element = elm.getAttribute( "element" );
836 			if( type.length() > 0 )
837 			{
838 				simpleSelect( item, "type", "Complex Types" );
839 			}
840 			else if( element.length() > 0 )
841 			{
842 				simpleSelect( item, "element", "Global Elements" );
843 			}
844 		}
845 	}
846 
847 	public class MessageSelector implements NodeSelector
848 	{
849 		public void selectNode( InspectItem item )
850 		{
851 			simpleSelect( item, "message", "Messages" );
852 		}
853 	}
854 
855 	public class GlobalElementSelector implements NodeSelector
856 	{
857 		public void selectNode( InspectItem item )
858 		{
859 			simpleSelect( item, "type", "Complex Types" );
860 		}
861 	}
862 
863 	public class PortSelector implements NodeSelector
864 	{
865 		public void selectNode( InspectItem item )
866 		{
867 			simpleSelect( item, "binding", "Bindings" );
868 		}
869 	}
870 
871 	public class BindingOperationSelector implements NodeSelector
872 	{
873 		public void selectNode( InspectItem item )
874 		{
875 			Element elm = item.getElement();
876 			String name = elm.getAttribute( "name" );
877 
878 			Element operationElm = ( Element )elm.getParentNode();
879 			Element bindingElm = ( Element )operationElm.getParentNode();
880 
881 			String type = bindingElm.getAttribute( "type" );
882 
883 			if( type.length() > 0 )
884 			{
885 				int ix = type.indexOf( ':' );
886 				if( ix != -1 )
887 					type = type.substring( ix + 1 );
888 
889 				TreePath treePath = pathMap.get( "/" + getModelItem().getName() + "/PortTypes/" + type + "/"
890 						+ operationElm.getAttribute( "name" ) + "/" + name );
891 				if( treePath != null )
892 				{
893 					tree.setSelectionPath( treePath );
894 				}
895 			}
896 		}
897 	}
898 
899 	private class BackwardAction extends AbstractAction
900 	{
901 		public BackwardAction()
902 		{
903 			putValue( SMALL_ICON, UISupport.createImageIcon( "/arrow_left.png" ) );
904 			putValue( Action.SHORT_DESCRIPTION, "Navigate to previous selection" );
905 		}
906 
907 		public void actionPerformed( ActionEvent arg0 )
908 		{
909 			if( historyIndex > 0 )
910 			{
911 				historyIndex-- ;
912 				navigating = true;
913 				tree.setSelectionPath( navigationHistory.get( historyIndex ) );
914 				navigating = false;
915 			}
916 		}
917 	}
918 
919 	private class ForwardAction extends AbstractAction
920 	{
921 		public ForwardAction()
922 		{
923 			putValue( SMALL_ICON, UISupport.createImageIcon( "/arrow_right.png" ) );
924 			putValue( Action.SHORT_DESCRIPTION, "Navigate to next selection" );
925 		}
926 
927 		public void actionPerformed( ActionEvent arg0 )
928 		{
929 			if( historyIndex < navigationHistory.size() - 1 )
930 			{
931 				historyIndex++ ;
932 				navigating = true;
933 				tree.setSelectionPath( navigationHistory.get( historyIndex ) );
934 				navigating = false;
935 			}
936 
937 		}
938 	}
939 
940 	private class RunWSIAction extends AbstractAction
941 	{
942 		public RunWSIAction()
943 		{
944 			putValue( SMALL_ICON, UISupport.createImageIcon( "/run.gif" ) );
945 			putValue( Action.SHORT_DESCRIPTION, "Creates a WS-I report for this interface" );
946 		}
947 
948 		public void actionPerformed( ActionEvent arg0 )
949 		{
950 			WSIAnalyzeAction action = new WSIAnalyzeAction()
951 			{
952 				@Override
953 				protected void showReport( File reportFile, String configFile ) throws Exception
954 				{
955 					reportPanel = new WSIReportPanel( reportFile, configFile, null, false );
956 					reportPanel.setPreferredSize( new Dimension( 600, 400 ) );
957 					if( wsiPanel.getComponentCount() > 1 )
958 						wsiPanel.remove( 1 );
959 
960 					wsiPanel.add( reportPanel, BorderLayout.CENTER );
961 					wsiPanel.revalidate();
962 					saveWsiReportAction.setEnabled( true );
963 				}
964 			};
965 
966 			action.perform( getModelItem(), null );
967 		}
968 	}
969 
970 	private class WSIOptionsAction extends AbstractAction
971 	{
972 		public WSIOptionsAction()
973 		{
974 			putValue( SMALL_ICON, UISupport.createImageIcon( "/options.gif" ) );
975 			putValue( Action.SHORT_DESCRIPTION, "Sets WS-I report creation options" );
976 		}
977 
978 		public void actionPerformed( ActionEvent arg0 )
979 		{
980 			SoapUIPreferencesAction.getInstance().show( SoapUIPreferencesAction.WS_I_SETTINGS );
981 		}
982 	}
983 
984 	private class SaveWsiReportAction extends AbstractAction
985 	{
986 		public SaveWsiReportAction()
987 		{
988 			putValue( SMALL_ICON, UISupport.createImageIcon( "/export.gif" ) );
989 			putValue( Action.SHORT_DESCRIPTION, "Saved the current WS-I report to a file" );
990 
991 			setEnabled( false );
992 		}
993 
994 		public void actionPerformed( ActionEvent arg0 )
995 		{
996 			if( reportPanel != null )
997 				reportPanel.getSaveReportAction().actionPerformed( null );
998 		}
999 	}
1000 
1001 	private class OperationsTableModel extends AbstractTableModel
1002 	{
1003 		public int getColumnCount()
1004 		{
1005 			return 4;
1006 		}
1007 
1008 		public int getRowCount()
1009 		{
1010 			return iface.getOperationCount();
1011 		}
1012 
1013 		@Override
1014 		public String getColumnName( int column )
1015 		{
1016 			switch( column )
1017 			{
1018 			case 0 :
1019 				return "Name";
1020 			case 1 :
1021 				return "Use";
1022 			case 2 :
1023 				return "One-Way";
1024 			case 3 :
1025 				return "Action";
1026 			}
1027 
1028 			return null;
1029 		}
1030 
1031 		public Object getValueAt( int rowIndex, int columnIndex )
1032 		{
1033 			if( updatingInterface )
1034 				return "<updating>";
1035 
1036 			WsdlOperation operation = iface.getOperationAt( rowIndex );
1037 			BindingOperation bindingOperation = operation.getBindingOperation();
1038 
1039 			switch( columnIndex )
1040 			{
1041 			case 0 :
1042 				return operation.getName();
1043 			case 1 :
1044 			{
1045 				boolean in = WsdlUtils.isInputSoapEncoded( bindingOperation );
1046 				boolean out = operation.isUnidirectional() ? false : WsdlUtils.isOutputSoapEncoded( bindingOperation );
1047 
1048 				if( out && in )
1049 					return "SOAP Encoding";
1050 				if( !out && !in )
1051 					return "Literal";
1052 
1053 				return "Mixed";
1054 			}
1055 			case 3 :
1056 				return operation.getAction();
1057 			case 2 :
1058 				return Boolean.valueOf( operation.isUnidirectional() );
1059 			}
1060 
1061 			return null;
1062 		}
1063 	}
1064 }