Package org.jmule.core.sharingmanager

Source Code of org.jmule.core.sharingmanager.PartialFile

/*
*  JMule - Java file sharing client
*  Copyright (C) 2007-2008 JMule team ( jmule@jmule.org / http://jmule.org )
*
*  Any parts of this program derived from other projects, or contributed
*  by third-party developers are copyrighted by their respective authors.
*
*  This program is free software; you can redistribute it and/or
*  modify it under the terms of the GNU General Public License
*  as published by the Free Software Foundation; either version 2
*  of the License, or (at your option) any later version.
*
*  This program 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 General Public License for more details.
*
*  You should have received a copy of the GNU General Public License
*  along with this program; if not, write to the Free Software
*  Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
*
*/
package org.jmule.core.sharingmanager;

import static org.jmule.core.edonkey.E2DKConstants.FT_FILESIZE;
import static org.jmule.core.edonkey.E2DKConstants.PARTSIZE;

import java.io.File;
import java.io.IOException;
import java.io.RandomAccessFile;
import java.nio.ByteBuffer;
import java.util.Arrays;
import java.util.Queue;
import java.util.concurrent.ConcurrentLinkedQueue;

import org.jmule.core.InternalJMuleCore;
import org.jmule.core.JMThread;
import org.jmule.core.JMuleCoreEvent;
import org.jmule.core.JMuleCoreFactory;
import org.jmule.core.NotEnoughSpaceDownloadingFile;
import org.jmule.core.configmanager.ConfigurationManager;
import org.jmule.core.downloadmanager.FileChunk;
import org.jmule.core.edonkey.E2DKConstants;
import org.jmule.core.edonkey.FileHash;
import org.jmule.core.edonkey.PartHashSet;
import org.jmule.core.edonkey.metfile.PartMet;
import org.jmule.core.edonkey.metfile.PartMetException;
import org.jmule.core.edonkey.packet.tag.IntTag;
import org.jmule.core.edonkey.packet.tag.Tag;
import org.jmule.core.edonkey.packet.tag.TagList;
import org.jmule.core.utils.Convert;
import org.jmule.core.utils.MD4;
import org.jmule.core.utils.MD4FileHasher;
import org.jmule.core.utils.Misc;

/**
*
* @author binary256
* @version $$Revision: 1.19 $$
* Last changed by $$Author: binary255 $$ on $$Date: 2010/01/10 17:00:26 $$
*/
public class PartialFile extends SharedFile {
 
  public static final String PART_FILE_EXTENSION = ".part";
 
  private String tempFileName;
 
  private String metFileName;
 
  private boolean checkedParts[];
 
  private boolean hasHashSet = false;
 
  private PartMet partFile;
 
  public PartialFile(PartMet partFile) throws SharedFileException {
   
    String tempDir = ConfigurationManager.TEMP_DIR;
   
    file = new File(tempDir+File.separator+partFile.getTempFileName());
   
    try {
      readChannel = new RandomAccessFile(file,"rws").getChannel();
      readChannel.position(0);
    } catch (Throwable e) {
      throw new SharedFileException("Failed to open "+file+"\n"+Misc.getStackTrace(e));
    }
   
    try {
      writeChannel = new RandomAccessFile(file,"rws").getChannel();
      writeChannel.position(0);
    } catch (Throwable e) {
      throw new SharedFileException("Failed to open "+file+"\n"+Misc.getStackTrace(e));
    }
   
    this.partFile = partFile;
    this.tagList = new TagList(partFile.getTagList().getAsList());
    tagList.removeTag(E2DKConstants.JMuleInternalTags);
   
    tempFileName = tempDir + File.separator + partFile.getTempFileName();
   
    metFileName = tempDir + File.separator + partFile.getName();
   
    hashSet = partFile.getFileHashSet();
    if (hashSet.isEmpty()) {
      hasHashSet = false;
    }
    else
      hasHashSet = true;
   
    checkedParts = new boolean[Misc.getPartCount(length())];
   
    int partCount = Misc.getPartCount(length());
   
    for(int i = 0;i < partCount;i++) {
      if (partFile.getGapList().getIntersectedGaps(PARTSIZE*i, PARTSIZE*(i+1)-1).size()==0)
        checkedParts[i] = true;
        else
        checkedParts[i] = false;
    }
  }
 
