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