// See a filterable list of all projects
 @RequestMapping(value = "viewprojects", method = RequestMethod.GET)
 public ModelAndView viewprojects(String query) throws Exception {
   ModelAndView mav = new ModelAndView();
   List<Project> ps = projectDao.getProjects();
   List<Project> filtered = new LinkedList<Project>();
   String q = null;
   if (query != null && !query.equals("")) q = query.toLowerCase();
   // mark projects as due if a review or follow-up is due
   Date now = new Date();
   DateFormat df = new SimpleDateFormat("yyyy-MM-dd");
   for (Project p : ps) {
     String nextFollowUpDate = p.getNextFollowUpDate().trim();
     String nextReviewDate = p.getNextReviewDate().trim();
     if (!nextFollowUpDate.equals("") && now.after(df.parse(p.getNextFollowUpDate()))) {
       p.setNextFollowUpDate(p.getNextFollowUpDate() + " (due)");
     }
     if (!nextReviewDate.equals("") && now.after(df.parse(p.getNextReviewDate()))) {
       p.setNextReviewDate(p.getNextReviewDate() + " (due)");
     }
     if (q != null) {
       if (p.getName().toLowerCase().contains(q)
           || p.getDescription().toLowerCase().contains(q)
           || p.getHostInstitution().toLowerCase().contains(q)
           || p.getNotes().toLowerCase().contains(q)
           || p.getProjectCode().toLowerCase().contains(q)
           || p.getProjectTypeName().toLowerCase().contains(q)
           || p.getRequirements().toLowerCase().contains(q)
           || p.getTodo() != null && p.getTodo().toLowerCase().contains(q)) filtered.add(p);
     }
   }
   if (q == null) {
     mav.addObject("projects", ps);
   } else {
     mav.addObject("projects", filtered);
     mav.addObject("query", q);
   }
   return mav;
 }