/**********************************************************************************
* $URL: https://source.sakaiproject.org/svn/roster/trunk/roster-app/src/java/org/sakaiproject/tool/roster/FilteredParticipantListingBean.java $
* $Id: FilteredParticipantListingBean.java 127576 2013-07-23 12:12:54Z azeckoski@unicon.net $
***********************************************************************************
*
* Copyright (c) 2007, 2008 The Sakai Foundation
*
* Licensed under the Educational Community License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.opensource.org/licenses/ECL-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*
**********************************************************************************/
package org.sakaiproject.tool.roster;
import java.io.Serializable;
import java.text.MessageFormat;
import java.util.ArrayList;
import java.util.Collection;
import java.util.Iterator;
import java.util.List;
import java.util.SortedMap;
import java.util.TreeMap;
import java.util.Map.Entry;
import javax.faces.context.FacesContext;
import javax.faces.event.ActionEvent;
import javax.faces.model.SelectItem;
import org.apache.commons.lang.StringUtils;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.sakaiproject.api.app.roster.Participant;
import org.sakaiproject.exception.IdUnusedException;
import org.sakaiproject.jsf.util.LocaleUtil;
import org.sakaiproject.section.api.coursemanagement.CourseSection;
import org.sakaiproject.site.api.Site;
import org.sakaiproject.user.api.User;
public class FilteredParticipantListingBean implements Serializable {
private static final Log log = LogFactory.getLog(FilteredParticipantListingBean.class);
private static final long serialVersionUID = 1L;
protected ServicesBean services;
public void setServices(ServicesBean services) {
this.services = services;
}
protected SearchFilter searchFilter;
public void setSearchFilter(SearchFilter searchFilter) {
this.searchFilter = searchFilter;
}
protected String defaultSearchText;
protected String sectionFilter;
protected String groupFilter;
// Cache the participants list so we don't have to fetch it twice (once for the list,
// and again for its size)
protected List<Participant> participants;
protected Integer participantCount;
protected SortedMap<String, Integer> roleCounts;
protected boolean displayFilterSingleGroup;
/**
* Initialize this bean once, so we can call our access method as often as we like
* without invoking unnecessary service calls.
*/
public void init() {
this.participants = findParticipants();
this.participantCount = this.participants.size();
this.roleCounts = findRoleCounts(this.participants);
if(defaultSearchText == null) defaultSearchText = LocaleUtil.getLocalizedString(FacesContext.getCurrentInstance(),
ServicesBean.MESSAGE_BUNDLE, "roster_search_text");
if(getSearchFilterString() == null) searchFilter.setSearchFilter(defaultSearchText);
}
/**
* JSF hack to call init() when a filtering page is rendered.
* @return null;
*/
public String getInit() {
init();
return null;
}
// UI Actions
public void search(ActionEvent ae) {
// Nothing needs to be done to search
}
public void clearSearch(ActionEvent ae) {
searchFilter.setSearchFilter(defaultSearchText);
}
protected List<Participant> findParticipants() {
// Only get the participants we need
List<Participant> participants = new ArrayList();
try {
if(sectionFilter != null && isDisplaySectionsFilter()) {
participants = services.rosterManager.getRoster(sectionFilter);
} else {
participants = services.rosterManager.getRoster();
}
}
catch (Exception e) {
log.warn("Exception getting Roster",e);
}
for(Iterator<Participant> iter = participants.iterator(); iter.hasNext();) {
Participant participant = iter.next();
if(filterParticipant(participant)) iter.remove();
}
return participants;
}
/**
* Remove this participant if they don't pass the search filter
*/
protected boolean filterParticipant(Participant participant) {
return getSearchFilterString() != null && ! getSearchFilterString().equals(defaultSearchText) && ! searchMatches(getSearchFilterString(), participant.getUser());
}
protected SortedMap<String, Integer> findRoleCounts(Iterable<Participant> participants) {
SortedMap<String, Integer> roleCountMap = new TreeMap<String, Integer>();
for(Participant participant : participants) {
String role = participant.getRoleTitle();
if (role != null) {
if(roleCountMap.containsKey(role)) {
int count = roleCountMap.get(role) + 1;
roleCountMap.put(role, count);
} else {
roleCountMap.put(role, 1);
}
} else {
String partName = "Unknown";
//This doesn't seem likely either, but just in case!
if (participant.getUser() != null) {
partName = participant.getUser().getDisplayId();
}
log.info("Role null for participant:" + partName);
}
}
return roleCountMap;
}
protected boolean searchMatches(String search, User user) {
return user.getDisplayName().toLowerCase().startsWith(search.toLowerCase()) ||
user.getSortName().toLowerCase().startsWith(search.toLowerCase()) ||
user.getDisplayId().toLowerCase().startsWith(search.toLowerCase()) ||
user.getEmail().toLowerCase().startsWith(search.toLowerCase());
}
public List<SelectItem> getSectionSelectItems() {
List<SelectItem> list = new ArrayList<SelectItem>();
FacesContext facesContext = FacesContext.getCurrentInstance();
String sepLine = LocaleUtil.getLocalizedString(facesContext, ServicesBean.MESSAGE_BUNDLE, "roster_section_sep_line");
String all_sections = LocaleUtil.getLocalizedString(facesContext, ServicesBean.MESSAGE_BUNDLE, "roster_sections_all");
// Add the "all" select option and a separator line
list.add(new SelectItem("", all_sections));
list.add(new SelectItem(sepLine, sepLine));
// Get the available sections
List<CourseSection> sections = requestCache().viewableSections;
for(Iterator<CourseSection> iter = sections.iterator(); iter.hasNext();) {
CourseSection section = iter.next();
list.add(new SelectItem(section.getUuid(), section.getTitle()));
}
return list;
}
public boolean isDisplaySectionsFilter() {
if(!isHideSingleGroupFilter())return true;
return requestCache().viewableSections.size() > 1;
}
/**
* Display section/group dropdown filter when site has only a single group or section defined: true or false
* @return true or false
*/
public boolean isHideSingleGroupFilter() {
if("true".equalsIgnoreCase(services.serverConfigurationService.getString("roster.display.hideSingleGroupFilter")))return true;
return false;
}
public boolean isDisplayPhotoFirstNameLastName(){
if("true".equalsIgnoreCase(services.serverConfigurationService.getString("roster.display.firstNameLastName"))) return true;
return false;
}
public boolean isGroupedBy() {
String groupFilter = StringUtils.trimToNull(getGroupFilter());
if (groupFilter == null)
return false;
boolean grouped = Boolean.valueOf(groupFilter);
return grouped;
}
public String getSearchFilterString() {
return searchFilter.getSearchFilter();
}
public void setSearchFilterString(String searchFilter) {
String trimmedArg = StringUtils.trimToNull(searchFilter);
if(trimmedArg == null) {
this.searchFilter.setSearchFilter(defaultSearchText);
} else {
this.searchFilter.setSearchFilter(trimmedArg);
}
}
public String getSectionFilter() {
return sectionFilter;
}
public String getSectionFilterTitle(){
List<CourseSection> sections = requestCache().viewableSections;
for(Iterator<CourseSection> iter = sections.iterator(); iter.hasNext();) {
CourseSection section = iter.next();
if(section.getUuid().equals(getSectionFilter())) return section.getTitle();
}
return null;
}
public String getCourseFilterTitle(){
try {
Site site = services.siteService.getSite(getSiteContext());
return site.getTitle();
} catch (IdUnusedException ide) {
log.warn("Unable to find site: " + ide);
return "unknown site";
}
}
public void setGroupFilter(String groupFilter) {
// Don't allow this value to be set to the separater line
if(LocaleUtil.getLocalizedString(FacesContext.getCurrentInstance(),
ServicesBean.MESSAGE_BUNDLE, "roster_section_sep_line")
.equals(groupFilter)) {
this.groupFilter = null;
} else {
this.groupFilter = StringUtils.trimToNull(groupFilter);
}
}
public void setSectionFilter(String sectionFilter) {
// Don't allow this value to be set to the separater line
if(LocaleUtil.getLocalizedString(FacesContext.getCurrentInstance(),
ServicesBean.MESSAGE_BUNDLE, "roster_section_sep_line")
.equals(sectionFilter)) {
this.sectionFilter = null;
} else {
this.sectionFilter = StringUtils.trimToNull(sectionFilter);
}
}
public Integer getParticipantCount() {
return participantCount;
}
public List<Participant> getParticipants() {
return participants;
}
public String getRoleCountMessage() {
if(roleCounts.size() == 0) return "";
StringBuilder sb = new StringBuilder();
sb.append("(");
for(Iterator<Entry<String, Integer>> iter = roleCounts.entrySet().iterator(); iter.hasNext();) {
Entry<String, Integer> entry = iter.next();
String[] params = new String[] {entry.getValue().toString(), entry.getKey()};
sb.append(getFormattedMessage("role_breakdown_fragment", params));
if (iter.hasNext()) {
sb.append(", ");
}
}
sb.append(")");
return sb.toString();
}
private String getFormattedMessage(String key, String[] params) {
String rawString = LocaleUtil.getLocalizedString(FacesContext.getCurrentInstance(), ServicesBean.MESSAGE_BUNDLE, key);
MessageFormat format = new MessageFormat(rawString);
return format.format(params);
}
public String getGroupFilter() {
return groupFilter;
}
public List<SelectItem> getGroupSelectItems() {
List<SelectItem> list = new ArrayList<SelectItem>();
FacesContext facesContext = FacesContext.getCurrentInstance();
String ungrouped = LocaleUtil.getLocalizedString(facesContext, ServicesBean.MESSAGE_BUNDLE, "roster_group_ungrouped");
String byGroup = LocaleUtil.getLocalizedString(facesContext, ServicesBean.MESSAGE_BUNDLE, "roster_group_bygroup");
// Add the "all" select option and a separator line
list.add(new SelectItem("false", ungrouped));
list.add(new SelectItem("true", byGroup));
return list;
}
public boolean isDisplayingParticipants() {
// if we have entries in the roleCounts map, we have participants to display
return ! roleCounts.isEmpty();
}
protected String getSiteReference() {
return "/site/" + getSiteContext();
}
protected String getSiteContext() {
return services.toolManager.getCurrentPlacement().getContext();
}
public String getDefaultSearchText() {
return defaultSearchText;
}
// Request scoped caching
// We use these request-scoped beans to hold references to the sections in this site.
// DO NOT cache the RequestCache itself. Always obtain a reference using
// requestCache().
protected RequestCache requestCache() {
RequestCache rc = (RequestCache)resolveManagedBean("requestCache");
// Manually initialize the cache, if necessary
if( ! rc.isInitizlized()) rc.init(services);
return rc;
}
protected StatusRequestCache statusRequestCache() {
StatusRequestCache rc = (StatusRequestCache)resolveManagedBean("statusRequestCache");
// Manually initialize the cache, if necessary
if( ! rc.isInitialized()) rc.init(services);
return rc;
}
// This will either retrieve the existing managed bean, or generate a new one
protected Object resolveManagedBean(String managedBeanId) {
FacesContext facesContext = FacesContext.getCurrentInstance();
return facesContext.getApplication().getVariableResolver().resolveVariable(facesContext, managedBeanId);
}
}