Java tutorial
/* * 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> </td>"); content.append("\r\n<td align=\"right\">"); if (list[i].isDirectory()) { content.append(" <dir>"); } else { content.append(" " + list[i].length()); } content.append("</td>"); content.append("\r\n<td> </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); 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); 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; } }; } }