  public PartialFile(String fileName, long fileSize,FileHash fileHash,PartHashSet hashSet,TagList tagList) throws SharedFileException {
   
    String tempDir = ConfigurationManager.TEMP_DIR;
   
    tempFileName = tempDir + File.separator+fileName + PART_FILE_EXTENSION;
   
    metFileName = tempDir + File.separator+fileName +  PartMet.PART_MET_FILE_EXTENTSION;
   
    file = new File(tempFileName);
   
    try {
      readChannel = new RandomAccessFile(file,"rws").getChannel();
      readChannel.position(0);
    } catch (Throwable e) {
      throw new SharedFileException("Failed to open "+file+"\n"+Misc.getStackTrace(e));
    }
   
    try {
      writeChannel = new RandomAccessFile(file,"rws").getChannel();
      writeChannel.position(0);
    } catch (Throwable e) {
      throw new SharedFileException("Failed to open "+file+"\n"+Misc.getStackTrace(e));
    }
   
    try {
     
      partFile = new PartMet(metFileName);
     
    } catch (PartMetException e1) {
     
      throw new SharedFileException("Failed to create part.met file " + metFileName);
     
    }
   
    partFile.setTagList(tagList);
   
    partFile.setFileSize(Convert.longToInt((fileSize)));
   
    partFile.setTempFileName(fileName + ".part");
   
    partFile.setRealFileName(fileName);
   
   
    this.tagList = partFile.getTagList();
   
    GapList gapList = new GapList();
   
    gapList.addGap(0, fileSize);
   
    partFile.setGapList(gapList);
   
    if (hashSet==null) {
      hasHashSet = false;
      this.hashSet = new PartHashSet(fileHash);
    } else
      hasHashSet = true;

    checkedParts = new boolean[Misc.getPartCount(fileSize)];
   
    int partCount = Misc.getPartCount(fileSize);
   
    for(int i = 0;i<partCount;i++)
     
        checkedParts[i] = false;
       
    partFile.setFileHash(fileHash);
   
    partFile.setFileHashSet(hashSet);
   
    try {
     
      partFile.writeFile();
     
    } catch (PartMetException e) {
      e.printStackTrace();
      throw new SharedFileException("Failed to write part.met file\n"+Misc.getStackTrace(e));
    }

  }
   
  public void setHashSet(PartHashSet newSet) throws SharedFileException  {
    int partCount = Misc.getPartCount(this.length());
    if (newSet.size() < partCount)
      throw new SharedFileException("Wrong hash set response");
   
    hasHashSet = true;
    hashSet.clear();
    for(int i = 0;i<partCount;i++)
      hashSet.add(newSet.get(i));
     
   
    partFile.setFileHashSet(hashSet);
   
    try {
     
    partFile.writeFile();
   
    }catch(PartMetException e) {
      e.printStackTrace();
      throw new SharedFileException("Failed to save part.met file\n"+Misc.getStackTrace(e));
    }
  }
 
  public void deletePartialFile() {
    partFile.delete();
  }
 
  public void delete() {
    deletePartialFile();
    super.delete();
  }
 
  public String toString() {
   
    return "[ "+partFile.getName()+" "+this.length()+" Completed : "+Math.round(getPercentCompleted())+" % GapList : "+partFile.getGapList()+" ] ";
   
  }
 
  public String getSharingName() {
   
    if (partFile == null) return null;
   
    return this.partFile.getRealFileName();
   
  }
 
  public long getPartCount() {
    long part_count = (long) Math.ceil((double)length() / (double)PARTSIZE);
    if (length() % PARTSIZE!=0) part_count++;
    return part_count;
  }
 
  public long getAvailablePartCount() {
    long part_count = 0;
    for(int i = 0;i<checkedParts.length;i++)
      if (checkedParts[i])
        part_count++;
    return part_count;
  }

  public boolean isCompleted() {
    if (getPercentCompleted()== 100d) return true;
    return false;
  }
 
