001 package org.hackystat.projectbrowser.page.projectportfolio.detailspanel; 002 003 import java.io.File; 004 import java.io.FileInputStream; 005 import java.io.FileNotFoundException; 006 import java.io.InputStream; 007 import java.io.Serializable; 008 import java.util.ArrayList; 009 import java.util.Arrays; 010 import java.util.Collections; 011 import java.util.Comparator; 012 import java.util.HashMap; 013 import java.util.List; 014 import java.util.Map; 015 import java.util.logging.Logger; 016 import javax.xml.bind.JAXBContext; 017 import javax.xml.bind.JAXBException; 018 import javax.xml.bind.Unmarshaller; 019 import javax.xml.datatype.XMLGregorianCalendar; 020 import javax.xml.transform.stream.StreamSource; 021 import javax.xml.validation.Schema; 022 import javax.xml.validation.SchemaFactory; 023 import org.apache.wicket.PageParameters; 024 import org.apache.wicket.model.IModel; 025 import org.apache.wicket.model.Model; 026 import org.hackystat.projectbrowser.ProjectBrowserApplication; 027 import org.hackystat.projectbrowser.ProjectBrowserProperties; 028 import org.hackystat.projectbrowser.ProjectBrowserSession; 029 import org.hackystat.projectbrowser.page.loadingprocesspanel.Processable; 030 import org.hackystat.projectbrowser.page.projectportfolio.detailspanel.chart. 031 StreamDeviationClassifier; 032 import org.hackystat.projectbrowser.page.projectportfolio.detailspanel.chart.MiniBarChart; 033 import org.hackystat.projectbrowser.page.projectportfolio.detailspanel.chart.StreamClassifier; 034 import org.hackystat.projectbrowser.page.projectportfolio.detailspanel.chart. 035 StreamParticipationClassifier; 036 import org.hackystat.projectbrowser.page.projectportfolio.detailspanel.chart.StreamTrendClassifier; 037 import org.hackystat.projectbrowser.page.projectportfolio.jaxb.Measures; 038 import org.hackystat.projectbrowser.page.projectportfolio.jaxb.PortfolioDefinitions; 039 import org.hackystat.projectbrowser.page.projectportfolio.jaxb.Measures.Measure; 040 import org.hackystat.projectbrowser.page.telemetry.TelemetrySession; 041 import org.hackystat.sensorbase.resource.projects.ProjectUtils; 042 import org.hackystat.sensorbase.resource.projects.jaxb.Project; 043 import org.hackystat.telemetry.analyzer.configuration.ExtensionFileFilter; 044 import org.hackystat.telemetry.service.client.TelemetryClient; 045 import org.hackystat.telemetry.service.client.TelemetryClientException; 046 import org.hackystat.telemetry.service.resource.chart.jaxb.ParameterDefinition; 047 import org.hackystat.telemetry.service.resource.chart.jaxb.TelemetryChartData; 048 import org.hackystat.telemetry.service.resource.chart.jaxb.TelemetryChartRef; 049 import org.hackystat.utilities.logger.HackystatLogger; 050 import org.hackystat.utilities.tstamp.Tstamp; 051 import org.hackystat.utilities.uricache.UriCache; 052 import org.xml.sax.SAXException; 053 054 /** 055 * Data model to hold state of Project Portfolio. 056 * 057 * @author Shaoxuan Zhang 058 */ 059 public class ProjectPortfolioDataModel implements Serializable, Processable { 060 061 /** Support serialization. */ 062 private static final long serialVersionUID = 5465041655927215391L; 063 /** state of data loading process. */ 064 private volatile boolean inProcess = false; 065 /** result of data loading. */ 066 private volatile boolean complete = false; 067 /** message to display when data loading is in process. */ 068 private String processingMessage = ""; 069 070 /** host of the telemetry host. */ 071 private String telemetryHost; 072 /** email of the user. */ 073 private String userEmail; 074 /** password of the user. */ 075 private String password; 076 /** The telemetry session. */ 077 private TelemetrySession telemetrySession; 078 079 /** the granularity this data model focus. */ 080 private String granularity = "Week"; 081 /** If current day, week or month will be included in portfolio. */ 082 // private boolean includeCurrentWeek = true; 083 /** The start date this user has selected. */ 084 private long startDate = 0; 085 /** The end date this user has selected. */ 086 private long endDate = 0; 087 /** List of available stream classifiers. */ 088 public static final List<String> availableClassifiers = Arrays.asList(new String[]{ 089 "None", 090 StreamTrendClassifier.name, 091 StreamParticipationClassifier.name, 092 StreamDeviationClassifier.name 093 }); 094 095 /** 096 * the time phrase this data model focus. In scale of telemetryGranularity, from current to the 097 * past. 098 */ 099 // private int timePhrase = 5; 100 /** The projects this user has selected. */ 101 private List<Project> selectedProjects = new ArrayList<Project>(); 102 /** The charts in this model. */ 103 private Map<Project, List<MiniBarChart>> measuresCharts = 104 new HashMap<Project, List<MiniBarChart>>(); 105 /** The List of PortfolioMeasureConfiguration. */ 106 private final List<PortfolioMeasureConfiguration> measures = 107 new ArrayList<PortfolioMeasureConfiguration>(); 108 /** Alias for measure. Maps names from definition to names for display. */ 109 //private final Map<String, String> measureAlias = new HashMap<String, String>(); 110 /** The portfolio measure configuration loaded from xml file. */ 111 private PortfolioDefinitions portfolioDefinitions = getPortfolioDefinitions(); 112 /** The configuration saving capacity. */ 113 private static Long capacity = 1000L; 114 /** The max life of the saved configuration. */ 115 private static Double maxLife = 300.0; 116 117 /** The background color for table cells. */ 118 private String backgroundColor = "000000"; 119 /** The font color for table cells. */ 120 private String fontColor = "ffffff"; 121 /** The font color for N/A. */ 122 private String naColor = "888888"; 123 /** The color for good state. */ 124 private String goodColor = "00ff00"; 125 /** The color for soso state. */ 126 private String averageColor = "ffff00"; 127 /** The color for bad state. */ 128 private String poorColor = "ff0000"; 129 130 /** 131 * Constructor that initialize the measures. 132 * 133 * @param telemetryHost the telemetry host 134 * @param userEmail the user's email 135 * @param password the user's passowrd 136 */ 137 public ProjectPortfolioDataModel(String telemetryHost, String userEmail, String password) { 138 telemetrySession = ProjectBrowserSession.get().getTelemetrySession(); 139 this.telemetryHost = telemetryHost; 140 this.userEmail = userEmail; 141 this.password = password; 142 this.initializeMeasures(); 143 this.loadUserConfiguration(); 144 // List<ParameterDefinition> paramDefList = 145 // telemetrySession.getParameterList(measure.getName()); 146 } 147 148 /** 149 * @param startDate the start date. 150 * @param endDate the end date. 151 * @param selectedProjects the selected projects. 152 * @param granularity the granularity this data model focus. 153 */ 154 public void setModel(long startDate, long endDate, List<Project> selectedProjects, 155 String granularity) { 156 this.startDate = startDate; 157 this.endDate = endDate; 158 this.granularity = granularity; 159 this.selectedProjects = selectedProjects; 160 for (PortfolioMeasureConfiguration measure : getEnabledMeasures()) { 161 checkMeasureParameters(measure); 162 } 163 measuresCharts.clear(); 164 } 165 166 /** 167 * Initialize the measure configurations. 168 */ 169 private void initializeMeasures() { 170 // Load default measures 171 measures.clear(); 172 173 // Load additional user customized measures. 174 //PortfolioDefinitions portfolioDefinitions = getPortfolioDefinitions(); 175 if (portfolioDefinitions != null) { 176 for (Measure measure : portfolioDefinitions.getMeasures().getMeasure()) { 177 measures.add(new PortfolioMeasureConfiguration(measure.getName(), measure.getAlias(), 178 measure.getMerge(), measure.isEnabled(), getClassifier(measure), this)); 179 } 180 } 181 for (PortfolioMeasureConfiguration measure : getEnabledMeasures()) { 182 checkMeasureParameters(measure); 183 } 184 } 185 186 /** 187 * Get a {@link StreamClassifier} according to the given Measure. 188 * @param measure a given {@link Measure} object. 189 * @return a {@link StreamClassifier} instance, 190 * null if no supported classifier defined in the Measure object. 191 */ 192 protected static StreamClassifier getClassifier(Measure measure) { 193 if (measure == null) { 194 return null; 195 } 196 String classifierMethod = measure.getClassifierMethod(); 197 if ("StreamTrend".equalsIgnoreCase(classifierMethod)) { 198 if (measure.getStreamTrendParameters() == null) { 199 return new StreamTrendClassifier(0, 0, true, false); 200 } 201 Double lowerThreshold = measure.getStreamTrendParameters().getLowerThresold(); 202 if (lowerThreshold == null) { 203 lowerThreshold = 0.0; 204 } 205 Double higherThreshold = measure.getStreamTrendParameters().getHigherThresold(); 206 if (higherThreshold == null) { 207 higherThreshold = 0.0; 208 } 209 Boolean higherBetter = true; 210 if (measure.getStreamTrendParameters().isSetHigherBetter()) { 211 higherBetter = measure.getStreamTrendParameters().isHigherBetter(); 212 } 213 Boolean scaleWithGranularity = false; 214 if (measure.getStreamTrendParameters().isSetScaleWithGranularity()) { 215 scaleWithGranularity = measure.getStreamTrendParameters().isScaleWithGranularity(); 216 } 217 return new StreamTrendClassifier( 218 lowerThreshold, higherThreshold, higherBetter, scaleWithGranularity); 219 } 220 else if ("Participation".equalsIgnoreCase(classifierMethod)) { 221 if (measure.getParticipationParameters() == null) { 222 return new StreamParticipationClassifier(50, 0, 50, true); 223 } 224 Double memberPercentage = measure.getParticipationParameters().getMemberPercentage(); 225 if (memberPercentage == null) { 226 memberPercentage = 50.0; 227 } 228 Double valueThreshold = measure.getParticipationParameters().getThresoldValue(); 229 if (valueThreshold == null) { 230 valueThreshold = 0.0; 231 } 232 Double frequencyPercentage = 233 measure.getParticipationParameters().getFrequencyPercentage(); 234 if (frequencyPercentage == null) { 235 frequencyPercentage = 50.0; 236 } 237 Boolean scaleWithGranularity = true; 238 if (measure.getParticipationParameters().isSetScaleWithGranularity()) { 239 scaleWithGranularity = measure.getParticipationParameters().isScaleWithGranularity(); 240 } 241 return new StreamParticipationClassifier( 242 memberPercentage, valueThreshold, frequencyPercentage, scaleWithGranularity); 243 } 244 else if ("Deviation".equalsIgnoreCase(classifierMethod)) { 245 if (measure.getDeviationParameters() == null) { 246 return new StreamDeviationClassifier(40, 20, 50, true); 247 } 248 Double moderateDeviation = measure.getDeviationParameters().getModerateDeviation(); 249 if (moderateDeviation == null) { 250 moderateDeviation = 40.0; 251 } 252 Double unacceptableDeviation = measure.getDeviationParameters().getUnacceptableDeviation(); 253 if (unacceptableDeviation == null) { 254 unacceptableDeviation = 20.0; 255 } 256 Double expectationValue = measure.getDeviationParameters().getExpectationValue(); 257 if (expectationValue == null) { 258 expectationValue = 50.0; 259 } 260 Boolean scaleWithGranularity = true; 261 if (measure.getDeviationParameters().isSetScaleWithGranularity()) { 262 scaleWithGranularity = measure.getDeviationParameters().isScaleWithGranularity(); 263 } 264 return new StreamDeviationClassifier( 265 moderateDeviation, unacceptableDeviation, expectationValue, scaleWithGranularity); 266 } 267 return null; 268 } 269 270 /** 271 * Print the {@link Measure} for logging purpose. 272 * 273 * @param measure the {@link Measure} to log. 274 * @return the string 275 */ 276 private String printPortfolioMeasure(Measure measure) { 277 String s = "/"; 278 String classifierParameters = ""; 279 String classifier = measure.getClassifierMethod(); 280 if (StreamTrendClassifier.name.equalsIgnoreCase(classifier) && 281 measure.getStreamTrendParameters() != null) { 282 classifierParameters = measure.getStreamTrendParameters().getLowerThresold() + s + 283 measure.getStreamTrendParameters().getHigherThresold() + s + 284 measure.getStreamTrendParameters().isHigherBetter(); 285 } 286 else if (StreamParticipationClassifier.name.equals(classifier) && 287 measure.getParticipationParameters() != null) { 288 classifierParameters = measure.getParticipationParameters().getMemberPercentage() + s + 289 measure.getParticipationParameters().getThresoldValue() + s + 290 measure.getParticipationParameters().getFrequencyPercentage(); 291 } 292 String enabled = "disabled"; 293 if (measure.isEnabled()) { 294 enabled = "enabled"; 295 } 296 return "<" + measure.getName() + ": " + s + enabled + s 297 + classifier + s + classifierParameters + s + 298 measure.getTelemetryParameters() + "> "; 299 } 300 301 /** 302 * Save user's configuration to system's cache. 303 * 304 * @return change maked in this saving. 305 */ 306 public String saveUserConfiguration() { 307 StringBuffer log = new StringBuffer(); 308 UriCache userCache = this.getUserConfiguartionCache(); 309 for (PortfolioMeasureConfiguration measure : this.measures) { 310 String uri = userEmail + "/portfolio/" + measure.getName(); 311 Measure oldMeasure = null; 312 if (userCache.get(uri) instanceof Measure) { 313 oldMeasure = (Measure) userCache.get(uri); 314 } 315 else { 316 userCache.remove(uri); 317 } 318 Measure newMeasure = this.getMeasure(measure); 319 if (oldMeasure != null) { 320 String oldMeasureString = printPortfolioMeasure(oldMeasure); 321 String newMeasureString = printPortfolioMeasure(newMeasure); 322 if (!newMeasureString.equals(oldMeasureString)) { 323 mergeMeasures(newMeasure, oldMeasure); 324 userCache.put(uri, newMeasure); 325 log.append(newMeasureString); 326 } 327 } 328 } 329 330 if (log.length() > 0) { 331 ProjectBrowserSession.get().logUsage("PORTFOLIO CONFIGURATION: {changed} " + log.toString()); 332 } 333 return log.toString(); 334 } 335 336 /** 337 * Merge the old measure into the new one. 338 * @param newMeasure The new Measure. 339 * @param oldMeasure The old Measure. 340 */ 341 private void mergeMeasures(Measure newMeasure, Measure oldMeasure) { 342 if (oldMeasure == null) { 343 return; 344 } 345 if (newMeasure.getStreamTrendParameters() == null) { 346 newMeasure.setStreamTrendParameters(oldMeasure.getStreamTrendParameters()); 347 } 348 if (newMeasure.getParticipationParameters() == null) { 349 newMeasure.setParticipationParameters(oldMeasure.getParticipationParameters()); 350 } 351 } 352 353 /** 354 * Return a {@link Measure} represents the given PortfolioMeasureConfiguration. 355 * @param measureConfiguration a {@link PortfolioMeasureConfiguration}. 356 * @return a {@link Measure}. 357 */ 358 private Measure getMeasure(PortfolioMeasureConfiguration measureConfiguration) { 359 Measure measure = new Measure(); 360 measure.setName(measureConfiguration.getName()); 361 measure.setEnabled(measureConfiguration.isEnabled()); 362 measure.setTelemetryParameters(measureConfiguration.getParamtersString()); 363 measure.setClassifierMethod(measureConfiguration.getClassiferName()); 364 measureConfiguration.saveClassifierSetting(measure); 365 366 return measure; 367 } 368 369 /** 370 * Load user's configuration from system's cache. 371 */ 372 private void loadUserConfiguration() { 373 for (PortfolioMeasureConfiguration measure : this.measures) { 374 Measure savedMeausre = getSavedMeasure(measure); 375 if (savedMeausre != null) { 376 measure.setMeasureConfiguration(savedMeausre.isEnabled(), getClassifier(savedMeausre), 377 savedMeausre.getTelemetryParameters()); 378 } 379 } 380 } 381 382 /** 383 * Get the {@link Measure} instance associated with the given 384 * {@link PortfolioMeasureConfiguration} from UriCache. 385 * @param measure the given {@link PortfolioMeasureConfiguration} 386 * @return the {@link Measure} instance, null if not matched found in cache. 387 */ 388 protected final Measure getSavedMeasure(PortfolioMeasureConfiguration measure) { 389 UriCache userCache = this.getUserConfiguartionCache(); 390 String uri = userEmail + "/portfolio/" + measure.getName(); 391 Measure savedMeausre = null; 392 if (userCache.get(uri) instanceof Measure) { 393 savedMeausre = (Measure) userCache.get(uri); 394 } 395 else { 396 userCache.remove(uri); 397 } 398 return savedMeausre; 399 } 400 401 /** 402 * Reset user's configuration cache. 403 */ 404 public void resetUserConfiguration() { 405 // UriCache userCache = this.getUserConfiguartionCache(); 406 // userCache.clearAll(); 407 this.initializeMeasures(); 408 String msg = this.saveUserConfiguration(); 409 if (msg.length() > 0) { 410 ProjectBrowserSession.get().logUsage("CONFIGURATION: {reset to default} "); 411 } 412 } 413 414 /** 415 * Load the portfolio definitions from the xml file. 416 * 417 * @return a PortfolioDefinitions instance. null if fail to load the file. 418 */ 419 private PortfolioDefinitions getPortfolioDefinitions() { 420 PortfolioDefinitions portfolioDefinitions = new PortfolioDefinitions(); 421 portfolioDefinitions.setMeasures(new Measures()); 422 // load the basic default definitions. 423 424 getLogger().info("Reading basic portfolio definitions from: basic.portfolio.definition.xml"); 425 InputStream defStream = ProjectPortfolioDataModel.class 426 .getResourceAsStream("basic.portfolio.definition.xml"); 427 PortfolioDefinitions definition = getDefinitions(defStream); 428 if (definition != null) { 429 portfolioDefinitions.getMeasures().getMeasure().addAll(definition.getMeasures().getMeasure()); 430 } 431 432 433 // load user defined definitions. 434 String defDirString = ((ProjectBrowserApplication) ProjectBrowserApplication.get()) 435 .getPortfolioDefinitionDir(); 436 if (defDirString != null && defDirString.length() > 0) { 437 File defDir = new File(defDirString); 438 File[] xmlFiles = defDir.listFiles(new ExtensionFileFilter(".xml")); 439 if (xmlFiles.length > 0) { 440 getLogger().info("Reading portfolio definitions from: " + defDirString); 441 List<TelemetryChartRef> chartRefs = null; 442 try { 443 TelemetryClient telemetryClient = new TelemetryClient(telemetryHost, userEmail, password); 444 chartRefs = telemetryClient.getChartIndex().getTelemetryChartRef(); 445 } 446 catch (TelemetryClientException e1) { 447 getLogger().warning("Error retrieving telemetry chart definitions." + e1.getMessage()); 448 } 449 catch (Exception e) { 450 getLogger().warning("Unexpected error occurs. " + e.getMessage()); 451 } 452 for (File xmlFile : xmlFiles) { 453 try { 454 getLogger().info("Reading portfolio definitions from: " + xmlFile); 455 PortfolioDefinitions def = getDefinitions(new FileInputStream(xmlFile)); 456 if (def != null) { 457 List<Measure> measureList = def.getMeasures().getMeasure(); 458 if (chartRefs != null) { 459 List<Measure> invalidMeasures = new ArrayList<Measure>(); 460 for (Measure measure : measureList) { 461 if (!chartRefs.contains(measure.getName())) { 462 invalidMeasures.add(measure); 463 getLogger().warning("Found invalid measure:" + measure.getName() + 464 ". Please double check with the Telemetry Chart definitions."); 465 } 466 } 467 measureList.removeAll(invalidMeasures); 468 } 469 portfolioDefinitions.getMeasures().getMeasure().addAll(measureList); 470 } 471 } 472 catch (FileNotFoundException e) { 473 getLogger().info("Error reading definitions from: " + xmlFile + " " + e); 474 } 475 } 476 } 477 else { 478 getLogger().info("No portfolio definitions found in: " + defDirString); 479 } 480 } 481 else { 482 getLogger().info(ProjectBrowserProperties.PORTFOLIO_DEFINITION_DIR + " not defined."); 483 } 484 return portfolioDefinitions; 485 } 486 487 /** 488 * Returns a TelemetryDefinitions object constructed from defStream, or null if unsuccessful. 489 * 490 * @param defStream The input stream containing a TelemetryDefinitions object in XML format. 491 * @return The TelemetryDefinitions object. 492 */ 493 private PortfolioDefinitions getDefinitions(InputStream defStream) { 494 // Read in the definitions file. 495 try { 496 JAXBContext jaxbContext = JAXBContext 497 .newInstance(org.hackystat.projectbrowser.page.projectportfolio.jaxb.ObjectFactory.class); 498 Unmarshaller unmarshaller = jaxbContext.createUnmarshaller(); 499 // add schema checking 500 SchemaFactory schemaFactory = SchemaFactory.newInstance("http://www.w3.org/2001/XMLSchema"); 501 502 InputStream schemaStream = ProjectPortfolioDataModel.class 503 .getResourceAsStream("portfolioDefinitions.xsd"); 504 StreamSource schemaSources = new StreamSource(schemaStream); 505 Schema schema = schemaFactory.newSchema(schemaSources); 506 unmarshaller.setSchema(schema); 507 return (PortfolioDefinitions) unmarshaller.unmarshal(defStream); 508 } 509 catch (JAXBException e1) { 510 Logger logger = getLogger(); 511 logger.severe("Error occurs when parsing portfolio definition xml file with jaxb > " 512 + e1.getErrorCode() + ":" + e1.getMessage()); 513 e1.printStackTrace(); 514 } 515 catch (SAXException e) { 516 Logger logger = getLogger(); 517 logger.warning("Error occurs when loading schema file: " + defStream.toString() + " > " 518 + e.getMessage()); 519 } 520 return null; 521 } 522 523 /** 524 * Load data from Hackystat service. 525 */ 526 public void loadData() { 527 528 this.inProcess = true; 529 this.complete = false; 530 this.processingMessage = "Retrieving data from Hackystat Telemetry service.\n"; 531 try { 532 TelemetryClient telemetryClient = new TelemetryClient(telemetryHost, userEmail, password); 533 // prepare start and end time. 534 XMLGregorianCalendar startTime = getStartTimestamp(); 535 XMLGregorianCalendar endTime = getEndTimestamp(); 536 for (int i = 0; i < this.selectedProjects.size() && inProcess; i++) { 537 // prepare project's information 538 Project project = this.selectedProjects.get(i); 539 String owner = project.getOwner(); 540 String projectName = project.getName(); 541 542 this.processingMessage += "Retrieve data for project " + projectName + " (" + (i + 1) 543 + " of " + this.selectedProjects.size() + ").\n"; 544 545 // get charts of this project 546 List<MiniBarChart> charts = new ArrayList<MiniBarChart>(); 547 548 List<PortfolioMeasureConfiguration> enableMeasures = getEnabledMeasures(); 549 550 for (int j = 0; j < enableMeasures.size(); ++j) { 551 PortfolioMeasureConfiguration measure = enableMeasures.get(j); 552 553 this.processingMessage += "---> Retrieve " + measure.getName() + "<" 554 + measure.getParamtersString() + ">" + " (" + (i + 1) + " .. " + (j + 1) + " of " 555 + enableMeasures.size() + ").\n"; 556 // get data from hackystat 557 if (!ProjectUtils.isValidStartTime(project, startTime)) { 558 startTime = project.getStartTime(); 559 } 560 String s = "/"; 561 getLogger().finest( 562 "retriving telemetry: " + measure.getName() + s + owner + s + projectName + s 563 + granularity + s + startTime + s + endTime + s + measure.getParamtersString()); 564 TelemetryChartData chartData = telemetryClient.getChart(measure.getName(), owner, 565 projectName, granularity, startTime, endTime, measure.getParamtersString()); 566 // Log warning when portfolio definition refers to multi-stream telemetry chart. 567 if (chartData.getTelemetryStream().size() > 1) { 568 String merge = measure.getMerge(); 569 if ((merge == null || merge.length() <= 0) && i == 0) { 570 Logger logger = getLogger(); 571 logger.warning("Telemetry chart:" + measure.getName() + 572 " contains multiple streams, but there is no merge method found in portfolio " + 573 "defintion. Please check your portfolio and telemetry definitions"); 574 } 575 } 576 MiniBarChart chart = 577 new MiniBarChart(chartData.getTelemetryStream(), measure, this.granularity); 578 chart.setTelemetryPageParameters(this.getTelemetryPageParameters(measure, project)); 579 //chart.setDpdPageParameters(this.getDpdPageParameters( 580 //measure, project, chart.getLastValidIndex())); 581 charts.add(chart); 582 } 583 this.measuresCharts.put(project, charts); 584 } 585 } 586 catch (TelemetryClientException e) { 587 String errorMessage = "Errors when retrieving telemetry data: " + e.getMessage() + ". " 588 + "Please try again."; 589 this.processingMessage += errorMessage + "\n"; 590 591 this.complete = false; 592 this.inProcess = false; 593 return; 594 } 595 this.complete = inProcess; 596 if (this.complete) { 597 this.processingMessage += "All done.\n"; 598 } 599 this.inProcess = false; 600 } 601 602 /** 603 * Check the parameter in the given measure configuration. Set the parameter to default if it is 604 * incorrect. 605 * 606 * @param measure the given MeasureConfiguration. 607 */ 608 private void checkMeasureParameters(PortfolioMeasureConfiguration measure) { 609 List<ParameterDefinition> paramDefList = telemetrySession.getParameterList(measure.getName()); 610 List<IModel> parameters = measure.getParameters(); 611 //[1] check the size of parameters. 612 if (parameters.size() == paramDefList.size()) { 613 //[2] check data type compatible of each parameter. 614 for (int i = 0; i < parameters.size(); ++i) { 615 if (!TelemetrySession.isValueMatchType( 616 String.valueOf(measure.getParameters().get(i).getObject()), 617 paramDefList.get(i).getType())) { 618 parameters.remove(i); 619 parameters.add(i, new Model(paramDefList.get(i).getType().getDefault())); 620 621 } 622 } 623 } 624 //[1.5] rebuild the parameter if size is not match. 625 else { 626 parameters.clear(); 627 for (ParameterDefinition paramDef : paramDefList) { 628 parameters.add(new Model(paramDef.getType().getDefault())); 629 } 630 } 631 } 632 633 /** 634 * Cancel the data loading process. 635 */ 636 public void cancelDataUpdate() { 637 this.processingMessage += "Process Cancelled.\n"; 638 this.inProcess = false; 639 } 640 641 /** 642 * Return a PageParameters instance that include necessary information for telemetry. 643 * 644 * @param measure the telemetry analysis 645 * @param project the project 646 * @return the PagaParameters object 647 */ 648 private PageParameters getTelemetryPageParameters(PortfolioMeasureConfiguration measure, 649 Project project) { 650 PageParameters parameters = new PageParameters(); 651 652 parameters.put(TelemetrySession.TELEMETRY_KEY, measure.getName()); 653 parameters.put(TelemetrySession.START_DATE_KEY, getStartTimestamp().toString()); 654 parameters.put(TelemetrySession.END_DATE_KEY, getEndTimestamp().toString()); 655 parameters.put(TelemetrySession.SELECTED_PROJECTS_KEY, 656 ProjectBrowserSession.convertProjectListToString(Arrays.asList(new Project[]{project}))); 657 parameters.put(TelemetrySession.GRANULARITY_KEY, this.granularity); 658 parameters.put(TelemetrySession.TELEMETRY_PARAMERTERS_KEY, measure.getParamtersString()); 659 660 return parameters; 661 } 662 663 /** 664 * Return a PageParameters instance that include necessary information for telemetry. 665 * 666 * @param measure the telemetry analysis 667 * @param project the project 668 * @param indexOfLastValue the index of last valid value. 669 * @return the PagaParameters object, null if indexOfLastValue is negative, 670 * which means last value is not available. 671 */ 672 /* 673 private PageParameters getDpdPageParameters(PortfolioMeasureConfiguration measure, 674 Project project, int indexOfLastValue) { 675 if (indexOfLastValue < 0) { 676 return null; 677 } 678 PageParameters parameters = new PageParameters(); 679 680 681 parameters.put(DailyProjectDataSession.ANALYSIS_KEY, measure.getName()); 682 parameters.put(DailyProjectDataSession.DATE_KEY, ); 683 parameters.put(DailyProjectDataSession.SELECTED_PROJECTS_KEY, 684 ProjectBrowserSession.convertProjectListToString(Arrays.asList(new Project[]{project}))); 685 686 return parameters; 687 } 688 */ 689 690 /** 691 * Return the end time stamp for analysis. If includeCurrentWeek, it will return the time stamp of 692 * yesterday. If !includeCurrentWeek, it will return the time stamp of last Saturday. 693 * 694 * @return the XMLGregorianCalendar instance. 695 */ 696 private XMLGregorianCalendar getEndTimestamp() { 697 /* 698 * if (!this.includeCurrentWeek) { GregorianCalendar date = new GregorianCalendar(); 699 * date.setTime(ProjectBrowserBasePage.getDateBefore(1)); 700 * date.setFirstDayOfWeek(Calendar.MONDAY); int dayOfWeek = date.get(Calendar.DAY_OF_WEEK); 701 * XMLGregorianCalendar endTime = Tstamp.makeTimestamp(date.getTimeInMillis()); endTime = 702 * Tstamp.incrementDays(endTime, - dayOfWeek); return endTime; } return 703 * Tstamp.makeTimestamp(ProjectBrowserBasePage.getDateBefore(1).getTime()); 704 */ 705 return Tstamp.makeTimestamp(this.endDate); 706 } 707 708 /** 709 * Return the start time stamp for analysis. 710 * 711 * @return the XMLGregorianCalendar instance. 712 */ 713 private XMLGregorianCalendar getStartTimestamp() { 714 /* 715 * int days; if ("Month".equals(this.telemetryGranularity)) { days = this.timePhrase * 30; } 716 * else if ("Week".equals(this.telemetryGranularity)) { days = this.timePhrase * 7; } else { 717 * days = this.timePhrase; } return 718 * Tstamp.makeTimestamp(ProjectBrowserBasePage.getDateBefore(days).getTime()); 719 */ 720 return Tstamp.makeTimestamp(this.startDate); 721 } 722 723 /** 724 * @return the inProcess 725 */ 726 public boolean isInProcess() { 727 return inProcess; 728 } 729 730 /** 731 * @return the complete 732 */ 733 public boolean isComplete() { 734 return complete; 735 } 736 737 /** 738 * @return the processingMessage 739 */ 740 public String getProcessingMessage() { 741 return processingMessage; 742 } 743 744 /** 745 * @return the analysesCharts 746 */ 747 public Map<Project, List<MiniBarChart>> getMeasuresCharts() { 748 return measuresCharts; 749 } 750 751 /** 752 * @return the selectedProjects 753 */ 754 public List<Project> getSelectedProjects() { 755 return selectedProjects; 756 } 757 758 /** 759 * Returns true if this model does not contain any data. 760 * 761 * @return True if no data. 762 */ 763 public boolean isEmpty() { 764 return this.selectedProjects.isEmpty(); 765 } 766 767 /** 768 * Return the default parameters of the given measure. 769 * 770 * @param measure the given measure 771 * @return the parameters in a String 772 */ 773 /* 774 * public String getDefaultParametersString(String measure) { List<ParameterDefinition> 775 * paramDefList = getParameterDefinitions(measure); StringBuffer param = new StringBuffer(); for 776 * (int i = 0; i < paramDefList.size(); ++i) { ParameterDefinition paramDef = paramDefList.get(i); 777 * param.append(paramDef.getType().getDefault()); if (i < paramDefList.size() - 1) { 778 * param.append(','); } } return param.toString(); } 779 */ 780 781 /** 782 * @return the measures 783 */ 784 public List<PortfolioMeasureConfiguration> getMeasures() { 785 return measures; 786 } 787 788 /** 789 * @return the enabled measures 790 */ 791 public final List<PortfolioMeasureConfiguration> getEnabledMeasures() { 792 List<PortfolioMeasureConfiguration> enableMeasures = 793 new ArrayList<PortfolioMeasureConfiguration>(); 794 for (PortfolioMeasureConfiguration measure : measures) { 795 if (measure.isEnabled()) { 796 enableMeasures.add(measure); 797 } 798 } 799 return enableMeasures; 800 } 801 802 /** 803 * Return the names of enabled measures. If alias available for the measure, alias will be 804 * returned. Otherwise, name in measure's definition will be returned. 805 * 806 * @return the names of the enabled measures. 807 */ 808 public List<String> getEnabledMeasuresName() { 809 List<String> names = new ArrayList<String>(); 810 for (PortfolioMeasureConfiguration measure : measures) { 811 if (measure.isEnabled()) { 812 names.add(measure.getDisplayName()); 813 } 814 } 815 return names; 816 } 817 818 /** 819 * @param backgroundColor the backgroundColor to set 820 */ 821 /* 822 public void setBackgroundColor(String backgroundColor) { 823 this.backgroundColor = backgroundColor; 824 } 825 */ 826 827 /** 828 * @return the backgroundColor 829 */ 830 public String getBackgroundColor() { 831 return backgroundColor; 832 } 833 834 /** 835 * @return the goodColor 836 */ 837 public String getGoodColor() { 838 return goodColor; 839 } 840 841 /** 842 * @return the sosoColor 843 */ 844 public String getAverageColor() { 845 return averageColor; 846 } 847 848 /** 849 * @return the badColor 850 */ 851 public String getPoorColor() { 852 return poorColor; 853 } 854 855 /** 856 * @return the fontColor 857 */ 858 public String getFontColor() { 859 return fontColor; 860 } 861 862 /** 863 * @return the naColor 864 */ 865 public String getNAColor() { 866 return naColor; 867 } 868 869 /** 870 * @return the userConfiguartionCache 871 */ 872 private UriCache getUserConfiguartionCache() { 873 return new UriCache(userEmail, "portfolio", maxLife, capacity); 874 } 875 876 /** 877 * @return the logger that associated to this web application. 878 */ 879 public static Logger getLogger() { 880 return HackystatLogger.getLogger("org.hackystat.projectbrowser", "projectbrowser"); 881 } 882 883 /** 884 * Sort the table according to the given measure index. 885 * @param i the index of the measure in enabled measures. 886 */ 887 public void sortTable(final int i) { 888 Collections.sort(this.selectedProjects, new Comparator<Project>() { 889 public int compare(Project o1, Project o2) { 890 int result = (int) (measuresCharts.get(o2).get(i).getLatestValue() * 10 - 891 measuresCharts.get(o1).get(i).getLatestValue() * 10); 892 return result; 893 } 894 895 }); 896 } 897 898 /** 899 * Sort the table by the project's name. 900 */ 901 public void sortProjectNames() { 902 Collections.sort(this.selectedProjects, new Comparator<Project>() { 903 public int compare(Project o1, Project o2) { 904 return o1.getName().compareTo(o2.getName()); 905 } 906 907 }); 908 } 909 910 }