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;
14  
15  import java.util.ArrayList;
16  import java.util.Arrays;
17  import java.util.HashMap;
18  import java.util.HashSet;
19  import java.util.Iterator;
20  import java.util.List;
21  import java.util.Map;
22  import java.util.Set;
23  
24  import javax.wsdl.Binding;
25  import javax.wsdl.BindingOperation;
26  import javax.wsdl.Definition;
27  import javax.wsdl.Port;
28  import javax.wsdl.Service;
29  import javax.xml.namespace.QName;
30  
31  import org.apache.log4j.Logger;
32  
33  import com.eviware.soapui.SoapUI;
34  import com.eviware.soapui.config.DefinitionCacheConfig;
35  import com.eviware.soapui.config.EndpointsConfig;
36  import com.eviware.soapui.config.InterfaceConfig;
37  import com.eviware.soapui.config.OperationConfig;
38  import com.eviware.soapui.config.SoapVersionTypesConfig;
39  import com.eviware.soapui.impl.wsdl.mock.WsdlMockResponse;
40  import com.eviware.soapui.impl.wsdl.support.soap.SoapMessageBuilder;
41  import com.eviware.soapui.impl.wsdl.support.soap.SoapVersion;
42  import com.eviware.soapui.impl.wsdl.support.wsdl.CachedWsdlLoader;
43  import com.eviware.soapui.impl.wsdl.support.wsdl.UrlWsdlLoader;
44  import com.eviware.soapui.impl.wsdl.support.wsdl.WsdlContext;
45  import com.eviware.soapui.impl.wsdl.support.wsdl.WsdlLoader;
46  import com.eviware.soapui.impl.wsdl.support.wsdl.WsdlUtils;
47  import com.eviware.soapui.impl.wsdl.teststeps.WsdlTestRequest;
48  import com.eviware.soapui.impl.wsdl.teststeps.WsdlTestRequestStep;
49  import com.eviware.soapui.model.ModelItem;
50  import com.eviware.soapui.model.iface.Interface;
51  import com.eviware.soapui.model.iface.InterfaceListener;
52  import com.eviware.soapui.model.iface.Operation;
53  import com.eviware.soapui.settings.WsdlSettings;
54  import com.eviware.soapui.support.UISupport;
55  import com.eviware.soapui.support.types.StringList;
56  
57  /***
58   * WSDL implementation of Interface, maps to a WSDL Binding
59   * 
60   * @author Ole.Matzura
61   */
62  
63  public class WsdlInterface extends AbstractWsdlModelItem<InterfaceConfig> implements Interface
64  {
65  	public static final String STYLE_DOCUMENT = "Document";
66  	public static final String STYLE_RPC = "RPC";
67  
68  	public static final String JBOSSWS_ACTIONS = "jbossws";
69  	public static final String WSTOOLS_ACTIONS = "wstools";
70  	public static final String XML_ACTIONS = "xml";
71  
72  	private final static Logger log = Logger.getLogger( WsdlInterface.class );
73  	private List<WsdlOperation> operations = new ArrayList<WsdlOperation>();
74  	private WsdlProject project;
75  	private SoapMessageBuilder soapMessageBuilder;
76  	private WsdlContext wsdlContext;
77  	private Set<InterfaceListener> interfaceListeners = new HashSet<InterfaceListener>();
78  	private boolean updating = false;
79  
80  	public WsdlInterface( WsdlProject project, InterfaceConfig interfaceConfig )
81  	{
82  		super( interfaceConfig, project, "/interface2.gif" );
83  
84  		this.project = project;
85  
86  		if( interfaceConfig.getEndpoints() == null )
87  			interfaceConfig.addNewEndpoints();
88  
89  		List<OperationConfig> operationConfigs = interfaceConfig.getOperationList();
90  		for( int i = 0; i < operationConfigs.size(); i++ )
91  		{
92  			operations.add( new WsdlOperation( this, operationConfigs.get( i ) ) );
93  		}
94  
95  		for( InterfaceListener listener : SoapUI.getListenerRegistry().getListeners( InterfaceListener.class ) )
96  		{
97  			addInterfaceListener( listener );
98  		}
99  	}
100 
101 	public String[] getEndpoints()
102 	{
103 		EndpointsConfig endpoints = getConfig().getEndpoints();
104 		List<String> endpointArray = endpoints.getEndpointList();
105 		return endpointArray.toArray( new String[endpointArray.size()] );
106 	}
107 
108 	public WsdlOperation getOperationAt( int index )
109 	{
110 		return operations.get( index );
111 	}
112 
113 	public int getOperationCount()
114 	{
115 		return operations.size();
116 	}
117 	
118 	public WsdlOperation addNewOperation( BindingOperation operation )
119 	{
120 		WsdlOperation operationImpl = new WsdlOperation( this, getConfig().addNewOperation() );
121 		operations.add( operationImpl );
122 
123 		operationImpl.initFromBindingOperation( operation );
124 		fireOperationAdded( operationImpl );
125 		return operationImpl;
126 	}
127 
128 	public WsdlProject getProject()
129 	{
130 		return project;
131 	}
132 
133 	public void addEndpoint( String endpoint )
134 	{
135 		if( endpoint == null || endpoint.trim().length() == 0 )
136 			return;
137 
138 		endpoint = endpoint.trim();
139 		String[] endpoints = getEndpoints();
140 
141 		// dont add the same endpoint twice
142 		if( Arrays.asList( endpoints ).contains( endpoint ) )
143 			return;
144 
145 		getConfig().getEndpoints().addNewEndpoint().setStringValue( endpoint );
146 
147 		notifyPropertyChanged( ENDPOINT_PROPERTY, null, endpoint );
148 	}
149 
150 	public void changeEndpoint( String oldEndpoint, String newEndpoint )
151 	{
152 		if( oldEndpoint == null || oldEndpoint.trim().length() == 0 )
153 			return;
154 		if( newEndpoint == null || newEndpoint.trim().length() == 0 )
155 			return;
156 
157 		EndpointsConfig endpoints = getConfig().getEndpoints();
158 
159 		for( int c = 0; c < endpoints.sizeOfEndpointArray(); c++ )
160 		{
161 			if( endpoints.getEndpointArray( c ).equals( oldEndpoint ) )
162 			{
163 				endpoints.setEndpointArray( c, newEndpoint );
164 				notifyPropertyChanged( ENDPOINT_PROPERTY, oldEndpoint, newEndpoint );
165 				break;
166 			}
167 		}
168 	}
169 
170 	public void removeEndpoint( String endpoint )
171 	{
172 		EndpointsConfig endpoints = getConfig().getEndpoints();
173 
174 		for( int c = 0; c < endpoints.sizeOfEndpointArray(); c++ )
175 		{
176 			if( endpoints.getEndpointArray( c ).equals( endpoint ) )
177 			{
178 				endpoints.removeEndpoint( c );
179 				notifyPropertyChanged( ENDPOINT_PROPERTY, endpoint, null );
180 				break;
181 			}
182 		}
183 	}
184 
185 	public void setDefinition( String wsdlUrl, boolean cache )
186 	{
187 		String old = getDefinition();
188 
189 		getConfig().setDefinition( wsdlUrl );
190 
191 		if( wsdlContext != null )
192 		{
193 			wsdlContext.setDefinition( wsdlUrl, getConfig().getDefinitionCache() );
194 			wsdlContext.setSoapVersion( getSoapVersion() );
195 		}
196 
197 		notifyPropertyChanged( DEFINITION_PROPERTY, old, wsdlUrl );
198 	}
199 
200 	public DefinitionCacheConfig cacheDefinition( WsdlLoader loader ) throws Exception
201 	{
202 		log.debug( "Caching definition for [" + loader.getBaseURI() + "]" );
203 		if( getConfig().isSetDefinitionCache() )
204 			getConfig().unsetDefinitionCache();
205 
206 		DefinitionCacheConfig definitionCache = getConfig().addNewDefinitionCache();
207 		definitionCache.set( WsdlLoader.cacheWsdl( loader ) );
208 		return definitionCache;
209 	}
210 
211 	public String getDefinition()
212 	{
213 		return getConfig().isSetDefinition() ? getConfig().getDefinition() : null;
214 	}
215 
216 	public synchronized WsdlContext getWsdlContext()
217 	{
218 		if( wsdlContext == null )
219 		{
220 			wsdlContext = new WsdlContext( getDefinition(), getSoapVersion(), getConfig().getDefinitionCache(), this );
221 		}
222 
223 		return wsdlContext;
224 	}
225 
226 	/***
227 	 * Used by importer so we dont need to reload the context after importing..
228 	 * 
229 	 * @param wsdlContext
230 	 */
231 
232 	public void setWsdlContext( WsdlContext wsdlContext )
233 	{
234 		this.wsdlContext = wsdlContext;
235 		this.wsdlContext.setSoapVersion( getSoapVersion() );
236 		this.wsdlContext.setInterface( this );
237 
238 		if( !getConfig().isSetDefinitionCache() )
239 			getConfig().addNewDefinitionCache();
240 
241 		if( wsdlContext.getCacheConfig() != null )
242 		{
243 			// use cache from context
244 			getConfig().setDefinitionCache( wsdlContext.getCacheConfig() );
245 		}
246 	}
247 
248 	public SoapMessageBuilder getMessageBuilder()
249 	{
250 		if( soapMessageBuilder == null )
251 		{
252 			try
253 			{
254 				soapMessageBuilder = new SoapMessageBuilder( this );
255 			}
256 			catch( Exception e )
257 			{
258 				SoapUI.logError( e );
259 			}
260 		}
261 		return soapMessageBuilder;
262 	}
263 
264 	public void setSoapMessageBuilder( SoapMessageBuilder builder )
265 	{
266 		soapMessageBuilder = builder;
267 		soapMessageBuilder.setInterface( this );
268 	}
269 
270 	public QName getBindingName()
271 	{
272 		return getConfig().getBindingName() == null ? null : QName.valueOf( getConfig().getBindingName() );
273 	}
274 
275 	public void setBindingName( QName name )
276 	{
277 		getConfig().setBindingName( name.toString() );
278 	}
279 
280 	public SoapVersion getSoapVersion()
281 	{
282 		if( getConfig().getSoapVersion() == SoapVersionTypesConfig.X_1_2 )
283 			return SoapVersion.Soap12;
284 
285 		return SoapVersion.Soap11;
286 	}
287 
288 	public void setSoapVersion( SoapVersion version )
289 	{
290 		if( version == SoapVersion.Soap11 )
291 			getConfig().setSoapVersion( SoapVersionTypesConfig.X_1_1 );
292 		else if( version == SoapVersion.Soap12 )
293 			getConfig().setSoapVersion( SoapVersionTypesConfig.X_1_2 );
294 		else
295 			throw new RuntimeException( "Unknown soapVersion [" + version + "], must be 1.1 or 1.2" );
296 
297 		getWsdlContext().setSoapVersion( version );
298 	}
299 
300 	public boolean updateDefinition( String url, boolean createRequests ) throws Exception
301 	{
302 		if( getConfig().isSetDefinitionCache() )
303 			getConfig().unsetDefinitionCache();
304 
305 		WsdlContext newContext = getNewContext( url, getSettings().getBoolean( WsdlSettings.CACHE_WSDLS ) );
306 		if( !newContext.load() )
307 		{
308 			return false;
309 		}
310 
311 		BindingTuple tuple = findBinding( newContext );
312 		if( tuple == null )
313 			return false;
314 
315 		setBindingName( tuple.binding.getQName() );
316 
317 		// update name
318 		if( getSettings().getBoolean( WsdlSettings.NAME_WITH_BINDING ) )
319 			setName( tuple.binding.getQName().getLocalPart() );
320 
321 		// update context
322 		wsdlContext = newContext;
323 		if( soapMessageBuilder != null )
324 			soapMessageBuilder.setWsdlContext( wsdlContext );
325 
326 		transferOperations( tuple.binding, createRequests );
327 
328 		setDefinition( url, false );
329 
330 		transferEndpoints( tuple.port );
331 
332 		getProject().fireInterfaceUpdated( this );
333 
334 		return true;
335 	}
336 
337 	public BindingTuple prepareUpdateDefinition( String url ) throws Exception
338 	{
339 		WsdlContext newContext = getNewContext( url, false );
340 		if( !newContext.load() )
341 		{
342 			return null;
343 		}
344 
345 		BindingTuple tuple = findBinding( newContext );
346 		return tuple;
347 	}
348 
349 	public void updateDefinition( BindingTuple tuple ) throws Exception
350 	{
351 		setBindingName( tuple.binding.getQName() );
352 
353 		if( getConfig().isSetDefinitionCache() )
354 			getConfig().unsetDefinitionCache();
355 
356 		// update name
357 		if( getSettings().getBoolean( WsdlSettings.NAME_WITH_BINDING ) )
358 			setName( tuple.binding.getQName().getLocalPart() );
359 
360 		// update context
361 		wsdlContext = tuple.context;
362 		if( soapMessageBuilder != null )
363 			soapMessageBuilder.setWsdlContext( wsdlContext );
364 	}
365 
366 	private WsdlContext getNewContext( String url, boolean cache )
367 	{
368 		if( !cache )
369 		{
370 			return new WsdlContext( url, getSoapVersion(), null, null );
371 		}
372 		else
373 		{
374 			return new WsdlContext( url, getSoapVersion(), null, this );
375 		}
376 	}
377 
378 	public BindingOperation findBindingOperation( Definition definition, String bindingOperationName, String inputName,
379 				String outputName )
380 	{
381 		Binding binding = definition.getBinding( getBindingName() );
382 		return WsdlUtils.findBindingOperation( binding, bindingOperationName, inputName, outputName );
383 	}
384 
385 	@SuppressWarnings( "unchecked" )
386 	private BindingTuple findBinding( WsdlContext newContext ) throws Exception
387 	{
388 		BindingTuple tuple = new BindingTuple();
389 		tuple.context = newContext;
390 
391 		// start by finding the old binding in the new definition
392 		Definition definition = newContext.getDefinition();
393 		Map serviceMap = definition.getAllServices();
394 		Iterator<String> i = serviceMap.keySet().iterator();
395 		while( i.hasNext() )
396 		{
397 			tuple.service = ( Service ) serviceMap.get( i.next() );
398 			Map portMap = tuple.service.getPorts();
399 
400 			Iterator i2 = portMap.keySet().iterator();
401 			while( i2.hasNext() )
402 			{
403 				tuple.port = ( Port ) portMap.get( i2.next() );
404 				if( tuple.port.getBinding().getQName().equals( getBindingName() ) )
405 				{
406 					tuple.binding = tuple.port.getBinding();
407 				}
408 			}
409 
410 			if( tuple.binding != null )
411 				break;
412 			tuple.service = null;
413 		}
414 
415 		if( tuple.service == null && tuple.binding == null )
416 		{
417 			tuple.binding = definition.getBinding( getBindingName() );
418 		}
419 
420 		// missing matching binding, prompt for new one to use instead (will
421 		// happen if binding has been renamed)
422 		if( tuple.binding == null )
423 		{
424 			Map bindings = definition.getAllBindings();
425 
426 			Object retval = UISupport.prompt( "Missing matching binding [" + getBindingName()
427 						+ "] in definition, select new\nbinding to map to", "Map Binding", bindings.keySet().toArray() );
428 
429 			if( retval == null )
430 				return null;
431 
432 			tuple.binding = ( Binding ) bindings.get( retval );
433 		}
434 
435 		return tuple;
436 	}
437 
438 	@SuppressWarnings( "unchecked" )
439 	public void transferOperations( Binding binding, boolean createRequests )
440 	{
441 		// prepare for transfer of operations/requests
442 		List<BindingOperation> newOperations = new ArrayList<BindingOperation>( binding.getBindingOperations() );
443 		Map<String, WsdlOperation> oldOperations = new HashMap<String, WsdlOperation>();
444 		for( int c = 0; c < operations.size(); c++ )
445 			oldOperations.put( operations.get( c ).getBindingOperationName(), operations.get( c ) );
446 
447 		// clear existing from both collections
448 		for( int c = 0; c < newOperations.size(); c++ )
449 		{
450 			BindingOperation newOperation = newOperations.get( c );
451 			String bindingOperationName = newOperation.getName();
452 			if( oldOperations.containsKey( bindingOperationName ) )
453 			{
454 				log.info( "Synchronizing existing operation [" + bindingOperationName + "]" );
455 				WsdlOperation wsdlOperation = oldOperations.get( bindingOperationName );
456 				wsdlOperation.initFromBindingOperation( newOperation );
457 				fireOperationUpdated( wsdlOperation );
458 
459 				oldOperations.remove( bindingOperationName );
460 				newOperations.remove( c );
461 				c--;
462 			}
463 		}
464 
465 		// remove leftover operations
466 		Iterator<String> i = oldOperations.keySet().iterator();
467 		while( i.hasNext() )
468 		{
469 			String name = i.next();
470 
471 			if( newOperations.size() > 0 )
472 			{
473 				List<String> list = new ArrayList<String>();
474 				list.add( "none - delete operation" );
475 				for( int c = 0; c < newOperations.size(); c++ )
476 					list.add( newOperations.get( c ).getName() );
477 
478 				String retval = ( String ) UISupport.prompt( "Binding operation [" + name
479 							+ "] not found in new interface, select new\nbinding operation to map to", "Map Operation", list
480 							.toArray(), "none/cancel - delete operation" );
481 
482 				int ix = retval == null ? -1 : list.indexOf( retval ) - 1;
483 
484 				// delete operation?
485 				if( ix < 0 )
486 				{
487 					deleteOperation( name );
488 				}
489 				// change operation?
490 				else
491 				{
492 					BindingOperation newOperation = newOperations.get( ix );
493 					WsdlOperation wsdlOperation = oldOperations.get( name );
494 					wsdlOperation.initFromBindingOperation( newOperation );
495 					fireOperationUpdated( wsdlOperation );
496 					newOperations.remove( ix );
497 				}
498 
499 				oldOperations.remove( name );
500 			}
501 			else
502 			{
503 				deleteOperation( name );
504 				oldOperations.remove( name );
505 			}
506 
507 			i = oldOperations.keySet().iterator();
508 		}
509 
510 		// add leftover new operations
511 		if( newOperations.size() > 0 )
512 		{
513 			for( int c = 0; c < newOperations.size(); c++ )
514 			{
515 				BindingOperation newOperation = newOperations.get( c );
516 				WsdlOperation wsdlOperation = addNewOperation( newOperation );
517 
518 				if( createRequests )
519 				{
520 					WsdlRequest request = wsdlOperation.addNewRequest( "Request 1" );
521 					try
522 					{
523 						request.setRequestContent( wsdlOperation.createRequest( true ) );
524 					}
525 					catch( Exception e )
526 					{
527 						SoapUI.logError( e );
528 					}
529 				}
530 			}
531 		}
532 	}
533 
534 	public void transferEndpoints( Port port )
535 	{
536 		if( port != null )
537 		{
538 			String endpoint = WsdlUtils.getSoapEndpoint( port );
539 			if( endpoint != null )
540 			{
541 				StringList list = new StringList( getEndpoints() );
542 				if( !list.contains( endpoint ) )
543 				{
544 					if( UISupport.confirm( "Update existing requests with new endpoint\n[" + endpoint + "]",
545 								"Update Definition" ) )
546 					{
547 						for( int c = 0; c < getOperationCount(); c++ )
548 						{
549 							Operation operation = getOperationAt( c );
550 
551 							for( int ix = 0; ix < operation.getRequestCount(); ix++ )
552 							{
553 								operation.getRequestAt( ix ).setEndpoint( endpoint );
554 							}
555 						}
556 					}
557 
558 					addEndpoint( endpoint );
559 				}
560 			}
561 		}
562 	}
563 
564 	public void deleteOperation( String bindingOperationName )
565 	{
566 		for( int c = 0; c < operations.size(); c++ )
567 		{
568 			WsdlOperation wsdlOperation = operations.get( c );
569 			if( wsdlOperation.getBindingOperationName().equals( bindingOperationName ) )
570 			{
571 				log.info( "deleting operation [" + bindingOperationName + "]" );
572 
573 				// remove requests first (should this be done by some listener?)
574 				while( wsdlOperation.getRequestCount() > 0 )
575 					wsdlOperation.removeRequest( wsdlOperation.getRequestAt( 0 ) );
576 
577 				operations.remove( c );
578 
579 				try
580 				{
581 					fireOperationRemoved( wsdlOperation );
582 				}
583 				finally
584 				{
585 					wsdlOperation.release();
586 					getConfig().removeOperation( c );
587 				}
588 
589 				return;
590 			}
591 		}
592 	}
593 
594 	public void fireOperationAdded( WsdlOperation operation )
595 	{
596 		InterfaceListener[] a = interfaceListeners.toArray( new InterfaceListener[interfaceListeners.size()] );
597 
598 		for( int c = 0; c < a.length; c++ )
599 		{
600 			a[c].operationAdded( operation );
601 		}
602 	}
603 
604 	public void fireOperationUpdated( WsdlOperation operation )
605 	{
606 		InterfaceListener[] a = interfaceListeners.toArray( new InterfaceListener[interfaceListeners.size()] );
607 
608 		for( int c = 0; c < a.length; c++ )
609 		{
610 			a[c].operationUpdated( operation );
611 		}
612 	}
613 
614 	public void fireOperationRemoved( WsdlOperation operation )
615 	{
616 		InterfaceListener[] a = interfaceListeners.toArray( new InterfaceListener[interfaceListeners.size()] );
617 
618 		for( int c = 0; c < a.length; c++ )
619 		{
620 			a[c].operationRemoved( operation );
621 		}
622 	}
623 
624 	public void fireRequestAdded( WsdlRequest request )
625 	{
626 		InterfaceListener[] a = interfaceListeners.toArray( new InterfaceListener[interfaceListeners.size()] );
627 
628 		for( int c = 0; c < a.length; c++ )
629 		{
630 			a[c].requestAdded( request );
631 		}
632 	}
633 
634 	public void fireRequestRemoved( WsdlRequest request )
635 	{
636 		InterfaceListener[] a = interfaceListeners.toArray( new InterfaceListener[interfaceListeners.size()] );
637 
638 		for( int c = 0; c < a.length; c++ )
639 		{
640 			a[c].requestRemoved( request );
641 		}
642 	}
643 
644 	public void addInterfaceListener( InterfaceListener listener )
645 	{
646 		interfaceListeners.add( listener );
647 	}
648 
649 	public void removeInterfaceListener( InterfaceListener listener )
650 	{
651 		interfaceListeners.remove( listener );
652 	}
653 
654 	public WsdlOperation getOperationByName( String name )
655 	{
656 		return ( WsdlOperation ) getWsdlModelItemByName( operations, name );
657 	}
658 
659 	public boolean isCached()
660 	{
661 		return getConfig().isSetDefinitionCache();
662 	}
663 
664 	public WsdlLoader createWsdlLoader()
665 	{
666 		return isCached() ? new CachedWsdlLoader( getConfig().getDefinitionCache() )
667 					: new UrlWsdlLoader( getDefinition() );
668 	}
669 
670 	public void clearCache()
671 	{
672 		if( wsdlContext != null )
673 			wsdlContext.setDefinitionCache( null );
674 
675 		if( getConfig().isSetDefinitionCache() )
676 			getConfig().unsetDefinitionCache();
677 	}
678 
679 	public String getStyle()
680 	{
681 		if( wsdlContext == null || !wsdlContext.isLoaded() )
682 			return "<not loaded>";
683 
684 		try
685 		{
686 			Binding binding = wsdlContext.getDefinition().getBinding( getBindingName() );
687 			if( binding == null )
688 				return "<missing binding>";
689 
690 			if( WsdlUtils.isRpc( binding ) )
691 			{
692 				return STYLE_RPC;
693 			}
694 			else
695 			{
696 				return STYLE_DOCUMENT;
697 			}
698 		}
699 		catch( Exception e )
700 		{
701 			SoapUI.logError( e );
702 			return "<error>";
703 		}
704 	}
705 
706 	@Override
707 	public void release()
708 	{
709 		super.release();
710 
711 		for( WsdlOperation operation : operations )
712 			operation.release();
713 
714 		interfaceListeners.clear();
715 	}
716 
717 	public List<Operation> getOperationList()
718 	{
719 		return new ArrayList<Operation>( operations );
720 	}
721 
722 	@Override
723 	public void beforeSave()
724 	{
725 		for( WsdlOperation operation : operations )
726 			operation.beforeSave();
727 	}
728 
729 	public static class BindingTuple
730 	{
731 		public WsdlContext context = null;
732 		public Service service = null;
733 		public Port port = null;
734 		public Binding binding = null;
735 	}
736 
737 	public List<? extends ModelItem> getChildren()
738 	{
739 		return getOperationList();
740 	}
741 
742 	public boolean isUpdating()
743 	{
744 		return updating;
745 	}
746 
747 	public void setUpdating( boolean updating )
748 	{
749 		if( this.updating == updating )
750 			return;
751 
752 		if( updating )
753 		{
754 			List<AbstractWsdlModelItem> messages = getAllMessages();
755 			for( AbstractWsdlModelItem modelItem : messages )
756 			{
757 				modelItem.beforeSave();
758 			}
759 		}
760 
761 		boolean oldValue = this.updating;
762 		this.updating = updating;
763 
764 		notifyPropertyChanged( UPDATING_PROPERTY, oldValue, updating );
765 	}
766 
767 	public List<AbstractWsdlModelItem> getAllMessages()
768 	{
769 		ArrayList<AbstractWsdlModelItem> list = new ArrayList<AbstractWsdlModelItem>();
770 		getAllMessages( getProject(), list );
771 		return list;
772 	}
773 
774 	private void getAllMessages( ModelItem modelItem, List<AbstractWsdlModelItem> list )
775 	{
776 		if( modelItem instanceof WsdlRequest )
777 		{
778 			WsdlRequest wsdlRequest = ( WsdlRequest ) modelItem;
779 			if( wsdlRequest.getOperation().getInterface() == this )
780 				list.add( wsdlRequest );
781 		}
782 		else if( modelItem instanceof WsdlTestRequestStep )
783 		{
784 			WsdlTestRequestStep testRequestStep = ( WsdlTestRequestStep ) modelItem;
785 			WsdlTestRequest testRequest = testRequestStep.getTestRequest();
786 			if( testRequest.getOperation().getInterface() == this )
787 				list.add( testRequest );
788 		}
789 		else if( modelItem instanceof WsdlMockResponse )
790 		{
791 			WsdlMockResponse mockResponse = ( WsdlMockResponse ) modelItem;
792 			if( mockResponse.getMockOperation().getOperation().getInterface() == this )
793 				list.add( mockResponse );
794 		}
795 
796 		// Traverse the ModelItem hierarchy.
797 		for( ModelItem child : modelItem.getChildren() )
798 		{
799 			getAllMessages( child, list );
800 		}
801 	}
802 }