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 java.util.stream.Collectors; 44 import javax.servlet.RequestDispatcher; 45 import javax.servlet.ServletException; 46 import javax.servlet.http.HttpServletRequest; 47 import javax.servlet.http.HttpServletResponse; 48 import javax.servlet.http.HttpSession; 49 50 import static com.googlecode.objectify.ObjectifyService.ofy; 51 52 /** Represents the servlet that is invoked on loading the first page of dashboard. */ 53 public class DashboardMainServlet extends BaseServlet { 54 private static final String DASHBOARD_MAIN_JSP = "WEB-INF/jsp/dashboard_main.jsp"; 55 private static final String NO_TESTS_ERROR = "No test results available."; 56 57 @Override getNavParentType()58 public PageType getNavParentType() { 59 return PageType.TOT; 60 } 61 62 @Override getBreadcrumbLinks(HttpServletRequest request)63 public List<Page> getBreadcrumbLinks(HttpServletRequest request) { 64 return null; 65 } 66 67 /** Helper class for displaying test entries on the main dashboard. */ 68 public class TestDisplay implements Comparable<TestDisplay> { 69 private final Key testKey; 70 private final int passCount; 71 private final int failCount; 72 private boolean muteNotifications; 73 private boolean isFavorite; 74 75 /** 76 * Test display constructor. 77 * 78 * @param testKey The key of the test. 79 * @param passCount The number of tests passing. 80 * @param failCount The number of tests failing. 81 * @param muteNotifications The flag for user notification in case of test failure. 82 * @param isFavorite The flag for showing favorite mark on All Tests Tab page. 83 */ TestDisplay( Key testKey, int passCount, int failCount, boolean muteNotifications, boolean isFavorite)84 public TestDisplay( 85 Key testKey, 86 int passCount, 87 int failCount, 88 boolean muteNotifications, 89 boolean isFavorite) { 90 this.testKey = testKey; 91 this.passCount = passCount; 92 this.failCount = failCount; 93 this.muteNotifications = muteNotifications; 94 this.isFavorite = isFavorite; 95 } 96 97 /** 98 * Get the key of the test. 99 * 100 * @return The key of the test. 101 */ getName()102 public String getName() { 103 return this.testKey.getName(); 104 } 105 106 /** 107 * Get the number of passing test cases. 108 * 109 * @return The number of passing test cases. 110 */ getPassCount()111 public int getPassCount() { 112 return this.passCount; 113 } 114 115 /** 116 * Get the number of failing test cases. 117 * 118 * @return The number of failing test cases. 119 */ getFailCount()120 public int getFailCount() { 121 return this.failCount; 122 } 123 124 /** 125 * Get the notification mute status. 126 * 127 * @return True if the subscriber has muted notifications, false otherwise. 128 */ getMuteNotifications()129 public boolean getMuteNotifications() { 130 return this.muteNotifications; 131 } 132 133 /** Set the notification mute status. */ setMuteNotifications(boolean muteNotifications)134 public void setMuteNotifications(boolean muteNotifications) { 135 this.muteNotifications = muteNotifications; 136 } 137 138 /** 139 * Get the favorate status. 140 * 141 * @return True if an user set favorate for the test, false otherwise. 142 */ getIsFavorite()143 public boolean getIsFavorite() { 144 return this.isFavorite; 145 } 146 147 /** Set the favorite status. */ setIsFavorite(boolean isFavorite)148 public void setIsFavorite(boolean isFavorite) { 149 this.isFavorite = isFavorite; 150 } 151 152 @Override compareTo(TestDisplay test)153 public int compareTo(TestDisplay test) { 154 return this.testKey.getName().compareTo(test.getName()); 155 } 156 } 157 158 @Override doGetHandler(HttpServletRequest request, HttpServletResponse response)159 public void doGetHandler(HttpServletRequest request, HttpServletResponse response) 160 throws IOException { 161 UserService userService = UserServiceFactory.getUserService(); 162 User currentUser = userService.getCurrentUser(); 163 RequestDispatcher dispatcher = null; 164 DatastoreService datastore = DatastoreServiceFactory.getDatastoreService(); 165 HttpSession session = request.getSession(true); 166 PageType referTo = PageType.TREE; 167 if (session.getAttribute("treeDefault") != null) { 168 boolean treeDefault = (boolean) session.getAttribute("treeDefault"); 169 if (!treeDefault) { 170 referTo = PageType.TABLE; 171 } 172 } 173 174 List<TestDisplay> displayedTests = new ArrayList<>(); 175 List<Key> unprocessedTestKeys = new ArrayList<>(); 176 177 Map<Key, TestDisplay> testMap = new HashMap<>(); // map from table key to TestDisplay 178 Map<String, String> subscriptionMap = new HashMap<>(); 179 180 boolean showAll = request.getParameter("showAll") != null; 181 String error = null; 182 183 List<String> allTestNames = TestEntity.getAllTestNames(); 184 185 List<Key> favoriteKeyList = new ArrayList<Key>(); 186 Filter userFilter = 187 new FilterPredicate(UserFavoriteEntity.USER, FilterOperator.EQUAL, currentUser); 188 Query filterQuery = new Query(UserFavoriteEntity.KIND).setFilter(userFilter); 189 Iterable<Entity> favoriteIter = datastore.prepare(filterQuery).asIterable(); 190 favoriteIter.forEach( 191 fe -> { 192 Key testKey = UserFavoriteEntity.fromEntity(fe).testKey; 193 favoriteKeyList.add(testKey); 194 subscriptionMap.put(testKey.getName(), KeyFactory.keyToString(fe.getKey())); 195 }); 196 197 Query query = 198 new Query(TestStatusEntity.KIND) 199 .addProjection( 200 new PropertyProjection(TestStatusEntity.PASS_COUNT, Long.class)) 201 .addProjection( 202 new PropertyProjection(TestStatusEntity.FAIL_COUNT, Long.class)); 203 for (Entity status : datastore.prepare(query).asIterable()) { 204 TestStatusEntity statusEntity = TestStatusEntity.fromEntity(status); 205 if (statusEntity == null) continue; 206 Key testKey = KeyFactory.createKey(TestEntity.KIND, statusEntity.getTestName()); 207 boolean isFavorite = favoriteKeyList.contains(testKey); 208 TestDisplay display = new TestDisplay(testKey, -1, -1, false, isFavorite); 209 if (!unprocessedTestKeys.contains(testKey)) { 210 display = 211 new TestDisplay( 212 testKey, 213 statusEntity.getPassCount(), 214 statusEntity.getFailCount(), 215 false, 216 isFavorite); 217 } 218 testMap.put(testKey, display); 219 } 220 221 if (testMap.size() == 0) { 222 error = NO_TESTS_ERROR; 223 } 224 225 if (showAll) { 226 for (Key testKey : testMap.keySet()) { 227 displayedTests.add(testMap.get(testKey)); 228 } 229 } else { 230 if (testMap.size() > 0) { 231 for (Entity favoriteEntity : favoriteIter) { 232 UserFavoriteEntity favorite = UserFavoriteEntity.fromEntity(favoriteEntity); 233 Key testKey = favorite.testKey; 234 if (!testMap.containsKey(testKey)) { 235 continue; 236 } 237 TestDisplay display = testMap.get(testKey); 238 display.setMuteNotifications(favorite.muteNotifications); 239 displayedTests.add(display); 240 } 241 } 242 } 243 displayedTests.sort(Comparator.naturalOrder()); 244 245 response.setStatus(HttpServletResponse.SC_OK); 246 request.setAttribute("allTestsJson", new Gson().toJson(allTestNames)); 247 request.setAttribute("subscriptionMapJson", new Gson().toJson(subscriptionMap)); 248 request.setAttribute("testNames", displayedTests); 249 request.setAttribute("showAll", showAll); 250 request.setAttribute("error", error); 251 request.setAttribute("resultsUrl", referTo.defaultUrl); 252 dispatcher = request.getRequestDispatcher(DASHBOARD_MAIN_JSP); 253 try { 254 dispatcher.forward(request, response); 255 } catch (ServletException e) { 256 logger.log(Level.SEVERE, "Servlet Excpetion caught : ", e); 257 } 258 } 259 } 260