001    package org.hackystat.projectbrowser;
002    
003    import java.util.ArrayList;
004    import java.util.Collections;
005    import java.util.Comparator;
006    import java.util.List;
007    import java.util.logging.Logger;
008    
009    import org.apache.wicket.PageParameters;
010    import org.apache.wicket.Request;
011    import org.apache.wicket.Session;
012    import org.apache.wicket.protocol.http.WebSession;
013    import org.hackystat.dailyprojectdata.client.DailyProjectDataClient;
014    import org.hackystat.projectbrowser.page.dailyprojectdata.DailyProjectDataSession;
015    import org.hackystat.projectbrowser.page.projectportfolio.ProjectPortfolioSession;
016    import org.hackystat.projectbrowser.page.projects.ProjectsSession;
017    import org.hackystat.projectbrowser.page.sensordata.SensorDataSession;
018    import org.hackystat.projectbrowser.page.telemetry.TelemetrySession;
019    import org.hackystat.projectbrowser.page.trajectory.TrajectorySession;
020    import org.hackystat.sensorbase.client.SensorBaseClient;
021    import org.hackystat.sensorbase.client.SensorBaseClientException;
022    import org.hackystat.sensorbase.resource.projects.jaxb.Project;
023    import org.hackystat.sensorbase.resource.projects.jaxb.ProjectIndex;
024    import org.hackystat.sensorbase.resource.projects.jaxb.ProjectRef;
025    import org.hackystat.telemetry.service.client.TelemetryClient;
026    import org.hackystat.utilities.logger.HackystatLogger;
027    import org.hackystat.utilities.tstamp.Tstamp;
028    
029    /**
030     * Provides a session instance that holds authentication credentials.
031     * @author Philip Johnson
032     *
033     */
034    public class ProjectBrowserSession extends WebSession {
035      /** Support serialization. */
036      private static final long serialVersionUID = 1L;
037      /** The email used to connect to the SensorBase. */
038      private String email = null;
039      /** The password for the SensorBase. */
040      private String password = null;
041      /** The SensorBase client for this user. */
042      // Need to make this class serializable if we want to keep it in the session and not
043      // make a new one each request. 
044      //private SensorBaseClient client = null; 
045      /** The current signinFeedback message to display. */
046      private String signinFeedback = "";
047      /** The current registerFeedback message to display. */
048      private String registerFeedback = "";
049      /** If this user has been authenticated against the Sensorbase during this session. */
050      private boolean isAuthenticated = false;
051      /** The collection of Projects that this user has. */
052      //private Map<String, Project> projectMap = null;
053      /** The collection of Projects that this user has. */
054      private List<Project> projectList = null;
055      /** The analysis list. */
056      public List<String> analysisList = new ArrayList<String>();
057    
058      /** The separator for parameter values. */
059      public static final String PARAMETER_VALUE_SEPARATOR = ",";
060      /** The separator between project name and its onwer. */
061      public static final String PROJECT_NAME_OWNER_SEPARATR = "::";
062      
063      /** The SensorDataSession that holds page state for SensorData page. */
064      private SensorDataSession sensorDataSession = new SensorDataSession();
065      /** The DailyProjectDataSession that holds page state for DailyProjectData page. */
066      private DailyProjectDataSession dailyProjectDataSession = new DailyProjectDataSession();
067      /** The TelemetrySession that holds page state for Telemetry page. */
068      private TelemetrySession telemetrySession = new TelemetrySession();
069      /** ProjectPortfolioSession that holds page state for Project Portfolio page. */
070      private ProjectPortfolioSession projectPortfolioSession = new ProjectPortfolioSession();
071      /** ProjectBrowserSession that holds the page state for the Project page. */
072      private ProjectsSession projectsSession = new ProjectsSession();
073      /** Trajectory session - holds the page state for the Trajectory page. */
074      private TrajectorySession trajectorySession = new TrajectorySession();
075    
076      
077      /**
078       * Provide a constructor that initializes WebSession.
079       * @param request The request object.
080       */
081      public ProjectBrowserSession(Request request) {
082        super(request);
083        //analysisList.add("Build");
084        analysisList.add("Unit Test");
085        analysisList.add("Coverage");
086        //analysisList.add("Complexity");
087        //analysisList.add("Coupling");
088      }
089    
090      /**
091       * Obtain the current session. 
092       * @return The current ProjectBrowserSession.
093       */
094      public static ProjectBrowserSession get() {
095        return (ProjectBrowserSession) Session.get();
096      }
097      
098      /**
099       * Returns true if the user has been authenticated in this session.
100       * @return True if the user has supplied a valid email and password for this sensorbase.
101       */
102      public boolean isAuthenticated() {
103        return this.isAuthenticated;
104      }
105      
106      /**
107       * Used by the Signin form to provide the SensorBase authentication credentials to this session. 
108       * @param user The user.
109       * @param password The password. 
110       */
111      public void setCredentials(String user, String password) {
112        this.email = user;
113        this.password = password;
114      }
115      
116      /**
117       * Returns the string to be displayed in the SigninFeedback label.
118       * @return A signin feedback string. 
119       */
120      public String getSigninFeedback() {
121        return this.signinFeedback;
122      }
123      
124      /**
125       * Allows other components to set the feedback string for the signin form.
126       * @param signinFeedback The message to be displayed.
127       */
128      public void setSigninFeedback(String signinFeedback) {
129        this.signinFeedback = signinFeedback;
130      }
131      
132      /**
133       * Allows other components to set the feedback string for the register form.
134       * @param registerFeedback The message to be displayed.
135       */
136      public void setRegisterFeedback(String registerFeedback) {
137        this.registerFeedback = registerFeedback;
138      }
139      
140      /**
141       * Returns the string to be displayed in the registerFeedback label.
142       * @return A register feedback string. 
143       */
144      public String getRegisterFeedback() {
145        return this.registerFeedback;
146      }
147      
148      /**
149       * Returns true if this email/password combination is valid for this sensorbase. 
150       * @param email The email. 
151       * @param password The password.
152       * @return True if valid for this sensorbase. 
153       */
154      public boolean signin(String email, String password) {
155        try {
156          String host = ((ProjectBrowserApplication)getApplication()).getSensorBaseHost();
157          int timeout = 1000 * 60 * 60; 
158          //HACK!  This shouldn't be required! I'm doing it because I get a timeout in SensorData
159          // when trying to retrieve Hackystat data summaries for a month. 
160          System.getProperties().setProperty("sensorbaseclient.timeout", String.valueOf(timeout));
161          SensorBaseClient client = new SensorBaseClient(host, email, password);
162          // Set timeout to 60 minutes.
163          client.setTimeout(timeout);
164          client.authenticate();
165          this.email = email;
166          this.password = password;
167          this.isAuthenticated = true;
168          return true;
169        }
170        catch (Exception e) {
171          this.isAuthenticated = false;
172          return false;
173        }
174      }
175      
176      /**
177       * Returns a SensorBaseClient instance for this user and session. 
178       * @return The SensorBaseClient instance. 
179       */
180      public SensorBaseClient getSensorBaseClient() {
181        String host = ((ProjectBrowserApplication)getApplication()).getSensorBaseHost();
182        return new SensorBaseClient(host, this.email, this.password);
183      }
184      
185      /**
186       * Returns a TelemetryClient instance for this user and session.
187       * @return The TelemetryClient instance. 
188       */
189      public TelemetryClient getTelemetryClient() {
190        String host = ((ProjectBrowserApplication)getApplication()).getTelemetryHost();
191        return new TelemetryClient(host, this.email, this.password);
192      }
193      
194      /**
195       * Returns a DailyProjectDataClient instance for this user and session.
196       * @return The DailyProjectDataClient instance. 
197       */
198      public DailyProjectDataClient getDailyProjectDataClient() {
199        String host = ((ProjectBrowserApplication)getApplication()).getDailyProjectDataHost();
200        return new DailyProjectDataClient(host, this.email, this.password);
201      }
202      
203      /**
204       * Gets the user's email associated with this session. 
205       * @return The user.
206       */
207      public String getUserEmail() {
208        return this.email;
209      }
210      
211      /**
212       * Returns the list of project names associated with this user.
213       * @return The list of project names. 
214       */
215      /*
216      public List<String> getProjectNames() {
217        List<String> projectNames = new ArrayList<String>();
218        projectNames.addAll(getProjects().keySet());
219        Collections.sort(projectNames);
220        return projectNames;
221      }
222      */
223      
224      /**
225       * Return a map of project names to project instances associated with this user.  
226       * If the map has not yet been built, get it from the SensorBase and cache it. 
227       * @return The map of Project instances. 
228       */
229      /*
230      public Map<String, Project> getProjects() {
231        if (this.projectMap == null) {
232          this.projectMap = new HashMap<String, Project>();
233          try {
234            SensorBaseClient sensorBaseClient = ProjectBrowserSession.get().getSensorBaseClient();
235            ProjectIndex projectIndex = sensorBaseClient.getProjectIndex(this.email);
236            Set<String> duplicatedProjectNames = new TreeSet<String>();
237            for (ProjectRef projectRef : projectIndex.getProjectRef()) {
238              Project project = sensorBaseClient.getProject(projectRef);
239              Project temp = projectMap.put(project.getName(), project);
240              if (temp != null) {
241                duplicatedProjectNames.add(project.getName());
242                projectMap.put(temp.getName() + " - " + temp.getOwner(), temp);
243                projectMap.put(project.getName() + " - " + project.getOwner(), project);
244              }
245            }
246            for (String duplicatedProjectName : duplicatedProjectNames) {
247              projectMap.remove(duplicatedProjectName);
248            }
249          }
250          catch (SensorBaseClientException e) {
251            Logger logger = ((ProjectBrowserApplication)getApplication()).getLogger();
252            logger.warning("Error getting projects for " + this.email + StackTrace.toString(e));
253          }
254        }
255        return this.projectMap;
256      }
257      */
258    
259      /**
260       * Returns a Project instance that available to current user and 
261       * is matched to the given project name and project owner.
262       * @param projectName the given project name.
263       * @param projectOwner the given project owner.
264       * @return the Project instance. null if no matching project is found,
265       * which may means either the project name or project owner is null or there is no Project for
266       * this user with the same project name and owner as the given ones.
267       */
268      public Project getProject(String projectName, String projectOwner) {
269        if (projectName == null) {
270          return null;
271        }
272        for (Project project : getProjectList()) {
273          if (projectName.equals(project.getName()) && 
274              (projectOwner == null || projectOwner.equals(project.getOwner()))) {
275              return project;
276          }
277        }
278        return null;
279      }
280      
281    
282      /**
283       * Returns a single String represents a list of the projects, separated by comma.
284       * @param projects a list of selected projects.
285       * @return a String.
286       */
287      public static String convertProjectListToString(List<Project> projects) {
288        StringBuffer projectList = new StringBuffer();
289        for (int i = 0; i < projects.size(); ++i) {
290          Project project = projects.get(i);
291          if (project == null) {
292            continue;
293          }
294          projectList.append(project.getName());
295          projectList.append(PROJECT_NAME_OWNER_SEPARATR);
296          projectList.append(project.getOwner());
297          if (i < projects.size() - 1) {
298            projectList.append(PARAMETER_VALUE_SEPARATOR);
299          }
300        }
301        return projectList.toString();
302      }
303    
304      /**
305       * Returns the string that represents the given date in standard formatted.
306       * e.g. 2008-08-08T08:08:08+08:00, 
307       * the +08:00 in the end means the time zone of this time stamp is +08:00
308       * @param date the given date
309       * @return a String
310       */
311      public static String getFormattedDateString(long date) {
312        return Tstamp.makeTimestamp(date).toString();
313      }
314      
315      /**
316       * Return the project associated with the given id.
317       * Id is usually the project name. In case of projects with the same name, the id will become
318       * projectName - projectOwner
319       * @param projectNameId the given id
320       * @return the result project, null if not found.
321       */
322      /*
323      public Project getProjectByNameId(String projectNameId) {
324        return this.projectMap.get(projectNameId);
325      }
326      */
327      
328      /**
329       * Clear project list.
330       */
331      public void clearProjectList() {
332        if (this.projectList != null) {
333          this.projectList.clear();
334        }
335      }
336      
337      /**
338       * Returns the list of Projects associated with this user. 
339       * @return The list of Projects. 
340       */
341      public List<Project> getProjectList() {
342        if (this.projectList == null || this.projectList.size() <= 0) {
343          projectList = new ArrayList<Project>();
344          try {
345            SensorBaseClient sensorBaseClient = ProjectBrowserSession.get().getSensorBaseClient();
346            ProjectIndex projectIndex = sensorBaseClient.getProjectIndex(this.email);
347            for (ProjectRef projectRef : projectIndex.getProjectRef()) {
348              projectList.add(sensorBaseClient.getProject(projectRef));
349            }
350            Collections.sort(projectList, new Comparator<Project>() {
351              public int compare(final Project project1, final Project project2) {
352                int result = project1.getName().compareTo(project2.getName());
353                if (result == 0) {
354                  result = project1.getOwner().compareTo(project2.getOwner());
355                }
356                return result;
357              }
358            });
359          }
360          catch (SensorBaseClientException e) {
361            Logger logger = ((ProjectBrowserApplication)getApplication()).getLogger();
362            logger.warning("Error getting projects for " + this.email + ": " + e.getMessage());
363          }
364        }
365        return projectList;
366      }
367    
368    
369      /**
370       * @return the Default project.
371       */
372      public Project getDefaultProject() {
373        for (Project project : this.getProjectList()) {
374          if ("Default".equals(project.getName())) {
375            return project;
376          }
377        }
378        return null;
379      }
380      
381      /**
382       * Returns the SensorDataSession instance. 
383       * @return The session state for the sensor data page. 
384       */
385      public SensorDataSession getSensorDataSession() {
386        return this.sensorDataSession;
387      }
388    
389      /**
390       * Returns the DailyProjectDataSession instance. 
391       * @return The session state for the daily project data page. 
392       */
393      public DailyProjectDataSession getDailyProjectDataSession() {
394        return this.dailyProjectDataSession;
395      }
396    
397      /**
398       * Returns the TelemetrySession instance. 
399       * @return The session state for the telemetry page. 
400       */
401      public TelemetrySession getTelemetrySession() {
402        return this.telemetrySession;
403      }
404      
405      /**
406       * Returns the ProjectsDataSession instance. 
407       * @return The session state for the projects data page. 
408       */
409      public ProjectsSession getProjectsSession() {
410        return this.projectsSession;
411      }
412      
413      /**
414       * @return the password
415       */
416      public String getPassword() {
417        return password;
418      }
419    
420      /**
421       * @return the email
422       */
423      public String getEmail() {
424        return email;
425      }
426    
427      /**
428       * @return the projectPortfolioSession
429       */
430      public ProjectPortfolioSession getProjectPortfolioSession() {
431        return projectPortfolioSession;
432      }
433      
434      /**
435       * Log the user usage to special file.
436       * @param log the log message
437       */
438      public void logUsage(String log) {
439        if (((ProjectBrowserApplication)getApplication()).isLoggingUserUsage()) {
440          Logger logger = 
441            HackystatLogger.getLogger("org.hackystat.projectbrowser.usage", "projectbrowser");
442          logger.info("[" + email + "]" + " " + log);
443        }
444      }
445      
446      /**
447       * Print the indexed page parameters in format of /parameter0/parameter1/.../.
448       * @param parameters the indexed page parameter
449       * @return the result string.
450       */
451      public String printPageParameters(PageParameters parameters) {
452        StringBuffer paramString = new StringBuffer();
453        int i = 0;
454        boolean end = false;
455        while (!end) {
456          String key = String.valueOf(i);
457          if (parameters.containsKey(key)) {
458            paramString.append('/');
459            paramString.append(parameters.get(key).toString());
460            ++i;
461          }
462          else {
463            end = true;
464          }
465        }
466        return paramString.toString();
467      }
468      
469      /**
470       * @return the logger that associated to this web application.
471       */
472      public Logger getLogger() {
473        return ((ProjectBrowserApplication)ProjectBrowserApplication.get()).getLogger();
474      }
475    
476      /**
477       * Returns the TrajectorySession instance. 
478       * @return The session state for the trajectory page. 
479       */
480      public TrajectorySession getTrajectorySession() {
481        return this.trajectorySession;
482      }
483      }