View Javadoc

1   /*
2    *  soapUI, copyright (C) 2004-2009 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.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  
20  import javax.swing.AbstractAction;
21  import javax.swing.Action;
22  import javax.swing.JEditorPane;
23  import javax.swing.JLabel;
24  import javax.swing.JPanel;
25  import javax.swing.SwingUtilities;
26  
27  import org.mozilla.interfaces.nsIHttpChannel;
28  import org.mozilla.interfaces.nsIRequest;
29  import org.mozilla.interfaces.nsISupports;
30  import org.mozilla.interfaces.nsIURI;
31  import org.mozilla.interfaces.nsIWeakReference;
32  import org.mozilla.interfaces.nsIWebBrowser;
33  import org.mozilla.interfaces.nsIWebProgress;
34  import org.mozilla.interfaces.nsIWebProgressListener;
35  import org.mozilla.xpcom.Mozilla;
36  import org.mozilla.xpcom.XPCOMException;
37  
38  import com.eviware.soapui.SoapUI;
39  import com.eviware.soapui.support.Tools;
40  import com.eviware.soapui.support.UISupport;
41  import com.eviware.soapui.support.xml.XmlUtils;
42  import com.teamdev.jxbrowser.WebBrowser;
43  import com.teamdev.jxbrowser.WebBrowserFactory;
44  import com.teamdev.jxbrowser.WebBrowserWindow;
45  import com.teamdev.jxbrowser.WindowCreator;
46  import com.teamdev.jxbrowser.event.LocationEvent;
47  import com.teamdev.jxbrowser.event.RequestAdapter;
48  import com.teamdev.jxbrowser.event.StatusChangeEvent;
49  import com.teamdev.jxbrowser.event.StatusChangeListener;
50  import com.teamdev.jxbrowser.mozilla.MozillaWebBrowser;
51  import com.teamdev.xpcom.Xpcom;
52  
53  public class BrowserComponent implements nsIWebProgressListener, nsIWeakReference, StatusChangeListener
54  {
55  	private WebBrowser browser;
56  	private static WebBrowserFactory webBrowserFactory;
57  	private JPanel panel = new JPanel( new BorderLayout() );
58  	private JPanel statusBar;
59  	private JLabel statusLabel;
60  	private String errorPage;
61  	private WebBrowserWindow browserWindowAdapter = new BrowserWindowAdapter();
62  	private final boolean addToolbar;
63  	private boolean showingErrorPage;
64  	public String url;
65  	private static Boolean initialized = false;
66  
67  	public BrowserComponent( boolean addToolbar )
68  	{
69  		this.addToolbar = addToolbar;
70  
71  		if( !initialized )
72  		{
73  			synchronized( initialized )
74  			{
75  				if( !initialized )
76  				{
77  					try
78  					{
79  						if( !isJXBrowserDisabled() )
80  						{
81  							if( Xpcom.isMacOSX() )
82  							{
83  								final String currentCP = System.getProperty( "java.class.path" );
84  								final String appleJavaExtentions = ":/System/Library/Java";
85  								System.setProperty( "java.class.path", currentCP + appleJavaExtentions );
86  							}
87  
88  							Xpcom.initialize();
89  						}
90  
91  						initialized = true;
92  					}
93  					catch( Throwable t )
94  					{
95  						t.printStackTrace();
96  					}
97  				}
98  			}
99  		}
100 	}
101 
102 	public static boolean isJXBrowserDisabled()
103 	{
104 		String disable = System.getProperty( "soapui.jxbrowser.disable", "nope" );
105 		if( disable.equals( "true" ) )
106 			return true;
107 
108 		if( !disable.equals( "false" ) && "64".equals( System.getProperty( "sun.arch.data.model" ) ) )
109 			return true;
110 
111 		return false;
112 	}
113 
114 	public Component getComponent()
115 	{
116 		if( isJXBrowserDisabled() )
117 		{
118 			JEditorPane jxbrowserDisabledPanel = new JEditorPane();
119 			jxbrowserDisabledPanel.setText( "browser component disabled" );
120 			panel.add( jxbrowserDisabledPanel );
121 		}
122 		else
123 		{
124 			if( browser == null )
125 			{
126 				initBrowser();
127 				navigate( "about:blank", null );
128 
129 				statusBar = new JPanel();
130 				statusLabel = new JLabel();
131 				statusBar.add( statusLabel, BorderLayout.CENTER );
132 
133 				if( addToolbar )
134 					panel.add( buildToolbar(), BorderLayout.NORTH );
135 
136 				panel.add( browser.getComponent(), BorderLayout.CENTER );
137 				panel.add( statusBar, BorderLayout.SOUTH );
138 				
139 				panel.repaint();
140 			}
141 		}
142 		return panel;
143 	}
144 
145 	private Component buildToolbar()
146 	{
147 		JXToolBar toolbar = UISupport.createToolbar();
148 
149 		toolbar.addFixed( UISupport.createToolbarButton( new BackAction() ) );
150 		toolbar.addRelatedGap();
151 		toolbar.addFixed( UISupport.createToolbarButton( new ForwardAction() ) );
152 
153 		toolbar.addGlue();
154 
155 		return toolbar;
156 	}
157 
158 	private class BackAction extends AbstractAction
159 	{
160 		public BackAction()
161 		{
162 			putValue( SMALL_ICON, UISupport.createImageIcon( "/arrow_left.png" ) );
163 			putValue( Action.SHORT_DESCRIPTION, "Navigate to previous selection" );
164 		}
165 
166 		public void actionPerformed( ActionEvent e )
167 		{
168 			if( browser.getHistory().getCurrentPosition() == 0 )
169 				Toolkit.getDefaultToolkit().beep();
170 			else
171 				browser.goBack();
172 		}
173 	}
174 
175 	private class ForwardAction extends AbstractAction
176 	{
177 		public ForwardAction()
178 		{
179 			putValue( SMALL_ICON, UISupport.createImageIcon( "/arrow_right.png" ) );
180 			putValue( Action.SHORT_DESCRIPTION, "Navigate to next selection" );
181 		}
182 
183 		public void actionPerformed( ActionEvent e )
184 		{
185 			// WebBrowserHistory history = browser.getHistory();
186 			// List entries = history.getEntries();
187 			// if( history.getCurrentPosition() == entries.size()-1 )
188 			// Toolkit.getDefaultToolkit().beep();
189 			// else
190 			browser.goForward();
191 		}
192 	}
193 
194 	public void initBrowser()
195 	{
196 		if( webBrowserFactory == null )
197 			webBrowserFactory = WebBrowserFactory.getInstance();
198 
199 		browser = webBrowserFactory.createBrowser();
200 		nsIWebBrowser nsWebBrowser = ( ( MozillaWebBrowser )browser ).getWebBrowser();
201 		nsWebBrowser.addWebBrowserListener( this, nsIWebProgressListener.NS_IWEBPROGRESSLISTENER_IID );
202 		browser.addStatusChangeListener( this );
203 
204 		browser.setWindowCreator( new WindowCreator()
205 		{
206 			public WebBrowserWindow createChildWindow( Component parentComponent, long flags )
207 			{
208 				return browserWindowAdapter;
209 			}
210 		} );
211 
212 		browser.deactivate();
213 	}
214 
215 	public void release()
216 	{
217 		if( browser != null )
218 		{
219 			browser.stop();
220 			browser.deactivate();
221 			
222 			nsIWebBrowser nsWebBrowser = ( ( MozillaWebBrowser )browser ).getWebBrowser();
223 			nsWebBrowser.removeWebBrowserListener( this, nsIWebProgressListener.NS_IWEBPROGRESSLISTENER_IID );
224 			browser.removeStatusChangeListener( this );
225 			browser.dispose();
226 		}
227 		
228 		browser = null;
229 	}
230 
231 	public void setContent( String contentAsString, String contentType, String contextUri )
232 	{
233 		if( browser == null )
234 		{
235 			initBrowser();
236 		}
237 		browser.setContentWithContext( contentAsString, contentType, contextUri );
238 	}
239 
240 	public void setContent( String content, String contentType )
241 	{
242 		// setContent( content, contentType, null );
243 
244 		if( browser == null )
245 		{
246 			initBrowser();
247 		}
248 
249 		try
250 		{
251 			browser.setContent( content, contentType );
252 		}
253 		catch( Throwable t )
254 		{
255 			SoapUI.logError( t );
256 		}
257 	}
258 
259 	public boolean navigate( String url, String errorPage )
260 	{
261 		if( browser == null )
262 		{
263 			initBrowser();
264 		}
265 
266 		if( errorPage != null )
267 			setErrorPage( errorPage );
268 
269 		this.url = url;
270 		SwingUtilities.invokeLater( new Navigator() );
271 
272 		return true;
273 	}
274 
275 	public String getContent()
276 	{
277 		return browser == null ? null : XmlUtils.serialize( browser.getDocument() );
278 	}
279 
280 	private final class Navigator implements Runnable
281 	{
282 		public void run()
283 		{
284 			try
285 			{
286 				browser.navigate( getUrl() );
287 			}
288 			catch( Throwable e )
289 			{
290 				SoapUI.log( e.toString() );
291 			}
292 		}
293 	}
294 
295 	public String getUrl()
296 	{
297 		return url;
298 	}
299 
300 	public void setUrl( String url )
301 	{
302 		navigate( url, null );
303 	}
304 
305 	public nsISupports queryInterface( String uuid )
306 	{
307 		return Mozilla.queryInterface( this, uuid );
308 	}
309 
310 	public nsISupports queryReferent( String uuid )
311 	{
312 		return Mozilla.queryInterface( this, uuid );
313 	}
314 
315 	public void onLocationChange( nsIWebProgress arg0, nsIRequest arg1, nsIURI arg2 )
316 	{
317 	}
318 
319 	public void onProgressChange( nsIWebProgress arg0, nsIRequest arg1, int arg2, int arg3, int arg4, int arg5 )
320 	{
321 	}
322 
323 	public void onSecurityChange( nsIWebProgress arg0, nsIRequest arg1, long arg2 )
324 	{
325 	}
326 
327 	public void onStateChange( nsIWebProgress arg0, nsIRequest request, long arg2, long arg3 )
328 	{
329 		try
330 		{
331 			if( !getUrl().equals( "about:blank" ) )
332 			{
333 				nsIHttpChannel ch = null;
334 				try {
335 					ch = ( nsIHttpChannel )request.queryInterface( nsIHttpChannel.NS_IHTTPCHANNEL_IID );
336 				}
337 					catch( XPCOMException e )
338 					{
339 						if( (!browser.getLocationURL().equals( errorPage )) && ( e.errorcode != 2147500034l ) )
340 						{
341 							SoapUI.log.warn( "Error [" + e.getMessage() + "] for " + e.errorcode );
342 							browser.navigate( errorPage );
343 						}
344 					}
345 				if( ch != null && ch.getResponseStatus() >= 400 )
346 				{
347 					//SoapUI.log.warn( "Error [" + ch.getResponseStatus() + "] for " + ch.getOriginalURI().toString() );
348 					if( !showingErrorPage )
349 						showErrorPage();
350 				}
351 			}
352 		}
353 		catch( XPCOMException e )
354 		{
355 			//if( (!browser.getLocationURL().equals( errorPage )) && ( e.errorcode != 2147500034l ) )
356 			//{
357 				//SoapUI.log.warn( "Error [" + e.getMessage() + "] for " + e.errorcode );
358 				//browser.navigate( errorPage );
359 			//}
360 		}
361 	}
362 
363 	private void showErrorPage()
364 	{
365 		showingErrorPage = true;
366 		browser.navigate( errorPage );
367 		showingErrorPage = false;
368 	}
369 
370 	public String getErrorPage()
371 	{
372 		return errorPage;
373 	}
374 
375 	public void setErrorPage( String errorPage )
376 	{
377 		this.errorPage = errorPage;
378 	}
379 
380 	public void onStatusChange( nsIWebProgress arg0, nsIRequest arg1, long arg2, String arg3 )
381 	{
382 	}
383 
384 	private class BrowserWindowAdapter implements WebBrowserWindow
385 	{
386 		private boolean resizable;
387 
388 		public void close()
389 		{
390 		}
391 
392 		public boolean isClosed()
393 		{
394 			return true;
395 		}
396 
397 		public void setModal( boolean arg0 )
398 		{
399 		}
400 
401 		public void setSize( int arg0, int arg1 )
402 		{
403 		}
404 
405 		public void setVisible( boolean arg0 )
406 		{
407 		}
408 
409 		public void setWebBrowser( WebBrowser arg0 )
410 		{
411 			if( arg0 != null )
412 			{
413 				arg0.addRequestListener( new RequestAdapter()
414 				{
415 
416 					@Override
417 					public void locationChanged( final LocationEvent arg0 )
418 					{
419 						if( !arg0.getLocation().equals( "about:blank" ) )
420 						{
421 							if( UISupport.confirm( "Open url [" + arg0.getLocation() + "] in external browser?", "Open URL" ) )
422 								Tools.openURL( arg0.getLocation() );
423 
424 							arg0.getWebBrowser().stop();
425 							arg0.getWebBrowser().deactivate();
426 							arg0.getWebBrowser().dispose();
427 							arg0.getWebBrowser().removeRequestListener( this );
428 						}
429 						// Toolkit.getDefaultToolkit().beep();
430 					}
431 				} );
432 
433 				// arg0.stop();
434 				// arg0.deactivate();
435 				// arg0.dispose();
436 				//
437 				// Toolkit.getDefaultToolkit().beep();
438 			}
439 
440 		}
441 
442 		public boolean isResizable()
443 		{
444 			return resizable;
445 		}
446 
447 		public void setResizable( boolean resizable )
448 		{
449 			this.resizable = resizable;
450 		}
451 	}
452 
453 	public void statusChanged( final StatusChangeEvent event )
454 	{
455 		if( statusLabel != null )
456 		{
457 			SwingUtilities.invokeLater( new Runnable()
458 			{
459 				public void run()
460 				{
461 					statusLabel.setText( event.getStatus() );
462 				}
463 			} );
464 		}
465 	}
466 	
467 	public boolean isBrowserInitialised() {
468 		return browser != null;
469 	}
470 }