/******************************************************************************* * Copyright (c) 2000-present Liferay, Inc. All rights reserved. * * This library is free software; you can redistribute it and/or modify it under * the terms of the GNU Lesser General Public License as published by the Free * Software Foundation; either version 2.1 of the License, or (at your option) * any later version. * * This library is distributed in the hope that it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS * FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more * details. * *******************************************************************************/ package com.liferay.ide.server.remote; import com.liferay.ide.core.LiferayCore; import com.liferay.ide.server.core.LiferayServerCore; import java.io.BufferedInputStream; import java.io.IOException; import java.io.InputStream; import java.net.Authenticator; import java.net.MalformedURLException; import java.net.URI; import java.net.URISyntaxException; import java.net.URL; import java.net.URLConnection; import org.apache.commons.codec.binary.Base64; import org.eclipse.core.net.proxy.IProxyData; import org.eclipse.core.net.proxy.IProxyService; import org.eclipse.core.runtime.preferences.DefaultScope; import org.eclipse.core.runtime.preferences.IEclipsePreferences; import org.eclipse.wst.server.core.IServer; /** * @author Greg Amerson * @author Tao Tao * @author Simon Jiang */ public class RemoteLogStream extends BufferedInputStream { @SuppressWarnings( "deprecation" ) public static final IEclipsePreferences _defaultPrefs = new DefaultScope().getNode( LiferayServerCore.PLUGIN_ID ); public static final long LOG_QUERY_RANGE = _defaultPrefs.getLong( "log.query.range", 51200 ); //$NON-NLS-1$ public final static long OUTPUT_MONITOR_DELAY = _defaultPrefs.getLong( "output.monitor.delay", 1000 ); //$NON-NLS-1$ protected static URL createBaseUrl( IServer server, IRemoteServer remoteServer, IServerManagerConnection connection, String log ) { try { return new URL( getLogURI( connection, log ) + getFormatQuery() ); } catch( MalformedURLException e ) { } return null; } protected static InputStream createInputStream( IServer server, IRemoteServer remoteServer, IServerManagerConnection connection, String log ) { try { URL url = createBaseUrl( server, remoteServer, connection, log ); return openInputStream( connection, url ); } catch( Exception e ) { e.printStackTrace(); } return null; } protected static String getFormatQuery() { return "?format=raw"; //$NON-NLS-1$ } protected static String getLogURI( IServerManagerConnection connection, String log ) { return connection.getManagerURI() + "/server/log/" + log; //$NON-NLS-1$ } protected static InputStream openInputStream( IServerManagerConnection remote, URL url ) throws IOException { String username = remote.getUsername(); String password = remote.getPassword(); String authString = username + ":" + password; //$NON-NLS-1$ byte[] authEncBytes = Base64.encodeBase64( authString.getBytes() ); String authStringEnc = new String( authEncBytes ); final IProxyService proxyService = LiferayCore.getProxyService(); URLConnection conn = null; try { URI uri = new URI( "HTTP://" + url.getHost() + ":" + url.getPort() ); //$NON-NLS-1$ //$NON-NLS-2$ IProxyData[] proxyDataForHost = proxyService.select( uri ); for( IProxyData data : proxyDataForHost ) { if( data.getHost() != null ) { System.setProperty( "http.proxyHost", data.getHost() ); //$NON-NLS-1$ System.setProperty( "http.proxyPort", String.valueOf( data.getPort() ) ); //$NON-NLS-1$ break; } } uri = new URI( "SOCKS://" + url.getHost() + ":" + url.getPort() ); //$NON-NLS-1$ //$NON-NLS-2$ proxyDataForHost = proxyService.select( uri ); for( IProxyData data : proxyDataForHost ) { if( data.getHost() != null ) { System.setProperty( "socksProxyHost", data.getHost() ); //$NON-NLS-1$ System.setProperty( "socksProxyPort", String.valueOf( data.getPort() ) ); //$NON-NLS-1$ break; } } } catch( URISyntaxException e ) { LiferayServerCore.logError( "Could not read proxy data", e ); //$NON-NLS-1$ } conn = url.openConnection(); conn.setRequestProperty( "Authorization", "Basic " + authStringEnc ); //$NON-NLS-1$ //$NON-NLS-2$ Authenticator.setDefault( null ); conn.setAllowUserInteraction( false ); return conn.getInputStream(); } protected URL baseUrl = null; protected IServerManagerConnection connection; protected String log; protected long range = 0; public RemoteLogStream( IServer server, IRemoteServer remoteServer, IServerManagerConnection connection, String log ) { super( createInputStream( server, remoteServer, connection, log ), 8192 ); this.baseUrl = createBaseUrl( server, remoteServer, connection, log ); this.log = log; this.connection = connection; } @Override public int read( byte[] b ) throws IOException { int read = super.read( b ); if( read < 1 ) { waitOnNewInput(); read = super.read( b ); } range += read; return read; } @Override public synchronized int read( byte[] b, int off, int len ) throws IOException { int read = super.read( b, off, len ); if( read < 1 ) { waitOnNewInput(); read = super.read( b, off, len ); } range += read; return read; } protected void waitOnNewInput() throws IOException { // previous input stream was empty, so we need to move the range this.in.close(); // peek at the new stream boolean goodUrl = false; while( !goodUrl ) { URL newUrl = new URL( getLogURI( connection, log ) + "/" + range + getFormatQuery() ); //$NON-NLS-1$ try { goodUrl = urlPeek( newUrl ); } catch( Exception e ) { // failed to get a new good url, try again next time } if( goodUrl ) { this.in = openInputStream( connection, newUrl ); return; } try { Thread.sleep( OUTPUT_MONITOR_DELAY ); } catch( InterruptedException e ) { } } } boolean urlPeek( URL url ) throws IOException { byte[] buf = new byte[256]; int bufRead = new BufferedInputStream( openInputStream( connection, url ), 256 ).read( buf ); if( bufRead != -1 ) { String peek = new String( buf ); if( peek != null && ( !peek.contains( "Error 416: Invalid Range values." ) ) ) //$NON-NLS-1$ { return true; } } return false; } }