Package filesrv

Source Code of filesrv.Data

/*
* This file is part of the QuickServer library
* Copyright (C) 2003-2005 QuickServer.org
*
* Use, modification, copying and distribution of this software is subject to
* the terms and conditions of the GNU Lesser General Public License.
* You should have received a copy of the GNU LGP License along with this
* library; if not, you can download a copy from <http://www.quickserver.org/>.
*
* For questions, suggestions, bug-reports, enhancement-requests etc.
* visit http://www.quickserver.org
*
*/

package filesrv;

import org.quickserver.net.*;
import org.quickserver.net.server.*;
import org.quickserver.util.MyString;

import org.quickserver.util.pool.PoolableObject;
import org.apache.commons.pool.BasePoolableObjectFactory;
import org.apache.commons.pool.PoolableObjectFactory;

import java.io.*;
import java.net.*;
import java.util.*;
import java.util.logging.*;
import java.nio.*;
import java.nio.channels.*;

/**
* FileServer Example
* @author Akshathkumar Shetty
*/
public class Data implements ClientData, PoolableObject {
  public static String serverIP = null;
  private static Logger logger =  Logger.getLogger(Data.class.getName());
  static {
    try {
      serverIP = java.net.InetAddress.getLocalHost().getHostName();
    } catch(UnknownHostException e)  {
      serverIP = "UnknownHost";
    }
  }
  private static String userRootHome = "dist";

  public static void setUserRootHome(String name) {
    userRootHome = name;
  }

  private HashMap httpHeader;
  private String user_root = userRootHome;
  private ByteBuffer wrapedByteBuffer;
  private ByteBuffer pooledByteBuffer;
  private boolean sendFile = false;
  private FileChannel fileChannel;

  private long startRange = 0;
  private long endRange = -1;
  private long fileLength = -1;
  private boolean wroteFileHttpHeader;
  private boolean closeConWhenDone;

  private String nonBlockingWriteDesc = null;

  public boolean isHeaderReady() {
    return httpHeader!=null;
  }
 
  public void initHeader(String data) {
    httpHeader = new HashMap();
    int i = data.lastIndexOf(" HTTP/");
    httpHeader.put("FILE", data.substring(4, i));
  }

  public boolean addHeader(String data) {
    if(data.startsWith("GET /")) {
      initHeader(data);
      return false;
    }

    if(data.length()==0) return true;
    int i = data.indexOf(": ");
    if(i==-1) {
      logger.warning("Got unknown header: "+data);
      return false;
    }

    httpHeader.put(data.substring(0, i).toUpperCase(),
      data.substring(i+2));
    return false;
  }

  public File getFile() throws BadRequestException {
    String reqDir = (String) httpHeader.get("FILE");
    if(reqDir==null)
      throw new BadRequestException("No File Requested!");
    if(reqDir.length()==0) reqDir = File.separator;
    return new File(user_root+reqDir);
  }

  public boolean isDirList() throws BadRequestException {
    File file = getFile();
    if(file.canRead()==false) {
      logger.finest("File : "+file.getAbsolutePath());
      throw new BadRequestException("File Not Found: "+(String)httpHeader.get("FILE"));
    }
    if(file.isDirectory()) {
      String reqDir = (String) httpHeader.get("FILE");
      if(reqDir.charAt(reqDir.length()-1)!='/') {
        httpHeader.put("FILE", reqDir+"/");
      }
    }
    return file.isDirectory();
  }

  public String getDirList() throws BadRequestException {
    File file = getFile();
    File list[] = file.listFiles();
    String loc = (String)httpHeader.get("FILE");

    StringBuffer content = new StringBuffer();
    content.append("<html>\r\n<head>\r\n<title>"+serverIP+" - "+loc+"</title>\r\n</head>\r\n<body>\r\n");
    content.append("<H3>Filesrv Server - File List for "+serverIP+" - "+loc+"</H3>\r\n<hr/>\r\n");
    content.append("<blockquote>\r\n<table width=\"80%\">");
   
    if(loc.equals("/")==false) {
      content.append("\r\n<tr>\r\n<td colspan=\"5\">");
      String parent = file.getParent();
      parent = parent.replace('\\', '/');
      //parent = parent.replaceAll("\\("+user_root+"\\)", "");
      parent = MyString.replaceAll(parent, user_root, "");
      if(parent.equals("")) parent = "/";
      content.append("[<a href=\""+parent+"\">To Parent Directory</a>]"); //to fix
      content.append("\r\n</td>\r\n</tr>");
    }

    for(int i=0;i<list.length;i++) {
      content.append("\r\n<tr>");
     
      content.append("\r\n<td align=\"right\">");
      content.append(new java.util.Date(list[i].lastModified()));
      content.append("</td>");

      content.append("\r\n<td>&nbsp;&nbsp;</td>");

      content.append("\r\n<td align=\"right\">");
      if(list[i].isDirectory()) {
        content.append(" &lt;dir&gt;");
      } else {
        content.append(" "+list[i].length());
      }
      content.append("</td>");

      content.append("\r\n<td>&nbsp;&nbsp;</td>");

      content.append("\r\n<td><a href=\"");
      content.append(loc+list[i].getName());//to fix
      content.append("\">");
      content.append(list[i].getName());
      content.append("</a></td>");

      content.append("\r\n</tr>");
    }
    content.append("\r\n</table>\r\n</blockquote>");
    content.append("\r\n<hr/>\r\n</body>\r\n</html>");
    return content.toString();
  }

