1
2
3
4
5
6
7
8
9
10
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
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
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
318 if( getSettings().getBoolean( WsdlSettings.NAME_WITH_BINDING ) )
319 setName( tuple.binding.getQName().getLocalPart() );
320
321
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
357 if( getSettings().getBoolean( WsdlSettings.NAME_WITH_BINDING ) )
358 setName( tuple.binding.getQName().getLocalPart() );
359
360
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
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
421
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
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
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
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
485 if( ix < 0 )
486 {
487 deleteOperation( name );
488 }
489
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
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
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
797 for( ModelItem child : modelItem.getChildren() )
798 {
799 getAllMessages( child, list );
800 }
801 }
802 }