001: /**********************************************************************************
002: * $URL: https://source.sakaiproject.org/svn/presence/tags/sakai_2-4-1/presence-tool/tool/src/java/org/sakaiproject/presence/tool/PresenceTool.java $
003: * $Id: PresenceTool.java 18353 2006-11-21 20:42:31Z josrodri@iupui.edu $
004: ***********************************************************************************
005: *
006: * Copyright (c) 2003, 2004, 2005, 2006 The Sakai Foundation.
007: *
008: * Licensed under the Educational Community License, Version 1.0 (the "License");
009: * you may not use this file except in compliance with the License.
010: * You may obtain a copy of the License at
011: *
012: * http://www.opensource.org/licenses/ecl1.php
013: *
014: * Unless required by applicable law or agreed to in writing, software
015: * distributed under the License is distributed on an "AS IS" BASIS,
016: * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
017: * See the License for the specific language governing permissions and
018: * limitations under the License.
019: *
020: **********************************************************************************/package org.sakaiproject.presence.tool;
021:
022: import java.io.IOException;
023: import java.io.PrintWriter;
024: import java.util.Iterator;
025: import java.util.List;
026: import java.util.Vector;
027:
028: import javax.servlet.ServletConfig;
029: import javax.servlet.ServletException;
030: import javax.servlet.http.HttpServlet;
031: import javax.servlet.http.HttpServletRequest;
032: import javax.servlet.http.HttpServletResponse;
033:
034: import org.apache.commons.logging.Log;
035: import org.apache.commons.logging.LogFactory;
036: import org.sakaiproject.event.api.UsageSession;
037: import org.sakaiproject.event.cover.UsageSessionService;
038: import org.sakaiproject.presence.cover.PresenceService;
039: import org.sakaiproject.site.api.Site;
040: import org.sakaiproject.site.api.ToolConfiguration;
041: import org.sakaiproject.site.cover.SiteService;
042: import org.sakaiproject.tool.api.Placement;
043: import org.sakaiproject.tool.api.Session;
044: import org.sakaiproject.tool.api.ToolSession;
045: import org.sakaiproject.tool.cover.SessionManager;
046: import org.sakaiproject.tool.cover.ToolManager;
047: import org.sakaiproject.user.api.User;
048: import org.sakaiproject.user.cover.UserDirectoryService;
049: import org.sakaiproject.util.PresenceObservingCourier;
050: import org.sakaiproject.util.ResourceLoader;
051: import org.sakaiproject.util.Web;
052:
053: /**
054: * <p>
055: * Presence is an tool which presents an auto-updating user presence list.
056: * </p>
057: */
058: public class PresenceTool extends HttpServlet {
059: /** Our log (commons). */
060: private static Log M_log = LogFactory.getLog(PresenceTool.class);
061:
062: /** Tool state attribute where the observer is stored. */
063: protected static final String ATTR_OBSERVER = "observer";
064:
065: /** Common Tool ID for the Sakai Chat Tool */
066: protected static final String CHAT_COMMON_ID = "sakai.chat";
067:
068: /** Tool state attribute where the chat observer is stored. */
069: protected static final String ATTR_CHAT_OBSERVER = "chat_observer";
070:
071: /** Localized messages * */
072: ResourceLoader rb = new ResourceLoader("presence");
073:
074: /**
075: * Shutdown the servlet.
076: */
077: public void destroy() {
078: M_log.info("destroy()");
079:
080: super .destroy();
081: }
082:
083: /**
084: * Respond to access requests.
085: *
086: * @param req
087: * The servlet request.
088: * @param res
089: * The servlet response.
090: * @throws ServletException.
091: * @throws IOException.
092: */
093: protected void doGet(HttpServletRequest req, HttpServletResponse res)
094: throws ServletException, IOException {
095: // get the Sakai session
096: Session session = SessionManager.getCurrentSession();
097:
098: // get the current tool session, where we store our observer
099: ToolSession toolSession = SessionManager
100: .getCurrentToolSession();
101:
102: // get the current tool placement
103: Placement placement = ToolManager.getCurrentPlacement();
104:
105: // location is just placement
106: String location = placement.getId();
107:
108: // refresh our presence at the location
109: PresenceService.setPresence(location);
110:
111: // make sure we have an observing watching for presence change at location
112: PresenceObservingCourier observer = (PresenceObservingCourier) toolSession
113: .getAttribute(ATTR_OBSERVER);
114: if (observer == null) {
115: // setup an observer to notify us when presence at this location changes
116: observer = new PresenceObservingCourier(location);
117: toolSession.setAttribute(ATTR_OBSERVER, observer);
118: }
119:
120: // get the list of users at the location
121: List users = PresenceService.getPresentUsers(location,
122: placement.getContext());
123:
124: // get SiteId from the current placement and retrieve site
125: String siteId = placement.getContext();
126:
127: Site site = null;
128: ToolConfiguration toolConfig = null;
129: List chatUsers = null;
130:
131: if (siteId != null) {
132: try {
133: site = SiteService.getSiteVisit(siteId);
134: } catch (Exception e) {
135: // No problem - leave site null
136: }
137: }
138:
139: if (site != null) {
140: toolConfig = site.getToolForCommonId(CHAT_COMMON_ID);
141: }
142:
143: if (toolConfig != null) {
144: String chatLocation = toolConfig.getId();
145: chatUsers = PresenceService.getPresentUsers(chatLocation,
146: siteId);
147:
148: PresenceObservingCourier chatObserver = (PresenceObservingCourier) toolSession
149: .getAttribute(ATTR_CHAT_OBSERVER);
150: if (chatObserver == null) {
151: // Monitor presense changes at chatLocation and deliver them to this window's location with
152: // no sub window (null)
153: chatObserver = new PresenceObservingCourier(location,
154: null, chatLocation);
155: toolSession.setAttribute(ATTR_CHAT_OBSERVER,
156: chatObserver);
157: }
158: }
159:
160: // start the response
161: PrintWriter out = startResponse(req, res, "presence");
162:
163: sendAutoUpdate(out, req, placement.getId(), placement
164: .getContext());
165: sendPresence(out, users, chatUsers);
166:
167: // end the response
168: endResponse(out);
169: }
170:
171: /**
172: * End the response
173: *
174: * @param out
175: * @throws IOException
176: */
177: protected void endResponse(PrintWriter out) throws IOException {
178: out.println("</body></html>");
179: }
180:
181: /**
182: * Access the Servlet's information display.
183: *
184: * @return servlet information.
185: */
186: public String getServletInfo() {
187: return "Sakai Presence Tool";
188: }
189:
190: /**
191: * Initialize the servlet.
192: *
193: * @param config
194: * The servlet config.
195: * @throws ServletException
196: */
197: public void init(ServletConfig config) throws ServletException {
198: super .init(config);
199:
200: M_log.info("init()");
201: }
202:
203: /**
204: * Send the HTML / Javascript to invoke an automatic update
205: *
206: * @param out
207: * @param req
208: * @param placementId
209: * @param context
210: */
211: protected void sendAutoUpdate(PrintWriter out,
212: HttpServletRequest req, String placementId, String context) {
213: // set the refresh of the courier to 1/2 the presence timeout value
214: Web.sendAutoUpdate(out, req, placementId, PresenceService
215: .getTimeout() / 2);
216: }
217:
218: /**
219: * Format the list of users
220: *
221: * @param out
222: * @param users
223: */
224: protected void sendPresence(PrintWriter out, List users,
225: List chatUsers) {
226: // is the current user running under an assumed (SU) user id?
227: String asName = null;
228: String myUserId = null;
229: try {
230: UsageSession usageSession = UsageSessionService
231: .getSession();
232: if (usageSession != null) {
233: // this is the absolutely real end-user id, even if running as another user
234: myUserId = usageSession.getUserId();
235:
236: // this is the user id the current user is running as
237: String sessionUserId = SessionManager
238: .getCurrentSessionUserId();
239:
240: // if different
241: if (!myUserId.equals(sessionUserId)) {
242: asName = UserDirectoryService
243: .getUser(sessionUserId).getDisplayName();
244: }
245: }
246: } catch (Throwable any) {
247: }
248:
249: out.println("<ul class=\"presenceList\">");
250: if (users == null) {
251: out.println("<!-- Presence empty -->");
252: out.println("</ul>");
253: return;
254: }
255:
256: // first pass - list Chat users (if any)
257: if (chatUsers != null) {
258: for (Iterator i = chatUsers.iterator(); i.hasNext();) {
259: User u = (User) i.next();
260: String displayName = u.getDisplayName();
261:
262: // adjust if this is the current user running as someone else
263: if ((asName != null) && (u.getId().equals(myUserId))) {
264: displayName += " (" + asName + ")";
265: }
266:
267: String msg = rb.getString("inchat");
268: out.print("<li class=\"inChat\">");
269: out.print("<span title=\"" + msg + "\">");
270: out.print(Web.escapeHtml(displayName));
271: out.println("</span></li>");
272: }
273: }
274:
275: // second pass - list remaining non-chat users
276: List nonChatUsers = new Vector(users);
277: if (chatUsers != null) {
278: nonChatUsers.removeAll(chatUsers);
279: }
280: for (Iterator i = nonChatUsers.iterator(); i.hasNext();) {
281: User u = (User) i.next();
282:
283: String displayName = u.getDisplayName();
284:
285: // adjust if this is the current user running as someone else
286: if ((asName != null) && (u.getId().equals(myUserId))) {
287: displayName += " (" + asName + ")";
288: }
289:
290: String msg = rb.getString("insite");
291: out.print("<li>");
292: out.print("<span title=\"" + msg + "\">");
293: out.print(Web.escapeHtml(displayName));
294: out.println("</span></li>");
295: }
296:
297: out.println("</ul>");
298: }
299:
300: /**
301: * Start the response.
302: *
303: * @param req
304: * @param res
305: * @param title
306: * @param skin
307: * @return
308: * @throws IOException
309: */
310: protected PrintWriter startResponse(HttpServletRequest req,
311: HttpServletResponse res, String title) throws IOException {
312: // headers
313: res.setContentType("text/html; charset=UTF-8");
314: res.addDateHeader("Expires", System.currentTimeMillis()
315: - (1000L * 60L * 60L * 24L * 365L));
316: res.addDateHeader("Last-Modified", System.currentTimeMillis());
317: res
318: .addHeader("Cache-Control",
319: "no-store, no-cache, must-revalidate, max-age=0, post-check=0, pre-check=0");
320: res.addHeader("Pragma", "no-cache");
321:
322: // get the writer
323: PrintWriter out = res.getWriter();
324:
325: // form the head
326: out
327: .println("<!DOCTYPE html PUBLIC \"-//W3C//DTD XHTML 1.0 Transitional//EN\" "
328: + "\"http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd\">"
329: + "<html xmlns=\"http://www.w3.org/1999/xhtml\" lang=\"en\" xml:lang=\"en\">"
330: + " <head>"
331: + " <meta http-equiv=\"Content-Type\" content=\"text/html; charset=UTF-8\" />");
332:
333: // send the portal set-up head
334: String head = (String) req.getAttribute("sakai.html.head");
335: if (head != null) {
336: out.println(head);
337: }
338:
339: out.println("</head>");
340:
341: // Note: we ignore the portal set-up body onload
342:
343: // start the body
344: out.println("<body>");
345:
346: return out;
347: }
348: }
|