summaryrefslogblamecommitdiffstats
path: root/src/main/java/org/openslx/filetransfer/Downloader.java
blob: c860f5e7bb3e1314c40499e9af8c9893aa663c92 (plain) (tree)
1
2
3
4
5
6
7
8
9

                                 

                                
                    

                                
                                       
                                         


                                
                                      
 

                               
                       
 
                                   





                                                  
                                             
                                    
 
                                                                         


                                                                                 

                                                                               
           

                      
           
                                                                    
         












                                                                                                 

         

                                                                                 

                                                                          
           
                        
           
                                             
         






                                                                                                 

         

                                                                                 
                                             
           

                          
                                                        


                                          


                                                                                 
                                             
           
                                 


                                         
                                      
         


                                                                                 







































                                                                                                   
                                                




























                                                                                                   
           
           
                                
         


















                                                                                   
                                    


                                                               
                                                               


























                                                                                 
                                                                           


















                                                                                                   
                                                         


                                                     
                                






















































                                                                                                             
         


                                                                                 
                                                                                   
           
           
                                   
         
                                             
                     
                                                      
                                                            
                                        

                                                                                        

                                                                                                                            
                                                                                                            
                                                  

                                                                                             


                                                     
                                                               
 



                                                        
                                                                                   
                                     
                                         
                                            

                                                                                              
                                     
                                     
                           
                                             





                                                            
                 

                            









































                                                                                   
 
package org.openslx.filetransfer;

import java.io.DataInputStream;
import java.io.DataOutputStream;
import java.io.File;
import java.io.IOException;
import java.io.RandomAccessFile;
import java.net.SocketTimeoutException;
import java.nio.charset.StandardCharsets;

import javax.net.ssl.SSLContext;
import javax.net.ssl.SSLSocket;
import javax.net.ssl.SSLSocketFactory;

import org.apache.log4j.Logger;

public class Downloader
{
	// Some instance variables.
	private SSLSocketFactory sslSocketFactory;
	private SSLSocket satelliteSocket;
	private DataOutputStream dataToServer;
	private DataInputStream dataFromServer;
	private String TOKEN = null;
	private String RANGE = null;
	private String outputFilename = null;
	private String ERROR = null;

	private static Logger log = Logger.getLogger( Downloader.class );

	/***********************************************************************/
	/**
	 * Constructor for satellite downloader.
	 * Tries to connect to specific ip and port and sending type of action.
	 * 
	 * @param ip
	 * @param port
	 */
	public Downloader( String ip, int port, SSLContext context )
	{
		try {
			// create socket.
			sslSocketFactory = context.getSocketFactory();

			satelliteSocket = (SSLSocket)sslSocketFactory.createSocket( ip, port );
			satelliteSocket.setSoTimeout( 2000 ); // set socket timeout.

			dataToServer = new DataOutputStream( satelliteSocket.getOutputStream() );
			dataToServer.writeByte( 'D' );
			dataFromServer = new DataInputStream( satelliteSocket.getInputStream() );
		} catch ( Exception e ) {
			e.printStackTrace();
		}
	}

	/***********************************************************************/
	/**
	 * Constructor for master downloader.
	 * Given parameter is the socket over which the transfer is going.
	 * 
	 * @param socket
	 */
	public Downloader( SSLSocket socket )
	{
		try {
			satelliteSocket = socket;
			dataToServer = new DataOutputStream( satelliteSocket.getOutputStream() );
			dataFromServer = new DataInputStream( satelliteSocket.getInputStream() );
		} catch ( IOException e ) {
			e.printStackTrace();
		}
	}

	/***********************************************************************/
	/**
	 * Method for setting outputFilename.
	 * 
	 * @param filename
	 */
	public void setOutputFilename( String filename )
	{
		outputFilename = filename;
	}

	/***********************************************************************/
	/**
	 * Method for getting outputFilename.
	 * 
	 * @return outputFilename
	 */
	public String getOutputFilename()
	{
		return outputFilename;
	}