  public synchronized void writeData(FileChunk fileChunk) throws SharedFileException {
      try {
        if (writeChannel == null) {
         
          try {
            writeChannel = new RandomAccessFile(file,"rws").getChannel();
          } catch (Throwable e) {
            throw new SharedFileException("Error on opening file");
          }
         
        }
        //** Check file limit and add more data if need **//
        long toAdd = 0;
        if (writeChannel.size()<=fileChunk.getChunkStart()) {
          toAdd = fileChunk.getChunkStart() - writeChannel.size();
          toAdd += fileChunk.getChunkData().capacity();
         
        } else
        if ((writeChannel.size()>fileChunk.getChunkStart())&&(writeChannel.size()<=fileChunk.getChunkEnd())) {
          toAdd = fileChunk.getChunkEnd() - writeChannel.size();
        }
        if (toAdd != 0) {
          toAdd += E2DKConstants.PARTSIZE;
          if (toAdd + writeChannel.size()>length()) {
            toAdd = length() - writeChannel.size();
          }
          addBytes(toAdd);
        }
        writeChannel.position(fileChunk.getChunkStart());
        fileChunk.getChunkData().position(0);
        writeChannel.write(fileChunk.getChunkData());
        partFile.getGapList().removeGap(fileChunk.getChunkStart(), fileChunk.getChunkStart()+fileChunk.getChunkData().capacity());
       
        fileChunk.getChunkData().clear();
       
        try {
          partFile.writeFile();
        } catch (PartMetException e) {
          e.printStackTrace();
          throw new SharedFileException("Failed to save part.met file\n"+Misc.getStackTrace(e));
        }
        checkFilePartsIntegrity();
      }catch(Throwable t) {
        t.printStackTrace();
        if( t instanceof java.io.IOException ) {
          JMuleCoreFactory.getSingleton().
                      getDownloadManager().stopDownload();
          ((InternalJMuleCore)JMuleCoreFactory.getSingleton()).
                        notifyListenersEventOccured(JMuleCoreEvent.NOT_ENOUGH_SPACE,
                            new NotEnoughSpaceDownloadingFile(
                                 file.getName(),
                                             file.getTotalSpace(),
                                             file.getFreeSpace()
                                    )
                         );
        }
        throw new SharedFileException("Failed to write data\n"+Misc.getStackTrace(t));
      }
   
  }

  private void addBytes(long bytes) {
    long WRITE_BLOCK = 1024*1024*20;
    ByteBuffer block = Misc.getByteBuffer(WRITE_BLOCK)
    long blockCount = bytes / WRITE_BLOCK;
   
    try {
     
      writeChannel.position(writeChannel.size());
   
      long byteCount = 0;
     
      for(long i = 0;i<blockCount;i++) {
       
        byteCount +=WRITE_BLOCK;
       
        block.position(0);
       
        writeChannel.write(block);
       
      }
      block.clear();
      System.gc();
      if ((bytes - byteCount)==0) return ;
     
      ByteBuffer block2 = Misc.getByteBuffer(bytes - byteCount);
     
      block2.position(0);
     
      writeChannel.write(block2);
      block2.clear();
    } catch (IOException e) {
           
      e.printStackTrace();
     
    }
   
  }

  /**
   * @return true - file is ok !
   */
  public boolean checkFullFileIntegrity() {
    if (length()<PARTSIZE) {
      PartHashSet newSet = MD4FileHasher.calcHashSets(writeChannel);
      System.out.println(length() + "  \nNew hash : " + newSet.getFileHash());
      System.out.println("hash : " + getFileHash());
      if (newSet.getFileHash().equals(getFileHash()))
        return true;
      this.partFile.getGapList().addGap(0, length());
      return false;
    }
    if (!hasHashSet()) return false;
   
    PartHashSet fileHashSet = partFile.getFileHashSet();
    PartHashSet newSet = MD4FileHasher.calcHashSets(writeChannel);

    if (newSet.size()!=fileHashSet.size())
      return false;
   
    for(int i = 0;i<fileHashSet.size();i++) {
     
      byte b[] = newSet.get(i);
     
      byte a[] = fileHashSet.get(i);
       
     
     
      if (!Arrays.equals(a, b)) {
       
        long begin = PARTSIZE*i;
       
        long end = PARTSIZE*(i+1)-1;
       
        if (end>length()) end = length();
       
        //Adding gap
       
        this.partFile.getGapList().addGap(begin,end);
     
        return false;
      }
     
    }
   
    if (!newSet.getFileHash().equals(fileHashSet.getFileHash())) {
     
      partFile.getGapList().addGap(0, length());
     
      return false;
     
    }
   
    return true;
  }
 
  private boolean checkFilePartsIntegrity() {
   
    if (!hasHashSet()) {
      if (E2DKConstants.PARTSIZE < length()) return true;
      return false;
    }
   
    if (checkedParts.length==0) return true;
   
    boolean status = true;
   
    for(int i = 0;i<checkedParts.length;i++) {
     
      if (!checkedParts[i]) {
       
      long begin = PARTSIZE*i;
     
      long end = PARTSIZE*(i+1)-1;
     
      if(partFile.getGapList().getIntersectedGaps(begin, end).size()==0) {
       
        if (checkPartIntegrity(i)) checkedParts[i] = true;
       
        else {
         
          partFile.getGapList().addGap(begin, end);
         
          status = false;
         
        }
      }
     
      }
    }
   
    return status;
  }
 
 
  private boolean checkPartIntegrity(int partID) {
   
    long start = PARTSIZE*partID;
   
    MD4 msgDigest = new MD4();
   
    ByteBuffer partData = Misc.getByteBuffer(PARTSIZE);
    msgDigest.reset();
    try {
     
      readChannel.position(start);
     
      int count = readChannel.read(partData);
      partData.limit(count);
      msgDigest.update(partData);
     
      ByteBuffer hashset = Misc.getByteBuffer(16);
     
      msgDigest.finalDigest(hashset);
     
      if (!Arrays.equals(hashSet.get(partID),hashset.array())) {
        return false;
      }
      return true;
     
    } catch (IOException e) {
     
      return false;
     
    }
  }
 
