/********************************************************************************** * $URL: https://source.sakaiproject.org/svn/portal/trunk/portal-util/util/src/java/org/sakaiproject/portal/util/PortalSiteHelper.java $ * $Id: PortalSiteHelper.java 21708 2007-02-18 21:59:28Z ian@caret.cam.ac.uk $ *********************************************************************************** * * 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.chat2.tool; import java.io.IOException; import java.text.DateFormat; import java.text.MessageFormat; import java.text.SimpleDateFormat; import java.util.ArrayList; import java.util.Calendar; import java.util.Date; import java.util.HashMap; import java.util.Iterator; import java.util.List; import java.util.Map; import java.util.Map.Entry; import java.util.concurrent.ConcurrentHashMap; import javax.faces.application.FacesMessage; import javax.faces.component.UIComponent; import javax.faces.context.ExternalContext; import javax.faces.context.FacesContext; import javax.faces.model.SelectItem; import javax.faces.validator.ValidatorException; import javax.servlet.http.HttpServletRequest; import org.apache.commons.lang.time.DateUtils; import org.apache.commons.logging.Log; import org.apache.commons.logging.LogFactory; import org.sakaiproject.authz.api.PermissionsHelper; import org.sakaiproject.chat2.model.ChatMessage; import org.sakaiproject.chat2.model.ChatChannel; import org.sakaiproject.chat2.model.ChatManager; import org.sakaiproject.chat2.model.RoomObserver; import org.sakaiproject.chat2.model.ChatFunctions; import org.sakaiproject.chat2.model.PresenceObserver; import org.sakaiproject.chat2.tool.ColorMapper; import org.sakaiproject.component.cover.ServerConfigurationService; import org.sakaiproject.component.cover.ComponentManager; import org.sakaiproject.event.api.EventTrackingService; import org.sakaiproject.courier.api.CourierService; import org.sakaiproject.event.api.UsageSession; import org.sakaiproject.event.cover.UsageSessionService; import org.sakaiproject.exception.IdUnusedException; import org.sakaiproject.exception.PermissionException; import org.sakaiproject.site.api.Site; import org.sakaiproject.site.cover.SiteService; import org.sakaiproject.tool.api.Placement; import org.sakaiproject.tool.api.Session; import org.sakaiproject.tool.api.Tool; import org.sakaiproject.tool.api.ToolManager; import org.sakaiproject.tool.api.ToolSession; import org.sakaiproject.tool.cover.SessionManager; import org.sakaiproject.user.api.User; import org.sakaiproject.user.api.UserNotDefinedException; import org.sakaiproject.user.cover.UserDirectoryService; import org.sakaiproject.util.DirectRefreshDelivery; import org.sakaiproject.util.ResourceLoader; import org.sakaiproject.util.Validator; import org.sakaiproject.util.Web; /** * * This class is used in two ways: * 1) It is a JSF backing bean, with session scope. A new one is created * every time the user enters the main chat tool. This includes a refresh. * 2) It is an observer. It is put on a list of observers for the room * by AddRoomListener. * This double existence is messy, because JSF manages beans, but * if JSF replaces or finishes the bean, there is no automatic way for * it to get removed from the list of observers. * Getting it off the list of observers is kind of tricky, because * there's no direct way to know when the instance is no longer valid. * Since a refresh generates a new instance, we have to get rid of the * old one, or the list of observers keeps growing. The hash table * "tools" is used to keep track of instances so we can kill old ones. * This code was originally written when there was at most one chat * room per site. For that it made sense for the backing bean to have * session scope (because going to a new site goes through the main * entry and generates a new instance). We really need to redo this with * the bean at request scope and other data structures for things that * live longer. But I found out about this issue a week before 2.6 was * due. So I've adopted a hack. The bean is now in theory session scope * but actually may be shared by more than one chat room in a site. * It should never cross sites. That means there are now a couple of * data structures indexed by room ID, to handle more than one room. * The JSP's all set the current room ID when doing a submit. So * that lets them share the single backing bean. * The other way an instance can become invalid is if the session * goes away. So in userLeft and a couple of other places we check * we check whether the current session is * still alive, and if not, remove the instance. * This bookkeeping is done in SetCurrentChannel and * ResetCurrentChannel, so they should be the only code to call * AddRoomListener and RemoveRoomListener. * For final cleanup we depend upon the fact that all observers will * eventually get either UserLeft or ReceivedMessage, and the code will * notice that the session no longer exists. At times UserLeft seems to be * called when the session is still there, but when the next user logs out, * it will get called again with no session. * * Chat works by the courier but not the same way as the old message delivery * system. The courier sends messages into the JSF tool. When the user dials home * it then picks up the messages. * * COOL TECHNOLOGY ALERT: * TODO: The page that sends the messages is polled, the tool can wait on the * connection until it recieves a message to send or until it times out. This * would provide instant messaging as opposed to polling. * * When entering the tool the first main page calls the enterTool function which * redirects the users based upon the tool's preferences: go to select a room or * to a specific tool. NB: each time enterTool is called, we are dealing * with a new instance. * * The PresenceObserverHelper is placed on the current room. This this tool is informed * when a user enters and exits the room. * * * @author andersjb * */ public class ChatTool implements RoomObserver, PresenceObserver { /** Our logger. */ private static Log logger = LogFactory.getLog(ChatTool.class); /* */ private static final String IFRAME_ROOM_USERS = "Presence"; /* various pages that we can go to within the tool */ private static final String PAGE_EDIT_A_ROOM = "editRoom"; private static final String PAGE_LIST_ROOMS = "listRooms"; private static final String PAGE_ENTER_ROOM = "room"; private static final String PAGE_EDIT_ROOM = "editRoom"; private static final String PAGE_DELETE_ROOM_CONFIRM = "deleteRoomConfirm"; private static final String PAGE_DELETE_ROOM_MESSAGES_CONFIRM = "deleteRoomMessagesConfirm"; private static final String PAGE_DELETE_MESSAGE_CONFIRM = "deleteMessageConfirm"; private static final String PAGE_SYNOPTIC = "synoptic"; private static final String PAGE_SYNOPTIC_OPTIONS = "synopticOptions"; private static final String PERMISSION_ERROR = "perm_error"; private static final String PRESENCE_PREPEND = "chat_room_"; private static final String CHAT_CONTEXT_PRESENCE_PREFIX = "chat_site_"; private static final int MESSAGEOPTIONS_NULL = -99; private static final int MESSAGEOPTIONS_ALL_MESSAGES = -1; private static final int MESSAGEOPTIONS_MESSAGES_BY_DATE = 0; private static final int MESSAGEOPTIONS_MESSAGES_BY_NUMBER = 1; private static final int MESSAGEOPTIONS_NO_MESSAGES = 2; private static final int DATETIME_DISPLAY_NONE = 0x00; private static final int DATETIME_DISPLAY_TIME = 0x01; private static final int DATETIME_DISPLAY_DATE = 0x02; private static final int DATETIME_DISPLAY_DATETIME = 0x03; private static final int DATETIME_DISPLAY_ID = 0x04; private static final String PARAM_CHANNEL = "channel"; private static final String PARAM_DAYS = "days"; private static final String PARAM_ITEMS = "items"; private static final String PARAM_LENGTH = "length"; private static final int DEFAULT_DAYS = 10; private static final int DEFAULT_ITEMS = 3; private static final int DEFAULT_LENGTH = 50; /* All the managers */ /** The work-horse of chat */ private ChatManager chatManager; /** The tool manager */ private ToolManager toolManager; /** Constructor discovered injected CourierService. */ protected CourierService m_courierService = null; /* All the private variables */ /** The current channel the user is in */ private DecoratedChatChannel currentChannel = null; /** The current channel the user is editing */ private DecoratedChatChannel currentChannelEdit = null; /** The current message the user is deleting */ private DecoratedChatMessage currentMessage = null; private DecoratedSynopticOptions currentSynopticOptions = null; /** The location where the new message text goes */ private String newMessageText = ""; /** display the time (1), date(2), both(3), neither(0), or uniqueid(4) */ private int viewOptions = DATETIME_DISPLAY_DATETIME; /** display all messages (-1), past 3 days (0) */ private int messageOptions = MESSAGEOPTIONS_NULL; /** The id of the session. needed for adding messages to the courier because that runs in the notification thread */ private String sessionId = ""; /** The id of the placement of this sakai tool. the jsf tool bean needs this for passing to the delivery */ private String placementId = ""; /** Mapping the color of each message */ private ColorMapper colorMapper = new ColorMapper(); /** the worksite the tool is in */ private Site worksite = null; private String toolContext = null; /* room id maps */ private Map<String,PresenceObserverHelper> presenceChannelObservers = new ConcurrentHashMap<String,PresenceObserverHelper>(); private Map<String,DecoratedChatChannel> channels = new ConcurrentHashMap<String,DecoratedChatChannel>(); /* address maps */ private static Map<String,ChatTool> tools = new ConcurrentHashMap<String,ChatTool>(); protected void setupTool() { // "inject" a CourierService m_courierService = org.sakaiproject.courier.cover.CourierService.getInstance(); Session session = SessionManager.getCurrentSession(); sessionId = session.getId(); Placement placement = getToolManager().getCurrentPlacement(); placementId = placement.getId(); // Really only calling this just to make sure a room gets created getSiteChannels(); ChatChannel defaultChannel = getChatManager().getDefaultChannel(placement.getContext(), placement.getId()); setCurrentChannel(new DecoratedChatChannel(this, defaultChannel)); return; } /** * This is called from the first page to redirect the user to the proper view. * This is the first call after JSF creates a new instance, so initialization is * done here. * If the tool is set to go to the select a chat room view and there are multiple chat * rooms, then it will go to the select a room page. If the user is to select a room and * there is only one room, then it will go to that room. * * @return String */ public String getEnterTool() { setupTool(); // if there is no room selected to enter then go to select a room String url = PAGE_ENTER_ROOM; if(currentChannel == null) url = PAGE_LIST_ROOMS; ExternalContext context = FacesContext.getCurrentInstance().getExternalContext(); HttpServletRequest req = (HttpServletRequest) context.getRequest(); req.setAttribute(Tool.NATIVE_URL, null); //signal to WrappedRequest that we want the Sakai managed setToolContext(req.getContextPath()); req.setAttribute(Tool.NATIVE_URL, Tool.NATIVE_URL); try { context.redirect(url); } catch (IOException e) { throw new RuntimeException("Failed to redirect to " + url, e); } return ""; } /** * this gets the users in a channel. It is typically called from roomUsers.jsp * to display or refresh the list. Despite the name, if called from a JSP with * channel as an argument, it uses that channel. Otherwise the current channel. * * @return List of String display names */ public List<String> getUsersInCurrentChannel() { ExternalContext context = FacesContext.getCurrentInstance().getExternalContext(); HttpServletRequest req = (HttpServletRequest) context.getRequest(); // normally this comes from roomUsers.jsp, which has the channel as an argument // no need to validate input as weird input simply results in a failure String channelId = req.getParameter("channel"); if (channelId == null) channelId = getCurrentChatChannelId(); List<String> userList = new ArrayList<String>(); if (channelId == null) return userList; PresenceObserverHelper observer = presenceChannelObservers.get(channelId); if(observer == null) return userList; observer.updatePresence(); // get the current presence list (User objects) for this page List<User> users = observer.getPresentUsers(); if (users == null) return userList; //System.out.println("userincurrent channel: " + getCurrentChatChannelId() + " users " + users); // is the current user running under an assumed (SU) user id? String asName = null; String myUserId = null; try { UsageSession usageSession = UsageSessionService.getSession(); if (usageSession != null) { // this is the absolutely real end-user id, even if running as another user myUserId = usageSession.getUserId(); // this is the user id the current user is running as String sessionUserId = SessionManager.getCurrentSessionUserId(); // if different if (!myUserId.equals(sessionUserId)) { asName = UserDirectoryService.getUser(sessionUserId).getDisplayName(); } } } catch (Throwable any) { } for (Iterator<User> i = users.iterator(); i.hasNext();) { User u = (User) i.next(); String displayName = u.getDisplayName(); // adjust if this is the current user running as someone else if ((asName != null) && (u.getId().equals(myUserId))) { displayName += " (" + asName + ")"; } userList.add(Web.escapeHtml(displayName)); } //System.out.println("userincurrent channel return: " + userList); return userList; } //******************************************************************** // Interface Implementations /** * {@inheritDoc} * in the context of the event manager thread */ public void receivedMessage(String roomId, Object message) { DecoratedChatChannel channel = channels.get(roomId); // System.out.println("receivedmessager " + sessionId + " " + roomId + " " + channel + " " + SessionManager.getSession(sessionId)); if (channel != null) { String address = sessionId + roomId; if (SessionManager.getSession(sessionId) == null) { // System.out.println("expire session " + sessionId + " " + currentChannel); logger.debug("received msg expired session " + sessionId + " " + currentChannel); resetCurrentChannel(channel); m_courierService.clear(address); } else { m_courierService.deliver(new ChatDelivery(address, "Monitor", message, placementId, false, getChatManager())); } } } /** * {@inheritDoc} */ public void roomDeleted(String roomId) { DecoratedChatChannel channel = channels.get(roomId); if (channel != null) { resetCurrentChannel(channel); m_courierService.clear(sessionId+roomId); } } /** * {@inheritDoc} */ public void userJoined(String location, String user) { m_courierService.deliver(new DirectRefreshDelivery(sessionId+location, IFRAME_ROOM_USERS)); } /** * {@inheritDoc} * In addition to refreshing the list, this code takes care of * removing instances associated with processes that are now dead. * Despite the user argument, the API doesn't tell us what user * left. So the best we can do is check ourself, and rely on the * fact that this will be called once for each user who has an * observer in the room observer list, so the user who left * should catch himself. */ // new impl that counts the number of system in the location public void userLeft(String location, String user) { DecoratedChatChannel channel = channels.get(location); // System.out.println("userLeft " + sessionId + " " + location + " " + channel + " " + SessionManager.getSession(sessionId)); if (channel != null && SessionManager.getSession(sessionId) == null) { // System.out.println("expire session " + sessionId + " " + currentChannel); resetCurrentChannel(channel); m_courierService.clear(sessionId+location); } else m_courierService.deliver(new DirectRefreshDelivery(sessionId+location, IFRAME_ROOM_USERS)); } //******************************************************************** // Tool Process Actions /** * resets various variables for the tool */ private void clearToolVars() { } /** * Make sure that the channel has a title when saving, the title isn't * too long, and the description isn't too long * @param channel * @return Returns if the channel validates */ protected boolean validateChannel(ChatChannel channel) { boolean validates = true; if (channel.getTitle() == null || channel.getTitle().length() == 0) { setErrorMessage("editRoomForm:title", "title_required", new String[] {}); validates = false; } if (channel.getTitle() != null && channel.getTitle().length() > 64) { setErrorMessage("editRoomForm:title", "title_too_long", new String[] {Integer.toString(64)}); validates = false; } if (channel.getDescription() != null && channel.getDescription().length() > 255) { setErrorMessage("editRoomForm:desc", "desc_too_long", new String[] {Integer.toString(255)}); validates = false; } if (logger.isDebugEnabled()) logger.debug("chat start ("+channel.getStartDate()+") and end ("+channel.getEndDate()+") dates"); // validate the dates if (channel.getStartDate() != null && channel.getEndDate() != null) { // check the dates are valid if (channel.getStartDate().after(channel.getEndDate())) { setErrorMessage("editRoomForm:startDate", "custom_date_error_order", new Object[] {channel.getStartDate(), channel.getEndDate()}); validates = false; } } if (!validates) setErrorMessage("validation_error", new String[] {}); return validates; } /** * When the user wants to cancel changing a room * @return String next page */ public String processActionCancelChangeChannel() { clearToolVars(); return PAGE_ENTER_ROOM; } public String processActionSetAsDefaultRoom(DecoratedChatChannel decoChannel) { ChatChannel channel = decoChannel.getChatChannel(); channel.setPlacementDefaultChannel(true); getChatManager().makeDefaultContextChannel(channel, getToolManager().getCurrentPlacement().getId()); return PAGE_LIST_ROOMS; } public String processActionAddRoom() { try { ChatChannel newChannel = getChatManager().createNewChannel(getContext(), "", false, true, getToolManager().getCurrentPlacement().getId()); currentChannelEdit = new DecoratedChatChannel(this, newChannel, true); //init the filter param if (currentChannelEdit.getChatChannel().getFilterType().equals(ChatChannel.FILTER_ALL) || currentChannelEdit.getChatChannel().getFilterType().equals(ChatChannel.FILTER_BY_NUMBER) || currentChannelEdit.getChatChannel().getFilterType().equals(ChatChannel.FILTER_BY_TIME) || currentChannelEdit.getChatChannel().getFilterType().equals(ChatChannel.FILTER_NONE)) { currentChannelEdit.setFilterParamLast(currentChannelEdit.getChatChannel().getNumberParam()); currentChannelEdit.setFilterParamPast(currentChannelEdit.getChatChannel().getTimeParam()); currentChannelEdit.setFilterParamNone(0); } return PAGE_EDIT_A_ROOM; } catch (PermissionException e) { setErrorMessage(PERMISSION_ERROR, new String[] {ChatFunctions.CHAT_FUNCTION_NEW_CHANNEL}); return ""; } } @SuppressWarnings("unchecked") public String processActionPermissions() { ExternalContext context = FacesContext.getCurrentInstance().getExternalContext(); ToolSession toolSession = SessionManager.getCurrentToolSession(); try { String url = "sakai.permissions.helper.helper/tool?" + "session." + PermissionsHelper.DESCRIPTION + "=" + org.sakaiproject.util.Web.escapeUrl(getPermissionsMessage()) + "&session." + PermissionsHelper.TARGET_REF + "=" + getWorksite().getReference() + "&session." + PermissionsHelper.PREFIX + "=" + getChatFunctionPrefix(); // Set permission descriptions if (toolSession != null) { ResourceLoader pRb = new ResourceLoader("permissions"); HashMap<String, String> pRbValues = new HashMap<String, String>(); for (Iterator<Entry<String, String>> mapIter = pRb.entrySet().iterator();mapIter.hasNext();) { Entry<String, String> entry = mapIter.next(); pRbValues.put(entry.getKey(), entry.getValue()); } toolSession.setAttribute("permissionDescriptions", pRbValues); } // Invoke Permissions helper context.redirect(url); } catch (IOException e) { throw new RuntimeException("Failed to redirect to helper", e); } return null; } public String processActionSynopticOptions() { DecoratedSynopticOptions dso = lookupSynopticOptions(); setCurrentSynopticOptions(dso); return PAGE_SYNOPTIC_OPTIONS; } public String processActionSynopticOptionsSave() { DecoratedSynopticOptions dso = getCurrentSynopticOptions(); Placement placement = getToolManager().getCurrentPlacement(); if (placement != null) { //placement.getPlacementConfig().setProperty(PARAM_CHANNEL, (String) state.getAttribute(STATE_CHANNEL_REF)); placement.getPlacementConfig().setProperty(PARAM_DAYS, Integer.toString(dso.getDays())); placement.getPlacementConfig().setProperty(PARAM_ITEMS, Integer.toString(dso.getItems())); placement.getPlacementConfig().setProperty(PARAM_LENGTH, Integer.toString(dso.getChars())); placement.save(); } setCurrentSynopticOptions(null); return PAGE_SYNOPTIC; } public String processActionSynopticOptionsCancel() { setCurrentSynopticOptions(null); return PAGE_SYNOPTIC; } public String processActionBackToRoom() { DecoratedChatChannel dChannel = getCurrentChannel(); String filter = dChannel != null ? dChannel.getChatChannel().getFilterType() : ""; if(filter.equals(ChatChannel.FILTER_ALL)){ setMessageOptions(Integer.toString(MESSAGEOPTIONS_ALL_MESSAGES)); }else if(filter.equals(ChatChannel.FILTER_BY_NUMBER)){ setMessageOptions(Integer.toString(MESSAGEOPTIONS_MESSAGES_BY_NUMBER)); }else if(filter.equals(ChatChannel.FILTER_BY_TIME)){ setMessageOptions(Integer.toString(MESSAGEOPTIONS_MESSAGES_BY_DATE)); }else if(filter.equals(ChatChannel.FILTER_NONE)){ setMessageOptions(Integer.toString(MESSAGEOPTIONS_NO_MESSAGES)); } return PAGE_ENTER_ROOM; } public String getChatFunctionPrefix() { return ChatFunctions.CHAT_FUNCTION_PREFIX; } public String getPermissionsMessage() { return getMessageFromBundle("perm_description", new Object[]{ getToolManager().getCurrentTool().getTitle(), getWorksite().getTitle()}); } /** * @return the translated message based on the current date settings for this channel */ public String getDatesMessage() { String msg = null; if (this.currentChannel != null) { DateFormat df = DateFormat.getDateInstance(DateFormat.MEDIUM); if (this.currentChannel.getStartDate() != null && this.currentChannel.getEndDate() != null) { msg = getMessageFromBundle("custom_date_display", new Object[] {df.format(this.currentChannel.getStartDate()), df.format(this.currentChannel.getEndDate())} ); } else if (this.currentChannel.getStartDate() != null) { msg = getMessageFromBundle("custom_date_display_start", new Object[] {df.format(this.currentChannel.getStartDate()), ""} ); } else if (this.currentChannel.getEndDate() != null) { msg = getMessageFromBundle("custom_date_display_end", new Object[] {"", df.format(this.currentChannel.getEndDate())} ); } } return msg; } /** * @return true if chat posting is restricted by configured dates or false otherwise */ public boolean isDatesRestricted() { boolean restricted = false; if (this.currentChannel != null) { Date today = new Date(); Date start = this.currentChannel.getStartDate(); if (start == null) { start = today; } Date end = this.currentChannel.getEndDate(); if (end == null) { end = today; } if ( today.before(start) || today.after(end) ) { // today is outside the configured dates so posting restricted by dates restricted = true; } } return restricted; } public Site getWorksite() { if (worksite == null) { try { worksite = SiteService.getSite(getToolManager().getCurrentPlacement().getContext()); } catch (IdUnusedException e) { throw new RuntimeException(e); } } return worksite; } //******************************************************************** // Channel Process Actions /** * Sets the current room and goes to the room page * @param chatChannel * @return String selects a new room to go into */ protected String processActionEnterRoom(DecoratedChatChannel chatChannel) { setCurrentChannel(chatChannel); setMessageOptions(Integer.toString(MESSAGEOPTIONS_NULL)); return PAGE_ENTER_ROOM; } public String processActionListRooms() { return PAGE_LIST_ROOMS; } /** * Sets the current room and goes to edit that room * @param chatChannel * @return String goes to the edit room view */ protected String processActionEditRoom(DecoratedChatChannel chatChannel) { //Init the filter param here chatChannel.setFilterParamNone(0); chatChannel.setFilterParamLast(chatChannel.getChatChannel().getNumberParam()); chatChannel.setFilterParamPast(chatChannel.getChatChannel().getTimeParam()); setCurrentChannelEdit(chatChannel); return PAGE_EDIT_ROOM; } /** * Sets the current room to null * @return String goes to the edit room view */ public String processActionEditRoomSave() { //Set the filter param here DecoratedChatChannel dChannel = getCurrentChannelEdit(); if (dChannel != null) { ChatChannel channel = dChannel.getChatChannel(); boolean directEdit = dChannel.isDirectEdit(); //set default number and time values based on the decordatedChannel class channel.setNumberParam(dChannel.getFilterParamLast()); channel.setTimeParam(dChannel.getFilterParamPast()); if (channel.getFilterType().equals(ChatChannel.FILTER_BY_NUMBER)) { int pLast = dChannel.getFilterParamLast(); if (pLast > 9999) { pLast = 9999; } else if (pLast <= 0) { pLast = 10; } channel.setFilterParam(pLast); } else if (channel.getFilterType().equals(ChatChannel.FILTER_BY_TIME)) { int pPast = dChannel.getFilterParamPast(); if (pPast > 999) { pPast = 999; } else if (pPast <= 0) { pPast = 1; } channel.setFilterParam(pPast); } else if (channel.getFilterType().equals(ChatChannel.FILTER_NONE)) { channel.setFilterParam(0); } String retView = PAGE_LIST_ROOMS; if (directEdit) retView = PAGE_ENTER_ROOM; else retView = PAGE_LIST_ROOMS; // copy the dates into the channel for saving channel.setStartDate(dChannel.getStartDate()); channel.setEndDate(dChannel.getEndDate()); if (validateChannel(channel)) try { getChatManager().updateChannel(channel, true); if (dChannel != null && dChannel.getChatChannel().getId().equals(channel.getId())) { setCurrentChannel(new DecoratedChatChannel(this, channel)); } setCurrentChannelEdit(null); } catch (PermissionException e) { setErrorMessage(PERMISSION_ERROR, new String[] {ChatFunctions.CHAT_FUNCTION_EDIT_CHANNEL}); return ""; } else { //Message should get set in the validateChannel method //setErrorMessage(VALIDATION_ERROR, new String[] {ChatFunctions.CHAT_FUNCTION_DELETE_PREFIX}); retView = ""; } return retView; } else { return ""; } } /** * Sets the current room to null * @return String goes to the edit room view */ public String processActionEditRoomCancel() { DecoratedChatChannel dChannel = getCurrentChannelEdit(); boolean directEdit = dChannel != null ? dChannel.isDirectEdit() : false; setCurrentChannelEdit(null); if (directEdit) return PAGE_ENTER_ROOM; else return PAGE_LIST_ROOMS; } /** * Sets the current room and goes to confirm deleting the room * @param chatChannel * @return String goes to the delete room confirmation page */ protected String processActionDeleteRoomConfirm(DecoratedChatChannel chatChannel) { setCurrentChannelEdit(chatChannel); return PAGE_DELETE_ROOM_CONFIRM; } /** * deletes the current room and all it's messages * @return String goes to the select a room page */ public String processActionDeleteRoom() { try { getChatManager().deleteChannel(currentChannelEdit.getChatChannel()); setCurrentChannelEdit(null); return PAGE_LIST_ROOMS; } catch (PermissionException e) { setErrorMessage(PERMISSION_ERROR, new String[] {ChatFunctions.CHAT_FUNCTION_DELETE_CHANNEL}); return ""; } } /** * cancels the deletion of a room via the confirmation * @return String goes to the select a room page */ public String processActionDeleteRoomCancel() { setCurrentChannelEdit(null); return PAGE_LIST_ROOMS; } // ************* /** * Sets the current room and goes to confirm deleting the room's messages * @param chatChannel * @return String goes to the delete room messages confirmation page */ protected String processActionDeleteRoomMessagesConfirm(DecoratedChatChannel chatChannel) { setCurrentChannelEdit(chatChannel); return PAGE_DELETE_ROOM_MESSAGES_CONFIRM; } /** * deletes the current room's messages * @return String goes to the select a room page */ public String processActionDeleteRoomMessages() { try { getChatManager().deleteChannelMessages(currentChannelEdit.getChatChannel()); setCurrentChannelEdit(null); return PAGE_LIST_ROOMS; } catch (PermissionException e) { setErrorMessage(PERMISSION_ERROR, new String[] {ChatFunctions.CHAT_FUNCTION_DELETE_ANY}); return ""; } } /** * cancels the deletion of a room's messages via the confirmation * @return String goes to the select a room page */ public String processActionDeleteRoomMessagesCancel() { setCurrentChannelEdit(null); return PAGE_LIST_ROOMS; } // ******************************************************************** // Message Process Actions /** * Deletes the current message * @return String goes to the room's main page */ public String processActionDeleteMessage() { try { DecoratedChatMessage msg = getCurrentMessage(); if (msg != null) getChatManager().deleteMessage(msg.getChatMessage()); return PAGE_ENTER_ROOM; } catch (PermissionException e) { setErrorMessage(PERMISSION_ERROR, new String[] {ChatFunctions.CHAT_FUNCTION_DELETE_PREFIX}); return ""; } } /** * Deletes the specified message * @param message * @return String goes to the delete message page */ protected String processActionDeleteMessageConfirm(DecoratedChatMessage message) { setCurrentMessage(message); //getChatManager().deleteMessage(message); return PAGE_DELETE_MESSAGE_CONFIRM; } /** * Cancels the delete of the current message * @return String goes to the room's main page */ public String processActionDeleteMessageCancel() { setCurrentMessage(null); return PAGE_ENTER_ROOM; } //******************************************************************** // Getters and Setters /** * This allows us to change/give the courier address. * We want the courier to respond to the chat room. * @return String */ public String getCourierString() { StringBuilder courierString = new StringBuilder("/courier/"); courierString.append(getCurrentChatChannelId()); courierString.append("/"); courierString.append(CHAT_CONTEXT_PRESENCE_PREFIX); courierString.append(getContext()); courierString.append("?userId="); courierString.append(SessionManager.getCurrentSessionUserId()); return courierString.toString(); } /** * Check for add/edit/del perms on the channel * @return */ public boolean getCanManageTool() { boolean any = getCanCreateChannel() || getCanEditChannel(null) || getCanRemoveChannel(null); return any; } /** * gets the channel id of the current channel. If there isn't one then * give a blank string * @return ChatManager */ public String getCurrentChatChannelId() { if(currentChannel == null) return ""; return currentChannel.getChatChannel().getId(); } public void setCurrentChatChannelId(String channelId) { ChatChannel newChannel = getChatManager().getChatChannel(channelId); if (newChannel != null) setCurrentChannel(new DecoratedChatChannel(this, newChannel)); } /** * gets the current channel * @return ChatChannel */ public DecoratedChatChannel getCurrentChannel() { if (currentChannel == null) { // reset to the default channel setupTool(); } return currentChannel; } /** * Implements a change of the chat room. It removes presence from the prior room, * adds observation of the new room, and then becomes present in the new room * @param channel */ public void setCurrentChannel(DecoratedChatChannel channel) { // if changing to the same channel, nothing to do // this is a fairly expensive operation, so it's worth optimizing out if (this.currentChannel != null && channel != null && this.currentChannel.getChatChannel().getId().equals( channel.getChatChannel().getId())) { return; } // turn off observation for the old channel String channelId = null; if (channel != null) { channelId = channel.getChatChannel().getId(); String address = sessionId+channelId; DecoratedChatChannel oldChannel = channels.get(channelId); if (oldChannel != null) { resetCurrentChannel(oldChannel); } ChatTool tool = tools.remove(address); if (tool != null) { tool.resetCurrentChannel(channel); } } this.currentChannel = channel; if (channel != null) { // place a presence observer on this tool. PresenceObserverHelper helper = new PresenceObserverHelper(this, channelId); presenceChannelObservers.put(channelId, helper); tools.put(sessionId+channelId, this); // hmmmm.... should this all be under the synchronize? getChatManager().addRoomListener(this, channelId); channels.put(channelId, channel); helper.updatePresence(); } } // this removes the current channel but doesn't add a new one. sort of // half of setCurrentChannel. protected void resetCurrentChannel(DecoratedChatChannel oldChannel) { String channelId = oldChannel.getChatChannel().getId(); String address = sessionId+channelId; PresenceObserverHelper observer = presenceChannelObservers.get(channelId); if (observer != null) { observer.endObservation(); observer.removePresence(); getChatManager().removeRoomListener(this, channelId); } m_courierService.clear(address); presenceChannelObservers.remove(channelId); channels.remove(channelId); tools.remove(address); currentChannel = null; // System.out.println("resetcurrent channel " + presenceChannelObservers.size() + " " + channels.size() + " " + tools.size() ); } /** * @return the currentChannelEdit */ public DecoratedChatChannel getCurrentChannelEdit() { return currentChannelEdit; } /** * @param currentChannelEdit the currentChannelEdit to set */ public void setCurrentChannelEdit(DecoratedChatChannel currentChannelEdit) { this.currentChannelEdit = currentChannelEdit; } /** * @return the currentMessage */ public DecoratedChatMessage getCurrentMessage() { DecoratedChatMessage tmpCurrent = null; if (currentMessage == null) { String messageId = (String)SessionManager.getCurrentToolSession().getAttribute("current_message"); if(messageId != null) { ChatMessage message = getChatManager().getMessage(messageId); if(message==null) return null; tmpCurrent = new DecoratedChatMessage(this, message); return tmpCurrent; } } return currentMessage; } /** * @param currentMessage the currentMessage to set */ public void setCurrentMessage(DecoratedChatMessage currentMessage) { this.currentMessage = currentMessage; } public DecoratedSynopticOptions lookupSynopticOptions() { DecoratedSynopticOptions dso = new DecoratedSynopticOptions(); Placement placement = getToolManager().getCurrentPlacement(); try { dso.setDays(Integer.parseInt(placement.getPlacementConfig().getProperty(PARAM_DAYS))); } catch (NumberFormatException e) { dso.setDays(DEFAULT_DAYS); logger.debug("Can't get tool property for synoptic chat. Using default option"); } try { dso.setItems(Integer.parseInt(placement.getPlacementConfig().getProperty(PARAM_ITEMS))); } catch (NumberFormatException e) { dso.setItems(DEFAULT_ITEMS); logger.debug("Can't get tool property for synoptic chat. Using default option"); } try { dso.setChars(Integer.parseInt(placement.getPlacementConfig().getProperty(PARAM_LENGTH))); } catch (NumberFormatException e) { dso.setChars(DEFAULT_LENGTH); logger.debug("Can't get tool property for synoptic chat. Using default option"); } return dso; } /** * @return the synopticOptions */ public DecoratedSynopticOptions getCurrentSynopticOptions() { return currentSynopticOptions; } /** * @param synopticOptions the synopticOptions to set */ public void setCurrentSynopticOptions(DecoratedSynopticOptions currentSynopticOptions) { this.currentSynopticOptions = currentSynopticOptions; } /** * This creates select items out of the channels available to the tool * @return List of SelectItem */ public List<SelectItem> getChatRoomsSelectItems() { List<SelectItem> items = new ArrayList<SelectItem>(); for (ChatChannel channel : getSiteChannels()) { items.add(createSelect(channel.getId(), channel.getTitle())); } return items; } /** * gets the tool decorated channels * @return */ public List<DecoratedChatChannel> getChatChannels() { List<DecoratedChatChannel> items = new ArrayList<DecoratedChatChannel>(); for (ChatChannel channel : getSiteChannels()) { items.add(new DecoratedChatChannel(this, channel)); } return items; } /** * gets the chatManager * @return ChatManager */ public ChatManager getChatManager() { return chatManager; } public String getViewOptions() { return Integer.toString(viewOptions); } public void setViewOptions(String d) { viewOptions = Integer.parseInt(d); } protected int initMessageOptions() { int result = MESSAGEOPTIONS_ALL_MESSAGES; DecoratedChatChannel dChannel = getCurrentChannel(); if (dChannel != null && dChannel.getChatChannel().getFilterType().equals(ChatChannel.FILTER_ALL)) { result = MESSAGEOPTIONS_ALL_MESSAGES; } else if (dChannel != null && dChannel.getChatChannel().getFilterType().equals(ChatChannel.FILTER_BY_NUMBER)) { result = MESSAGEOPTIONS_MESSAGES_BY_NUMBER; } else if (dChannel != null && dChannel.getChatChannel().getFilterType().equals(ChatChannel.FILTER_BY_TIME)) { result = MESSAGEOPTIONS_MESSAGES_BY_DATE; } else if (dChannel != null && dChannel.getChatChannel().getFilterType().equals(ChatChannel.FILTER_NONE)) { result = MESSAGEOPTIONS_NO_MESSAGES; } return result; } /** * @return the messageOptions */ public String getMessageOptions() { if (messageOptions == MESSAGEOPTIONS_NULL) messageOptions = initMessageOptions(); return Integer.toString(messageOptions); } /** * @param messageOptions the messageOptions to set */ public void setMessageOptions(String messageOptions) { this.messageOptions = Integer.parseInt(messageOptions); } public String getNewMessageText() { return newMessageText; } public void setNewMessageText(String newMessageText) { this.newMessageText = newMessageText; } /** * Sets the chatManager * @param chatManager ChatManager */ public void setChatManager(ChatManager chatManager) { this.chatManager = chatManager; } public ToolManager getToolManager() { return toolManager; } public void setToolManager(ToolManager toolManager) { this.toolManager = toolManager; } public ColorMapper getColorMapper() { return colorMapper; } public void setColorMapper(ColorMapper colorMapper) { this.colorMapper = colorMapper; } public boolean getDisplayDate() { int val = Integer.parseInt(getViewOptions()); return ((val & DATETIME_DISPLAY_DATE) == DATETIME_DISPLAY_DATE); } public boolean getDisplayTime() { int val = Integer.parseInt(getViewOptions()); return ((val & DATETIME_DISPLAY_TIME) == DATETIME_DISPLAY_TIME); } public boolean getDisplayId() { int val = Integer.parseInt(getViewOptions()); return ((val & DATETIME_DISPLAY_ID) == DATETIME_DISPLAY_ID); } public boolean getCanRenderAllMessages() { DecoratedChatChannel dChannel = getCurrentChannel(); return (!getCanRenderMessageOptions() && dChannel != null && dChannel.getChatChannel().getFilterType().equals(ChatChannel.FILTER_ALL)) || (getCanRenderMessageOptions() && messageOptions == MESSAGEOPTIONS_ALL_MESSAGES); } public boolean getCanRenderDateMessages() { DecoratedChatChannel dChannel = getCurrentChannel(); return (!getCanRenderMessageOptions() && dChannel != null && dChannel.getChatChannel().getFilterType().equals(ChatChannel.FILTER_BY_TIME)) || (getCanRenderMessageOptions() && messageOptions == MESSAGEOPTIONS_MESSAGES_BY_DATE); } public boolean getCanRenderNumberMessages() { DecoratedChatChannel dChannel = getCurrentChannel(); return (!getCanRenderMessageOptions() && dChannel != null && dChannel.getChatChannel().getFilterType().equals(ChatChannel.FILTER_BY_NUMBER)) || (getCanRenderMessageOptions() && messageOptions == MESSAGEOPTIONS_MESSAGES_BY_NUMBER); } public boolean getCanRenderNoMessages() { DecoratedChatChannel dChannel = getCurrentChannel(); return (!getCanRenderMessageOptions() && dChannel != null && dChannel.getChatChannel().getFilterType().equals(ChatChannel.FILTER_NONE)) || (getCanRenderMessageOptions() && messageOptions == MESSAGEOPTIONS_NO_MESSAGES); } public List<SelectItem> getMessageOptionsList() { List<SelectItem> messageOptions = new ArrayList<SelectItem>(); DecoratedChatChannel dChannel = getCurrentChannel(); int numberParam = dChannel != null ? dChannel.getChatChannel().getNumberParam() : 0; int timeParam = dChannel != null ? dChannel.getChatChannel().getTimeParam() : 0; if(getCanRenderMessageOptions()){ // Commenting out the original here for now in case this is ever truly implemented. Instead, display the true maximum limit // SelectItem item1 = new SelectItem(Integer.toString(MESSAGEOPTIONS_ALL_MESSAGES), getMessageFromBundle("allMessages")); SelectItem item1 = new SelectItem(Integer.toString(MESSAGEOPTIONS_ALL_MESSAGES), getCustomOptionText(ChatChannel.FILTER_BY_NUMBER, getChatManager().getMessagesMax())); SelectItem item2 = new SelectItem(Integer.toString(MESSAGEOPTIONS_MESSAGES_BY_NUMBER), getCustomOptionText(ChatChannel.FILTER_BY_NUMBER, numberParam)); SelectItem item3 = new SelectItem(Integer.toString(MESSAGEOPTIONS_MESSAGES_BY_DATE), getCustomOptionText(ChatChannel.FILTER_BY_TIME, timeParam)); SelectItem item4 = new SelectItem(Integer.toString(MESSAGEOPTIONS_NO_MESSAGES), getCustomOptionText(ChatChannel.FILTER_NONE, 0)); messageOptions.add(item1); messageOptions.add(item2); messageOptions.add(item3); messageOptions.add(item4); }else{ String filter = dChannel != null ? dChannel.getChatChannel().getFilterType() : ""; SelectItem item = null; if(filter.equals(ChatChannel.FILTER_ALL)){ // Commenting out the original here for now in case this is ever truly implemented. Instead, display the true maximum limit // item = new SelectItem(Integer.toString(MESSAGEOPTIONS_ALL_MESSAGES), getMessageFromBundle("allMessages")); item = new SelectItem(Integer.toString(MESSAGEOPTIONS_ALL_MESSAGES), getCustomOptionText(ChatChannel.FILTER_BY_NUMBER, getChatManager().getMessagesMax())); }else if(filter.equals(ChatChannel.FILTER_BY_NUMBER)){ item = new SelectItem(Integer.toString(MESSAGEOPTIONS_MESSAGES_BY_NUMBER), getCustomOptionText(ChatChannel.FILTER_BY_NUMBER, numberParam)); }else if(filter.equals(ChatChannel.FILTER_BY_TIME)){ item = new SelectItem(Integer.toString(MESSAGEOPTIONS_MESSAGES_BY_DATE), getCustomOptionText(ChatChannel.FILTER_BY_TIME, timeParam)); }else if(filter.equals(ChatChannel.FILTER_NONE)){ item = new SelectItem(Integer.toString(MESSAGEOPTIONS_NO_MESSAGES), getCustomOptionText(ChatChannel.FILTER_NONE, 0)); } messageOptions.add(item); } return messageOptions; } /** * Determins if the message option display dropdown gets rendered or not * @return */ public boolean getCanRenderMessageOptions() { DecoratedChatChannel dChannel = getCurrentChannel(); return dChannel != null? dChannel.getChatChannel().isEnableUserOverride() : false; } protected String getCustomOptionValue(String filterType) { int val = MESSAGEOPTIONS_MESSAGES_BY_DATE; if (filterType.equals(ChatChannel.FILTER_BY_TIME)) { val = MESSAGEOPTIONS_MESSAGES_BY_DATE; } else if (filterType.equals(ChatChannel.FILTER_BY_NUMBER)) { val = MESSAGEOPTIONS_MESSAGES_BY_NUMBER; } else if (filterType.equals(ChatChannel.FILTER_NONE)) { val = MESSAGEOPTIONS_NO_MESSAGES; } return Integer.toString(val); } protected String getCustomOptionText(String filterType, int filterParam) { String result = getPastXDaysText(filterParam); if (filterType.equals(ChatChannel.FILTER_BY_TIME)) { result = getPastXDaysText(filterParam); } else if (filterType.equals(ChatChannel.FILTER_BY_NUMBER)) { result = getPastXMessagesText(filterParam); } else if (filterType.equals(ChatChannel.FILTER_NONE)) { result = getNoMessagesText(); } return result; } public boolean getSoundAlert() { return true; } protected int countChannelMessages(ChatChannel channel) { return getChatManager().countChannelMessages(channel); } public List<DecoratedChatMessage> getRoomMessages() { // NOTE: make sure this uses the same method to find the date as #getRoomMessagesCount() below Date xDaysOld = null; int maxMessages = 0; DecoratedChatChannel dChannel = getCurrentChannel(); if (Integer.parseInt(getMessageOptions()) == MESSAGEOPTIONS_MESSAGES_BY_DATE) { int x = dChannel != null? dChannel.getChatChannel().getTimeParam():0; xDaysOld = getChatManager().calculateDateByOffset(x); maxMessages = getChatManager().getMessagesMax(); } else if (Integer.parseInt(getMessageOptions()) == MESSAGEOPTIONS_MESSAGES_BY_NUMBER) { int x = dChannel != null?dChannel.getChatChannel().getNumberParam():0; maxMessages = x; } else if (Integer.parseInt(getMessageOptions()) == MESSAGEOPTIONS_ALL_MESSAGES) { maxMessages = getChatManager().getMessagesMax(); } else if (Integer.parseInt(getMessageOptions()) == MESSAGEOPTIONS_NO_MESSAGES) { maxMessages = 0; } EventTrackingService ets = (EventTrackingService) ComponentManager.get(EventTrackingService.class); if (ets != null && dChannel != null && dChannel.getChatChannel() != null) { ets.post(ets.newEvent("chat.read", dChannel.getChatChannel().getReference(), false)); } return getMessages(getContext(), xDaysOld, maxMessages, true); } /** * Finds the current messages count for the current room * @return the count of the total messages for this chatroom */ public int getRoomMessagesCount() { // NOTE: make sure this uses the same method to find the date as #getRoomMessages() above Date xDaysOld = null; DecoratedChatChannel dChannel = getCurrentChannel(); if (Integer.parseInt(getMessageOptions()) == MESSAGEOPTIONS_MESSAGES_BY_DATE) { int x = dChannel != null? dChannel.getChatChannel().getTimeParam():0; xDaysOld = getChatManager().calculateDateByOffset(x); } return getMessagesCount(getContext(), xDaysOld); } public List<DecoratedChatMessage> getSynopticMessages() { DecoratedSynopticOptions dso = lookupSynopticOptions(); if(getChatManager() == null){ return null; }else{ Date date = getChatManager().calculateDateByOffset(dso.getDays()); return getMessages(getContext(), date, dso.getItems(), false); } } /** * * @param context * @param limitDate * @param numMessages * @param sortAsc * @return the set of all messages in this channel, limited to a max of 100 for paging */ protected List<DecoratedChatMessage> getMessages(String context, Date limitDate, int numMessages, boolean sortAsc) { if (numMessages > getChatManager().getMessagesMax()) { numMessages = getChatManager().getMessagesMax(); } List<ChatMessage> messages = new ArrayList<ChatMessage>(); try { ChatChannel channel = (currentChannel==null) ? null : currentChannel.getChatChannel(); messages = getChatManager().getChannelMessages(channel, context, limitDate, 0, numMessages, sortAsc); } catch (PermissionException e) { setErrorMessage(PERMISSION_ERROR, new String[] {ChatFunctions.CHAT_FUNCTION_READ}); } List<DecoratedChatMessage> decoratedMessages = new ArrayList<DecoratedChatMessage>(); for (ChatMessage message : messages) { DecoratedChatMessage decoratedMessage = new DecoratedChatMessage(this, message); decoratedMessages.add(decoratedMessage); } return decoratedMessages; } /** * @return the number of items in this channel, mostly for paging */ protected int getMessagesCount(String context, Date limitDate) { ChatChannel channel = (currentChannel==null) ? null : currentChannel.getChatChannel(); return getChatManager().getChannelMessagesCount(channel, context, limitDate); } public boolean getCanRemoveMessage(ChatMessage message) { return getChatManager().getCanDelete(message); } public boolean getCanRemoveChannel(ChatChannel channel) { return getChatManager().getCanDelete(channel); } public boolean getCanRemoveChannelMessages(ChatChannel channel) { return getChatManager().getCanDeleteAnyMessage(channel.getContext()); } public boolean getCanEditChannel(ChatChannel channel) { return getChatManager().getCanEdit(channel); } public boolean getCanCreateChannel() { return getChatManager().getCanCreateChannel(getContext()); } public boolean getCanRead(ChatChannel channel) { return getChatManager().getCanReadMessage(channel); } public boolean getCanPost() { return (getCurrentChannel() == null) ? false : getChatManager().getCanPostMessage(getCurrentChannel().getChatChannel()); } public boolean getMaintainer() { return (getChatManager() == null) ? false : getChatManager().isMaintainer(getContext()); } public String getMessageOwnerDisplayName(ChatMessage message) { User sender = null; try { sender = UserDirectoryService.getUser(message.getOwner()); } catch(UserNotDefinedException e) { logger.error(e); return message.getOwner(); } return sender.getDisplayName(); } protected String getPastXDaysText(int x) { return getMessageFromBundle("past_x_days", new Object[]{x}); } protected String getPastXMessagesText(int x) { return getMessageFromBundle("past_x_messages", new Object[]{x}); } protected String getNoMessagesText() { return getMessageFromBundle("shownone"); } protected String getAllMessagesText() { return getMessageFromBundle("allMessages"); } public String getMessagesShownTotalText() { return getMessageFromBundle("messages_shown_total", new Object[]{"*SHOWN*","*TOTAL*"}); } public String getViewingChatRoomText() { String title = null; DecoratedChatChannel dChannel = getCurrentChannel(); if (dChannel != null && dChannel.getChatChannel() != null) { title = dChannel.getChatChannel().getTitle(); } return getMessageFromBundle("viewingChatRoomText", new Object[]{title}); } private void setErrorMessage(String errorMsg, Object[] extras) { setErrorMessage(null, errorMsg, extras); } private void setErrorMessage(String field, String errorMsg, Object[] extras) { logger.debug("setErrorMessage(String " + errorMsg + ")"); FacesContext.getCurrentInstance().addMessage(field, new FacesMessage(getMessageFromBundle(errorMsg, extras))); } public String getServerUrl() { return ServerConfigurationService.getServerUrl(); } //******************************************************************** // Utilities /** * Gets the id of the tool we are in * @return String */ public String getToolString() { return placementId; } /** * Gets the id of the site we are in * @return String */ protected String getContext() { return getToolManager().getCurrentPlacement().getContext(); } /** * Returns the frame identifier for resizing * @return */ public String getFramePlacementId() { return Validator.escapeJavascript("Main" + getToolManager().getCurrentPlacement().getId()); } /** * gets the channels in this site * @return List of ChatChannel */ protected List<ChatChannel> getSiteChannels() { return getChatManager().getContextChannels(getContext(), getMessageFromBundle("default_new_channel_title"), getToolManager().getCurrentPlacement().getId()); } /** * gets the number of channels in this site * @return int */ public int getSiteChannelCount() { return getChatManager().getContextChannels(getContext(), getMessageFromBundle("default_new_channel_title"), getToolManager().getCurrentPlacement().getId()).size(); } //******************************************************************** // Common Utilities private ResourceLoader toolBundle; public SelectItem createSelect(Object id, String description) { SelectItem item = new SelectItem(id, description); return item; } public String getMessageFromBundle(String key, Object[] args) { return MessageFormat.format(getMessageFromBundle(key), args); } public String getMessageFromBundle(String key) { if (toolBundle == null) { String bundle = FacesContext.getCurrentInstance().getApplication().getMessageBundle(); toolBundle = new ResourceLoader(bundle); } return toolBundle.getString(key); } public String getToolContext() { return toolContext; } public void setToolContext(String toolContext) { this.toolContext = toolContext; } public String getSessionId() { return sessionId; } public void validatePositiveNumber(FacesContext context, UIComponent component, Object value){ if (value != null) { if ((Integer) value < 0) { FacesMessage message = new FacesMessage(getMessageFromBundle("neg_num_error",null)); message.setSeverity(FacesMessage.SEVERITY_WARN); throw new ValidatorException(message); } } } //SAK-19700 method to get name of tool so it can be rendered with the option link, for screenreaders public String getToolTitle() { return toolManager.getCurrentPlacement().getTitle(); } //SAK-19700 renders a complete Options link with an additional span link for accessiblity public String getAccessibleOptionsLink() { StringBuilder sb = new StringBuilder(); sb.append(getMessageFromBundle("manage_tool")); sb.append("<span class=\"skip\">"); sb.append(getToolTitle()); sb.append("</span>"); return sb.toString(); } }