// $HeadURL$ // $Id$ // // Copyright © 2006, 2010, 2011, 2012 by the President and Fellows of Harvard College. // // Screensaver is an open-source project developed by the ICCB-L and NSRB labs // at Harvard Medical School. This software is distributed under the terms of // the GNU General Public License. package edu.harvard.med.screensaver.ui.arch.view; import java.awt.Color; import java.util.Arrays; import java.util.Iterator; import java.util.Map; import javax.faces.application.Application; import javax.faces.application.FacesMessage; import javax.faces.component.UIComponent; import javax.faces.component.UIViewRoot; import javax.faces.context.ExternalContext; import javax.faces.context.FacesContext; import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse; import javax.servlet.http.HttpSession; import org.apache.log4j.Logger; import org.springframework.mock.web.MockHttpServletRequest; import org.springframework.mock.web.MockHttpServletResponse; import org.springframework.mock.web.MockHttpSession; import com.google.common.collect.Maps; import edu.harvard.med.lincs.screensaver.LincsScreensaverConstants; import edu.harvard.med.screensaver.ScreensaverConstants; import edu.harvard.med.screensaver.ScreensaverProperties; import edu.harvard.med.screensaver.model.users.ScreeningRoomUser; import edu.harvard.med.screensaver.model.users.ScreensaverUser; import edu.harvard.med.screensaver.model.users.ScreensaverUserRole; import edu.harvard.med.screensaver.policy.CurrentScreensaverUser; import edu.harvard.med.screensaver.ui.arch.util.Messages; import edu.harvard.med.screensaver.ui.arch.util.servlet.ScreensaverServletFilter; /** * A base class for JSF backing beans. A backing bean is responsible for * managing UI state via bean properties, providing methods to access the * underlying domain model entities, and providing methods to handle JSF actions * (command invocation) and events. This base class provides a grab bag of * convenience methods for * <ul> * <li>application information (name,version)</li> * <li>accessing servlet session and request state</li> * <li>accessing JSF state (FacesContext) and current view's UI components</li> * <li>reporting application and system errors back to the user</li> * <li>obtaining internationalized, parameterized message strings</li> * <li>accessing the current user and his/her roles and privileges</li> * <li>closing the current HTTP session</li> * </ul> * * @author <a mailto="andrew_tolopko@hms.harvard.edu">Andrew Tolopko</a> * @author <a mailto="john_sullivan@hms.harvard.edu">John Sullivan</a> */ public abstract class AbstractBackingBean implements ScreensaverConstants { private static Logger log = Logger.getLogger(AbstractBackingBean.class); private ScreensaverProperties _applicationProperties; private Messages _messages; private CurrentScreensaverUser _currentScreensaverUser; private Map<String,Boolean> _isPanelCollapsedMap = Maps.newHashMap(); private Boolean _isLINCS; /** * Get the application name (without version number). */ public String getApplicationName() { return _applicationProperties.getProperty(APPLICATION_NAME_PROPERTY); } /** * Get the application version number, as a string. */ public String getApplicationVersion() { return _applicationProperties.getVersion(); } /** * Get the application title as "[Application Name] [Version]". */ public String getApplicationTitle() { return getApplicationName() + " " + getApplicationVersion(); } public Color getScreensaverThemeColor() { return SCREENSAVER_THEME_COLOR; //return _applicationProperties.getProperty(SCREENSAVER_THEME_COLOR_PROPERTY); } public Color getScreensaverThemeHeaderColor() { return HEADER_COLOR; //return _applicationProperties.getProperty(HEADER_COLOR_PROPERTY); } public ScreensaverProperties getApplicationProperties() { return _applicationProperties; } public void setApplicationProperties(ScreensaverProperties applicationProperties) { _applicationProperties = applicationProperties; } /** * Get the group of messages that was injected into this backing bean. * * @return messages the Messages */ public Messages getMessages() { return _messages; } /** * Set the group of messages that can be accessed by this backing bean. * * @param messages the Messages */ public void setMessages(Messages messages) { _messages = messages; } /** * Get whether user can view any data in the current view. * * @return <code>true</code> iff user can view any data in the current view */ public boolean isReadAdmin() { return isUserInRole(ScreensaverUserRole.READ_EVERYTHING_ADMIN); } public boolean isScreener() { return getScreensaverUser() instanceof ScreeningRoomUser; } public boolean isAuthenticatedUser() { boolean isAuthenticatedUser = getScreensaverUser() != null; boolean pendingSessionCloseRequest = Boolean.FALSE.equals(getHttpSession().getAttribute(ScreensaverServletFilter.CLOSE_HTTP_SESSION)); return isAuthenticatedUser && !pendingSessionCloseRequest; } /** * Returns the ScreensaverUser entity representing the user that is logged in * to the current HTTP session. * * @return the ScreensaverUser that is logged in to the current HTTP session */ public ScreensaverUser getScreensaverUser() { return _currentScreensaverUser.getScreensaverUser(); } /** * Set the CurrentScreensaverUser. * * @param currentScreensaverUser */ public void setCurrentScreensaverUser(CurrentScreensaverUser currentScreensaverUser) { _currentScreensaverUser = currentScreensaverUser; } /** * Get the CurrentScreensaverUser. * * @return a CurrentScreensaverUser */ public CurrentScreensaverUser getCurrentScreensaverUser() { return _currentScreensaverUser; } protected FacesContext getFacesContext() { return FacesContext.getCurrentInstance(); } protected Application getApplicationContext() { return getFacesContext() == null ? null : getFacesContext().getApplication(); } protected ExternalContext getExternalContext() { return getFacesContext() == null ? null : getFacesContext().getExternalContext(); } protected Map getRequestMap() { return getExternalContext().getRequestMap(); } protected Map getRequestParameterMap() { return getExternalContext().getRequestParameterMap(); } protected Object getRequestParameter(String parameterName) { return getRequestParameterMap().get(parameterName); } protected HttpSession getHttpSession() { Object httpSession = getExternalContext() == null ? null : getExternalContext().getSession(false); if (httpSession == null) { log.warn("using MockHttpSession"); httpSession = new MockHttpSession(); } assert httpSession instanceof HttpSession : "not running in an HTTP-based application server"; return (HttpSession) httpSession; } protected HttpServletRequest getHttpServletRequest() { Object request = getExternalContext().getRequest(); if (request == null) { log.warn("using MockHttpServletRequest"); request = new MockHttpServletRequest(); } assert request instanceof HttpServletRequest : "not running in an Servlet-based application server"; return (HttpServletRequest) request; } protected HttpServletResponse getHttpServletResponse() { Object response = getExternalContext().getResponse(); if (response == null) { log.warn("using MockHttpServletResponset"); response = new MockHttpServletResponse(); } assert response instanceof HttpServletResponse : "not running in an Servlet-based application server"; return (HttpServletResponse) response; } // // The "JSF way" to get a message (ignores Spring) // public String getMessage(String messageKey) // { // String text = null; // try { // ResourceBundle bundle = // // TODO: parameterize bundle name // ResourceBundle.getBundle("messages", // getFacesContext().getViewRoot().getLocale()); // text = bundle.getString(messageKey); // } catch (Exception e) { // log.error("message key '" + messageKey + "' not found"); // text = "???" + messageKey + "???"; // } // return text; // } public String getMessage(String messageKey, Object... messageArgs) { return _messages.getMessage(messageKey, messageArgs); } /** * Adds the message of the specified key to the component specified by the * localId. (requires a <pre> <h:message for="localId"/></pre> * JSF element in the view) * * @param facesContext * @param localId the "simple" component ID, as specified in the "id" * attribute of its defining JSF tag (not the fully-qualified client * ID expression required by UIComponent.findComponent(), such as * ":formId:subviewId:fieldId"). If the specified component cannot be * found then the messages will be sent to the generalized message * list, see {@link #showMessage(String, Object...)} * @param msgKey the key to the message resource in the * <code>messages</code> bean. * @param msgArgs arguments for the message resource * @return null if the component can not be found * @see Messages */ protected FacesMessage showMessageForLocalComponentId(FacesContext facesContext, String localId, String msgKey, Object... msgArgs) { // UIComponent c = getFacesContext().getViewRoot().findComponent(localID); this didn't work UIComponent component = null; UIViewRoot viewRoot = facesContext.getViewRoot(); component = org.apache.myfaces.custom.util.ComponentUtils.findComponentById(getFacesContext(), viewRoot, localId); if (component != null) { String clientId = component.getClientId(getFacesContext()); return showMessageForComponent(msgKey, clientId, msgArgs); } else { log.warn("Error creating messages: " + msgKey + ": " + Arrays.asList(msgArgs) + ", could not find the component: " + localId); showMessage(msgKey, msgArgs); return null; } } /** * Adds the message of the specified key to the view (requires an h:messages * JSF element in the view). * * @param messageKey the key of the message to be shown * @return the FacesMessage that was set */ protected FacesMessage showMessage(String messageKey) { return showMessage(messageKey, new Object[] {}); } /** * Adds the message of the specified key to the view (requires an h:messages * JSF element in the view). * * @param messageKey the key of the message to be shown * @param messageArgs the args that will be used to parameterize this message * (replacing the "{0}", ..., "{n}" placeholders in the message * string) * @return the FacesMessage that was set */ protected FacesMessage showMessage(String messageKey, Object... messageArgs) { return _messages.setFacesMessageForComponent(messageKey, null, messageArgs); } /** * Adds the message of the specified key to the specified component. Any * request parameters that have a name of the form * "<componentId>MessageParam*" will be used to parameterize the messsage. * * @param messageKey the key of the message to be shown * @param messageArgs the args that will be used to parameterize this message * (replacing the "{0}", ..., "{n}" placeholders in the message * string) * @param componentId the fully-qualified client ID expression required by * UIComponent.findComponent(), such as ":formId:subviewId:fieldId". * To give only the local name, i.e."fieldId", see * {@link #showMessageForLocalComponentId(FacesContext, String, String, Object...)} * @return the FacesMessage that was set */ protected FacesMessage showMessageForComponent(String messageKey, String componentId, Object... messageArgs) { return _messages.setFacesMessageForComponent(messageKey, componentId, messageArgs); } /** * Report the provided application error message to the user. An application * error is one that a developer would not be concerned about, and that * occurred due to so-called "user error". * * @deprecated use {@link #showMessage(String)} instead */ @Deprecated protected void reportApplicationError(String errorMessage) { showMessage("applicationError", errorMessage); } protected void reportApplicationError(String errorMessage, Throwable t) { log.error(errorMessage, t); showMessage("applicationError", errorMessage); } protected void closeHttpSession() { log.debug("requesting close of HTTP session"); getHttpSession().setAttribute(ScreensaverServletFilter.CLOSE_HTTP_SESSION, Boolean.TRUE); } /** * A convenience method for determining if the current user is in a particular * role (with role type safety!) * * @param role * @return true iff the user is in the specified role */ protected boolean isUserInRole(ScreensaverUserRole role) { return getCurrentScreensaverUser().getScreensaverUser() != null && getCurrentScreensaverUser().getScreensaverUser().isUserInRole(role); } private UIComponent doFindComponent(UIComponent container, String componentId) { if (componentId == null) { return null; } if (componentId.equals(container.getId())) { return container; } for (Iterator iter = container.getChildren().iterator(); iter.hasNext();) { UIComponent child = (UIComponent) iter.next(); UIComponent result = doFindComponent(child, componentId); if (result != null) { return result; } } return null; } public Map<String,Boolean> getIsPanelCollapsedMap() { return _isPanelCollapsedMap; } /** * Indicates that the application was built for the LINCS project * see {@link http://lincs.hms.harvard.edu/} and {@link http://lincsproject.org/} * @return true if the project was built for the LINCS project. * @see ScreensaverProperties#getFacilityKey() **/ public boolean isLINCS() { if (_isLINCS == null) { _isLINCS = getApplicationProperties().isFacility(LincsScreensaverConstants.FACILITY_KEY); } return _isLINCS; } }