summaryrefslogblamecommitdiffstats
path: root/src/main/java/org/openslx/imagemaster/serverconnection/ImageProcessor.java
blob: 272b924fbcfbfed9ddd233700ddd8914ccf1465a (plain) (tree)
1
2
3
4
5
6
7
8
9
10









                                                 
                                                          



                                                        



                                                                                 

                           
 
                                                                                   






                                                                                          
                          
                                     
           







                                                                                                    



                                                                                                      
           







                                                                                               
 
                                             
 
                                                                                                                                                                                                                        


                                                                                 
                                                   
                                                                        



                                                                                                  
 
                                                      

                                                                                               
                                                                     
                                                                                                                         


                                                                           
                                                                                       
                                                                                                     


                                                                                                                                    
                                                                                                                                                                     

                                                                                                                             

                                                                                 
                                                                                                                          





                                                                                 
 























































                                                                                                                          

                                                        
           

                                                                                      
                                     


                                                                                     

                                                                             
                                                          
 

                                             
 


                                                    

                                        

                                                          
 

                              
 


                                                                                          
           

                      

                                                     
                                          
                                                  
                                                               
                 
                                                               
                                                                                               
                                                                               
                                                                       
         
 


                                                                                  
              
         
                                                                  

                                                   
                                                                                                            

                                                                                                                                                              
                 
                                                                                                 
         



                                 
 
package org.openslx.imagemaster.serverconnection;

import java.sql.Timestamp;
import java.util.HashMap;
import java.util.LinkedList;
import java.util.List;

import org.apache.log4j.Logger;
import org.openslx.imagemaster.Globals;
import org.openslx.imagemaster.db.DbImage;
import org.openslx.imagemaster.thrift.iface.DownloadInfos;
import org.openslx.imagemaster.thrift.iface.ImageData;
import org.openslx.imagemaster.thrift.iface.UploadInfos;
import org.openslx.imagemaster.util.RandomString;

/**
 * Processing the up- and download of images.
 * Handles who is authorized and knows which blocks are missing / need to be sent
 */
public class ImageProcessor
{

	private static final Logger log = Logger.getLogger( ImageProcessor.class );

	/**
	 * The amount of blocks that is return in UploadInfos (after request of satellite)
	 */
	private static final int AMOUNT = 20;
	/**
	 * The uploading images.
	 * Key: imageUUID,
	 * Value: uploadingImageInfos
	 */
	private static HashMap<String, UploadingImageInfos> uploadingImages = new HashMap<>();

	/**
	 * The downloading clients.
	 * Key: serverSessionId
	 * Value: downloadingClientInfos
	 */
	private static HashMap<String, DownloadingClientInfos> downloadingClients = new HashMap<>();

	/**
	 * Checks if this image is already uploading and returns a new list with missing blocks if so.
	 * Puts the new image into processing list else.
	 * 
	 * @param serverSessionId The uploading server
	 * @param imageData The data of the image
	 * @return
	 */
	public static UploadInfos getUploadInfos( String serverSessionId, ImageData imageData )
	{
		// check image data
		// TODO: do security checks

		String uuid = imageData.uuid;

		// check if image is already uploading TODO: what if two clients call this at the same time? -> Good question.. (Thought about not sending the last requested. But then the upload will never finish...)
		if ( uploadingImages.containsKey( uuid ) ) {
			List<Integer> missing = getMissingBlocks( uuid, AMOUNT );
			if ( missing.isEmpty() ) {
				uploadDone( uuid );
				return new UploadInfos( null, missing );
			}
			uploadingImages.get( uuid ).setLastSentBlocks( missing );
			return new UploadInfos( uploadingImages.get( uuid ).getToken(), missing );
		}

		// insert new image and start listener
		synchronized ( uploadingImages ) {
			int nBlocks = (int)Math.ceil( imageData.fileSize / Globals.blockSize );
			List<Integer> allBlocks = new LinkedList<>();
			for ( int i = 0; i < nBlocks; i++ ) {			// fill empty list with all block numbers
				allBlocks.add( i );
			}
			String token = RandomString.generate( 100, false );
			String filepath = Globals.getImageDir() + "/" + uuid + ".vmdk";
			ConnectionHandler.addConnection( token, filepath, ConnectionData.UPLOADING );
			// TODO: proper synchronization, interface is multi threaded.
			// should synchronize operations on the map (use concurrent map) and then synchronize on the uploading image
			// when handing the missing blocks etc...
			uploadingImages.put( uuid, new UploadingImageInfos( token, allBlocks, serverSessionId, new Timestamp( System.currentTimeMillis() ), uuid ) );
			DbImage.insert( imageData, System.currentTimeMillis(), token, allBlocks, serverSessionId, filepath );

			List<Integer> missing = getMissingBlocks( uuid, AMOUNT );
			if ( missing.isEmpty() ) {
				// TODO: if this is empty, check if there are pending blocks and if so, request them again
				uploadDone( uuid );
			}
			uploadingImages.get( uuid ).setLastSentBlocks( missing );
			return new UploadInfos( token, missing );
		}
	}

