GCS Log File Info Access from appspot project am: 6a63048585 am: edb54eddb6
am: d0fbaa9d30

Change-Id: I270abacd029a0a28636fe67cd258a2a5c256b970
diff --git a/.gitignore b/.gitignore
index 9a94e36..80791fb 100644
--- a/.gitignore
+++ b/.gitignore
@@ -1,6 +1,9 @@
 # Google App Engine generated folder
 appengine-generated/
 
+# Secutiry Key file folder
+src/main/webapp/WEB-INF/keys
+
 # Java
 *.class
 
@@ -42,4 +45,4 @@
 Session.vim
 .netrwhist
 *~
-tags
\ No newline at end of file
+tags
diff --git a/pom.xml b/pom.xml
index 7008b51..ee3e319 100644
--- a/pom.xml
+++ b/pom.xml
@@ -23,6 +23,10 @@
   <artifactId>vts-dashboard</artifactId>
 
   <properties>
+    <app.id>s~google.com:android-vts-staging</app.id>
+    <app.version>4</app.version>
+    <appengine.version>1.9.62</appengine.version>
+
     <appengine.clientID></appengine.clientID>
     <appengine.serviceClientID></appengine.serviceClientID>
     <appengine.senderEmail></appengine.senderEmail>
@@ -32,6 +36,10 @@
     <gerrit.scope></gerrit.scope>
     <analytics.id></analytics.id>
 
+    <gcs.projectID></gcs.projectID>
+    <gcs.keyFile></gcs.keyFile>
+    <gcs.bucketName></gcs.bucketName>
+
     <maven.compiler.target>1.8</maven.compiler.target>
     <maven.compiler.source>1.8</maven.compiler.source>
     <maven.war.filteringDeploymentDescriptors>true</maven.war.filteringDeploymentDescriptors>
@@ -99,7 +107,7 @@
     <dependency>
       <groupId>com.google.appengine</groupId>
       <artifactId>appengine-api-1.0-sdk</artifactId>
-      <version>1.9.60</version>
+      <version>${appengine.version}</version>
     </dependency>
 
     <dependency>
@@ -118,19 +126,19 @@
     <dependency>
       <groupId>com.google.appengine</groupId>
       <artifactId>appengine-testing</artifactId>
-      <version>1.9.60</version>
+      <version>${appengine.version}</version>
       <scope>test</scope>
     </dependency>
     <dependency>
         <groupId>com.google.appengine</groupId>
         <artifactId>appengine-api-stubs</artifactId>
-        <version>1.9.60</version>
+        <version>${appengine.version}</version>
         <scope>test</scope>
     </dependency>
     <dependency>
         <groupId>com.google.appengine</groupId>
         <artifactId>appengine-tools-sdk</artifactId>
-        <version>1.9.60</version>
+        <version>${appengine.version}</version>
         <scope>test</scope>
     </dependency>
 
@@ -172,7 +180,11 @@
       <plugin>
         <groupId>com.google.appengine</groupId>
         <artifactId>appengine-maven-plugin</artifactId>
-        <version>1.9.60</version>
+        <version>${appengine.version}</version>
+        <configuration>
+          <appId>${app.id}</appId>
+          <version>${app.version}</version>
+        </configuration>
       </plugin>
 
     </plugins>
