View Javadoc

1   /*
2    *  soapui, copyright (C) 2005 Ole Matzura / eviware.com 
3    *
4    *  SoapUI is free software; you can redistribute it and/or modify it under the 
5    *  terms of the GNU Lesser General Public License as published by the Free Software Foundation; 
6    *  either version 2.1 of the License, or (at your option) any later version.
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.swing.ImageIcon;
25  import javax.swing.JOptionPane;
26  import javax.wsdl.Binding;
27  import javax.wsdl.BindingOperation;
28  import javax.wsdl.Definition;
29  import javax.wsdl.Port;
30  import javax.wsdl.Service;
31  import javax.wsdl.extensions.soap.SOAPAddress;
32  import javax.xml.namespace.QName;
33  
34  import org.apache.log4j.Logger;
35  
36  import com.eviware.soapui.SoapUI;
37  import com.eviware.soapui.config.EndpointConfig;
38  import com.eviware.soapui.config.EndpointsConfig;
39  import com.eviware.soapui.config.InterfaceConfig;
40  import com.eviware.soapui.config.OperationConfig;
41  import com.eviware.soapui.impl.wsdl.actions.iface.InterfaceEndpointsAction;
42  import com.eviware.soapui.impl.wsdl.actions.iface.RemoveInterfaceAction;
43  import com.eviware.soapui.impl.wsdl.actions.iface.UpdateInterfaceAction;
44  import com.eviware.soapui.impl.wsdl.panels.iface.WsdlInterfacePanelBuilder;
45  import com.eviware.soapui.impl.wsdl.support.SoapRequestBuilder;
46  import com.eviware.soapui.impl.wsdl.support.WsdlContext;
47  import com.eviware.soapui.impl.wsdl.support.WsdlUtils;
48  import com.eviware.soapui.model.PanelBuilder;
49  import com.eviware.soapui.model.iface.Interface;
50  import com.eviware.soapui.model.iface.InterfaceListener;
51  import com.eviware.soapui.model.iface.Operation;
52  import com.eviware.soapui.model.iface.RequestBuilder;
53  import com.eviware.soapui.model.project.Project;
54  import com.eviware.soapui.model.tree.SoapUITreeNode;
55  import com.eviware.soapui.model.tree.nodes.InterfaceTreeNode;
56  import com.eviware.soapui.support.UISupport;
57  
58  /***
59   * WSDL implementation of Interface, maps to a WSDL Binding
60   * 
61   * @author Ole.Matzura
62   */
63  
64  public class WsdlInterface extends AbstractWsdlModelItem implements Interface
65  {
66  	private final static Logger log = Logger.getLogger( WsdlInterface.class );
67  	
68     private InterfaceConfig interfaceConfig;
69     private List<WsdlOperation> operations = new ArrayList<WsdlOperation>();
70     private final WsdlProject project;
71     private SoapRequestBuilder soapRequestBuilder;
72     private WsdlInterfacePanelBuilder wsdlInterfacePanelBuilder;
73     private WsdlContext wsdlContext;
74     private ImageIcon interfaceIcon;
75     private Set<InterfaceListener> listeners = new HashSet<InterfaceListener>();
76     
77     public WsdlInterface( WsdlProject project, InterfaceConfig interfaceConfig )
78     {
79        this.project = project;
80        this.interfaceConfig = interfaceConfig;
81        
82        if( interfaceConfig.getEndpoints() == null )
83           interfaceConfig.addNewEndpoints();
84        
85        OperationConfig [] operationConfigs = interfaceConfig.getOperationArray();
86        for (int i = 0; i < operationConfigs.length; i++)
87        {
88           operations.add( new WsdlOperation( this, operationConfigs[i] ));
89        }
90        
91        addAction( new InterfaceEndpointsAction( this ) );
92        addAction( new UpdateInterfaceAction( this ) );
93        addAction( new RemoveInterfaceAction( this ) );
94        
95        wsdlInterfacePanelBuilder = new WsdlInterfacePanelBuilder( this );
96        interfaceIcon = SoapUI.createImageIcon("/interface.gif");
97     }
98     
99     public PanelBuilder getPanelBuilder()
100    {
101       return wsdlInterfacePanelBuilder;
102    }
103    
104    public String[] getEndpoints()
105    {
106       EndpointsConfig endpoints = interfaceConfig.getEndpoints();
107       EndpointConfig[] endpointArray = endpoints.getEndpointArray();
108       
109       String [] result = new String[endpointArray.length];
110       
111       for( int c = 0; c < endpointArray.length; c++ )
112       {
113       	EndpointConfig endpoint = endpointArray[c];
114       	if( endpoint.isSetLabel() )
115       		result[c] = endpoint.getLabel();
116       	else
117       		result[c] = endpoint.getStringValue();
118       }
119       
120 		return result; 
121    }
122 
123    public Operation getOperationAt(int index)
124    {
125       return operations.get(index);
126    }
127 
128    public int getOperationCount()
129    {
130       return operations.size();
131    }
132 
133    public String getName()
134    {
135       try
136       {
137          return interfaceConfig.getName();
138       }
139       catch( Exception e )
140       {
141          return null;
142       }
143    }
144    
145    public void setName( String name )
146    {
147       String oldName = getName();
148       interfaceConfig.setName( name );
149       notifyPropertyChanged( NAME_PROPERTY, oldName, name );
150    }
151 
152    public InterfaceConfig getInterfaceConfig()
153    {
154       return interfaceConfig;
155    }
156 
157    public WsdlOperation addNewOperation()
158    {
159       WsdlOperation operationImpl = new WsdlOperation( this, interfaceConfig.addNewOperation() );
160       operations.add( operationImpl );
161       return operationImpl;
162    }
163 
164    public Project getProject()
165    {
166       return project;
167    }
168 
169    public void addEndpoint(String endpoint)
170    {
171       if( endpoint == null || endpoint.trim().length() == 0 ) return;
172       
173       String[] endpoints = getEndpoints();
174       
175       // dont add the same endpoint twice
176       if( Arrays.asList( endpoints ).contains( endpoint )) return;
177       
178 		interfaceConfig.getEndpoints().addNewEndpoint().setStringValue(endpoint);
179 		
180 		notifyPropertyChanged(ENDPOINT_PROPERTY, null, endpoint);
181    }
182    
183    public void changeEndpoint(String oldEndpoint, String newEndpoint)
184 	{
185    	EndpointsConfig endpoints = interfaceConfig.getEndpoints();
186       EndpointConfig[] endpointArray = endpoints.getEndpointArray();
187       
188       String [] result = new String[endpointArray.length];
189       
190       for( int c = 0; c < endpointArray.length; c++ )
191       {
192       	EndpointConfig endpoint = endpointArray[c];
193       	if( endpoint.getStringValue().equals( oldEndpoint ) )
194       	{
195       		endpoint.setStringValue( newEndpoint );
196          	notifyPropertyChanged(ENDPOINT_PROPERTY, oldEndpoint, newEndpoint);
197          	break;
198       	}
199       }
200 	}
201 
202 	public void removeEndpoint(String endpoint)
203 	{
204 		EndpointsConfig endpoints = interfaceConfig.getEndpoints();
205       EndpointConfig[] endpointArray = endpoints.getEndpointArray();
206       
207       String [] result = new String[endpointArray.length];
208       
209       for( int c = 0; c < endpointArray.length; c++ )
210       {
211       	EndpointConfig ep = endpointArray[c];
212       	if( ep.getStringValue().equals( endpoint ) )
213       	{
214       		endpoints.removeEndpoint( c );
215          	notifyPropertyChanged(ENDPOINT_PROPERTY, endpoint, null );
216          	break;
217       	}
218       }
219 	}
220 
221 	public void setDefinition( String wsdlUrl )
222    {
223       String old = getDefinition();
224       if( old != null && wsdlUrl.equals(old)) return;
225       
226       interfaceConfig.setDefinition( wsdlUrl );
227       if( wsdlContext != null )
228       	wsdlContext.setDefinition( wsdlUrl );
229       
230       notifyPropertyChanged( DEFINITION_PROPERTY, old, wsdlUrl );
231    }
232    
233    public String getDefinition()
234    {
235       try
236       {
237          return interfaceConfig.isSetDefinition() ? interfaceConfig.getDefinition() : null;
238       }
239       catch( Exception e )
240       {
241          return null;
242       }
243    }
244    
245    public WsdlContext getWsdlContext()
246    {
247       if( wsdlContext == null )
248          wsdlContext = new WsdlContext( getDefinition() );
249       
250       return wsdlContext;
251    }
252 
253    public RequestBuilder getRequestBuilder()
254    {
255       if( soapRequestBuilder == null )
256       {
257          try
258          {
259             soapRequestBuilder = new SoapRequestBuilder( this );
260          }
261          catch (Exception e)
262          {
263             e.printStackTrace();
264          }
265       }
266       return soapRequestBuilder;
267    }
268 
269    public void setSoapRequestBuilder(SoapRequestBuilder builder)
270    {
271       this.soapRequestBuilder = builder;
272    }
273 
274    public QName getBindingName()
275    {
276       return interfaceConfig.getBindingName() == null ? null : QName.valueOf(interfaceConfig.getBindingName());
277    }
278 
279    public void setBindingName(QName name)
280    {
281       interfaceConfig.setBindingName( name.toString() );
282    }
283 
284    public ImageIcon getIcon()
285    {
286       return interfaceIcon;
287    }
288 
289    protected SoapUITreeNode createTreeNode()
290    {
291       return new InterfaceTreeNode( this );
292    }
293 
294 	public void updateDefinition(String url) throws Exception
295 	{
296 		WsdlContext newContext = new WsdlContext( url );
297 		
298 		Definition definition = newContext.getDefinition();
299 		Service service = null;
300 		Port port = null;
301 		Binding binding = null;
302 		
303 		// start by finding the old binding in the new definition
304 		Map serviceMap = definition.getServices();
305 		Iterator<String> i = serviceMap.keySet().iterator();
306 		while( i.hasNext() )
307 		{
308 			service = (Service) serviceMap.get( i.next() );
309 			Map portMap = service.getPorts();
310 			
311 			Iterator i2 = portMap.keySet().iterator();
312 			while( i2.hasNext() )
313 			{
314 				port = (Port) portMap.get( i2.next() );
315 				if( port.getBinding().getQName().equals( getBindingName() ))
316 				{
317 					binding = port.getBinding();
318 				}
319 			}
320 			
321 			if( binding != null ) break;
322 			service = null;
323 		}
324 		
325 		if( service == null && binding == null )
326 		{
327 			binding = definition.getBinding( getBindingName() );
328 		}
329 
330 		// missing matching binding, prompt for new one to use instead (will happen if binding has been renamed)
331 		if( binding == null )
332 		{
333 			Map bindings = definition.getBindings();
334 			
335 			Object retval = JOptionPane.showInputDialog( SoapUI.getInstance().getFrame(), 
336 					"Missing matching binding [" + getBindingName() + "] in definition, select new\nbinding to map to", 
337 					"Map Binding", JOptionPane.QUESTION_MESSAGE, null, bindings.keySet().toArray(), null );
338 			
339 			if( retval == null )
340 				return;
341 			
342 			binding = (Binding) bindings.get( retval );
343 			setBindingName( binding.getQName() );
344 		}
345 		
346 		// prepare for transfer of operations/requests
347 		List<BindingOperation> newOperations = new ArrayList<BindingOperation>( binding.getBindingOperations() );
348 		Map<String,WsdlOperation> oldOperations = new HashMap<String,WsdlOperation>();
349 		for( int c = 0; c < operations.size(); c++ )
350 			oldOperations.put( operations.get( c ).getBindingOperationName(), operations.get( c ) );
351 		
352 		// clear existing from both collections
353 		for( int c = 0; c < newOperations.size(); c++ )
354 		{
355 			BindingOperation newOperation = newOperations.get( c );
356 			String bindingOperationName = newOperation.getName();
357 			if( oldOperations.containsKey( bindingOperationName) )
358 			{
359 				log.info( "Synchronizing existing operation [" + bindingOperationName + "]" );
360 				WsdlOperation wsdlOperation = oldOperations.get( bindingOperationName );
361 				wsdlOperation.setAction( WsdlUtils.getSoapAction( newOperation));
362 				wsdlOperation.setName( newOperation.getOperation().getName() );
363 				
364 				oldOperations.remove( bindingOperationName );
365 				newOperations.remove( c );
366 				c--;
367 			}
368 		}
369 		
370 		//	remove leftover operations
371 		i = oldOperations.keySet().iterator();
372 		while( i.hasNext())
373 		{
374 			String name = i.next();
375 			
376 			if( newOperations.size() > 0 )
377 		   {
378 				List<String> list = new ArrayList<String>();
379 				list.add( "none - delete operation" );
380 				for( int c = 0; c < newOperations.size(); c++ )
381 					list.add( newOperations.get( c ).getName() );
382 				
383 				String retval = (String) JOptionPane.showInputDialog( SoapUI.getInstance().getFrame(), 
384 						"Binding operation [" + name + "] not found in new interface, select new\nbinding operation to map to", 
385 						"Map Operation", JOptionPane.QUESTION_MESSAGE, null, list.toArray(), "none - delete operation" );
386 				
387 				if( retval == null )
388 				{
389 				   UISupport.showErrorMessage( "Aborting update of interface" );
390 				   return;
391 				}
392 				
393 				int ix = list.indexOf( retval)-1;
394 				
395 				// delete operation?
396 				if( ix < 0 )
397 				{
398 					deleteOperation( name );
399 				}
400 				// change operation?
401 				else
402 				{
403 					BindingOperation newOperation = newOperations.get( ix );
404 					WsdlOperation wsdlOperation = oldOperations.get( name );
405 					wsdlOperation.setAction( WsdlUtils.getSoapAction( newOperation));
406 					wsdlOperation.setName( newOperation.getOperation().getName() );
407 					wsdlOperation.setBindingOperationName( newOperation.getName() );
408 
409 					newOperations.remove( ix );
410 				}
411 
412 				oldOperations.remove( name );
413 		   }
414 			else 
415 			{
416 				deleteOperation( name );
417 				oldOperations.remove( name );
418 			}
419 			
420 			i = oldOperations.keySet().iterator();
421 		}
422 		
423 		// add leftover new operations
424 		for( int c = 0; c < newOperations.size(); c++ )
425 		{
426 			BindingOperation newOperation = newOperations.get( c );
427 			WsdlOperation wsdlOperation = addNewOperation();
428 			wsdlOperation.setAction( WsdlUtils.getSoapAction( newOperation));
429 			wsdlOperation.setName( newOperation.getOperation().getName() );
430 			wsdlOperation.setBindingOperationName( newOperation.getName() );
431 			
432 			notifyOperationAdded( wsdlOperation );
433 		}
434 		
435 		wsdlContext = newContext;
436 		if( soapRequestBuilder != null )
437 			soapRequestBuilder.setWsdlContext( wsdlContext );
438 		
439     	setDefinition( url );
440 
441 		if( port != null )
442 		{
443 	      SOAPAddress address = (SOAPAddress) WsdlUtils.getExtensiblityElement( port.getExtensibilityElements(), SOAPAddress.class );
444 	      if( address != null )
445 	         addEndpoint( address.getLocationURI() );
446 		}
447 	}
448 
449 	private void deleteOperation(String bindingOperationName)
450 	{
451 		for( int c = 0; c < operations.size(); c++ )
452 		{
453 			WsdlOperation wsdlOperation = operations.get( c );
454 			if( wsdlOperation.getBindingOperationName().equals( bindingOperationName ))
455 			{
456 				log.info( "deleting operation [" + bindingOperationName + "]" ); 
457 				notifyOperationRemoved( wsdlOperation );
458 				wsdlOperation.release();
459 				
460 				operations.remove( c );
461 				interfaceConfig.removeOperation( c );
462 				
463 				return;
464 			}
465 		}
466 	}
467 	
468 	public void notifyOperationAdded( WsdlOperation operation )
469    {
470       InterfaceListener[] a = listeners.toArray( new InterfaceListener[listeners.size()] );
471       
472       for (int c = 0; c < a.length; c++ )
473       {
474          a[c].operationAdded( operation );
475       }
476    }
477    
478    public void notifyOperationRemoved( WsdlOperation operation )
479    {
480    	InterfaceListener[] a = listeners.toArray( new InterfaceListener[listeners.size()] );
481       
482       for (int c = 0; c < a.length; c++ )
483       {
484          a[c].operationRemoved( operation );
485       }
486    }
487    
488    public void notifyRequestAdded( WsdlRequest request )
489    {
490    	InterfaceListener[] a = listeners.toArray( new InterfaceListener[listeners.size()] );
491       
492       for (int c = 0; c < a.length; c++ )
493       {
494          a[c].requestAdded( request );
495       }
496    }
497    
498    public void notifyRequestRemoved( WsdlRequest request )
499    {
500    	InterfaceListener[] a = listeners.toArray( new InterfaceListener[listeners.size()] );
501       
502       for (int c = 0; c < a.length; c++ )
503       {
504          a[c].requestRemoved( request );
505       }
506    }
507 
508 	public void addInterfaceListener(InterfaceListener listener)
509 	{
510 		listeners.add( listener );
511 	}
512 
513 	public void removeInterfaceListener(InterfaceListener listener)
514 	{
515 		listeners.remove( listener );
516 	}
517 
518 	/***
519 	 * Gets the endpoint url for the specified endpoint (which may be a label)
520 	 * 
521 	 * @param endpoint the endpoint to get for
522 	 * @return the endpoints url
523 	 */
524 	
525 	public String getEndpointURL(String endpoint)
526 	{
527 		EndpointConfig[] endpointArray = interfaceConfig.getEndpoints().getEndpointArray();
528 		for( int c = 0; c < endpointArray.length; c++ )
529 		{
530 			EndpointConfig endpointConfig = endpointArray[c];
531 			if( endpointConfig.isSetLabel() && endpointConfig.getLabel().equals( endpoint ))
532 				return endpointConfig.getStringValue();
533 		}
534 		
535 		return endpoint;
536 	}
537 }