  private String makeFileResponseHeader(ClientHandler handler) {
    String range = (String) httpHeader.get("RANGE");

    StringBuffer sb = new StringBuffer();

    if(range==null || range.startsWith("bytes=")==false) {
      sb.append("HTTP/1.1 200 OK\r\n");
      sb.append("Content-Length: "+fileLength).append("\r\n");
      startRange = 0;
      endRange = fileLength-1;
    } else {
      try {
        range = range.substring(6); //skip bytes=
        int i = range.indexOf("-");
        if(i==-1) i = range.length();
        startRange = Integer.parseInt(range.substring(0, i));
        i++;
        if(i<range.length()) {
          endRange = Integer.parseInt(range.substring(i));
        } else {
          endRange = fileLength-1;
        }
      } catch(Exception e) {
        logger.finest("IGNORE Error: "+e);
      }
      sb.append("HTTP/1.1 206 Partial content\r\n");
      sb.append("Content-Range: bytes "+startRange+"-"+endRange+
        "/"+fileLength+"\r\n");

    }
    sb.append("Server: ").append(handler.getServer().getName()).append("\r\n");
    sb.append("Content-Type: application/octet-stream").append("\r\n");
    sb.append("\r\n");
   
    return sb.toString();
  }

  public void sendFileNonBlocking(ClientHandler handler)
      throws IOException, BadRequestException {
    fileLength = getFile().length();
    String header = makeFileResponseHeader(handler);
    logger.fine("Will Send: \n"+header);

    makeNonBlockingWrite(handler, header.getBytes(), true,
      "Sending HTTP header for file.", false);
  }

  public void makeNonBlockingWrite(ClientHandler handler, byte data[],
      boolean sendFileFlag, String desc, boolean closeConWhenDone) throws IOException {
    if(wrapedByteBuffer!=null) {
      //this client must have sent another req. with out waiting for res.. let close him..
      throw new IOException("The old data was still not fully written sorry!");
    }
    wrapedByteBuffer = ByteBuffer.wrap(data);
    sendFile = sendFileFlag;
    nonBlockingWriteDesc = desc;
    this.closeConWhenDone = closeConWhenDone;
    handler.registerForWrite();
  }

  public void sendFileBlocking(ClientHandler handler)
      throws IOException, BadRequestException {
    File file = getFile();
   
    fileLength = file.length();
    String header = makeFileResponseHeader(handler);
   
    FileInputStream in = null;
    byte buffer[] = new byte[1024*1024];
    try {
      in = new FileInputStream(file);
      if(startRange>0) {
        logger.finest("Will skip: "+startRange);
        in.skip(startRange);
      }
      int i = 0;
     
      i = in.read(buffer);
      logger.finest("Sending HTTP header for file.");
      handler.sendClientBytes(header);

      handler.setDataMode(DataMode.BINARY, DataType.OUT);
      logger.finest("Sending file data: "+file);
      long remain = fileLength-startRange;
      logger.finest("Remain: "+remain+", startRange: "+startRange+", i: "+i);

      while(i!=-1 && remain!=0) {       
        if(i>remain) i = (int) remain;       

        handler.sendClientBinary(buffer,0, i);
        startRange+=i;

        remain = fileLength-startRange;
        i = in.read(buffer);
        logger.finest("Remain: "+remain+", startRange: "+startRange+", i: "+i);
        Thread.currentThread().yield();
      }
      logger.fine("Sent the file!");
    } catch(Exception er) {
      logger.info("Error sending file: "+er);
    } finally {
      if(in!=null) in.close();
      handler.setDataMode(DataMode.BYTE, DataType.OUT);
    }
   
    if(false) {
      handler.closeConnection();
    } else {
      //so that we can take more req.
      clean();
    }
  }

