View Javadoc

1   /*
2    *  soapUI, copyright (C) 2004-2008 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.rest;
14  
15  import com.eviware.soapui.config.AttachmentConfig;
16  import com.eviware.soapui.config.RestMethodConfig;
17  import com.eviware.soapui.config.RestResourceRepresentationConfig;
18  import com.eviware.soapui.impl.rest.RestRepresentation.Type;
19  import com.eviware.soapui.impl.rest.support.MediaTypeHandler;
20  import com.eviware.soapui.impl.rest.support.MediaTypeHandlerRegistry;
21  import com.eviware.soapui.impl.rest.support.XmlBeansRestParamsTestPropertyHolder;
22  import com.eviware.soapui.impl.rest.support.XmlBeansRestParamsTestPropertyHolder.RestParamProperty;
23  import com.eviware.soapui.impl.support.AbstractHttpRequest;
24  import com.eviware.soapui.impl.wsdl.HttpAttachmentPart;
25  import com.eviware.soapui.impl.wsdl.MutableTestPropertyHolder;
26  import com.eviware.soapui.impl.wsdl.WsdlSubmit;
27  import com.eviware.soapui.impl.wsdl.submit.RequestTransportRegistry;
28  import com.eviware.soapui.impl.wsdl.submit.transports.http.HttpResponse;
29  import com.eviware.soapui.impl.wsdl.support.PathUtils;
30  import com.eviware.soapui.model.ModelItem;
31  import com.eviware.soapui.model.iface.Attachment;
32  import com.eviware.soapui.model.iface.MessagePart;
33  import com.eviware.soapui.model.iface.MessagePart.ContentPart;
34  import com.eviware.soapui.model.iface.SubmitContext;
35  import com.eviware.soapui.model.propertyexpansion.PropertyExpansion;
36  import com.eviware.soapui.model.propertyexpansion.PropertyExpansionUtils;
37  import com.eviware.soapui.model.propertyexpansion.PropertyExpansionsResult;
38  import com.eviware.soapui.model.testsuite.TestProperty;
39  import com.eviware.soapui.model.testsuite.TestPropertyListener;
40  import com.eviware.soapui.support.StringUtils;
41  import com.eviware.soapui.support.UISupport;
42  import com.eviware.soapui.support.types.StringList;
43  import org.apache.log4j.Logger;
44  import org.apache.xmlbeans.SchemaGlobalElement;
45  import org.apache.xmlbeans.SchemaType;
46  import org.apache.xmlbeans.XmlString;
47  
48  import javax.xml.namespace.QName;
49  import java.beans.PropertyChangeEvent;
50  import java.beans.PropertyChangeListener;
51  import java.net.MalformedURLException;
52  import java.net.URL;
53  import java.util.*;
54  
55  /***
56   * Request implementation holding a SOAP request
57   *
58   * @author Ole.Matzura
59   */
60  
61  public class RestRequest extends AbstractHttpRequest<RestMethodConfig> implements MutableTestPropertyHolder, PropertyChangeListener
62  {
63     public final static Logger log = Logger.getLogger( RestRequest.class );
64     public static final String DEFAULT_MEDIATYPE = "application/xml";
65     private List<RestRepresentation> representations = new ArrayList<RestRepresentation>();
66  
67     private XmlBeansRestParamsTestPropertyHolder params;
68     public static final String REST_XML_RESPONSE = "restXmlResponse";
69     public static final String REST_XML_REQUEST = "restXmlRequest";
70     private PropertyChangeListener representationPropertyChangeListener = new RepresentationPropertyChangeListener();
71  
72     public RestRequest( RestResource resource, RestMethodConfig requestConfig, boolean forLoadTest )
73     {
74        super( requestConfig, resource, "/rest_request.gif", false );
75  
76        if( requestConfig.getParameters() == null )
77           requestConfig.addNewParameters();
78  
79        if( !requestConfig.isSetMethod() )
80           setMethod( RequestMethod.GET );
81  
82        if( requestConfig.getParameters() == null )
83           requestConfig.addNewParameters();
84  
85        for( RestResourceRepresentationConfig config : requestConfig.getRepresentationList() )
86        {
87           RestRepresentation representation = new RestRepresentation( this, config );
88           representation.addPropertyChangeListener( representationPropertyChangeListener );
89           representations.add( representation );
90        }
91  
92        params = new XmlBeansRestParamsTestPropertyHolder( this, requestConfig.getParameters() );
93  
94        if( resource != null )
95           resource.addPropertyChangeListener( this );
96     }
97  
98     protected RequestIconAnimator<?> initIconAnimator()
99     {
100       return new RequestIconAnimator<AbstractHttpRequest<?>>( this, "/rest_request.gif", "/exec_rest_request", 4, "gif" );
101    }
102 
103    public MessagePart[] getRequestParts()
104    {
105       List<MessagePart> result = new ArrayList<MessagePart>();
106 
107       for( int c = 0; c < getPropertyCount(); c++ )
108       {
109          result.add( new ParameterMessagePart( getPropertyAt( c ) ) );
110       }
111 
112       if( getMethod() == RequestMethod.POST || getMethod() == RequestMethod.PUT )
113       {
114          result.add( new RestContentPart() );
115       }
116 
117       return result.toArray( new MessagePart[result.size()] );
118    }
119 
120    public RestRepresentation[] getRepresentations()
121    {
122       return getRepresentations( null, null );
123    }
124 
125    public RestRepresentation[] getRepresentations( RestRepresentation.Type type )
126    {
127       return getRepresentations( type, null );
128    }
129    
130    public RestRepresentation[] getRepresentations( RestRepresentation.Type type, String mediaType )
131    {
132       List<RestRepresentation> result = new ArrayList<RestRepresentation>();
133       Set<String> addedTypes = new HashSet<String>();
134 
135       for( RestRepresentation representation : representations )
136       {
137          if( ( type == null || type == representation.getType() ) && ( mediaType == null || mediaType.equals( representation.getMediaType() ) ) )
138          {
139             result.add( representation );
140             addedTypes.add( representation.getMediaType() );
141          }
142       }
143 
144       if( type == RestRepresentation.Type.REQUEST )
145       {
146          for( Attachment attachment : getAttachments())
147          {
148             if( (mediaType == null || mediaType.equals( attachment.getContentType())) && !addedTypes.contains( attachment.getContentType() ))
149             {
150                RestRepresentation representation = new RestRepresentation( this, RestResourceRepresentationConfig.Factory.newInstance() );
151                representation.setType( RestRepresentation.Type.REQUEST );
152                representation.setMediaType( attachment.getContentType() );
153                result.add( representation );
154             }
155          }
156       }
157 
158       return result.toArray( new RestRepresentation[result.size()] );
159    }
160 
161    public MessagePart[] getResponseParts()
162    {
163       return new MessagePart[0];
164    }
165 
166    public void setMethod( RequestMethod method )
167    {
168       RequestMethod old = getMethod();
169       getConfig().setMethod( method.toString() );
170       notifyPropertyChanged( "method", old, method );
171    }
172 
173    public RequestMethod getMethod()
174    {
175       String method = getConfig().getMethod();
176       return method == null ? null : RequestMethod.valueOf( method );
177    }
178 
179    public String getAccept()
180    {
181       String accept = getConfig().getAccept();
182       return accept == null ? "" : accept;
183    }
184 
185    public void setAccept( String acceptEncoding )
186    {
187       String old = getAccept();
188       getConfig().setAccept( acceptEncoding );
189       notifyPropertyChanged( "accept", old, acceptEncoding );
190    }
191 
192    public void setMediaType( String mediaType )
193    {
194       String old = getMediaType();
195       getConfig().setMediaType( mediaType );
196       notifyPropertyChanged( "mediaType", old, mediaType );
197    }
198 
199    public String getMediaType()
200    {
201       String mediaType = getConfig().getMediaType();
202       return mediaType;
203    }
204 
205    public WsdlSubmit<RestRequest> submit( SubmitContext submitContext, boolean async ) throws SubmitException
206    {
207       String endpoint = PropertyExpansionUtils.expandProperties( submitContext, getEndpoint() );
208 
209       if( StringUtils.isNullOrEmpty( endpoint ) )
210       {
211          try
212          {
213             endpoint = new URL( getPath() ).toString();
214          }
215          catch( MalformedURLException e )
216          {
217          }
218       }
219 
220       if( StringUtils.isNullOrEmpty( endpoint ) )
221       {
222          UISupport.showErrorMessage( "Missing endpoint for request [" + getName() + "]" );
223          return null;
224       }
225 
226       try
227       {
228          WsdlSubmit<RestRequest> submitter = new WsdlSubmit<RestRequest>( this, getSubmitListeners(),
229                  RequestTransportRegistry.getTransport( endpoint, submitContext ) );
230          submitter.submitRequest( submitContext, async );
231          return submitter;
232       }
233       catch( Exception e )
234       {
235          throw new SubmitException( e.toString() );
236       }
237    }
238 
239    public PropertyExpansion[] getPropertyExpansions()
240    {
241       PropertyExpansionsResult result = new PropertyExpansionsResult( this, this );
242       result.addAll( super.getPropertyExpansions() );
243       result.addAll( params.getPropertyExpansions() );
244 
245       return result.toArray();
246    }
247 
248    public RestParamProperty addProperty( String name )
249    {
250       return params.addProperty( name );
251    }
252 
253    public void moveProperty( String propertyName, int targetIndex )
254    {
255       params.moveProperty( propertyName, targetIndex );
256    }
257 
258    public RestParamProperty removeProperty( String propertyName )
259    {
260       return params.removeProperty( propertyName );
261    }
262 
263    public boolean renameProperty( String name, String newName )
264    {
265       return params.renameProperty( name, newName );
266    }
267 
268    public void addTestPropertyListener( TestPropertyListener listener )
269    {
270       params.addTestPropertyListener( listener );
271    }
272 
273    public ModelItem getModelItem()
274    {
275       return this;
276    }
277 
278    @Override
279    public RestResource getOperation()
280    {
281       return ( RestResource ) super.getOperation();
282    }
283 
284    public Map<String, TestProperty> getProperties()
285    {
286       return params.getProperties();
287    }
288 
289    public RestParamProperty getProperty( String name )
290    {
291       return params.getProperty( name );
292    }
293 
294    public RestParamProperty getPropertyAt( int index )
295    {
296       return params.getPropertyAt( index );
297    }
298 
299    public int getPropertyCount()
300    {
301       return params.getPropertyCount();
302    }
303 
304    public String[] getPropertyNames()
305    {
306       return params.getPropertyNames();
307    }
308 
309    public String getPropertyValue( String name )
310    {
311       return params.getPropertyValue( name );
312    }
313 
314    public boolean hasProperty( String name )
315    {
316       return params.hasProperty( name );
317    }
318 
319    public void removeTestPropertyListener( TestPropertyListener listener )
320    {
321       params.removeTestPropertyListener( listener );
322    }
323 
324    public void setPropertyValue( String name, String value )
325    {
326       params.setPropertyValue( name, value );
327    }
328 
329    public void propertyChange( PropertyChangeEvent evt )
330    {
331       if( evt.getPropertyName().equals( "path" ) )
332       {
333          notifyPropertyChanged( "path", null, getPath() );
334       }
335    }
336 
337    public String[] getResponseMediaTypes()
338    {
339       StringList result = new StringList();
340 
341       for( RestRepresentation representation : getRepresentations( Type.RESPONSE, null ) )
342       {
343          if( !result.contains( representation.getMediaType() ) )
344             result.add( representation.getMediaType() );
345       }
346 
347       return result.toStringArray();
348    }
349 
350    public boolean isPostQueryString()
351    {
352       return getConfig().getPostQueryString();
353    }
354 
355    public void setPostQueryString( boolean b )
356    {
357       boolean old = isPostQueryString();
358       getConfig().setPostQueryString( b );
359       notifyPropertyChanged( "postQueryString", old, b );
360 
361       setMediaType( b ? "application/x-www-form-urlencoded" : "");
362    }
363 
364    public final static class ParameterMessagePart extends MessagePart.ParameterPart
365    {
366       private String name;
367 
368       public ParameterMessagePart( TestProperty propertyAt )
369       {
370          this.name = propertyAt.getName();
371       }
372 
373       @Override
374       public SchemaType getSchemaType()
375       {
376          return XmlString.type;
377       }
378 
379       @Override
380       public SchemaGlobalElement getPartElement()
381       {
382          return null;
383       }
384 
385       @Override
386       public QName getPartElementName()
387       {
388          return new QName( getName() );
389       }
390 
391       public String getDescription()
392       {
393          return null;
394       }
395 
396       public String getName()
397       {
398          return name;
399       }
400    }
401 
402    public String getPropertiesLabel()
403    {
404       return "Request Params";
405    }
406 
407    public XmlBeansRestParamsTestPropertyHolder getParams()
408    {
409       return params;
410    }
411 
412    public HttpAttachmentPart getAttachmentPart( String partName )
413    {
414       return null;
415    }
416 
417    public HttpAttachmentPart[] getDefinedAttachmentParts()
418    {
419       return new HttpAttachmentPart[0];
420    }
421 
422    public class RestContentPart extends ContentPart implements MessagePart
423    {
424       @Override
425       public SchemaGlobalElement getPartElement()
426       {
427          return null;
428       }
429 
430       @Override
431       public QName getPartElementName()
432       {
433          return null;
434       }
435 
436       @Override
437       public SchemaType getSchemaType()
438       {
439          return null;
440       }
441 
442       public String getDescription()
443       {
444          return null;
445       }
446 
447       public String getName()
448       {
449          return null;
450       }
451 
452       public String getMediaType()
453       {
454          return "application/xml";
455       }
456    }
457 
458    public boolean hasRequestBody()
459    {
460       RequestMethod method = getMethod();
461       return method == RequestMethod.POST || method == RequestMethod.PUT;
462    }
463 
464    public RestResource getResource()
465    {
466       return getOperation();
467    }
468 
469    public String getPath()
470    {
471       if( getConfig().isSetFullPath() || getResource() == null )
472          return getConfig().getFullPath();
473       else
474          return getResource().getFullPath();
475    }
476 
477    public void setPath( String fullPath )
478    {
479       String old = getPath();
480 
481       if( getResource() != null && getResource().getFullPath().equals( fullPath ) )
482          getConfig().unsetFullPath();
483       else
484          getConfig().setFullPath( fullPath );
485 
486       notifyPropertyChanged( "path", old, fullPath );
487    }
488 
489    public String getResponseContentAsXml()
490    {
491       HttpResponse response = getResponse();
492       if( response == null )
493          return null;
494 
495       return response.getProperty( REST_XML_RESPONSE );
496    }
497 
498    public void setResponse( HttpResponse response, SubmitContext context )
499    {
500       response.setProperty( REST_XML_RESPONSE, createXmlResponse( response ) );
501       super.setResponse( response, context );
502    }
503 
504    private String createXmlResponse( HttpResponse response )
505    {
506       MediaTypeHandler typeHandler = MediaTypeHandlerRegistry.getTypeHandler( response.getContentType() );
507       if( typeHandler != null )
508          return typeHandler.createXmlRepresentation( response );
509       else
510          return null;
511    }
512 
513    @Override
514    public void release()
515    {
516       super.release();
517       params.release();
518 
519       if( getResource() != null )
520          getResource().removePropertyChangeListener( this );
521 
522       for( RestRepresentation representation : representations )
523       {
524          representation.release();
525       }
526    }
527 
528    public void updateConfig( RestMethodConfig request )
529    {
530       setConfig( request );
531 
532       params.resetPropertiesConfig( request.getParameters() );
533 
534       for( int c = 0; c < request.sizeOfRepresentationArray(); c++ )
535       {
536          representations.get( c ).setConfig( request.getRepresentationArray( c ) );
537       }
538 
539       List<AttachmentConfig> attachmentConfigs = getConfig().getAttachmentList();
540       for( int i = 0; i < attachmentConfigs.size(); i++ )
541       {
542          AttachmentConfig config = attachmentConfigs.get( i );
543          getAttachmentsList().get( i ).updateConfig( config );
544       }
545    }
546 
547    public RestParamProperty addProperty( RestParamProperty prop )
548    {
549       return params.addProperty( prop );
550    }
551 
552    public RestRepresentation addNewRepresentation( Type type )
553    {
554       RestRepresentation representation = new RestRepresentation( this, getConfig().addNewRepresentation() );
555       representation.setType( type );
556 
557       representation.addPropertyChangeListener( representationPropertyChangeListener );
558 
559       representations.add( representation );
560 
561       notifyPropertyChanged( "representations", null, representation );
562 
563       return representation;
564    }
565 
566    public void removeRepresentation( RestRepresentation representation )
567    {
568       int ix = representations.indexOf( representation );
569 
570       representations.remove( ix );
571       representation.removePropertyChangeListener( representationPropertyChangeListener );
572 
573       notifyPropertyChanged( "representations", representation, null );
574       getConfig().removeRepresentation( ix );
575       representation.release();
576    }
577 
578    public boolean hasEndpoint()
579    {
580       return super.hasEndpoint() || PathUtils.isHttpPath( getPath() );
581    }
582 
583    private class RepresentationPropertyChangeListener implements PropertyChangeListener
584    {
585       public void propertyChange( PropertyChangeEvent evt )
586       {
587          if( evt.getPropertyName().equals( "mediaType" ) && ((RestRepresentation)evt.getSource()).getType() == Type.RESPONSE )
588          {
589             RestRequest.this.notifyPropertyChanged( "responseMediaTypes", null, getResponseMediaTypes() );
590          }
591       }
592    }
593 }