	/***********************************************************************/
	/**
	 * Method for sending token for identification from satellite to master.
	 * 
	 * @param t
	 */
	public Boolean sendToken( String token )
	{
		try {
			TOKEN = token;
			String sendToken = "TOKEN=" + TOKEN;
			byte[] data = sendToken.getBytes( StandardCharsets.UTF_8 );
			dataToServer.writeByte( data.length );
			dataToServer.write( data );
		} catch ( SocketTimeoutException ste ) {
			ste.printStackTrace();
			log.info( "Socket timeout occured ... close connection." );
			this.close();
		} catch ( IOException e ) {
			e.printStackTrace();
			readMetaData();
			if ( ERROR != null ) {
				if ( ERROR == "timeout" ) {
					log.info( "Socket timeout occured ... close connection." );
					this.close();
				}
			}
			log.info( "Sending TOKEN in Downloader failed..." );
			return false;
		}
		return true;
	}

	/***********************************************************************/
	/**
	 * Method to send range of the file, which should be uploaded.
	 * Helpful for knowing how much was already uploaded if
	 * connection aborts.
	 * 
	 * @param a
	 * @param b
	 */
	public Boolean sendRange( int a, int b )
	{
		try {
			RANGE = a + ":" + b;
			String sendRange = "RANGE=" + RANGE;
			byte[] data = sendRange.getBytes( StandardCharsets.UTF_8 );
			dataToServer.writeByte( data.length );
			dataToServer.write( data );
		} catch ( SocketTimeoutException ste ) {
			ste.printStackTrace();
			log.info( "Socket timeout occured ... close connection." );
			this.close();
		} catch ( IOException e ) {
			e.printStackTrace();
			readMetaData();
			if ( ERROR != null ) {
				if ( ERROR == "timeout" ) {
					log.info( "Socket timeout occured ... close connection." );
					this.close();
				}
			}
			log.info( "Sending RANGE in Uploader failed..." );
			return false;
		}
		return true;
	}

	/***********************************************************************/
	/**
	 * Method for reading incoming token for identification.
	 * 
	 */
	public String getToken()
	{
		return TOKEN;
	}

	/***********************************************************************/
	/**
	 * Method for reading range of file, which is downloaded.
	 * Helpful for knowing how much is already downloaded if connection aborts.
	 */
	public String getRange()
	{
		return RANGE;
	}

	/***********************************************************************/
	/**
	 * Getter for beginning of RANGE.
	 * 
	 * @return
	 */
	public int getStartOfRange()
	{
		if ( RANGE != null ) {
			String[] splitted = RANGE.split( ":" );
			return Integer.parseInt( splitted[0] );
		}
		return -1;
	}

	/***********************************************************************/
	/**
	 * Getter for end of RANGE.
	 * 
	 * @return
	 */
	public int getEndOfRange()
	{
		if ( RANGE != null ) {
			String[] splitted = RANGE.split( ":" );
			return Integer.parseInt( splitted[1] );
		}
		return -1;
	}

	/***********************************************************************/
	/**
	 * Method for returning difference of current Range.
	 * 
	 * @return
	 */
	public int getDiffOfRange()
	{
		int diff = Math.abs( getEndOfRange() - getStartOfRange() );
		return diff;
	}