  public void writeData(ClientHandler handler) throws Exception {
    if(wrapedByteBuffer!=null && wrapedByteBuffer.remaining()!=0) {
      logger.finest(nonBlockingWriteDesc);
      int written = handler.getSocketChannel().write(wrapedByteBuffer);
      if(written>0) {
        handler.updateLastCommunicationTime();
      }
      logger.finest("Written "+written+" Bytes");
      if(wrapedByteBuffer.remaining()!=0) {
        handler.registerForWrite();
        return;
      }
      wroteFileHttpHeader = true;
      if(sendFile==false) {
        wrapedByteBuffer = null;
        if(closeConWhenDone) {
          handler.closeConnection();
        }
        return;
      }
    }
   
    if(sendFile==true) {
      if(fileChannel==null) {
        File file = getFile();
        logger.finest("Sending file data: "+file);
        FileInputStream fin = new FileInputStream(file);
        fileChannel = fin.getChannel();
        fileChannel.position(startRange);
      }
     
      if(pooledByteBuffer==null) {
        pooledByteBuffer = (ByteBuffer)
          handler.getServer().getByteBufferPool().borrowObject();
      }

      if(pooledByteBuffer.hasRemaining()) {
        int ret = -1;
        long remain = fileLength-startRange;
        logger.finest("Remain: "+remain);

        if(pooledByteBuffer.remaining()>remain) {
          pooledByteBuffer.limit(
            (int) (pooledByteBuffer.position()+remain) );
        }

        ret = fileChannel.read(pooledByteBuffer);

        logger.finest("Read "+ret+" Bytes from file");
        if(ret<0 || remain==0) {//EOF
          fileChannel.close();
          //fileChannel = null;
        } else {
          startRange+=ret;
        }       
      }
      pooledByteBuffer.flip();
     
      if(pooledByteBuffer.hasRemaining()) {
        int written = handler.getSocketChannel().write(pooledByteBuffer);
        if(written>0) {
          handler.updateLastCommunicationTime();
        }
        logger.finest("Written "+written+" Bytes to socket");
      }

      long remain = fileLength-startRange;
      if(remain==0 && pooledByteBuffer.hasRemaining()==false) {
        fileChannel.close();
      }

      if(pooledByteBuffer.hasRemaining()==false && fileChannel.isOpen()==false) {
        sendFile = false;
        logger.finest("Sent the file!");
       
        if(false) {
          handler.closeConnection();
        } else {
          //so that we can take more req.
          clean();
        }
        return; //work done
      }
      pooledByteBuffer.compact(); //In case of partial write
      handler.registerForWrite();
    } //end of sendFile
  }

  public void cleanPooledByteBuffer(QuickServer quickserver) {
    if(pooledByteBuffer!=null) {
      try {
        quickserver.getByteBufferPool().returnObject(pooledByteBuffer)
      } catch(Exception er) {
        logger.warning("Could not return ByteBuffer back to pool: "+er);
      }   
      pooledByteBuffer = null;
    }
  }

  public boolean getWroteFileHttpHeader() {
    return wroteFileHttpHeader;
  }

  //--- pool --
  public void clean() {
    httpHeader = null;
    user_root = userRootHome;
    wrapedByteBuffer = null;
    if(pooledByteBuffer!=null) {
      pooledByteBuffer.clear();
    }
    sendFile = false;
    if(fileChannel!=null) {
      try {
        fileChannel.close()
      } catch(Exception er) {}     
      fileChannel = null;
    }   
    startRange = 0;
    endRange = -1;
    fileLength = -1;
    wroteFileHttpHeader = false;

    nonBlockingWriteDesc = null;
    closeConWhenDone = false;
  }


  public boolean isPoolable() {
    return true;
  }

  public PoolableObjectFactory getPoolableObjectFactory() {
    return  new BasePoolableObjectFactory() {
      public Object makeObject() {
        return new Data();
      }
      public void passivateObject(Object obj) {
        Data d = (Data)obj;
        d.clean();
      }
      public void destroyObject(Object obj) {
        if(obj==null) return;
        passivateObject(obj);
        obj = null;
      }
      public boolean validateObject(Object obj) {
        if(obj==null)
          return false;
        else
          return true;
      }
    };
  }
}


TOP

Related Classes of filesrv.Data

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.