  public GapList getGapList() {
   
    return partFile.getGapList();
   
  }
 
  public String getMetFileName() {
   
    return metFileName;
   
 
 

  public PartMet getPartMetFile() {
   
    return partFile;
   
  }
 

  public long getDownloadedBytes() {
   
    return length() - partFile.getGapList().byteCount();
   
  }
 
  public double getPercentCompleted() {
   
    return (double)(getDownloadedBytes()*100)/(double)length();
   
  }
 
  public boolean hasHashSet() {
    if (length() < E2DKConstants.PARTSIZE) return true;
    return this.hasHashSet;
   
  }

  public String getTempFileName() {
   
    return tempFileName;
   
  }

   
  public long length() {
   
    try {
     
      return Convert.intToLong((Integer)tagList.getTag(FT_FILESIZE).getValue());
     
    } catch (Throwable e) {
      return 0; }
  }
 
  public void closeFile() {
   
    if (write_thread != null)
      if (write_thread.isAlive()) write_thread.JMStop();
    partFile.close();
    super.closeFile();
  }
 
  public void markDownloadStarted() {
    IntTag tag = new IntTag(E2DKConstants.FT_NAME_STATUS, 0x00);
    partFile.getTagList().addTag(tag, true);
    try {
      partFile.writeFile();
    } catch (PartMetException e) {
      e.printStackTrace();
    }
  }
 
  public void markDownloadStopped() {
    IntTag tag = new IntTag(E2DKConstants.FT_NAME_STATUS, 0x01);
    partFile.getTagList().addTag(tag, true);
    try {
      partFile.writeFile();
    } catch (PartMetException e) {
      e.printStackTrace();
    }
  }
 
  public boolean isDownloadStarted() {
    Tag tag = partFile.getTagList().getTag(E2DKConstants.FT_NAME_STATUS);
    if (tag == null)
      return true;
    int value = (Integer)tag.getValue();
    if (value==0x00) return true;
    return false;
  }
 
 
  /*
   *  speed research
   */
  private Queue<FileChunk> write_list = new ConcurrentLinkedQueue<FileChunk>();
 
  private WriteThread write_thread;
 
  private void writeChunk(FileChunk chunk) {
    write_list.offer(chunk);
    if (write_thread != null)
      if (write_thread.isAlive()) return ;
    write_thread = new WriteThread();
    write_thread.start();
  }
 
  private class WriteThread extends JMThread {
   
    private boolean stop = false;
   
    public void JMStop() {
      stop = true;
    }
   
    public WriteThread() {
      super("File write thread");
    }
   
    public void run() {
      while(!stop) {
        if (write_list.size() == 0) return ;
        System.out.println("Before Size : " + write_list.size());
        FileChunk chunk = write_list.poll();
        System.out.println("After Size : " + write_list.size());
        try {
         
          /** Check file limit and add more data if need **/
         
          long toAdd = 0;
         
          if (readChannel.size()<=chunk.getChunkStart()) {
           
            toAdd = chunk.getChunkStart() - readChannel.size();
           
            toAdd += chunk.getChunkData().capacity();
           
          } else
           
          if ((readChannel.size()>chunk.getChunkStart())&&(readChannel.size()<=chunk.getChunkEnd())) {
           
            toAdd = chunk.getChunkEnd() - readChannel.size();
           
          }
          System.out.println("A");
          if (toAdd != 0) {
           
            addBytes(toAdd);
           
          }
          System.out.println("B");
          readChannel.position(chunk.getChunkStart());
         
          chunk.getChunkData().position(0);
         
          readChannel.write(chunk.getChunkData());
          System.out.println("C");
          try {
           
            partFile.writeFile();
           
          } catch (PartMetException e) {
            e.printStackTrace();
            throw new SharedFileException("Failed to save part.met file\n"+Misc.getStackTrace(e));
           
          }
          System.out.println("D");
          checkFilePartsIntegrity();
         
        }catch(Throwable t) {
         
        }
       
      }
    }
  }
 
}
TOP

Related Classes of org.jmule.core.sharingmanager.PartialFile

TOP
Copyright © 2018 www.massapi.com. All rights reserved.
All source code are property of their respective owners. Java is a trademark of Sun Microsystems, Inc and owned by ORACLE Inc. Contact coftware#gmail.com.