/* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You under the Apache License, Version 2.0 * (the "License"); you may not use this file except in compliance with * the License. You may obtain a copy of the License at * http://www.apache.org/licenses/LICENSE-2.0 * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package tachyon.web; import org.apache.log4j.Logger; import org.apache.thrift.TException; import tachyon.Constants; import tachyon.client.InStream; import tachyon.client.ReadType; import tachyon.client.TachyonFS; import tachyon.client.TachyonFile; import tachyon.master.BlockInfo; import tachyon.master.MasterInfo; import tachyon.thrift.ClientFileInfo; import tachyon.thrift.FileDoesNotExistException; import tachyon.thrift.InvalidPathException; import tachyon.util.CommonUtils; import javax.servlet.ServletException; import javax.servlet.http.HttpServlet; import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse; import java.io.IOException; import java.net.UnknownHostException; import java.util.ArrayList; import java.util.Collections; import java.util.List; /** * Servlet that provides data for browsing the file system. */ public class WebInterfaceBrowseServlet extends HttpServlet { /** * Class to make referencing file objects more intuitive. Mainly to avoid * implicit association by array indexes. */ public class UiBlockInfo implements Comparable<UiBlockInfo> { private final long ID; private final long BLOCK_LENGTH; private final boolean IN_MEMORY; public UiBlockInfo(BlockInfo blockInfo) { ID = blockInfo.BLOCK_ID; BLOCK_LENGTH = blockInfo.LENGTH; IN_MEMORY = blockInfo.isInMemory(); } @Override public int compareTo(UiBlockInfo p) { return (ID < p.ID ? -1 : (ID == p.ID ? 0 : 1)); } public long getBlockLength() { return BLOCK_LENGTH; } public long getID() { return ID; } public boolean inMemory() { return IN_MEMORY; } } private static final long serialVersionUID = 6121623049981468871L; private final Logger LOG = Logger.getLogger(Constants.LOGGER_TYPE); private MasterInfo mMasterInfo; public WebInterfaceBrowseServlet(MasterInfo masterInfo) { mMasterInfo = masterInfo; } /** * This function displays 5KB of a file from a specific offset if it is in * ASCII format. * * @param path * The path of the file to display * @param request * The HttpServletRequest object * @param offset * Where the file starts to display. * @throws FileDoesNotExistException * @throws IOException * @throws InvalidPathException * @throws TException */ private void displayFile(String path, HttpServletRequest request, long offset) throws FileDoesNotExistException, InvalidPathException, IOException { String masterAddress = Constants.HEADER + mMasterInfo.getMasterAddress().getHostName() + ":" + mMasterInfo.getMasterAddress().getPort(); TachyonFS tachyonClient = TachyonFS.get(masterAddress); TachyonFile tFile = tachyonClient.getFile(path); String fileData = null; if (tFile == null) { throw new FileDoesNotExistException(path); } if (tFile.isComplete()) { InStream is = tFile.getInStream(ReadType.NO_CACHE); int len = (int) Math.min(5 * Constants.KB, tFile.length() - offset); byte[] data = new byte[len]; is.skip(offset); is.read(data, 0, len); fileData = CommonUtils.convertByteArrayToStringWithoutEscape(data); if (fileData == null) { fileData = "The requested file is not completely encoded in ascii"; } is.close(); } else { fileData = "The requested file is not complete yet."; } try { tachyonClient.close(); } catch (TException e) { LOG.error(e.getMessage()); } List<BlockInfo> rawBlockList = mMasterInfo.getBlockList(path); List<UiBlockInfo> uiBlockInfo = new ArrayList<UiBlockInfo>(); for (BlockInfo blockInfo : rawBlockList) { uiBlockInfo.add(new UiBlockInfo(blockInfo)); } request.setAttribute("fileBlocks", uiBlockInfo); request.setAttribute("fileData", fileData); return; } /** * Populates attribute fields with data from the MasterInfo associated with * this servlet. Errors will be displayed in an error field. Debugging can be * enabled to display additional data. Will eventually redirect the request to a jsp. * * @param request * The HttpServletRequest object * @param response * The HttpServletResponse object * @throws ServletException * @throws IOException * @throws UnknownHostException */ @Override protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException, UnknownHostException { request.setAttribute("debug", Constants.DEBUG); request.setAttribute("masterNodeAddress", mMasterInfo.getMasterAddress().toString()); request.setAttribute("invalidPathError", ""); List<ClientFileInfo> filesInfo = null; String currentPath = request.getParameter("path"); if (currentPath == null || currentPath.isEmpty()) { currentPath = Constants.PATH_SEPARATOR; } request.setAttribute("currentPath", currentPath); request.setAttribute("viewingOffset", 0); try { ClientFileInfo clientFileInfo = mMasterInfo.getClientFileInfo(currentPath); UiFileInfo currentFileInfo = new UiFileInfo(clientFileInfo); request.setAttribute("currentDirectory", currentFileInfo); request.setAttribute("blockSizeByte", currentFileInfo.getBlockSizeBytes()); if (!currentFileInfo.getIsDirectory()) { String tmpParam = request.getParameter("offset"); long offset = 0; try { if (tmpParam != null) { offset = Long.valueOf(tmpParam); } } catch (NumberFormatException nfe) { offset = 0; } if (offset < 0) { offset = 0; } else if (offset > clientFileInfo.getLength()) { offset = clientFileInfo.getLength(); } displayFile(currentFileInfo.getAbsolutePath(), request, offset); request.setAttribute("viewingOffset", offset); getServletContext().getRequestDispatcher("/viewFile.jsp").forward(request, response); return; } CommonUtils.validatePath(currentPath); setPathDirectories(currentPath, request); filesInfo = mMasterInfo.getFilesInfo(currentPath); } catch (FileDoesNotExistException fdne) { request.setAttribute("invalidPathError", "Error: Invalid Path " + fdne.getMessage()); getServletContext().getRequestDispatcher("/browse.jsp").forward(request, response); return; } catch (InvalidPathException ipe) { request.setAttribute("invalidPathError", "Error: Invalid Path " + ipe.getLocalizedMessage()); getServletContext().getRequestDispatcher("/browse.jsp").forward(request, response); return; } catch (IOException ie) { request.setAttribute("invalidPathError", "Error: File " + currentPath + " is not available " + ie.getMessage()); getServletContext().getRequestDispatcher("/browse.jsp").forward(request, response); return; } List<UiFileInfo> fileInfos = new ArrayList<UiFileInfo>(filesInfo.size()); for (ClientFileInfo fileInfo : filesInfo) { UiFileInfo toAdd = new UiFileInfo(fileInfo); try { if (!toAdd.getIsDirectory() && fileInfo.getLength() > 0) { toAdd .setFileLocations(mMasterInfo.getFileLocations(toAdd.getId()).get(0).getLocations()); } } catch (FileDoesNotExistException fdne) { request.setAttribute("invalidPathError", "Error: Invalid Path " + fdne.getMessage()); getServletContext().getRequestDispatcher("/browse.jsp").forward(request, response); return; } fileInfos.add(toAdd); } Collections.sort(fileInfos); request.setAttribute("fileInfos", fileInfos); getServletContext().getRequestDispatcher("/browse.jsp").forward(request, response); } /** * This function sets the fileinfos for folders that are in the path to the * current directory. * * @param path * The path of the current directory. * @param request * The HttpServletRequest object * @throws FileDoesNotExistException * @throws InvalidPathException */ private void setPathDirectories(String path, HttpServletRequest request) throws FileDoesNotExistException, InvalidPathException { if (path.equals(Constants.PATH_SEPARATOR)) { request.setAttribute("pathInfos", new UiFileInfo[0]); return; } String[] splitPath = path.split(Constants.PATH_SEPARATOR); UiFileInfo[] pathInfos = new UiFileInfo[splitPath.length - 1]; String currentPath = Constants.PATH_SEPARATOR; pathInfos[0] = new UiFileInfo(mMasterInfo.getClientFileInfo(currentPath)); for (int i = 1; i < splitPath.length - 1; i ++) { currentPath = CommonUtils.concat(currentPath, splitPath[i]); pathInfos[i] = new UiFileInfo(mMasterInfo.getClientFileInfo(currentPath)); } request.setAttribute("pathInfos", pathInfos); return; } }