001 package org.hackystat.projectbrowser.page.projectportfolio; 002 003 import java.io.Serializable; 004 import java.util.ArrayList; 005 import java.util.Arrays; 006 import java.util.Date; 007 import java.util.List; 008 import java.util.logging.Logger; 009 import javax.xml.datatype.XMLGregorianCalendar; 010 import org.apache.wicket.PageParameters; 011 import org.hackystat.projectbrowser.ProjectBrowserApplication; 012 import org.hackystat.projectbrowser.ProjectBrowserSession; 013 import org.hackystat.projectbrowser.page.ProjectBrowserBasePage; 014 import org.hackystat.projectbrowser.page.projectportfolio.detailspanel.ProjectPortfolioDataModel; 015 import org.hackystat.sensorbase.resource.projects.jaxb.Project; 016 import org.hackystat.utilities.tstamp.Tstamp; 017 018 /** 019 * Session to hold state for Project Portfolio. 020 * @author Shaoxuan Zhang 021 */ 022 public class ProjectPortfolioSession implements Serializable { 023 024 /** Support serialization. */ 025 private static final long serialVersionUID = 1L; 026 027 /** The parameter key of start date. */ 028 public static final String START_DATE_KEY = "0"; 029 /** The parameter key of end date. */ 030 public static final String END_DATE_KEY = "1"; 031 /** The parameter key of granularity. */ 032 public static final String GRANULARITY_KEY = "2"; 033 /** The parameter key of selectedProjects. */ 034 public static final String SELECTED_PROJECTS_KEY = "3"; 035 /** 036 * The last parameter key that is required. 037 * The telemetry parameters key is optional because not all telemetries have parameter. 038 */ 039 private static final String LAST_REQUIRED_KEY = "3"; 040 /** The last parameter key. */ 041 public static final String PARAMETER_ORDER_MESSAGE = "Correct parameter order is : " + 042 "/<startDate>/<endDate>/<granularity>/<projects> or " + 043 "/last/<number>/<granularity>/<projects>/"; 044 045 046 /** the feedback string. */ 047 private String feedback = ""; 048 049 /** The data model to hold state for details panel. */ 050 private ProjectPortfolioDataModel dataModel; 051 052 /** The start date this user has selected. */ 053 private long startDate = ProjectBrowserBasePage.getDateBefore(5).getTime(); 054 /** The end date this user has selected. */ 055 private long endDate = ProjectBrowserBasePage.getDateBefore(1).getTime(); 056 /** The projects this user has selected. */ 057 private List<Project> selectedProjects = new ArrayList<Project>(); 058 /** the granularity this data model focus. */ 059 private String granularity = "Day"; 060 /** The available granularities. */ 061 private final String[] granularities = {"Day", "Week", "Month"}; 062 063 /** Error message when parsing page paramters. */ 064 private String paramErrorMessage = ""; 065 066 /** 067 * Update the data model. 068 */ 069 public void updateDataModel() { 070 071 072 boolean backgroundProcessEnable = ((ProjectBrowserApplication)ProjectBrowserApplication.get()). 073 isBackgroundProcessEnable("projectportfolio"); 074 this.dataModel.setModel(startDate, endDate, selectedProjects, granularity); 075 076 ProjectBrowserSession.get().logUsage("PORTFOLIO: {invoked} " + 077 ProjectBrowserSession.get().printPageParameters(this.getPageParameters())); 078 079 if (backgroundProcessEnable) { 080 Thread thread = new Thread() { 081 @Override 082 public void run() { 083 dataModel.loadData(); 084 } 085 }; 086 thread.start(); 087 } 088 else { 089 dataModel.loadData(); 090 } 091 } 092 093 /** 094 * @param selectedProjects the selectedProjects to set 095 */ 096 public void setSelectedProjects(List<Project> selectedProjects) { 097 this.selectedProjects = selectedProjects; 098 } 099 100 /** 101 * @return the selectedProjects 102 */ 103 public List<Project> getSelectedProjects() { 104 return selectedProjects; 105 } 106 107 /** 108 * @return the dataModel 109 */ 110 public ProjectPortfolioDataModel getDataModel() { 111 return dataModel; 112 } 113 114 /** 115 * @param feedback the feedback to set 116 */ 117 public void setFeedback(String feedback) { 118 this.feedback = feedback; 119 } 120 121 /** 122 * @return the feedback 123 */ 124 public String getFeedback() { 125 String returnString = this.feedback; 126 this.feedback = ""; 127 return returnString; 128 } 129 130 /** 131 * @param startDate the startDate to set 132 */ 133 public void setStartDate(Date startDate) { 134 this.startDate = startDate.getTime(); 135 } 136 137 /** 138 * @return the startDate 139 */ 140 public Date getStartDate() { 141 return new Date(startDate); 142 } 143 144 /** 145 * @param endDate the endDate to set 146 */ 147 public void setEndDate(Date endDate) { 148 this.endDate = endDate.getTime(); 149 } 150 151 /** 152 * @return the endDate 153 */ 154 public Date getEndDate() { 155 return new Date(endDate); 156 } 157 158 /** 159 * @param granularity the granularity to set 160 */ 161 public void setGranularity(String granularity) { 162 this.granularity = granularity; 163 } 164 165 /** 166 * @return the granularity 167 */ 168 public String getGranularity() { 169 return granularity; 170 } 171 172 /** 173 * @return the granularities 174 */ 175 public List<String> getGranularities() { 176 return Arrays.asList(this.granularities); 177 } 178 179 /** 180 * Initialize the dataModel. 181 * Only initialize it when it is null. 182 * @return true if the dataModel is initialized, otherwise false. 183 */ 184 public boolean initializeDataModel() { 185 if (this.dataModel == null) { 186 this.dataModel = new ProjectPortfolioDataModel( 187 ((ProjectBrowserApplication)ProjectBrowserApplication.get()).getTelemetryHost(), 188 ProjectBrowserSession.get().getEmail(), ProjectBrowserSession.get().getPassword()); 189 return true; 190 } 191 return false; 192 } 193 194 /** 195 * Returns a PageParameters instance that represents the content of the input form. 196 * @return a PageParameters instance. 197 */ 198 public PageParameters getPageParameters() { 199 PageParameters parameters = new PageParameters(); 200 201 parameters.put(GRANULARITY_KEY, this.getGranularity()); 202 parameters.put(START_DATE_KEY, ProjectBrowserSession.getFormattedDateString(this.startDate)); 203 parameters.put(END_DATE_KEY, ProjectBrowserSession.getFormattedDateString(this.endDate)); 204 parameters.put(SELECTED_PROJECTS_KEY, 205 ProjectBrowserSession.convertProjectListToString(this.getSelectedProjects())); 206 207 return parameters; 208 } 209 210 /** 211 * Load data from URL parameters into this session. 212 * @param parameters the URL parameters 213 * @return true if all parameters are loaded correctly 214 */ 215 public boolean loadPageParameters(PageParameters parameters) { 216 boolean isLoadSucceed = true; 217 Logger logger = ProjectBrowserSession.get().getLogger(); 218 if (!parameters.containsKey(LAST_REQUIRED_KEY)) { 219 isLoadSucceed = false; 220 String error = "Some parameters are missing, should be " + LAST_REQUIRED_KEY + "\n" + 221 PARAMETER_ORDER_MESSAGE; 222 logger.warning(error); 223 this.paramErrorMessage = error + "\n"; 224 return false; 225 } 226 StringBuffer errorMessage = new StringBuffer(1000); 227 228 //load granularity 229 if (parameters.containsKey(GRANULARITY_KEY)) { 230 String granularityString = parameters.getString(GRANULARITY_KEY); 231 if (this.getGranularities().contains(granularityString)) { 232 this.setGranularity(granularityString); 233 } 234 else { 235 isLoadSucceed = false; 236 String error = "Granularity is not supported: " + granularityString; 237 logger.warning(error); 238 errorMessage.append(error); 239 errorMessage.append('\n'); 240 } 241 } 242 else { 243 isLoadSucceed = false; 244 errorMessage.append("granularity is missing in URL parameters.\n"); 245 } 246 //load dates 247 String startDateString = ""; 248 if (parameters.containsKey(START_DATE_KEY)) { 249 startDateString = parameters.getString(START_DATE_KEY); 250 } 251 else { 252 isLoadSucceed = false; 253 errorMessage.append("startDate is missing in URL parameters.\n"); 254 } 255 String endDateString = ""; 256 if (parameters.containsKey(END_DATE_KEY)) { 257 endDateString = parameters.getString(END_DATE_KEY); 258 } 259 else { 260 isLoadSucceed = false; 261 errorMessage.append("endDate is missing in URL parameters.\n"); 262 } 263 //check last X format first. 264 if ("last".equalsIgnoreCase(startDateString)) { 265 int time; 266 try { 267 time = Integer.valueOf(endDateString); 268 int interval = 1; 269 if ("Month".equalsIgnoreCase(this.granularity)) { 270 interval = 30; 271 } 272 else if ("Week".equalsIgnoreCase(this.granularity)) { 273 interval = 7; 274 } 275 time *= interval; 276 XMLGregorianCalendar today = Tstamp.makeTimestamp(); 277 endDate = Tstamp.incrementDays(today, -interval).toGregorianCalendar().getTimeInMillis(); 278 startDate = Tstamp.incrementDays(today, -time).toGregorianCalendar().getTimeInMillis(); 279 } 280 catch (NumberFormatException e) { 281 String error = endDateString + " cannot be parsed as an integer."; 282 logger.warning(error + " > " + e.getMessage()); 283 errorMessage.append(error); 284 errorMessage.append('\n'); 285 } 286 } 287 else if (endDateString.length() > 0 && startDateString.length() > 0) { 288 try { 289 this.endDate = 290 Tstamp.makeTimestamp(endDateString).toGregorianCalendar().getTimeInMillis(); 291 } 292 catch (Exception e) { 293 isLoadSucceed = false; 294 String error = "Errors when parsing end date from URL parameter: " + endDateString; 295 logger.warning(error + " > " + e.getMessage()); 296 errorMessage.append(error); 297 errorMessage.append('\n'); 298 } 299 try { 300 this.startDate = 301 Tstamp.makeTimestamp(startDateString).toGregorianCalendar().getTimeInMillis(); 302 } 303 catch (Exception e) { 304 isLoadSucceed = false; 305 String error = 306 "Errors when parsing start date from URL parameter: " + startDateString; 307 logger.warning(error + " > " + e.getMessage()); 308 errorMessage.append(error); 309 errorMessage.append('\n'); 310 } 311 } 312 313 //load seletecd project 314 if (parameters.containsKey(SELECTED_PROJECTS_KEY)) { 315 String[] projectsStringArray = 316 parameters.getString(SELECTED_PROJECTS_KEY).split( 317 ProjectBrowserSession.PARAMETER_VALUE_SEPARATOR); 318 List<Project> projectsList = new ArrayList<Project>(); 319 for (String projectString : projectsStringArray) { 320 int index = projectString.lastIndexOf(ProjectBrowserSession.PROJECT_NAME_OWNER_SEPARATR); 321 String projectName = projectString; 322 String projectOwner = null; 323 if (index > 0 && index < projectString.length()) { 324 projectName = projectString.substring(0, index); 325 projectOwner = projectString.substring( 326 index + ProjectBrowserSession.PROJECT_NAME_OWNER_SEPARATR.length()); 327 /* 328 isLoadSucceed = false; 329 String error = "Error URL parameter: project: " + projectString + 330 " >> project name and owner are missing or not formatted correctly."; 331 logger.warning(error); 332 errorMessage.append(error); 333 errorMessage.append('\n'); 334 continue; 335 */ 336 } 337 Project project = ProjectBrowserSession.get().getProject(projectName, projectOwner); 338 if (project == null) { 339 isLoadSucceed = false; 340 String error = "Error URL parameter: project: " + projectString + 341 " >> matching project not found under user: " + 342 ProjectBrowserSession.get().getEmail(); 343 logger.warning(error); 344 errorMessage.append(error); 345 errorMessage.append('\n'); 346 } 347 else { 348 projectsList.add(project); 349 } 350 } 351 if (!projectsList.isEmpty()) { 352 this.setSelectedProjects(projectsList); 353 } 354 } 355 else { 356 isLoadSucceed = false; 357 errorMessage.append("projects is missing in URL parameters.\n"); 358 } 359 360 if (errorMessage.length() > 0) { 361 this.paramErrorMessage = errorMessage.append(PARAMETER_ORDER_MESSAGE).toString(); 362 } 363 return isLoadSucceed; 364 } 365 366 367 /** 368 * @return the paramErrorMessage 369 */ 370 public String getParamErrorMessage() { 371 String temp = this.paramErrorMessage; 372 this.clearParamErrorMessage(); 373 return temp; 374 } 375 376 /** 377 * Clears the paramErrorMessage. 378 */ 379 public void clearParamErrorMessage() { 380 this.paramErrorMessage = ""; 381 } 382 383 }