content: /* The contents of this file are subject to the terms
   * of the Common Development and Distribution License
   * (the License). You may not use this file except in
   * compliance with the License.
   *
   * You can obtain a copy of the License at
   * http://www.sun.com/cddl/cddl.html or
   * install_dir/legal/LICENSE
   * See the License for the specific language governing
   * permission and limitations under the License.
   *
   * When distributing Covered Code, include this CDDL
   * Header Notice in each file and include the License file
   * at install_dir/legal/LICENSE.
   * If applicable, add the following below the CDDL Header,
   * with the fields enclosed by brackets [] replaced by
   * your own identifying information:
   * "Portions Copyrighted [year] [name of copyright owner]"
   *
   * Copyright 2005-2009 Sun Microsystems Inc. All Rights Reserved
   */
  package com.sun.faban.harness.webclient;
  
  import com.sun.faban.harness.common.Config;
  
  import javax.servlet.http.HttpServlet;
  import javax.servlet.http.HttpServletRequest;
  import javax.servlet.http.HttpServletResponse;
  import javax.servlet.ServletException;
  import javax.servlet.ServletOutputStream;
  import java.io.IOException;
  import java.io.File;
  import java.io.FileInputStream;
  import java.util.ArrayList;
  
  /**
   * The content reader reads requests for output files from the actual file
   * location which is not a subpath of the context and sends it back to the
   * requestor.
   *
   * @author Akara Sucharitakul
   */
  public class ContentReader extends HttpServlet {
      ObjectPool bufferPool = new ObjectPool();
  
      @Override public void doGet(HttpServletRequest request,
                                  HttpServletResponse response)
              throws ServletException, IOException {
          String path = request.getContextPath();
          String uri = request.getRequestURI();
          ServletOutputStream out = response.getOutputStream();
  
          // Safety check making sure the resource is part of URI.
          if (!uri.startsWith(path)) {
              response.setStatus(HttpServletResponse.SC_BAD_REQUEST);
              out.println("Could not identify requested resource.");
              out.flush();
              out.close();
              return;
          }
  
          // Now create a resource path with the context and servlet path
          // taken out.
          path = uri.substring(path.length());
  
          // Now we have a resource i.e. /output/xmark.1A/summary.xml
          // We need to know the resource type by extracting the next level.
          int idx = path.indexOf('/', 1);
  
          // Then we break down the resource further to the actual file we wanted
          String resource = "";
          if (idx != -1) {
              resource = path.substring(idx + 1);
              path = path.substring(0, idx);
          }
  
          // Now the resource is actually the resource resource we want.
          // We have to append the real output dir to it.
          if ("/output".equals(path)) {
              resource = Config.OUT_DIR + resource;
          } else if ("/analysis".equals(path)) {
              resource = Config.ANALYSIS_DIR + resource;
          } else if ("/bench_downloads".equals(path)) {
              resource = Config.BENCHMARK_DIR + resource;
          } else if ("/service_downloads".equals(path)) {
              resource = Config.SERVICE_DIR + resource;
          }else if ("/benchmarks".equals(path)) {
              // This is the form /benchmarks/<bench_name>/resource
              // It maps to public_html under the benchmark.
              int idx1 = resource.indexOf('/');
              String benchName = resource.substring(0, idx1);
              resource = Config.BENCHMARK_DIR + benchName + "/public_html/" +
                                                  resource.substring(idx1 + 1);
          } else {
              String msg = "Routing of path " + path + " not implemented.";
              out.println(msg);
              response.sendError(HttpServletResponse.SC_NOT_IMPLEMENTED, msg);
              out.flush();
              out.close();
              return;
          }
  
          // Need to check that this file exists and is not a directory.
          File f = new File(resource);
          if (!f.exists()) {
              String msg = "Resource " + resource + " not found.";
              out.println("Resource " + resource + " not found.");
              response.sendError(HttpServletResponse.SC_NOT_FOUND, msg);
              out.flush();
              out.close();
              return;
          }
  
          // For directory, we send a text list of entries in the directory.
          // This is even easier to parse than XML.
          if (f.isDirectory()) {
              response.setContentType("text/plain");
              // Note: wWe use '\n' instead of println so we can be sure it is
              // always '\n' and not '\r\n', etc.
              out.print(" Directory: " + f.getName() + '\n');
              File[] entries = f.listFiles();
              for (int i = 0; i < entries.length; i++) {
                  char postfix;
                  if (!entries[i].exists())
                      continue;
                  if (entries[i].isDirectory())
                      postfix = '/';
                  else
                      postfix = ' ';
                  out.print(entries[i].getName() + postfix + '\n');
              }
              out.flush();
              out.close();
              return;
          }
          if (resource.endsWith(".html") || resource.endsWith(".htm"))
              response.setContentType("text/html");
  
          else if (resource.contains(".log.") || resource.contains(".xan.") ||
                  resource.endsWith(".log") || resource.endsWith(".xan"))
              response.setContentType("text/plain");
  
          // We don't want to keep allocating 8K all the time, so we keep
          // our buffers in a pool.
          byte[] buffer = (byte[]) bufferPool.get();
          if (buffer == null)
              buffer = new byte[8192];
  
          // Then we just transfer the file to the servlet output.
          FileInputStream fIn = new FileInputStream(f);
          for (;;) {
              int length = fIn.read(buffer);
              if (length > 0)
                  out.write(buffer, 0, length);
              else if (length == -1)
                  break;
          }
  
          // Now return the buffer to the pool.
          bufferPool.put(buffer);
  
          // All done. Now we just close everything.
          out.flush();
          out.close();
      }
  
      static class ObjectPool {
  
          ArrayList backingList = new ArrayList();
  
          public synchronized Object get() {
              if (backingList.size() == 0)
                  return null;
              return backingList.remove(backingList.size() - 1);
          }
  
          public synchronized void put(Object o) {
              backingList.add(o);
          }
      }
  }
  