diff --git a/src/main/java/com/android/vts/servlet/ShowGcsLogServlet.java b/src/main/java/com/android/vts/servlet/ShowGcsLogServlet.java
new file mode 100644
index 0000000..337494f
--- /dev/null
+++ b/src/main/java/com/android/vts/servlet/ShowGcsLogServlet.java
@@ -0,0 +1,149 @@
+/*
+ * Copyright (c) 2018 Google Inc. All Rights Reserved.
+ *
+ * Licensed 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 com.android.vts.servlet;
+
+import com.google.auth.oauth2.ServiceAccountCredentials;
+import com.google.cloud.storage.Blob;
+import com.google.cloud.storage.Bucket;
+import com.google.cloud.storage.Storage;
+import com.google.cloud.storage.Storage.BlobListOption;
+import com.google.cloud.storage.StorageOptions;
+import java.io.IOException;
+import java.io.InputStream;
+import java.nio.file.Path;
+import java.nio.file.Paths;
+import java.util.ArrayList;
+import java.util.Iterator;
+import java.util.List;
+import java.util.logging.Level;
+import javax.servlet.RequestDispatcher;
+import javax.servlet.ServletConfig;
+import javax.servlet.ServletException;
+import javax.servlet.http.HttpServletRequest;
+import javax.servlet.http.HttpServletResponse;
+
+/**
+ * A GCS log servlet read log zip file from Google Cloud Storage bucket and show the content in it
+ * from the zip file by unarchiving it
+ */
+@SuppressWarnings("serial")
+public class ShowGcsLogServlet extends BaseServlet {
+
+    private static final String GCS_LOG_JSP = "WEB-INF/jsp/show_gcs_log.jsp";
+
+    private static final String GCS_PROJECT_ID = System.getProperty("GCS_PROJECT_ID");
+    private static final String GCS_KEY_FILE = System.getProperty("GCS_KEY_FILE");
+    private static final String GCS_BUCKET_NAME = System.getProperty("GCS_BUCKET_NAME");
+
+    /**
+     * This is the key file to access vtslab-gcs project. It will allow the dashboard to have a full
+     * controll of the bucket.
+     */
+    private InputStream keyFileInputStream;
+
+    /** This is the instance of java google storage library */
+    private Storage storage;
+
+    @Override
+    public void init(ServletConfig cfg) throws ServletException {
+        super.init(cfg);
+        keyFileInputStream =
+                this.getServletContext().getResourceAsStream("/WEB-INF/keys/" + GCS_KEY_FILE);
+
+        try {
+            storage =
+                    StorageOptions.newBuilder()
+                            .setProjectId(GCS_PROJECT_ID)
+                            .setCredentials(
+                                    ServiceAccountCredentials.fromStream(keyFileInputStream))
+                            .build()
+                            .getService();
+        } catch (IOException e) {
+            logger.log(Level.SEVERE, "Error on creating storage instance!");
+        }
+    }
+
+    @Override
+    public PageType getNavParentType() {
+        return PageType.TOT;
+    }
+
+    @Override
+    public List<Page> getBreadcrumbLinks(HttpServletRequest request) {
+        return null;
+    }
+
+    @Override
+    public void doGetHandler(HttpServletRequest request, HttpServletResponse response)
+            throws IOException {
+
+        String path = request.getParameter("path") == null ? "" : request.getParameter("path");
+        Path pathInfo = Paths.get(path);
+
+        Bucket vtsReportBucket = storage.get(GCS_BUCKET_NAME);
+
+        List<String> dirList = new ArrayList<>();
+        List<String> fileList = new ArrayList<>();
+        if (pathInfo.endsWith(".zip")) {
+            Blob blobFile = vtsReportBucket.get(path);
+        } else {
+
+            logger.log(Level.INFO, "path info => " + pathInfo);
+            logger.log(Level.INFO, "path name count => " + pathInfo.getNameCount());
+
+            BlobListOption[] listOptions;
+            if (pathInfo.getNameCount() == 0) {
+                listOptions = new BlobListOption[] {BlobListOption.currentDirectory()};
+            } else {
+                if (pathInfo.getNameCount() <= 1) {
+                    dirList.add("/");
+                } else {
+                    dirList.add(pathInfo.getParent().toString());
+                }
+                listOptions =
+                        new BlobListOption[] {
+                            BlobListOption.currentDirectory(),
+                            BlobListOption.prefix(pathInfo.toString() + "/")
+                        };
+            }
+
+            Iterator<Blob> blobIterator = vtsReportBucket.list(listOptions).iterateAll();
+            while (blobIterator.hasNext()) {
+                Blob blob = blobIterator.next();
+                logger.log(Level.INFO, "blob name => " + blob);
+                if (blob.isDirectory()) {
+                    logger.log(Level.INFO, "directory name => " + blob.getName());
+                    dirList.add(blob.getName());
+                } else {
+                    logger.log(Level.INFO, "file name => " + blob.getName());
+                    fileList.add(blob.getName());
+                }
+            }
+        }
+
+        response.setStatus(HttpServletResponse.SC_OK);
+        request.setAttribute("dirList", dirList);
+        request.setAttribute("fileList", fileList);
+        request.setAttribute("path", path);
+        RequestDispatcher dispatcher = request.getRequestDispatcher(GCS_LOG_JSP);
+        try {
+            dispatcher.forward(request, response);
+        } catch (ServletException e) {
+            logger.log(Level.SEVERE, "Servlet Excpetion caught : ", e);
+        }
+    }
+}
diff --git a/src/main/webapp/WEB-INF/appengine-web.xml b/src/main/webapp/WEB-INF/appengine-web.xml
index a7d50bf..4023fb1 100644
--- a/src/main/webapp/WEB-INF/appengine-web.xml
+++ b/src/main/webapp/WEB-INF/appengine-web.xml
@@ -13,8 +13,6 @@
 -->
 
 <appengine-web-app xmlns="http://appengine.google.com/ns/1.0">