	/***********************************************************************/
	/**
	 * Method for reading MetaData, like TOKEN and FileRange.
	 * Split incoming bytes after first '=' and store value to specific
	 * variable.
	 * 
	 */
	public Boolean readMetaData()
	{
		try {
			while ( true ) {
				byte[] incoming = new byte[ 255 ]; // TODO: problematische Größe.

				// First get length.
				int retLengthByte;
				retLengthByte = dataFromServer.read( incoming, 0, 1 );
				if (retLengthByte != 1) {
					this.close();
					return false;
				}
				
				int length = incoming[0] & 0xFF;
				log.info( "length (downloader): " + length );

				if ( length == 0 )
					break;

				/**
				 * Read the next available bytes and split by '=' for
				 * getting TOKEN or RANGE.
				 */
				int hasRead = 0;
				while ( hasRead < length ) {
					int ret = dataFromServer.read( incoming, hasRead, length - hasRead );
					if ( ret == -1 ) {
						log.info( "Error occured while reading Metadata." );
						return false;
					}
					hasRead += ret;
				}

				String data = new String( incoming, 0, length, "UTF-8" );
				// System.out.println(data);

				String[] splitted = data.split( "=" );
				// System.out.println("splitted[0]: " + splitted[0]);
				// System.out.println("splitted[1]: " + splitted[1]);
				if ( splitted[0] != null && splitted[0].equals( "TOKEN" ) ) {
					if ( splitted[1] != null )
						TOKEN = splitted[1];
					log.info( "TOKEN: " + TOKEN );
				}
				else if ( splitted[0].equals( "RANGE" ) ) {
					if ( splitted[1] != null )
						RANGE = splitted[1];
					log.info( "RANGE: '" + RANGE + "'" );
				}
				else if ( splitted[0].equals( "ERROR" ) ) {
					if ( splitted[1] != null )
						ERROR = splitted[1];
					log.info( "ERROR: " + ERROR );
					return false;
				}
			}
		} catch ( SocketTimeoutException ste ) {
			ste.printStackTrace();
			sendErrorCode( "timeout" );
			log.info( "Socket Timeout occured in Downloader." );
			this.close();
			return false;
		} catch ( Exception e ) {
			e.printStackTrace();
			this.close();
			return false;
		}
		return true;
	}

	/***********************************************************************/
	/**
	 * Method for reading Binary. Reading the current Range of incoming binary.
	 * 
	 */
	public Boolean readBinary()
	{
		RandomAccessFile file = null;
		try {
			int length = getDiffOfRange();
			byte[] incoming = new byte[ 4000 ]; 
			int hasRead = 0;
			file = new RandomAccessFile( new File( outputFilename ), "rw" );
			file.seek( getStartOfRange() );
			while ( hasRead < length ) {
				int ret = dataFromServer.read( incoming, 0, Math.min( length - hasRead, incoming.length ) );
				// log.info("hasRead: " + hasRead + " length: " + length + " ret: " + ret); 
				if ( ret == -1 ) {
					log.info( "Error occured in Downloader.readBinary(),"
							+ " while reading binary." );
					return false;
				}
				hasRead += ret;
				file.write( incoming, 0, ret );

			}
		} catch ( SocketTimeoutException ste ) {
			ste.printStackTrace();
			sendErrorCode( "timeout" );
			log.info( "Socket timeout occured ... close connection." );
			this.close();
		} catch ( Exception e ) {
			e.printStackTrace();
			log.info( "Reading RANGE " + getStartOfRange() + ":" + getEndOfRange()
					+ " of file failed..." );
			this.close();
			return false;
		} finally {
			if ( file != null ) {
				try {
					file.close();
				} catch ( IOException e ) {
					e.printStackTrace();
				}
			}
		}
		return true;
	}

	/***********************************************************************/
	/**
	 * Method for sending error Code to server. For example in case of wrong
	 * token, send code for wrong token.
	 * 
	 */
	public Boolean sendErrorCode( String errString )
	{
		try {
			String sendError = "ERROR=" + errString;
			byte[] data = sendError.getBytes( StandardCharsets.UTF_8 );
			dataToServer.writeByte( data.length );
			dataToServer.write( data );
		} catch ( IOException e ) {
			e.printStackTrace();
			this.close();
			return false;
		}
		return true;
	}

	/***********************************************************************/
	/**
	 * Method for closing connection, if download has finished.
	 * 
	 */
	public void close()
	{
		try {
			if ( satelliteSocket != null ) {
				this.satelliteSocket.close();
				satelliteSocket = null;
			}
			if ( dataFromServer != null )
				dataFromServer.close();
			if ( dataToServer != null )
				dataToServer.close();
		} catch ( IOException e ) {
			e.printStackTrace();
		}
	}
}