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