001    package org.hackystat.projectbrowser.page.dailyprojectdata;
002    
003    import java.io.Serializable;
004    import java.text.SimpleDateFormat;
005    import java.util.ArrayList;
006    import java.util.Arrays;
007    import java.util.Date;
008    import java.util.HashMap;
009    import java.util.List;
010    import java.util.Locale;
011    import java.util.Map;
012    import java.util.logging.Logger;
013    
014    import org.apache.wicket.PageParameters;
015    import org.hackystat.projectbrowser.ProjectBrowserSession;
016    import org.hackystat.projectbrowser.page.ProjectBrowserBasePage;
017    import org.hackystat.projectbrowser.page.contextsensitive.ContextSensitiveMenu;
018    import org.hackystat.projectbrowser.page.contextsensitive.ContextSensitivePanel;
019    import org.hackystat.projectbrowser.page.dailyprojectdata.build.BuildDataModel;
020    import org.hackystat.projectbrowser.page.dailyprojectdata.commit.CommitDataModel;
021    import org.hackystat.projectbrowser.page.dailyprojectdata.complexity.ComplexityDataModel;
022    import org.hackystat.projectbrowser.page.dailyprojectdata.coupling.CouplingDataModel;
023    import org.hackystat.projectbrowser.page.dailyprojectdata.coverage.CoverageDataModel;
024    import org.hackystat.projectbrowser.page.dailyprojectdata.devtime.DevTimeDataModel;
025    import org.hackystat.projectbrowser.page.dailyprojectdata.filemetric.FileMetricDataModel;
026    import org.hackystat.projectbrowser.page.dailyprojectdata.issue.IssueDataModel;
027    import org.hackystat.projectbrowser.page.dailyprojectdata.unittest.UnitTestDataModel;
028    import org.hackystat.sensorbase.resource.projects.jaxb.Project;
029    import org.hackystat.utilities.tstamp.Tstamp;
030    
031    /**
032     * Session instance for the daily project data page to hold its state.
033     * @author Philip Johnson
034     * @author Shaoxuan Zhang
035     */
036    public class DailyProjectDataSession implements Serializable {
037    
038      /** Support serialization. */
039      private static final long serialVersionUID = 1L;
040    
041      /** The parameter key of dpd analysis. */
042      public static final String ANALYSIS_KEY = "0";
043      /** The parameter key of date. */
044      public static final String DATE_KEY = "1";
045      /** The parameter key of selectedProjects. */
046      public static final String SELECTED_PROJECTS_KEY = "2";
047      /**
048       * The last parameter key that is required. 
049       */
050      private static final String LAST_REQUIRED_KEY = "2";
051    
052      /** The parameter instruction message. */
053      public static final String PARAMETER_ORDER_MESSAGE = "Correct parameter order is : "
054          + "/<analysis>/<date>/<projects>";
055    
056      /** Error message when parsing page paramters. */
057      private String paramErrorMessage = "";
058      
059      /** The date this user has selected in the ProjectDate form. */
060      private long date = ProjectBrowserBasePage.getDateYesterday().getTime();
061    
062      /** The projects this user has selected. */
063      private List<Project> selectedProjects = new ArrayList<Project>();
064      
065      /** The analysis this user has selected. Defaults to Build. */
066      private String analysis = "Coverage";
067      
068      /** The list of analysis choices. */
069      private static final List<String> analysisList = 
070        Arrays.asList("Build", "Commit", "Coupling", "Coverage", "Complexity", "DevTime", "FileMetric", 
071            "Issue", "UnitTest");
072    
073      /** the feedback string. */
074      private String feedback = "";
075    
076      /** The context sensitive panel.  We keep a pointer to this in the session for Ajax updating. */
077      private ContextSensitivePanel csPanel; 
078      
079      /** Holds the state of the context-sensitive menus in the context sensitive panel. */
080      private Map<String, ContextSensitiveMenu> csMenus = new HashMap<String, ContextSensitiveMenu>();
081      
082      /** The Coverage data model. */
083      private CoverageDataModel coverageDataModel = new CoverageDataModel();
084      
085      /** The Unit Test analysis data model. */
086      private UnitTestDataModel unitTestDataModel = new UnitTestDataModel();
087      
088      /** The coupling data model. */
089      private CouplingDataModel couplingDataModel = new CouplingDataModel();
090    
091      /** The complexity data model. */
092      private ComplexityDataModel complexityDataModel = new ComplexityDataModel();
093    
094      /** The build data model. */
095      private BuildDataModel buildDataModel = new BuildDataModel();
096    
097      /** The DevTime data model. */
098      private DevTimeDataModel devTimeDataModel = new DevTimeDataModel();
099    
100      /** The FileMetric data model. */
101      private FileMetricDataModel fileMetricDataModel = new FileMetricDataModel();
102      
103      /** The Commit data model. */
104      private CommitDataModel commitDataModel = new CommitDataModel();
105    
106      /** The Issue data model. */
107      private IssueDataModel issueDataModel = new IssueDataModel();
108    
109      /**
110       * Initialize this session, including the list of context-sensitive menus.
111       */
112      public DailyProjectDataSession() {
113        // Initialize the context sensitive menus.  
114        // Since the default analysis is Coverage, the Values and Coverage Type menus are visible.
115        csMenus.put("Values", new ContextSensitiveMenu("Values", "Count", 
116            Arrays.asList("Count", "Percentage"), true));
117        csMenus.put("Coverage Type", new ContextSensitiveMenu("Coverage Type", "Method", 
118            Arrays.asList("Block", "Class", "Conditional", "Element", "Line", "Method", "Statement"), 
119            true));
120        csMenus.put("Coupling Type", new ContextSensitiveMenu("Coupling Type", "Afferent+Efferent", 
121            Arrays.asList("Afferent", "Efferent", "Afferent+Efferent"), 
122            false));
123      }
124    
125      /**
126       * Return the associated DPD analysis with the given telemetry.
127       * @param telemetryName the name of the given telemetry
128       * @return the associated DPD, null if not found a match one.
129       */
130      public static String getAssociatedDpdAnalysis(final String telemetryName) {
131        if (telemetryName == null || telemetryName.length() <= 0) {
132          return null;
133        }
134        for (String analysis : analysisList) {
135          if (telemetryName.contains(analysis)) {
136            return analysis;
137          }
138        }
139        return null;
140      }
141      /**
142       * Returns a PageParameters instance that represents the content of the input form.
143       * 
144       * @return a PageParameters instance.
145       */
146      public PageParameters getPageParameters() {
147        PageParameters parameters = new PageParameters();
148    
149        parameters.put(ANALYSIS_KEY, this.getAnalysis());
150        parameters.put(DATE_KEY, ProjectBrowserSession.getFormattedDateString(this.date));
151        parameters.put(SELECTED_PROJECTS_KEY, 
152            ProjectBrowserSession.convertProjectListToString(this.getSelectedProjects()));
153    
154        return parameters;
155      }
156      
157      /**
158       * Load data from URL parameters into this session.
159       * @param parameters the URL parameters
160       * @return true if all parameters are loaded correctly
161       */
162      public boolean loadPageParameters(PageParameters parameters) {
163        boolean isLoadSucceed = true;
164        //boolean isDpdLoaded = false;
165        Logger logger = ProjectBrowserSession.get().getLogger();
166        if (!parameters.containsKey(LAST_REQUIRED_KEY)) {
167          isLoadSucceed = false;
168          String error = "Some parameters are missing, should be " + LAST_REQUIRED_KEY + "\n" +
169              PARAMETER_ORDER_MESSAGE;
170          logger.warning(error);
171          this.paramErrorMessage = error + "\n";
172          return false;
173        }
174        StringBuffer errorMessage = new StringBuffer(1000);
175    
176        // load dpd analysis name
177        if (parameters.containsKey(ANALYSIS_KEY)) {
178          String analysisString = parameters.getString(ANALYSIS_KEY);
179          if (this.getAnalysisList().contains(analysisString)) {
180            this.setAnalysis(analysisString);
181            //isDpdLoaded = true;
182          }
183          else {
184            isLoadSucceed = false;
185            String error = "Analysis from URL parameter is unknown: " + analysisString;
186            logger.warning(error);
187            errorMessage.append(error);
188            errorMessage.append('\n');
189          }
190        }
191        else {
192          isLoadSucceed = false;
193          errorMessage.append("Analysis key is missing in URL parameters.\n");
194        }
195        
196        //load dates
197        if (parameters.containsKey(DATE_KEY)) {
198          String startDateString = parameters.getString(DATE_KEY);
199          try {
200            this.date = Tstamp.makeTimestamp(startDateString).toGregorianCalendar()
201                .getTimeInMillis();
202          }
203          catch (Exception e) {
204            isLoadSucceed = false;
205            String error = "Errors when parsing date from URL parameter: " + startDateString;
206            logger.warning(error + " > " + e.getMessage());
207            errorMessage.append(error);
208            errorMessage.append('\n');
209          }
210        }
211        else {
212          isLoadSucceed = false;
213          errorMessage.append("date key is missing in URL parameters.\n");
214        }
215        
216        //load seletecd project
217        if (parameters.containsKey(SELECTED_PROJECTS_KEY)) {
218          String[] projectsStringArray = 
219            parameters.getString(SELECTED_PROJECTS_KEY).split(
220                ProjectBrowserSession.PARAMETER_VALUE_SEPARATOR);
221          List<Project> projectsList = new ArrayList<Project>();
222          for (String projectString : projectsStringArray) {
223            int index = projectString.lastIndexOf(ProjectBrowserSession.PROJECT_NAME_OWNER_SEPARATR);
224            String projectName = projectString;
225            String projectOwner = null;
226            if (index > 0 && index < projectString.length()) {
227              projectName = projectString.substring(0, index);
228              projectOwner = projectString.substring(
229                  index + ProjectBrowserSession.PROJECT_NAME_OWNER_SEPARATR.length());
230            }
231            Project project = ProjectBrowserSession.get().getProject(projectName, projectOwner);
232            if (project == null) {
233              isLoadSucceed = false;
234              String error = "Error URL parameter: project: " + projectString +
235                  " >> matching project not found under user: " + 
236                  ProjectBrowserSession.get().getEmail();
237              logger.warning(error);
238              errorMessage.append(error);
239              errorMessage.append('\n');
240            }
241            else {
242              projectsList.add(project);
243            }
244          }
245          if (!projectsList.isEmpty()) {
246            this.setSelectedProjects(projectsList);
247          }
248        }
249        else {
250          isLoadSucceed = false;
251          errorMessage.append("projects is missing in URL parameters.\n");
252        }
253        
254        if (errorMessage.length() > 0) {
255          this.paramErrorMessage = errorMessage.append(PARAMETER_ORDER_MESSAGE).toString();
256        }
257        return isLoadSucceed;
258      }
259      
260      /**
261       * Gets the date associated with this page. 
262       * @return The date for this page. 
263       */
264      public Date getDate() {
265        return new Date(this.date);
266      }
267      
268      /**
269       * Sets the date associated with this page. 
270       * @param date The date for this page. 
271       */
272      public void setDate(Date date) {
273        this.date = date.getTime();
274      }
275    
276      /**
277       * Returns the current date in yyyy-MM-dd format.  
278       * @return The date as a simple string. 
279       */
280      public String getDateString() {
281        SimpleDateFormat format = 
282          new SimpleDateFormat(ProjectBrowserBasePage.DATA_FORMAT, Locale.ENGLISH);
283        return format.format(new Date(this.date));
284      }
285      
286      
287      /**
288       * Returns the list of projects selected by the user. 
289       * @return The list of projects selected by the user. 
290       */
291      public List<Project> getSelectedProjects() {
292        return this.selectedProjects;
293      }
294      
295      /**
296       * Sets the set of selected projects.
297       * @param projects The projects.
298       */
299      public void setSelectedProjects(List<Project> projects) {
300        this.selectedProjects = projects;
301      }
302    
303      /**
304       * Sets the selected analysis.
305       * @param analysis The analysis to set.
306       */
307      public void setAnalysis(String analysis) {
308        this.analysis = analysis;
309      }
310    
311      /**
312       * Gets the selected analysis.
313       * @return The analysis.
314       */
315      public String getAnalysis() {
316        return analysis;
317      }
318    
319      /**
320       * Returns the list of possible analyses. 
321       * @return The analysisList.
322       */
323      public List<String> getAnalysisList() {
324        return analysisList;
325      }
326    
327      /**
328       * Sets the feedback string. 
329       * @param feedback The feedback to set.
330       */
331      public void setFeedback(String feedback) {
332        this.feedback = feedback;
333      }
334    
335      /**
336       * Gets the feedback string, and also clears it.
337       * @return The feedback string. 
338       */
339      public String getFeedback() {
340        String returnString = this.feedback;
341        this.feedback = "";
342        return returnString;
343      }
344    
345      /**
346       * Gets all context sensitive menus.
347       * @return The context sensitive menus.
348       */
349      public List<ContextSensitiveMenu> getContextSensitiveMenus() {
350        return new ArrayList<ContextSensitiveMenu>(this.csMenus.values());
351      }
352      
353      /**
354       * Gets the context sensitive menu with the passed name, or null if not found.
355       * @param name The name of the context sensitive menu.
356       * @return The menu instance, or null if not found.
357       */
358      public ContextSensitiveMenu getContextSensitiveMenu(String name) {
359        return this.csMenus.get(name);
360      }
361      
362      /**
363       * Get the context sensitive panel holding the context sensitive menus.
364       * @return The context sensitive panel.
365       */
366      public ContextSensitivePanel getContextSensitivePanel() { 
367        return this.csPanel;
368      }
369      
370      /**
371       * Sets the panel containing the context sensitive menus.
372       * @param panel The panel.
373       */
374      public void setContextSensitivePanel(ContextSensitivePanel panel) {
375        this.csPanel = panel;
376      }
377      
378      /**
379       * Get the Coverage data model. 
380       * @return The Coverage data model associated with this session.
381       */
382      public CoverageDataModel getCoverageDataModel() {
383        return this.coverageDataModel;
384      }
385      
386      /**
387       * Gets the Unit test model associated with this session.
388       * @return The Unit Test model. 
389       */
390      public UnitTestDataModel getUnitTestDataModel() {
391        return this.unitTestDataModel;
392      }
393      
394      
395      /**
396       * Gets the Coupling model associated with this session.
397       * @return The Coupling model. 
398       */
399      public CouplingDataModel getCouplingDataModel() {
400        return this.couplingDataModel;
401      }
402      
403      /**
404       * Gets the Complexity model associated with this session.
405       * @return The Complexity model. 
406       */
407      public ComplexityDataModel getComplexityDataModel() {
408        return this.complexityDataModel;
409      }
410      
411      /**
412       * Gets the Build model associated with this session.
413       * @return The Build model. 
414       */
415      public BuildDataModel getBuildDataModel() {
416        return this.buildDataModel;
417      }
418      
419      /**
420       * Gets the DevTime model associated with this session.
421       * @return The DevTime model. 
422       */
423      public DevTimeDataModel getDevTimeDataModel() {
424        return this.devTimeDataModel;
425      }
426      
427      /**
428       * Gets the FileMetric model associated with this session.
429       * @return The FileMetric model. 
430       */
431      public FileMetricDataModel getFileMetricDataModel() {
432        return this.fileMetricDataModel;
433      }
434      
435      /**
436       * Gets the Commit model associated with this session.
437       * @return The Commit model. 
438       */
439      public CommitDataModel getCommitDataModel() {
440        return this.commitDataModel;
441      }
442    
443      /**
444       * Gets the Issue model associated with this session.
445       * @return The Issue model. 
446       */
447      public IssueDataModel getIssueDataModel() {
448        return this.issueDataModel;
449      }
450      
451      /**
452       * @return the paramErrorMessage
453       */
454      public String getParamErrorMessage() {
455        String temp = this.paramErrorMessage;
456        this.clearParamErrorMessage();
457        return temp;
458      }
459    
460      /**
461       * Clears the paramErrorMessage.
462       */
463      public void clearParamErrorMessage() {
464        this.paramErrorMessage = "";
465      }
466      
467      /**
468       * Sets all analysis data models to their empty state. 
469       */
470      public void clearDataModels() {
471        this.coverageDataModel.clear();
472        this.unitTestDataModel.clear();
473        this.couplingDataModel.clear();
474        this.complexityDataModel.clear();
475        this.buildDataModel.clear();
476        this.devTimeDataModel.clear();
477        this.fileMetricDataModel.clear();
478        this.commitDataModel.clear();
479      }
480    }