	public static DownloadInfos getDownloadInfos( String serverSessionId, String uuid, List<Integer> requestedBlocks )
	{
		// check if server is already downloading
		if ( downloadingClients.containsKey( serverSessionId ) ) {
			DownloadingClientInfos client = downloadingClients.get( serverSessionId );

			// remove download if done
			if ( requestedBlocks.isEmpty() )
			{
				downloadDone( serverSessionId, uuid );
				return new DownloadInfos();
			}

			if ( client.isDownloading( uuid ) )
			{
				// client was downloading this image
				// update the requested blocks
				client.requestBlocks( uuid, requestedBlocks );
				return new DownloadInfos( client.getToken( uuid ) );
			}

			// server was downloading another image and now gets a new connection for this new download
			String token = RandomString.generate( 100, false );
			String filepath = DbImage.getImageByUUID( uuid ).imagePath;
			client.addDownload( uuid, requestedBlocks, token );

			downloadingClients.put( serverSessionId, client );
			ConnectionHandler.addConnection( token, filepath, ConnectionData.DOWNLOADING );
			return new DownloadInfos( token );
		}

		// insert new client and start listener
		synchronized ( downloadingClients ) {
			DownloadingClientInfos client = new DownloadingClientInfos();
			String token = RandomString.generate( 100, false );
			String filepath = DbImage.getImageByUUID( uuid ).imagePath;
			client.addDownload( uuid, requestedBlocks, token );

			downloadingClients.put( serverSessionId, client );
			ConnectionHandler.addConnection( token, filepath, ConnectionData.DOWNLOADING );
			return new DownloadInfos( token );
		}
	}

	private static void downloadDone( String serverSessionId, String uuid )
	{
		synchronized ( downloadingClients ) {
			DownloadingClientInfos client = downloadingClients.get( serverSessionId );
			client.removeDownload( uuid );
			ConnectionHandler.removeConnection( client.getToken( uuid ) );
			if ( !client.hasDownloads() ) {
				downloadingClients.remove( serverSessionId );
			}
		}
	}

	/**
	 * Returns a specified number of missing blocks.
	 * 
	 * @param imageUUID The image of which you want to get the missing blocks from
	 * @param amount The amount of blocks that you want to get
	 * @return The missing blocks
	 */
	private static List<Integer> getMissingBlocks( String imageUUID, int amount )
	{
		UploadingImageInfos image = uploadingImages.get( imageUUID );
		List<Integer> list = image.getMissingBlocks();
		List<Integer> result = new LinkedList<>();

		if ( amount > list.size() )
			amount = list.size();

		for ( int i = 0; i < amount; i++ ) {
			result.add( list.get( i ) );
		}

		synchronized ( image ) {
			image.setLastSentBlocks( result );
		}

		return result;
	}

	/**
	 * Is triggered when an upload of an image is done.
	 * Removes image from process list, updates db entry and moves file on hard drive.
	 * 
	 * @param uuid
	 */
	private static void uploadDone( String uuid )
	{
		UploadingImageInfos image;
		synchronized ( uploadingImages ) {
			image = uploadingImages.remove( uuid );
		}
		image.getDbImage().updateMissingBlocks( null );
		// file was already downloaded in the right location by the updownloader class.
		// remove the connection so that it can be used by a new client
		ConnectionHandler.removeConnection( image.getToken() );
	}

	/**
	 * Checks pending uploads in database and adds them to process list again.
	 */
	static
	{
		List<DbImage> list = DbImage.getUploadingImages();
		for ( DbImage image : list ) {
			String token = image.token;
			ConnectionHandler.addConnection( token, image.imagePath, ConnectionData.UPLOADING );
			UploadingImageInfos infos = new UploadingImageInfos( token, image.missingBlocks, image.serverSessionId, image.timestamp, image.uuid );
			uploadingImages.put( image.uuid, infos );
		}
		log.info( "Added " + list.size() + " pending upload(s) to process list again." );
	}

	public static void init()
	{
	}
}