1
2
3
4
5
6
7
8
9
10
11
12
13 package com.eviware.soapui.support.components;
14
15 import java.awt.BorderLayout;
16 import java.awt.Component;
17 import java.awt.Toolkit;
18 import java.awt.event.ActionEvent;
19 import java.awt.image.BufferedImage;
20 import java.io.File;
21 import java.lang.reflect.InvocationTargetException;
22 import java.net.URL;
23
24 import javax.swing.AbstractAction;
25 import javax.swing.Action;
26 import javax.swing.JEditorPane;
27 import javax.swing.JLabel;
28 import javax.swing.JPanel;
29 import javax.swing.SwingUtilities;
30
31 import org.mozilla.interfaces.nsIHttpChannel;
32 import org.mozilla.interfaces.nsIRequest;
33 import org.mozilla.interfaces.nsISupports;
34 import org.mozilla.interfaces.nsIURI;
35 import org.mozilla.interfaces.nsIWeakReference;
36 import org.mozilla.interfaces.nsIWebBrowser;
37 import org.mozilla.interfaces.nsIWebProgress;
38 import org.mozilla.interfaces.nsIWebProgressListener;
39 import org.mozilla.xpcom.Mozilla;
40 import org.mozilla.xpcom.XPCOMException;
41 import org.w3c.dom.Document;
42
43 import com.eviware.soapui.SoapUI;
44 import com.eviware.soapui.model.propertyexpansion.PropertyExpander;
45 import com.eviware.soapui.model.propertyexpansion.PropertyExpansionContext;
46 import com.eviware.soapui.model.settings.Settings;
47 import com.eviware.soapui.settings.ProxySettings;
48 import com.eviware.soapui.support.StringUtils;
49 import com.eviware.soapui.support.Tools;
50 import com.eviware.soapui.support.UISupport;
51 import com.eviware.soapui.support.xml.XmlUtils;
52 import com.teamdev.jxbrowser.BrowserAttributes;
53 import com.teamdev.jxbrowser.ClipboardSupport;
54 import com.teamdev.jxbrowser.ContentHandler;
55 import com.teamdev.jxbrowser.SearchParams;
56 import com.teamdev.jxbrowser.WebBrowser;
57 import com.teamdev.jxbrowser.WebBrowserFactory;
58 import com.teamdev.jxbrowser.WebBrowserHistory;
59 import com.teamdev.jxbrowser.WebBrowserWindow;
60 import com.teamdev.jxbrowser.WindowCreator;
61 import com.teamdev.jxbrowser.event.ContextMenuListener;
62 import com.teamdev.jxbrowser.event.HistoryChangeListener;
63 import com.teamdev.jxbrowser.event.LocationEvent;
64 import com.teamdev.jxbrowser.event.RequestAdapter;
65 import com.teamdev.jxbrowser.event.RequestListener;
66 import com.teamdev.jxbrowser.event.StatusChangeEvent;
67 import com.teamdev.jxbrowser.event.StatusChangeListener;
68 import com.teamdev.jxbrowser.event.TitleChangeListener;
69 import com.teamdev.jxbrowser.mozilla.MozillaWebBrowser;
70 import com.teamdev.jxbrowser.printing.WebBrowserPrinting;
71 import com.teamdev.jxbrowser.ssl.BadCertificateHandler;
72 import com.teamdev.xpcom.AsyncHandlerFactory;
73 import com.teamdev.xpcom.PoxyAuthenticationHandler;
74 import com.teamdev.xpcom.ProxyConfiguration;
75 import com.teamdev.xpcom.ProxyServerAuthInfo;
76 import com.teamdev.xpcom.ProxyServerType;
77 import com.teamdev.xpcom.Services;
78 import com.teamdev.xpcom.Xpcom;
79
80 public class BrowserComponent implements nsIWebProgressListener, nsIWeakReference, StatusChangeListener
81 {
82 private static String disabledReason;
83
84 public class DummyBrowser implements WebBrowser
85 {
86 public void activate()
87 {
88 }
89
90 public void addContentHandler( ContentHandler arg0 )
91 {
92 }
93
94 public void addContextMenuListener( ContextMenuListener arg0 )
95 {
96 }
97
98 public void addHistoryChangeListener( HistoryChangeListener arg0 )
99 {
100 }
101
102 public void addRequestListener( RequestListener arg0 )
103 {
104 }
105
106 public void addStatusChangeListener( StatusChangeListener arg0 )
107 {
108 }
109
110 public void addTitleChangeListener( TitleChangeListener arg0 )
111 {
112 }
113
114 public void deactivate()
115 {
116 }
117
118 public void displayAsSource( boolean arg0 )
119 {
120 }
121
122 public void dispose()
123 {
124 }
125
126 public String evaluateScript( String arg0 )
127 {
128 return null;
129 }
130
131 public boolean findString( String arg0 )
132 {
133 return false;
134 }
135
136 public AsyncHandlerFactory getAsyncHandler()
137 {
138 return null;
139 }
140
141 public BrowserAttributes getAttributes()
142 {
143 return null;
144 }
145
146 public boolean getCanGoBack()
147 {
148 return false;
149 }
150
151 public boolean getCanGoForward()
152 {
153 return false;
154 }
155
156 public ClipboardSupport getClipboardSupport()
157 {
158 return null;
159 }
160
161 public Component getComponent()
162 {
163 return new JLabel( "Browser Component Disabled: [" + disabledReason + "]" );
164 }
165
166 public Document getDocument()
167 {
168
169 return null;
170 }
171
172 public String getDocumentContent( String arg0 )
173 {
174
175 return null;
176 }
177
178 public WebBrowserHistory getHistory()
179 {
180
181 return null;
182 }
183
184 public String getLocationURL()
185 {
186
187 return null;
188 }
189
190 public WebBrowserPrinting getPrinting()
191 {
192
193 return null;
194 }
195
196 public String getTitle()
197 {
198
199 return null;
200 }
201
202 public void goBack()
203 {
204
205
206 }
207
208 public void goForward()
209 {
210
211
212 }
213
214 public boolean isDisposed()
215 {
216
217 return false;
218 }
219
220 public void navigate( String arg0 )
221 {
222
223
224 }
225
226 public void navigate( String arg0, String arg1 )
227 {
228
229
230 }
231
232 public void pageDown()
233 {
234
235
236 }
237
238 public void pageUp()
239 {
240
241
242 }
243
244 public void refresh()
245 {
246
247
248 }
249
250 public void removeContextMenuListener( ContextMenuListener arg0 )
251 {
252
253
254 }
255
256 public void removeHistoryChangeListener( HistoryChangeListener arg0 )
257 {
258
259
260 }
261
262 public void removeRequestListener( RequestListener arg0 )
263 {
264
265
266 }
267
268 public void removeStatusChangeListener( StatusChangeListener arg0 )
269 {
270
271
272 }
273
274 public void removeTitleChangeListener( TitleChangeListener arg0 )
275 {
276
277
278 }
279
280 public void resetBadCertificateHandler( BadCertificateHandler arg0 )
281 {
282
283
284 }
285
286 public void saveCurrentDocument( File arg0, RequestListener arg1 )
287 {
288
289
290 }
291
292 public void saveURLtoFile( URL arg0, File arg1, RequestListener arg2 )
293 {
294
295
296 }
297
298 public void setAsyncHandler( AsyncHandlerFactory arg0 )
299 {
300
301
302 }
303
304 public void setAttributes( BrowserAttributes arg0 )
305 {
306
307
308 }
309
310 public void setContent( String arg0, String arg1 )
311 {
312
313
314 }
315
316 public void setContent( String arg0, String arg1, String arg2 )
317 {
318
319
320 }
321
322 public void setContentWithContext( String arg0, String arg1, String arg2 )
323 {
324
325
326 }
327
328 public void setFocusAtFirstElement()
329 {
330
331
332 }
333
334 public void setWindowCreator( WindowCreator arg0 )
335 {
336
337
338 }
339
340 public void showOpenFileDialog()
341 {
342
343
344 }
345
346 public void showSaveFileDialog()
347 {
348
349
350 }
351
352 public void stop()
353 {
354
355
356 }
357
358 public BufferedImage toImage()
359 {
360
361 return null;
362 }
363
364 public boolean findNext( String arg0, SearchParams arg1 )
365 {
366
367 return false;
368 }
369
370 public void setContent( String arg0 )
371 {
372
373
374 }
375
376 }
377
378 private WebBrowser browser;
379 private static WebBrowserFactory webBrowserFactory;
380 private JPanel panel = new JPanel( new BorderLayout() );
381 private JPanel statusBar;
382 private JLabel statusLabel;
383 private String errorPage;
384 private WebBrowserWindow browserWindowAdapter = new BrowserWindowAdapter();
385 private final boolean addToolbar;
386 private boolean showingErrorPage;
387 public String url;
388 private static Boolean initialized = false;
389 private Boolean possibleError = false;
390 @SuppressWarnings( "unused" )
391 private boolean disposed;
392 private static boolean disabled;
393
394 public BrowserComponent( boolean addToolbar )
395 {
396 this.addToolbar = addToolbar;
397 initialize();
398 }
399
400 public static void setDisabled( boolean disabled )
401 {
402 BrowserComponent.disabled = disabled;
403 }
404
405 public synchronized static void initialize()
406 {
407 if( initialized )
408 return;
409
410 try
411 {
412 if( !isJXBrowserDisabled() )
413 {
414 if( Xpcom.isMacOSX() )
415 {
416 final String currentCP = System.getProperty( "java.class.path" );
417 final String appleJavaExtentions = ":/System/Library/Java";
418 System.setProperty( "java.class.path", currentCP + appleJavaExtentions );
419 }
420
421 Xpcom.initialize();
422 webBrowserFactory = WebBrowserFactory.getInstance();
423 }
424
425 initialized = true;
426 }
427 catch( Throwable t )
428 {
429 disabledReason = t.getMessage();
430 t.printStackTrace();
431 }
432 }
433
434 public static boolean isJXBrowserDisabled()
435 {
436 if( disabled )
437 return true;
438
439 String disable = System.getProperty( "soapui.jxbrowser.disable", "nope" );
440 if( disable.equals( "true" ) )
441 return true;
442
443 if( !disable.equals( "false" )
444 && ( !Xpcom.isMacOSX() && "64".equals( System.getProperty( "sun.arch.data.model" ) ) ) )
445 return true;
446
447 return false;
448 }
449
450 public Component getComponent()
451 {
452 if( isJXBrowserDisabled() )
453 {
454 JEditorPane jxbrowserDisabledPanel = new JEditorPane();
455 jxbrowserDisabledPanel.setText( "browser component disabled" );
456 panel.add( jxbrowserDisabledPanel );
457 }
458 else
459 {
460 if( browser == null )
461 {
462
463 statusBar = new JPanel();
464 statusLabel = new JLabel();
465 statusBar.add( statusLabel, BorderLayout.CENTER );
466
467 if( addToolbar )
468 panel.add( buildToolbar(), BorderLayout.NORTH );
469
470 panel.add( statusBar, BorderLayout.SOUTH );
471
472 initBrowser();
473
474 browser.navigate( "about:blank" );
475 }
476 }
477 return panel;
478 }
479
480 private Component buildToolbar()
481 {
482 JXToolBar toolbar = UISupport.createToolbar();
483
484 toolbar.addFixed( UISupport.createToolbarButton( new BackAction() ) );
485 toolbar.addRelatedGap();
486 toolbar.addFixed( UISupport.createToolbarButton( new ForwardAction() ) );
487
488 toolbar.addGlue();
489
490 return toolbar;
491 }
492
493 private class BackAction extends AbstractAction
494 {
495 public BackAction()
496 {
497 putValue( SMALL_ICON, UISupport.createImageIcon( "/arrow_left.png" ) );
498 putValue( Action.SHORT_DESCRIPTION, "Navigate to previous selection" );
499 }
500
501 public void actionPerformed( ActionEvent e )
502 {
503 if( browser.getHistory().getCurrentPosition() == 0 )
504 Toolkit.getDefaultToolkit().beep();
505 else
506 browser.goBack();
507 }
508 }
509
510 private class ForwardAction extends AbstractAction
511 {
512 public ForwardAction()
513 {
514 putValue( SMALL_ICON, UISupport.createImageIcon( "/arrow_right.png" ) );
515 putValue( Action.SHORT_DESCRIPTION, "Navigate to next selection" );
516 }
517
518 public void actionPerformed( ActionEvent e )
519 {
520 browser.goForward();
521 }
522 }
523
524 public synchronized boolean initBrowser()
525 {
526 if( browser != null )
527 return false;
528
529 browser = webBrowserFactory == null ? new DummyBrowser() : webBrowserFactory.createBrowser();
530 panel.add( browser.getComponent(), BorderLayout.CENTER );
531 browser.addContentHandler( new ContentHandler()
532 {
533
534 public boolean canHandleContent( String arg0 )
535 {
536 return true;
537 }
538
539 public void handleContent( URL arg0 )
540 {
541 SoapUI.log.info( "Ignoring content for [" + arg0 + "]" );
542 }
543
544 public boolean isPreferred( String arg0 )
545 {
546 return true;
547 }
548 } );
549
550 if( webBrowserFactory != null )
551 {
552 nsIWebBrowser nsWebBrowser = ( ( MozillaWebBrowser )browser ).getWebBrowser();
553 nsWebBrowser.addWebBrowserListener( this, nsIWebProgressListener.NS_IWEBPROGRESSLISTENER_IID );
554 browser.addStatusChangeListener( this );
555
556 browser.setWindowCreator( new WindowCreator()
557 {
558 public WebBrowserWindow createChildWindow( Component parentComponent, long flags )
559 {
560 return browserWindowAdapter;
561 }
562 } );
563
564 setUpProxy();
565 }
566 return true;
567 }
568
569 public void release()
570 {
571 if( browser != null )
572 {
573 disposed = true;
574
575 if( !SwingUtilities.isEventDispatchThread() )
576 {
577 SwingUtilities.invokeLater( new Runnable()
578 {
579 public void run()
580 {
581 cleanup();
582 }
583 } );
584 }
585 else
586 cleanup();
587 }
588
589 possibleError = false;
590 }
591
592 private void cleanup()
593 {
594 browser.stop();
595
596 if( webBrowserFactory != null )
597 {
598 nsIWebBrowser nsWebBrowser = ( ( MozillaWebBrowser )browser ).getWebBrowser();
599 nsWebBrowser.removeWebBrowserListener( BrowserComponent.this,
600 nsIWebProgressListener.NS_IWEBPROGRESSLISTENER_IID );
601 browser.removeStatusChangeListener( BrowserComponent.this );
602 browser.dispose();
603 }
604 browser = null;
605 }
606
607 public void setContent( String contentAsString, String contentType, String contextUri )
608 {
609 if( !SwingUtilities.isEventDispatchThread() )
610 {
611 SwingUtilities.invokeLater( new ContentSetter( contentAsString, contentType, contextUri ) );
612 }
613 else
614 {
615 if( browser == null )
616 {
617 initBrowser();
618 }
619
620 browser.activate();
621 browser.setContentWithContext( contentAsString, contentType, contextUri );
622 }
623 }
624
625 public void setContent( String content, String contentType )
626 {
627 if( !SwingUtilities.isEventDispatchThread() )
628 {
629 SwingUtilities.invokeLater( new ContentSetter( content, contentType, null ) );
630 }
631 else
632 {
633 if( browser == null )
634 {
635 initBrowser();
636 }
637
638 browser.activate();
639 browser.setContent( content, contentType );
640 }
641 }
642
643 public boolean navigate( String url, String errorPage )
644 {
645 if( errorPage != null )
646 setErrorPage( errorPage );
647
648 this.url = url;
649 Xpcom.invokeLater( new Navigator() );
650 return true;
651 }
652
653 public String getContent()
654 {
655 return browser == null ? null : XmlUtils.serialize( browser.getDocument() );
656 }
657
658 private final class Navigator implements Runnable
659 {
660 public void run()
661 {
662 try
663 {
664 if( browser == null )
665 {
666 initBrowser();
667 }
668
669 browser.activate();
670 browser.navigate( getUrl() );
671
672 if( showingErrorPage )
673 showingErrorPage = false;
674 }
675 catch( Throwable e )
676 {
677 SoapUI.log( e.toString() );
678 }
679 }
680 }
681
682 public String getUrl()
683 {
684 return url;
685 }
686
687 public void setUrl( String url ) throws InterruptedException, InvocationTargetException
688 {
689 navigate( url, null );
690 }
691
692 public nsISupports queryInterface( String uuid )
693 {
694 return Mozilla.queryInterface( this, uuid );
695 }
696
697 public nsISupports queryReferent( String uuid )
698 {
699 return Mozilla.queryInterface( this, uuid );
700 }
701
702 public void onLocationChange( nsIWebProgress arg0, nsIRequest arg1, nsIURI arg2 )
703 {
704 if( getUrl() != null && !getUrl().equals( "about:blank" ) )
705 {
706 if( !possibleError )
707 possibleError = true;
708 else
709 {
710 if( !showingErrorPage )
711 {
712 showErrorPage();
713 }
714 }
715 }
716 }
717
718 public void onProgressChange( nsIWebProgress arg0, nsIRequest arg1, int arg2, int arg3, int arg4, int arg5 )
719 {
720
721 }
722
723 public void onSecurityChange( nsIWebProgress arg0, nsIRequest arg1, long arg2 )
724 {
725 }
726
727 public void onStateChange( nsIWebProgress arg0, nsIRequest request, long arg2, long arg3 )
728 {
729 try
730 {
731 if( getUrl() != null && !getUrl().equals( "about:blank" ) )
732 {
733 nsIHttpChannel ch = null;
734
735 ch = ( nsIHttpChannel )request.queryInterface( nsIHttpChannel.NS_IHTTPCHANNEL_IID );
736
737 if( ch != null )
738 {
739 possibleError = false;
740 showingErrorPage = false;
741 }
742 }
743 }
744 catch( XPCOMException e )
745 {
746 if( possibleError && !showingErrorPage )
747 showErrorPage();
748 }
749
750 }
751
752 private void showErrorPage()
753 {
754 if( errorPage != null && !errorPage.equals( getUrl() ) )
755 {
756 try
757 {
758 showingErrorPage = true;
759 setUrl( errorPage );
760 }
761 catch( Throwable e )
762 {
763 e.printStackTrace();
764 }
765 }
766 }
767
768 public String getErrorPage()
769 {
770 return errorPage;
771 }
772
773 public void setErrorPage( String errorPage )
774 {
775 this.errorPage = errorPage;
776 }
777
778 public void onStatusChange( nsIWebProgress arg0, nsIRequest arg1, long arg2, String arg3 )
779 {
780 try
781 {
782 if( getUrl() != null && !getUrl().equals( "about:blank" ) )
783 {
784 nsIHttpChannel ch = null;
785
786 ch = ( nsIHttpChannel )arg1.queryInterface( nsIHttpChannel.NS_IHTTPCHANNEL_IID );
787
788 if( ch != null )
789 {
790 possibleError = false;
791 showingErrorPage = false;
792 }
793 }
794 }
795 catch( XPCOMException e )
796 {
797 if( possibleError && !showingErrorPage )
798 showErrorPage();
799 }
800 }
801
802 private class BrowserWindowAdapter implements WebBrowserWindow
803 {
804 private boolean resizable;
805
806 public void close()
807 {
808 }
809
810 public boolean isClosed()
811 {
812 return true;
813 }
814
815 public void setModal( boolean arg0 )
816 {
817 }
818
819 public void setSize( int arg0, int arg1 )
820 {
821 }
822
823 public void setVisible( boolean arg0 )
824 {
825 }
826
827 public void setWebBrowser( WebBrowser arg0 )
828 {
829 if( arg0 != null )
830 {
831 arg0.addRequestListener( new PopupRequestAdapter() );
832 }
833 }
834
835 public boolean isResizable()
836 {
837 return resizable;
838 }
839
840 public void setResizable( boolean resizable )
841 {
842 this.resizable = resizable;
843 }
844 }
845
846 public void statusChanged( final StatusChangeEvent event )
847 {
848 if( statusLabel != null )
849 {
850 SwingUtilities.invokeLater( new Runnable()
851 {
852 public void run()
853 {
854 statusLabel.setText( event.getStatus() );
855 }
856 } );
857 }
858 }
859
860 public boolean isBrowserInitialised()
861 {
862 return browser != null;
863 }
864
865 private static class PopupRequestAdapter extends RequestAdapter
866 {
867 private LocationEvent event;
868
869 @Override
870 public void locationChanged( LocationEvent arg0 )
871 {
872 if( !arg0.getLocation().equals( "about:blank" ) )
873 {
874 event = arg0;
875 SwingUtilities.invokeLater( new Runnable()
876 {
877
878 public void run()
879 {
880 boolean opened = false;
881 if( UISupport.confirm( "Open url [" + event.getLocation() + "] in external browser?", "Open URL" ) )
882 {
883 opened = true;
884 SwingUtilities.invokeLater( new Runnable()
885 {
886
887 public void run()
888 {
889 Tools.openURL( event.getLocation() );
890 event = null;
891 }
892 } );
893 }
894
895 event.getWebBrowser().stop();
896 event.getWebBrowser().deactivate();
897 event.getWebBrowser().dispose();
898 event.getWebBrowser().removeRequestListener( PopupRequestAdapter.this );
899 if( !opened )
900 event = null;
901 }
902 } );
903 }
904 }
905 }
906
907 public class ContentSetter implements Runnable
908 {
909 private final String contentAsString;
910 private final String contentType;
911 private final String contextUri;
912
913 public ContentSetter( String contentAsString, String contentType, String contextUri )
914 {
915 this.contentAsString = contentAsString;
916 this.contentType = contentType;
917 this.contextUri = contextUri;
918 }
919
920 public void run()
921 {
922 if( StringUtils.hasContent( contextUri ) )
923 {
924 browser.setContentWithContext( contentAsString, contentType, contextUri );
925 }
926 else
927 {
928 browser.setContent( contentAsString, contentType );
929 }
930 }
931 }
932
933 /***
934 * Setups proxy configuration
935 */
936
937 void setUpProxy()
938 {
939 ProxyConfiguration proxyConf = Services.getProxyConfiguration();
940 if( proxyConf == null )
941 return;
942
943 Settings settings = SoapUI.getSettings();
944 PropertyExpansionContext context = null;
945
946
947 String proxyHost = System.getProperty( "http.proxyHost" );
948 String proxyPort = System.getProperty( "http.proxyPort" );
949
950 if( proxyHost == null )
951 proxyHost = PropertyExpander.expandProperties( context, settings.getString( ProxySettings.HOST, "" ) );
952
953 if( proxyPort == null )
954 proxyPort = PropertyExpander.expandProperties( context, settings.getString( ProxySettings.PORT, "" ) );
955
956 if( !StringUtils.isNullOrEmpty( proxyHost ) && !StringUtils.isNullOrEmpty( proxyPort ) )
957 {
958 proxyConf.setHttpHost( proxyHost );
959 proxyConf.setHttpPort( Integer.parseInt( proxyPort ) );
960
961 String[] excludes = PropertyExpander.expandProperties( context,
962 settings.getString( ProxySettings.EXCLUDES, "" ) ).split( "," );
963 for( String url : excludes )
964 {
965 proxyConf.setSkipProxyFor( url );
966 }
967
968 final String proxyUsername = PropertyExpander.expandProperties( context, settings.getString(
969 ProxySettings.USERNAME, null ) );
970 final String proxyPassword = PropertyExpander.expandProperties( context, settings.getString(
971 ProxySettings.PASSWORD, null ) );
972
973 if( proxyUsername != null )
974 {
975 proxyConf.setPoxyAuthenticationHandler( ProxyServerType.HTTP, new PoxyAuthenticationHandler()
976 {
977 /***
978 * manually sets user name and password for proxy server
979 */
980 public ProxyServerAuthInfo authenticationRequired()
981 {
982 return new ProxyServerAuthInfo( proxyUsername, proxyPassword );
983 }
984 } );
985 }
986 }
987 }
988 }