-  <application>s~google.com:android-vts-staging</application>
-  <version>4</version>
   <threadsafe>true</threadsafe>
   <sessions-enabled>true</sessions-enabled>
   <runtime>java8</runtime>
@@ -28,6 +26,9 @@
     <property name="GERRIT_URI" value="${gerrit.uri}" />
     <property name="GERRIT_SCOPE" value="${gerrit.scope}" />
     <property name="ANALYTICS_ID" value="${analytics.id}" />
+    <property name="GCS_PROJECT_ID" value="${gcs.projectID}" />
+    <property name="GCS_KEY_FILE" value="${gcs.keyFile}" />
+    <property name="GCS_BUCKET_NAME" value="${gcs.bucketName}" />
   </system-properties>
 
 </appengine-web-app>
\ No newline at end of file
diff --git a/src/main/webapp/WEB-INF/jsp/show_gcs_log.jsp b/src/main/webapp/WEB-INF/jsp/show_gcs_log.jsp
new file mode 100644
index 0000000..5c175ea
--- /dev/null
+++ b/src/main/webapp/WEB-INF/jsp/show_gcs_log.jsp
@@ -0,0 +1,69 @@
+<%--
+  ~ Copyright (c) 2018 Google Inc. All Rights Reserved.
+  ~
+  ~ Licensed 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.
+  --%>
+<%@ page contentType='text/html;charset=UTF-8' language='java' %>
+<%@ taglib prefix='fn' uri='http://java.sun.com/jsp/jstl/functions' %>
+<%@ taglib prefix='c' uri='http://java.sun.com/jsp/jstl/core'%>
+
+<html>
+  <%@ include file="header.jsp" %>
+  <link rel='stylesheet' href='/css/show_plan_release.css'>
+  <link rel='stylesheet' href='/css/plan_runs.css'>
+  <link rel='stylesheet' href='/css/search_header.css'>
+  <script src='https://www.gstatic.com/external_hosted/moment/min/moment-with-locales.min.js'></script>
+  <script src='js/time.js'></script>
+  <script src='js/plan_runs.js'></script>
+  <script src='js/search_header.js'></script>
+  <script type='text/javascript'>
+      var search;
+      $(document).ready(function() {
+
+      });
+  </script>
+
+  <body>
+    <div class='wide container'>
+      <div class='row' id='release-container'>
+        <h3>Directory List</h3>
+        <c:forEach varStatus="dirLoop" var="dirName" items="${dirList}">
+          <p>
+            <a href="${requestScope['javax.servlet.forward.servlet_path']}?path=${dirName}">
+              <c:out value="${dirName}"></c:out>
+                <c:if test="${dirLoop.first && path ne '/'}">
+                    (Move to Parent)
+                </c:if>
+            </a>
+          </p>
+          <c:if test="${!dirLoop.last}">
+          </c:if>
+        </c:forEach>
+        <hr/>
+        <h5>Current Directory Path : ${path}</h5>
+        <hr/>
+        <h3>File List</h3>
+        <c:forEach varStatus="fileLoop" var="fileName" items="${fileList}">
+          <p>
+            <a href="${requestScope['javax.servlet.forward.servlet_path']}?path=${fileName}">
+              <c:out value="${fileName}"></c:out>
+            </a>
+          </p>
+          <c:if test="${!fileLoop.last}">
+          </c:if>
+        </c:forEach>
+      </div>
+    </div>
+    <%@ include file="footer.jsp" %>
+  </body>
+</html>
diff --git a/src/main/webapp/WEB-INF/web.xml b/src/main/webapp/WEB-INF/web.xml
index dc1cf76..4c13bd7 100644
--- a/src/main/webapp/WEB-INF/web.xml
+++ b/src/main/webapp/WEB-INF/web.xml
@@ -86,6 +86,11 @@
 </servlet>
 
 <servlet>
+  <servlet-name>show_gcs_log</servlet-name>
+  <servlet-class>com.android.vts.servlet.ShowGcsLogServlet</servlet-class>
+</servlet>
+
+<servlet>
   <servlet-name>test_data</servlet-name>
   <servlet-class>com.android.vts.api.TestDataForDevServlet</servlet-class>
 </servlet>
@@ -211,6 +216,11 @@
 </servlet-mapping>
 
 <servlet-mapping>
+  <servlet-name>show_gcs_log</servlet-name>
+  <url-pattern>/show_gcs_log/*</url-pattern>
+</servlet-mapping>
+
+<servlet-mapping>
   <servlet-name>bigtable_legacy</servlet-name>
   <url-pattern>/api/bigtable/*</url-pattern>
 </servlet-mapping>