1 /* 2 * Copyright (c) 2016 Google Inc. All Rights Reserved. 3 * 4 * Licensed under the Apache License, Version 2.0 (the "License"); you 5 * may not use this file except in compliance with the License. You may 6 * obtain a copy of the License at 7 * 8 * http://www.apache.org/licenses/LICENSE-2.0 9 * 10 * Unless required by applicable law or agreed to in writing, software 11 * distributed under the License is distributed on an "AS IS" BASIS, 12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or 13 * implied. See the License for the specific language governing 14 * permissions and limitations under the License. 15 */ 16 17 package com.android.vts.servlet; 18 19 import com.android.vts.entity.TestEntity; 20 import com.android.vts.entity.TestStatusEntity; 21 import com.android.vts.entity.UserFavoriteEntity; 22 import com.google.appengine.api.datastore.DatastoreService; 23 import com.google.appengine.api.datastore.DatastoreServiceFactory; 24 import com.google.appengine.api.datastore.Entity; 25 import com.google.appengine.api.datastore.Key; 26 import com.google.appengine.api.datastore.KeyFactory; 27 import com.google.appengine.api.datastore.PropertyProjection; 28 import com.google.appengine.api.datastore.Query; 29 import com.google.appengine.api.datastore.Query.Filter; 30 import com.google.appengine.api.datastore.Query.FilterOperator; 31 import com.google.appengine.api.datastore.Query.FilterPredicate; 32 import com.google.appengine.api.users.User; 33 import com.google.appengine.api.users.UserService; 34 import com.google.appengine.api.users.UserServiceFactory; 35 import com.google.gson.Gson; 36 import java.io.IOException; 37 import java.util.ArrayList; 38 import java.util.Comparator; 39 import java.util.HashMap; 40 import java.util.List; 41 import java.util.Map; 42 import java.util.logging.Level; 43 import javax.servlet.RequestDispatcher; 44 import javax.servlet.ServletException; 45 import javax.servlet.http.HttpServletRequest; 46 import javax.servlet.http.HttpServletResponse; 47 import javax.servlet.http.HttpSession; 48 49 /** Represents the servlet that is invoked on loading the first page of dashboard. */ 50 public class DashboardMainServlet extends BaseServlet { 51 private static final String DASHBOARD_MAIN_JSP = "WEB-INF/jsp/dashboard_main.jsp"; 52 private static final String NO_TESTS_ERROR = "No test results available."; 53 54 @Override 55 public PageType getNavParentType() { 56 return PageType.TOT; 57 } 58 59 @Override 60 public List<Page> getBreadcrumbLinks(HttpServletRequest request) { 61 return null; 62 } 63 64 /** Helper class for displaying test entries on the main dashboard. */ 65 public class TestDisplay implements Comparable<TestDisplay> { 66 private final Key testKey; 67 private final int passCount; 68 private final int failCount; 69 private boolean muteNotifications; 70 private boolean isFavorite; 71 72 /** 73 * Test display constructor. 74 * 75 * @param testKey The key of the test. 76 * @param passCount The number of tests passing. 77 * @param failCount The number of tests failing. 78 * @param muteNotifications The flag for user notification in case of test failure. 79 * @param isFavorite The flag for showing favorite mark on All Tests Tab page. 80 */ 81 public TestDisplay(Key testKey, int passCount, int failCount, boolean muteNotifications, 82 boolean isFavorite) { 83 this.testKey = testKey; 84 this.passCount = passCount; 85 this.failCount = failCount; 86 this.muteNotifications = muteNotifications; 87 this.isFavorite = isFavorite; 88 } 89 90 /** 91 * Get the key of the test. 92 * 93 * @return The key of the test. 94 */ 95 public String getName() { 96 return this.testKey.getName(); 97 } 98 99 /** 100 * Get the number of passing test cases. 101 * 102 * @return The number of passing test cases. 103 */ 104 public int getPassCount() { 105 return this.passCount; 106 } 107 108 /** 109 * Get the number of failing test cases. 110 * 111 * @return The number of failing test cases. 112 */ 113 public int getFailCount() { 114 return this.failCount; 115 } 116 117 /** 118 * Get the notification mute status. 119 * 120 * @return True if the subscriber has muted notifications, false otherwise. 121 */ 122 public boolean getMuteNotifications() { 123 return this.muteNotifications; 124 } 125 126 /** Set the notification mute status. */ 127 public void setMuteNotifications(boolean muteNotifications) { 128 this.muteNotifications = muteNotifications; 129 } 130 131 /** 132 * Get the favorate status. 133 * 134 * @return True if an user set favorate for the test, false otherwise. 135 */ 136 public boolean getIsFavorite() { 137 return this.isFavorite; 138 } 139 140 /** Set the favorite status. */ 141 public void setIsFavorite(boolean isFavorite) { 142 this.isFavorite = isFavorite; 143 } 144 145 @Override 146 public int compareTo(TestDisplay test) { 147 return this.testKey.getName().compareTo(test.getName()); 148 } 149 } 150 151 @Override 152 public void doGetHandler(HttpServletRequest request, HttpServletResponse response) 153 throws IOException { 154 UserService userService = UserServiceFactory.getUserService(); 155 User currentUser = userService.getCurrentUser(); 156 RequestDispatcher dispatcher = null; 157 DatastoreService datastore = DatastoreServiceFactory.getDatastoreService(); 158 HttpSession session = request.getSession(true); 159 PageType referTo = PageType.TREE; 160 if (session.getAttribute("treeDefault") != null) { 161 boolean treeDefault = (boolean) session.getAttribute("treeDefault"); 162 if (!treeDefault) { 163 referTo = PageType.TABLE; 164 } 165 } 166 167 List<TestDisplay> displayedTests = new ArrayList<>(); 168 List<String> allTestNames = new ArrayList<>(); 169 List<Key> unprocessedTestKeys = new ArrayList<>(); 170 171 Map<Key, TestDisplay> testMap = new HashMap<>(); // map from table key to TestDisplay 172 Map<String, String> subscriptionMap = new HashMap<>(); 173 174 boolean showAll = request.getParameter("showAll") != null; 175 String error = null; 176 177 Query query = new Query(TestEntity.KIND).setKeysOnly(); 178 for (Entity test : datastore.prepare(query).asIterable()) { 179 allTestNames.add(test.getKey().getName()); 180 } 181 182 List<Key> favoriteKeyList = new ArrayList<Key>(); 183 Filter userFilter = 184 new FilterPredicate( 185 UserFavoriteEntity.USER, FilterOperator.EQUAL, currentUser); 186 Query filterQuery = new Query(UserFavoriteEntity.KIND).setFilter(userFilter); 187 Iterable<Entity> favoriteIter = datastore.prepare(filterQuery).asIterable(); 188 favoriteIter.forEach(fe -> { 189 Key testKey = UserFavoriteEntity.fromEntity(fe).testKey; 190 favoriteKeyList.add(testKey); 191 subscriptionMap.put(testKey.getName(), KeyFactory.keyToString(fe.getKey())); 192 }); 193 194 query = 195 new Query(TestStatusEntity.KIND) 196 .addProjection( 197 new PropertyProjection(TestStatusEntity.PASS_COUNT, Long.class)) 198 .addProjection( 199 new PropertyProjection(TestStatusEntity.FAIL_COUNT, Long.class)); 200 for (Entity status : datastore.prepare(query).asIterable()) { 201 TestStatusEntity statusEntity = TestStatusEntity.fromEntity(status); 202 if (statusEntity == null) continue; 203 Key testKey = KeyFactory.createKey(TestEntity.KIND, statusEntity.testName); 204 boolean isFavorite = favoriteKeyList.contains(testKey); 205 TestDisplay display = new TestDisplay(testKey, -1, -1, false, isFavorite); 206 if (!unprocessedTestKeys.contains(testKey)) { 207 display = new TestDisplay(testKey, statusEntity.passCount, statusEntity.failCount, 208 false, isFavorite); 209 } 210 testMap.put(testKey, display); 211 } 212 213 if (testMap.size() == 0) { 214 error = NO_TESTS_ERROR; 215 } 216 217 if (showAll) { 218 for (Key testKey : testMap.keySet()) { 219 displayedTests.add(testMap.get(testKey)); 220 } 221 } else { 222 if (testMap.size() > 0) { 223 for (Entity favoriteEntity : favoriteIter) { 224 UserFavoriteEntity favorite = UserFavoriteEntity.fromEntity(favoriteEntity); 225 Key testKey = favorite.testKey; 226 if (!testMap.containsKey(testKey)) { 227 continue; 228 } 229 TestDisplay display = testMap.get(testKey); 230 display.setMuteNotifications(favorite.muteNotifications); 231 displayedTests.add(display); 232 } 233 } 234 } 235 displayedTests.sort(Comparator.naturalOrder()); 236 237 response.setStatus(HttpServletResponse.SC_OK); 238 request.setAttribute("allTestsJson", new Gson().toJson(allTestNames)); 239 request.setAttribute("subscriptionMapJson", new Gson().toJson(subscriptionMap)); 240 request.setAttribute("testNames", displayedTests); 241 request.setAttribute("showAll", showAll); 242 request.setAttribute("error", error); 243 request.setAttribute("resultsUrl", referTo.defaultUrl); 244 dispatcher = request.getRequestDispatcher(DASHBOARD_MAIN_JSP); 245 try { 246 dispatcher.forward(request, response); 247 } catch (ServletException e) { 248 logger.log(Level.SEVERE, "Servlet Excpetion caught : ", e); 249 } 250 } 251 } 252