gt: 			catch (IllegalArgumentException e) {
context: package net.liveshift.storage;
  
  import java.io.EOFException;
  import java.io.File;
  import java.io.FileInputStream;
  import java.io.FileOutputStream;
  import java.io.IOException;
  import java.io.ObjectInputStream;
  import java.io.ObjectOutputStream;
  import java.lang.ref.SoftReference;
  import java.util.HashSet;
  import java.util.Iterator;
  import java.util.Map;
  import java.util.Map.Entry;
  import java.util.Set;
  import java.util.concurrent.ConcurrentSkipListMap;
  import java.util.concurrent.ScheduledFuture;
  import java.util.concurrent.TimeUnit;
  import java.util.concurrent.atomic.AtomicInteger;
  
  import net.liveshift.configuration.Configuration;
  import net.liveshift.core.LiveShiftApplication;
  import net.liveshift.download.Tuner;
  import net.liveshift.p2p.DHTInterface;
  import net.liveshift.signaling.messaging.SegmentBlock;
  import net.liveshift.util.ExecutorPool;
  
  import org.slf4j.Logger;
  import org.slf4j.LoggerFactory;
  
  
  /**
   *
   * @author Fabio Victora Hecht
   */
  public class SegmentStorage {
  
  	final private static Logger logger = LoggerFactory.getLogger(SegmentStorage.class);
  	//final private static Logger logger = LiveShiftApplication.getLogger(SegmentStorage.class);
  
  	// configuration parameters
  	private static final int MAX_BLOCKS_ON_DISK = 120*(60*1000)/(int)Configuration.SEGMENTBLOCK_SIZE_MS;  //120 minutes if 1 substream TODO how to take into account that different channels have different number of substreams?
  	private static final int CACHE_SIZE_BLOCKS = SegmentBlock.getBlocksPerSegment()*5;
  	private static final int INDEX_SAVE_FREQUENCY = 30000;
  	private final String storageDirectory;
  	
  	private Tuner tuner;
  	
  	// internal storage
  	protected ConcurrentSkipListMap<SegmentIdentifier, Segment> index;  //disk storage index
  	private final SoftReference<SegmentBlock>[] cache;
  	private AtomicInteger blocksOnDisk = new AtomicInteger(0);
  
  	//interfaces
  	private final DHTInterface dht;
  	
  	private Runnable indexSaver = new Runnable() {
  		
  		@Override
  		public void run() {
  			try {
  
  				if (blocksOnDisk.get() > MAX_BLOCKS_ON_DISK) {
  					if (logger.isDebugEnabled()) logger.debug("too many blocks on disk ("+blocksOnDisk+"/"+MAX_BLOCKS_ON_DISK+"), will delete 10% of blocks stored");
  					deleteBlocks((int)(blocksOnDisk.get()*.1));
  				}
  				
  				saveIndex();
  			}
  			catch (Exception e) {
  				logger.error("error in indexSaver: "+e.getMessage());
  				e.printStackTrace();
  			}
  		}
  	};
  	private final ScheduledFuture<?> scheduleIndexSaver;
  
  	public SegmentStorage(DHTInterface dht, String storageDirectory) {
  		
  		if (logger.isDebugEnabled()) logger.debug("in constructor");
  		
  		this.dht = dht;
  		this.storageDirectory = storageDirectory;
  
  		// gets index from disk
  		try {
  			this.loadIndex();
  		} catch (IOException e) {
  			logger.error("i/o error reading index - new one created");
  			e.printStackTrace();
  		} catch (ClassNotFoundException e) {
  			e.printStackTrace();
  		}
  		
  		this.index = new ConcurrentSkipListMap<SegmentIdentifier,Segment>();
  		this.cache = new SoftReference[CACHE_SIZE_BLOCKS];
  		
  		this.scheduleIndexSaver = ExecutorPool.getScheduledExecutorService().scheduleAtFixedRate(indexSaver, INDEX_SAVE_FREQUENCY, INDEX_SAVE_FREQUENCY, TimeUnit.MILLISECONDS);
  
  	}
  
  	//removes a number of segments enough to remove at least the number of blocks provided
  	protected void deleteBlocks(int numberOfBlocksToRemove) {
  		
  		if (logger.isDebugEnabled()) logger.debug("about to try and delete "+numberOfBlocksToRemove+" blocks");
  
  		int blocksRemoved=0;
  		
  		long playbackPosition = this.tuner.getVideoPlayer().getLastPlayedBlocksStartTimeMs();
  		Set<Segment> segmentsToDelete = new HashSet<Segment>(); 
  		
  		//first, deletes blocks from oldest segments before playback position
  
  		Iterator<Entry<SegmentIdentifier, Segment>> iter = this.index.entrySet().iterator();
  		
  		while (iter.hasNext() && blocksRemoved < numberOfBlocksToRemove) {
  			
  			Entry<SegmentIdentifier, Segment> mapEntry = iter.next();
  			Segment segment = mapEntry.getValue();
  			
  			if (segment.getSegmentIdentifier().getEndTimeMS() < playbackPosition) {
  				int blocksPresent = segment.getSegmentBlockMap().cardinality();
  				blocksRemoved += blocksPresent;
  			}
  		}
  		blocksOnDisk.addAndGet(-blocksRemoved);
  		
  		//then, (if necessary, hope not), deletes blocks from newest segments after playback position (but newest = rarest)
  		iter = this.index.descendingMap().entrySet().iterator();
  		
  		while (iter.hasNext() && blocksRemoved < numberOfBlocksToRemove) {
  			
  			Entry<SegmentIdentifier, Segment> mapEntry = iter.next();
  			Segment segment = mapEntry.getValue();
  			
  			if (segment.getSegmentIdentifier().getEndTimeMS() > playbackPosition) {
  				int blocksPresent = segment.getSegmentBlockMap().cardinality();
  				blocksRemoved += blocksPresent;
  			}
  		}
  		blocksOnDisk.addAndGet(-blocksRemoved);
  
  		//really deletes them
  
  		for (Segment segment : segmentsToDelete) {
  			if (logger.isDebugEnabled()) logger.debug("removing segment: "+segment);
  			
  			this.deleteSegmentFromDisk(segment);
  			iter.remove();
  			/*
  			try {
  				this.tuner.getDht().unPublishSegment(segment.getSegmentIdentifier());
  			} catch (IOException e) {
  				// TODO Auto-generated catch block
  				e.printStackTrace();
  			}
  			*/
  		}
  		
  		if (logger.isDebugEnabled()) logger.debug("deleted "+blocksRemoved+" blocks");
  
  	}
  
  	public void shutdown() {
  		if (logger.isDebugEnabled()) logger.debug("in shutdown()");
  		
  		// saves index to disk
  		this.scheduleIndexSaver.cancel(false);
  		this.saveIndex();
  	}
  
  	private void saveIndex() {
  
  		if (logger.isDebugEnabled()) logger.debug("saving index()");
  		
  		try {
  			FileOutputStream fos = new FileOutputStream(storageDirectory + "/index");
  			ObjectOutputStream oos = new ObjectOutputStream(fos);
  			
  			synchronized (index) {
  				oos.writeObject(index);
  			}
  			
  			oos.close();
  			fos.close();
  		}
  		catch (Exception e) {
  			logger.error("ERROR at saveIndex: " + e.getMessage());
  			e.printStackTrace();
  		}
  	}
  
  	public synchronized Segment getSegment(final SegmentIdentifier segmentIdentifier) {
  
  		if (logger.isDebugEnabled()) logger.debug("in getSegment("+segmentIdentifier.toString()+")");
  		
  		// checks index
  		Segment segment = this.index.get(segmentIdentifier);
  		
  		return segment;
  	}
  
  	public Segment getOrCreateSegment(SegmentIdentifier segmentIdentifier, long startBlockTime) {
  		
  		if (startBlockTime > 0 && !segmentIdentifier.timeBelongsHere(startBlockTime)) {
  			logger.error("given startBlockTime ("+startBlockTime+") does not belong in given segmentIdentifier ("+segmentIdentifier+")");
  			LiveShiftApplication.quit("given startBlockTime ("+startBlockTime+") does not belong in given segmentIdentifier ("+segmentIdentifier+")");
  		}
  		
  		return this.getOrCreateSegment(segmentIdentifier, SegmentBlock.getBlockNumber(startBlockTime));
  	}
  	public synchronized Segment getOrCreateSegment(SegmentIdentifier segmentIdentifier, int startBlockNumber) {
  		
  		if (logger.isDebugEnabled()) logger.debug("in getOrCreateSegment("+segmentIdentifier.toString()+", startBlock#"+startBlockNumber+")");
  		
  		// checks index
  		Segment segment = this.index.get(segmentIdentifier);
  		
  		if (segment==null) {
  			//if not here, gives a new one
  			segment = new Segment(segmentIdentifier, startBlockNumber);
  			if (logger.isDebugEnabled()) logger.debug("new segment created");
  			
  			this.putSegment(segment);
  		}
  		else if (startBlockNumber != segment.getSegmentBlockMap().getStartBlockNumber()) {
  			segment.getSegmentBlockMap().setStartBlockNumber(startBlockNumber);
  			if (logger.isDebugEnabled()) logger.debug("existing segment taken, startBlockNumber set to "+startBlockNumber);
  			
  			this.putSegment(segment);
  		}
  		else {
  			if (logger.isDebugEnabled()) logger.debug("existing segment taken, startBlockNumber matches");
  		}
  		
  		return segment;
  	}
  
  	/**
  	 * 
  	 * @throws IOException 
  	 * @see csg.liveshift.dht.SegmentStorage#putSegment(csg.liveshift.Segment)
  	 * 
  	 * puts a new segment in the disk storage
  	 * 
  	 */
  	
  	private void putSegment(Segment segment) {
  		
  		if (logger.isDebugEnabled()) logger.debug("in putSegment("+segment.toString()+")");
  
  		// adds it to memory buffer
  		this.index.put(segment.getSegmentIdentifier(), segment);
  		
  		//announces availability on DHT
  		this.announceOnDht(segment.getSegmentIdentifier());
  
  	}
  
  	
  	public synchronized void announceAllOnDht() {
  		this.announceOnDht(this.index);
  	}
  	private void announceOnDht(Map<SegmentIdentifier, Segment> map) {
  		
  		if (!this.dht.isConnected())
  			return;
  
  		synchronized (this.index) {
  			for (SegmentIdentifier segmentIdentifier : this.index.keySet())
  				this.announceOnDht(segmentIdentifier);
  		}
  		
  	}
  	private void announceOnDht(SegmentIdentifier segmentIdentifier) {
  		
  		if (logger.isDebugEnabled()) logger.debug("announcing si on DHT ("+segmentIdentifier+")");
  		
  		if (!this.dht.isConnected())
  			return;
  		
  		try {
  			this.dht.publishSegment(segmentIdentifier);
  		} catch (IOException e) {
  			logger.error("error annnouncing segment on DHT: "+e.getMessage());
  			e.printStackTrace();
  		}
  	}
  
  	@SuppressWarnings("unchecked")
  	private void loadIndex() throws IOException, ClassNotFoundException {
  		
  		if (logger.isDebugEnabled()) logger.debug("in loadIndex");
  		
  		String fileName = this.storageDirectory + "/index";
  		File file = new File(fileName);
  		boolean exists = file.exists();
  		
  		if (!exists) {
  			
  
  			boolean success;
  			
  			//creates directory if needed
  			this.mkdirs(this.storageDirectory);
  			
  			//creates it
  			success = file.createNewFile();
  			
  			if (logger.isDebugEnabled()) logger.debug("new index created");
  			
  			if (!success) {
  				SegmentStorage.logger.error("ERROR creating new index file");
  			}
  			
  			this.index = new ConcurrentSkipListMap<SegmentIdentifier, Segment>();
  			
  			return;
  		}
  		
  		ObjectInputStream ois;
  
  		try {
  			FileInputStream fis = new FileInputStream(file);
  			ois = new ObjectInputStream(fis);
  
  			this.index = (ConcurrentSkipListMap<SegmentIdentifier, Segment>) ois.readObject();
  			
  			if (logger.isDebugEnabled()) logger.debug("existing index loaded");
  			
  			ois.close();
  			fis.close();
  		}
  		catch (EOFException e) {
  			logger.error("error loading index: "+e.getMessage());
  
  			this.index = new ConcurrentSkipListMap<SegmentIdentifier, Segment>();
  		}
  		catch (ClassCastException e) {
  			logger.error("error loading index, the type is incompatible: "+e.getMessage());
  			
  			this.index = new ConcurrentSkipListMap<SegmentIdentifier, Segment>();
  		}
  		
  		//announces availability on DHT
  		this.announceOnDht(this.index);
  		
  	}
  	
  	private boolean mkdirs(String dirname) {
  		
  		boolean success = false;
  		
  		try {
  			// Create multiple directories
  			success = (new File(dirname)).mkdirs();
  			if (success)
  				if (logger.isDebugEnabled()) logger.debug("Directory (" + dirname + ") created");
  		}
  		catch (Exception e) {//Catch exception if any
  			SegmentStorage.logger.error("ERROR creating directory (" + dirname + "): " + e.getMessage());
  			return false;
  		}
  		
  		return success;
  	}
  
  	private int getIndexCount() {
  		return this.index.size();
  	}
  
  	private synchronized void deleteSegmentFromDisk(Segment segment) {
  		
  		String filename = segment.getSegmentIdentifier().getStringIdentifier();
  		
  		if (logger.isDebugEnabled()) logger.debug("in deleteSegmentFromDisk("+filename+")");
  		
  		//deletes all blocks
  		SegmentBlockMap segmentBlockMap = segment.getSegmentBlockMap();
  		int index = -1;
  		while (-1 != (index = segmentBlockMap.nextSetBit(index+1))) {
  			try {
  				this.deleteBlock(segment.getSegmentIdentifier(), index);
  				segmentBlockMap.clear(index);
  			}
  