001: /**********************************************************************************
002: * $URL: https://source.sakaiproject.org/svn/portal/tags/sakai_2-4-1/portal-mercury/mercury/src/java/org/sakaiproject/portal/tool/MercuryPortal.java $
003: * $Id: MercuryPortal.java 22574 2007-03-13 22:32:18Z ian@caret.cam.ac.uk $
004: ***********************************************************************************
005: *
006: * Copyright (c) 2005, 2006, 2007 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.portal.tool;
021:
022: import java.io.IOException;
023: import java.io.PrintWriter;
024: import java.text.DateFormat;
025: import java.util.Date;
026: import java.util.Enumeration;
027: import java.util.HashMap;
028: import java.util.HashSet;
029: import java.util.Iterator;
030: import java.util.Map;
031: import java.util.Properties;
032: import java.util.Set;
033: import java.util.TreeSet;
034:
035: import javax.servlet.ServletConfig;
036: import javax.servlet.ServletException;
037: import javax.servlet.http.HttpServlet;
038: import javax.servlet.http.HttpServletRequest;
039: import javax.servlet.http.HttpServletResponse;
040:
041: import org.apache.commons.logging.Log;
042: import org.apache.commons.logging.LogFactory;
043: import org.sakaiproject.component.cover.ServerConfigurationService;
044: import org.sakaiproject.event.cover.UsageSessionService;
045: import org.sakaiproject.id.cover.IdManager;
046: import org.sakaiproject.portal.util.ErrorReporter;
047: import org.sakaiproject.portal.util.ToolURLManagerImpl;
048: import org.sakaiproject.tool.api.ActiveTool;
049: import org.sakaiproject.tool.api.Placement;
050: import org.sakaiproject.tool.api.Session;
051: import org.sakaiproject.tool.api.Tool;
052: import org.sakaiproject.tool.api.ToolException;
053: import org.sakaiproject.tool.api.ToolSession;
054: import org.sakaiproject.tool.api.ToolURL;
055: import org.sakaiproject.tool.cover.ActiveToolManager;
056: import org.sakaiproject.tool.cover.SessionManager;
057: import org.sakaiproject.tool.cover.ToolManager;
058: import org.sakaiproject.user.api.Authentication;
059: import org.sakaiproject.user.api.AuthenticationException;
060: import org.sakaiproject.user.api.Evidence;
061: import org.sakaiproject.user.cover.AuthenticationManager;
062: import org.sakaiproject.util.IdPwEvidence;
063: import org.sakaiproject.util.Web;
064:
065: /**
066: * <p>
067: * Mercury is the Sakai developers portal. It can be used while developing a new Sakai application to invoke the tool in the way that the tool will be
068: * invoked by any of the Sakai navigation / portal technologies. Mercury is easier to use in development because you don't have to setup a Site or
069: * build SuperStructure to test your application.
070: * </p>
071: * <p>
072: * Mercury supports a few URL patterns, but those give you the ability to:
073: * <ul>
074: * <li>login to Sakai</li>
075: * <li>see all registered tools</li>
076: * <li>visit any tool complete with context and placement</li>
077: * </ul>
078: * </p>
079: * <p>
080: * Mercury is configured to be packaged into the "mercury.war" web application, so it can be visited with the <code>/mercury</code> URL.
081: * </p>
082: * <p>
083: * To login, use the <code>/mercury/login</code> URL.
084: * </p>
085: * To visit any registered tool, use the URL pattern:
086: * <ul>
087: * <li><code>/mercury/TOOL-ID/CONTEXT/path-for-tool</code></li>
088: * </ul>
089: * where TOOL_ID is the tool's well known registered tool id (such as 'sakai.chat'), and CONTEXT is the tool context string.
090: * </p>
091: * <p>
092: * A placement will be created for each tool in the context as needed, and will be tracked for the duration of the server run.
093: * </p>
094: */
095: public class MercuryPortal extends HttpServlet {
096: /** Our log (commons). */
097: private static Log M_log = LogFactory.getLog(MercuryPortal.class);
098:
099: /** Map of context+toolId -> Placement for keeping tool placements. */
100: protected Map m_placements = new HashMap();
101:
102: /**
103: * Access the Servlet's information display.
104: *
105: * @return servlet information.
106: */
107: public String getServletInfo() {
108: return "Sakai Mercury Portal";
109: }
110:
111: /**
112: * Initialize the servlet.
113: *
114: * @param config
115: * The servlet config.
116: * @throws ServletException
117: */
118: public void init(ServletConfig config) throws ServletException {
119: super .init(config);
120:
121: M_log.info("init()");
122: }
123:
124: /**
125: * Shutdown the servlet.
126: */
127: public void destroy() {
128: M_log.info("destroy()");
129:
130: super .destroy();
131: }
132:
133: /**
134: * Respond to navigation / access requests.
135: *
136: * @param req
137: * The servlet request.
138: * @param res
139: * The servlet response.
140: * @throws ServletException.
141: * @throws IOException.
142: */
143: protected void doGet(HttpServletRequest req, HttpServletResponse res)
144: throws ServletException, IOException {
145: try {
146: // make sure the portal is enabled
147: if (!ServerConfigurationService.getString(
148: "mercury.enabled", "false")
149: .equalsIgnoreCase("true")) {
150: doDisabled(req, res);
151: return;
152: }
153:
154: // get the Sakai session
155: Session session = SessionManager.getCurrentSession();
156:
157: // recognize what to do from the path
158: String option = req.getPathInfo();
159:
160: // if missing, set it to home
161: if ((option == null) || ("/".equals(option))) {
162: option = "/home";
163: }
164:
165: // get the parts, [0] = "", [1] is /login, or [1] is /home, or [2] is context and [1] is known tool id and [3..n] are for the tool
166: String[] parts = option.split("/");
167:
168: // recognize and dispatch the 'home' option
169: if ((parts.length == 2) && (parts[1].equals("home"))) {
170: doHome(req, res, session);
171: }
172:
173: // recognize and dispatch the 'login' option
174: else if ((parts.length == 2) && (parts[1].equals("login"))) {
175: doLogin(req, res, session);
176: }
177: // recognize and dispatch the 'logout' option
178: else if ((parts.length == 2) && (parts[1].equals("logout"))) {
179: doLogout(req, res, session);
180: } else if ((parts.length == 3)
181: && (parts[1].equals("loginx"))) {
182: doLoginx(req, res, parts[2], session);
183: }
184:
185: // recognize and dispatch a tool request option: parts[2] is the context, parts[1] is a known tool id, parts[3..n] are for the tool
186: else if (parts.length >= 3) {
187: doTool(req, res, session, parts[1], parts[2], req
188: .getContextPath()
189: + req.getServletPath()
190: + Web.makePath(parts, 1, 3), Web.makePath(
191: parts, 3, parts.length));
192: }
193:
194: // handle an unrecognized request
195: else {
196: doError(req, res, session);
197: }
198: } catch (Throwable t) {
199: doThrowableError(req, res, t);
200: }
201: }
202:
203: protected void doHome(HttpServletRequest req,
204: HttpServletResponse res, Session session)
205: throws IOException {
206: // get all tools
207: Set tools = ToolManager.findTools(null, null);
208:
209: // get the test tools
210: Set categories = new HashSet();
211: categories.add("sakai.test");
212: Set testTools = ToolManager.findTools(categories, null);
213:
214: // get the helper tools
215: categories.clear();
216: categories.add("sakai.helper");
217: Set helperTools = ToolManager.findTools(categories, null);
218:
219: // get the sample tools
220: categories.clear();
221: categories.add("sakai.sample");
222: Set sampleTools = ToolManager.findTools(categories, null);
223:
224: // remove the test, sample and helper tools from the main list
225: tools.removeAll(testTools);
226: tools.removeAll(helperTools);
227: tools.removeAll(sampleTools);
228:
229: // start the response
230: res.setContentType("text/html; charset=UTF-8");
231: res.addDateHeader("Expires", System.currentTimeMillis()
232: - (1000L * 60L * 60L * 24L * 365L));
233: res.addDateHeader("Last-Modified", System.currentTimeMillis());
234: res
235: .addHeader("Cache-Control",
236: "no-store, no-cache, must-revalidate, max-age=0, post-check=0, pre-check=0");
237: res.addHeader("Pragma", "no-cache");
238:
239: PrintWriter out = res.getWriter();
240: out
241: .println("<html><head><title>Sakai Mercury Portal</title></head><body>");
242:
243: // fun
244: out
245: .println("<img src=\"/library/image/sakai.jpg\" width=\"110\" height=\"66\">");
246: out
247: .println("<img src=\"/library/image/Hg-TableImage.png\" width=\"250\" height=\"75\">");
248: out
249: .println("<img src=\"/library/image/mercury.gif\" width=\"78\" height=\"69\">");
250: out
251: .println("<img src=\"/library/image/mercsymb.gif\" width=\"94\" height=\"75\"><br />");
252:
253: // login
254: if ((session.getUserId() == null)
255: && (session.getUserEid() == null)) {
256: out.println("<p><a href=\"" + Web.returnUrl(req, "/login")
257: + "\">login</a></p>");
258:
259: String[] loginIds = ServerConfigurationService
260: .getStrings("mercury.login");
261: int i = 0;
262: if (loginIds != null) {
263: for (String loginId : loginIds) {
264: out.println("<p><a href=\""
265: + Web.returnUrl(req, "/loginx/"
266: + Integer.toString(i++))
267: + "\">login: " + loginId + "</a></p>");
268: }
269: }
270: } else {
271: out.println("<p><a href=\"" + Web.returnUrl(req, "/logout")
272: + "\">logout</a></p>");
273: }
274: // Show session information
275: out.println("<H2>Session</H2>");
276: showSession(out, true);
277:
278: // list the main tools
279: out.println("<H2>Tools</H2>");
280: out
281: .println("<p>These are the tools registered with Sakai:</p>");
282: out
283: .println("<table border='1'><tr><th>id</th><th>title</th><th>description</th><th>final configuration</th><th>mutable configuration</th><th>categories</th><th>keywords</th></tr>");
284:
285: // sorted
286: TreeSet sorted = new TreeSet(tools);
287: for (Iterator i = sorted.iterator(); i.hasNext();) {
288: Tool t = (Tool) i.next();
289: String toolUrl = Web.returnUrl(req, "/" + t.getId()
290: + "/mercury");
291: out.println("<tr><td><a href=\"" + toolUrl + "\">"
292: + t.getId() + "</a></td><td>" + t.getTitle()
293: + "</td><td>" + t.getDescription() + "</td><td>"
294: + printConfiguration(t.getFinalConfig())
295: + "</td><td>"
296: + printConfiguration(t.getMutableConfig())
297: + "</td><td>" + printCategories(t.getCategories())
298: + "</td><td>" + printKeywords(t.getKeywords())
299: + "</td></tr>");
300: }
301: out.println("</table>");
302:
303: // list the helper tools
304: out.println("<H2>Helper Tools</H2>");
305: out
306: .println("<p>These are the tools registered as helperswith Sakai. (Helper tools cannot be directly invoked): </p>");
307: out
308: .println("<table border='1'><tr><th>id</th><th>title</th><th>description</th><th>final configuration</th><th>mutable configuration</th><th>categories</th><th>keywords</th></tr>");
309:
310: // sorted
311: sorted = new TreeSet(helperTools);
312: for (Iterator i = sorted.iterator(); i.hasNext();) {
313: Tool t = (Tool) i.next();
314: String toolUrl = Web.returnUrl(req, "/" + t.getId()
315: + "/mercury");
316: out.println("<tr><td>" + t.getId() + "</td><td>"
317: + t.getTitle() + "</td><td>" + t.getDescription()
318: + "</td><td>"
319: + printConfiguration(t.getFinalConfig())
320: + "</td><td>"
321: + printConfiguration(t.getMutableConfig())
322: + "</td><td>" + printCategories(t.getCategories())
323: + "</td><td>" + printKeywords(t.getKeywords())
324: + "</td></tr>");
325: }
326: out.println("</table>");
327:
328: // list the sample tools
329: out.println("<H2>Sample Tools</H2>");
330: out
331: .println("<p>These are the tools registered with Sakai, categorized as <i>sakai.sample</i>:</p>");
332: out
333: .println("<table border='1'><tr><th>id</th><th>title</th><th>description</th><th>final configuration</th><th>mutable configuration</th><th>categories</th><th>keywords</th></tr>");
334:
335: // sorted
336: sorted = new TreeSet(sampleTools);
337: for (Iterator i = sorted.iterator(); i.hasNext();) {
338: Tool t = (Tool) i.next();
339: String toolUrl = Web.returnUrl(req, "/" + t.getId()
340: + "/mercury");
341: out.println("<tr><td><a href=\"" + toolUrl + "\">"
342: + t.getId() + "</a></td><td>" + t.getTitle()
343: + "</td><td>" + t.getDescription() + "</td><td>"
344: + printConfiguration(t.getFinalConfig())
345: + "</td><td>"
346: + printConfiguration(t.getMutableConfig())
347: + "</td><td>" + printCategories(t.getCategories())
348: + "</td><td>" + printKeywords(t.getKeywords())
349: + "</td></tr>");
350: }
351: out.println("</table>");
352:
353: // list the test tools
354: out.println("<H2>Test Tools</H2>");
355: out
356: .println("<p>These are the tools registered with Sakai, categorized as <i>sakai.test</i>:</p>");
357: out
358: .println("<table border='1'><tr><th>id</th><th>title</th><th>description</th><th>final configuration</th><th>mutable configuration</th><th>categories</th><th>keywords</th></tr>");
359:
360: // sorted
361: sorted = new TreeSet(testTools);
362: for (Iterator i = sorted.iterator(); i.hasNext();) {
363: Tool t = (Tool) i.next();
364: String toolUrl = Web.returnUrl(req, "/" + t.getId()
365: + "/mercury");
366: out.println("<tr><td><a href=\"" + toolUrl + "\">"
367: + t.getId() + "</a></td><td>" + t.getTitle()
368: + "</td><td>" + t.getDescription() + "</td><td>"
369: + printConfiguration(t.getFinalConfig())
370: + "</td><td>"
371: + printConfiguration(t.getMutableConfig())
372: + "</td><td>" + printCategories(t.getCategories())
373: + "</td><td>" + printKeywords(t.getKeywords())
374: + "</td></tr>");
375: }
376: out.println("</table>");
377:
378: // list placements
379: out.println("<H2>Tool Placements</H2>");
380: out
381: .println("<p>These are the placements we are tracking so far:</p>");
382: out
383: .println("<table border='1'><tr><th>id</th><th>context</th><th>tool</th><th>configuration</th></tr>");
384: for (Iterator i = m_placements.values().iterator(); i.hasNext();) {
385: Placement p = (Placement) i.next();
386: out.println("<tr><td>" + p.getId() + "</td><td>"
387: + p.getContext() + "</td><td>" + p.getToolId()
388: + "</td><td>"
389: + printConfiguration(p.getPlacementConfig())
390: + "</td></tr>");
391: }
392: out.println("</table>");
393:
394: out.println("<H2>Snoop</H2>");
395: Web.snoop(out, true, getServletConfig(), req);
396:
397: // close the response
398: out.println("</body></html>");
399: }
400:
401: protected void doLogin(HttpServletRequest req,
402: HttpServletResponse res, Session session)
403: throws ToolException {
404: // setup for the helper if needed (Note: in session, not tool session, special for Login helper)
405: if (session.getAttribute(Tool.HELPER_DONE_URL) == null) {
406: // where to go after
407: session.setAttribute(Tool.HELPER_DONE_URL, Web.returnUrl(
408: req, null));
409: }
410:
411: // map the request to the helper, leaving the path after ".../options" for the helper
412: ActiveTool tool = ActiveToolManager
413: .getActiveTool("sakai.login");
414: String context = req.getContextPath() + req.getServletPath()
415: + "/login";
416: tool.help(req, res, context, null);
417: }
418:
419: protected void doLoginx(HttpServletRequest req,
420: HttpServletResponse res, String which, Session session)
421: throws ToolException, IOException {
422: String[] loginIds = ServerConfigurationService
423: .getStrings("mercury.login");
424: String[] loginPws = ServerConfigurationService
425: .getStrings("mercury.password");
426:
427: int i = Integer.parseInt(which);
428: String eid = loginIds[i];
429: String pw = loginPws[i];
430:
431: Evidence e = new IdPwEvidence(eid, pw);
432:
433: // authenticate
434: try {
435: if ((eid.length() == 0) || (pw.length() == 0)) {
436: throw new AuthenticationException(
437: "missing required fields");
438: }
439:
440: Authentication a = AuthenticationManager.authenticate(e);
441:
442: // login the user
443: UsageSessionService.login(a, req);
444: } catch (AuthenticationException ex) {
445: }
446:
447: doHome(req, res, session);
448: }
449:
450: /**
451: * Process a logout - borrowed from CharonPortal.java
452: *
453: * @param req
454: * Request object
455: * @param res
456: * Response object
457: * @param session
458: * Current session
459: * @throws IOException
460: */
461: protected void doLogout(HttpServletRequest req,
462: HttpServletResponse res, Session session)
463: throws ToolException {
464: // setup for the helper if needed (Note: in session, not tool session, special for Login helper)
465: if (session.getAttribute(Tool.HELPER_DONE_URL) == null) {
466: // where to go after
467: session.setAttribute(Tool.HELPER_DONE_URL, Web.returnUrl(
468: req, null));
469: }
470:
471: ActiveTool tool = ActiveToolManager
472: .getActiveTool("sakai.login");
473: String context = req.getContextPath() + req.getServletPath()
474: + "/logout";
475: tool.help(req, res, context, "/logout");
476: }
477:
478: protected void doTool(HttpServletRequest req,
479: HttpServletResponse res, Session session, String toolId,
480: String context, String toolContextPath, String toolPathInfo)
481: throws ToolException, IOException {
482: ActiveTool tool = ActiveToolManager.getActiveTool(toolId);
483: if (tool == null) {
484: doError(req, res, session);
485: }
486:
487: else {
488: // find / make the placement id for this tool - a Placement is stored keyed by context+toolId
489: String key = context + "-" + toolId;
490: Placement p = (Placement) m_placements.get(key);
491: if (p == null) {
492: p = new org.sakaiproject.util.Placement(IdManager
493: .createUuid(), toolId, tool, null, context,
494: null);
495: m_placements.put(key, p);
496: }
497:
498: forwardTool(tool, req, res, p, toolContextPath,
499: toolPathInfo);
500: }
501: }
502:
503: protected void doError(HttpServletRequest req,
504: HttpServletResponse res, Session session)
505: throws IOException {
506: // start the response
507: res.setContentType("text/html; charset=UTF-8");
508: res.addDateHeader("Expires", System.currentTimeMillis()
509: - (1000L * 60L * 60L * 24L * 365L));
510: res.addDateHeader("Last-Modified", System.currentTimeMillis());
511: res
512: .addHeader("Cache-Control",
513: "no-store, no-cache, must-revalidate, max-age=0, post-check=0, pre-check=0");
514: res.addHeader("Pragma", "no-cache");
515:
516: PrintWriter out = res.getWriter();
517: out
518: .println("<html><head><title>Sakai Mercury Portal</title></head><body>");
519:
520: // Show session information
521: out.println("<H2>Session</H2>");
522: showSession(out, true);
523:
524: out.println("<H2>Unknown Request</H2>");
525: Web.snoop(out, true, getServletConfig(), req);
526:
527: // close the response
528: out.println("</body></html>");
529: }
530:
531: protected void doDisabled(HttpServletRequest req,
532: HttpServletResponse res) throws IOException {
533: // start the response
534: res.setContentType("text/html; charset=UTF-8");
535: res.addDateHeader("Expires", System.currentTimeMillis()
536: - (1000L * 60L * 60L * 24L * 365L));
537: res.addDateHeader("Last-Modified", System.currentTimeMillis());
538: res
539: .addHeader("Cache-Control",
540: "no-store, no-cache, must-revalidate, max-age=0, post-check=0, pre-check=0");
541: res.addHeader("Pragma", "no-cache");
542:
543: PrintWriter out = res.getWriter();
544: out
545: .println("<html><head><title>Sakai Mercury Portal</title></head><body>");
546:
547: // Show session information
548: out.println("<H2>Disabled</H2>");
549: out.println("<p>The Mercury Portal is currently disabled.</p>");
550: out
551: .println("<p>To enable this, set \"mercury.enabled=true\" in your sakai.properties file.</p>");
552:
553: // close the response
554: out.println("</body></html>");
555: }
556:
557: protected void doThrowableError(HttpServletRequest req,
558: HttpServletResponse res, Throwable t) {
559: ErrorReporter err = new ErrorReporter();
560: err.report(req, res, t);
561: }
562:
563: /**
564: * Respond to data posting requests.
565: *
566: * @param req
567: * The servlet request.
568: * @param res
569: * The servlet response.
570: * @throws ServletException.
571: * @throws IOException.
572: */
573: protected void doPost(HttpServletRequest req,
574: HttpServletResponse res) throws ServletException,
575: IOException {
576: try {
577: // get the Sakai session
578: Session session = SessionManager.getCurrentSession();
579:
580: // recognize what to do from the path
581: String option = req.getPathInfo();
582:
583: // if missing, set it to home
584: if ((option == null) || ("/".equals(option))) {
585: option = "/home";
586: }
587:
588: // get the parts, [0] = "", [1] is /login, or [1] is /home, or [2] is context and [1] is known tool id and [3..n] are for the tool
589: String[] parts = option.split("/");
590:
591: // recognize and dispatch the 'home' option
592: if ((parts.length == 2) && (parts[1].equals("home"))) {
593: postHome(req, res, session);
594: }
595:
596: // recognize and dispatch the 'login' option
597: else if ((parts.length == 2) && (parts[1].equals("login"))) {
598: postLogin(req, res, session);
599: }
600:
601: // recognize and dispatch a tool request option: parts[2] is the context, parts[1] is a known tool id, parts[3..n] are for the tool
602: else if (parts.length >= 3) {
603: postTool(req, res, session, parts[1], parts[2], req
604: .getContextPath()
605: + req.getServletPath()
606: + Web.makePath(parts, 1, 3), Web.makePath(
607: parts, 3, parts.length));
608: }
609:
610: // handle an unrecognized request
611: else {
612: doError(req, res, session);
613: }
614: } catch (Throwable t) {
615: doThrowableError(req, res, t);
616: }
617: }
618:
619: protected void postLogin(HttpServletRequest req,
620: HttpServletResponse res, Session session)
621: throws ToolException {
622: ActiveTool tool = ActiveToolManager
623: .getActiveTool("sakai.login");
624: String context = req.getContextPath() + req.getServletPath()
625: + "/login";
626: tool.help(req, res, context, null);
627: }
628:
629: protected void postHome(HttpServletRequest req,
630: HttpServletResponse res, Session session)
631: throws IOException {
632: }
633:
634: protected void postTool(HttpServletRequest req,
635: HttpServletResponse res, Session session, String toolId,
636: String context, String toolContextPath, String toolPathInfo)
637: throws ToolException, IOException {
638: ActiveTool tool = ActiveToolManager.getActiveTool(toolId);
639: if (tool == null) {
640: doError(req, res, session);
641: }
642:
643: else {
644: // find / make the placement id for this tool - a Placement is stored keyed by context+toolId
645: String key = context + "-" + toolId;
646: Placement p = (Placement) m_placements.get(key);
647: if (p == null) {
648: p = new org.sakaiproject.util.Placement(IdManager
649: .createUuid(), toolId, tool, null, context,
650: null);
651: m_placements.put(key, p);
652: }
653:
654: forwardTool(tool, req, res, p, toolContextPath,
655: toolPathInfo);
656: }
657: }
658:
659: /**
660: * Forward to the tool - setup JavaScript/CSS etc that the tool will render
661: */
662: protected void forwardTool(ActiveTool tool, HttpServletRequest req,
663: HttpServletResponse res, Placement p,
664: String toolContextPath, String toolPathInfo)
665: throws ToolException {
666: String skin = ServerConfigurationService
667: .getString("skin.default");
668: String skinRepo = ServerConfigurationService
669: .getString("skin.repo");
670:
671: // setup html information that the tool might need (skin, body on load, js includes, etc).
672: String headCssToolBase = "<link href=\""
673: + skinRepo
674: + "/tool_base.css\" type=\"text/css\" rel=\"stylesheet\" media=\"all\" />\n";
675: String headCssToolSkin = "<link href=\""
676: + skinRepo
677: + "/"
678: + skin
679: + "/tool.css\" type=\"text/css\" rel=\"stylesheet\" media=\"all\" />\n";
680: String headCss = headCssToolBase + headCssToolSkin;
681: String headJs = "<script type=\"text/javascript\" language=\"JavaScript\" src=\"/library/js/headscripts.js\"></script>\n";
682: String head = headCss + headJs;
683: StringBuilder bodyonload = new StringBuilder();
684: if (p != null) {
685: String element = Web.escapeJavascript("Main" + p.getId());
686: bodyonload.append("setMainFrameHeight('" + element + "');");
687: }
688: bodyonload.append("setFocus(focus_path);");
689:
690: req.setAttribute("sakai.html.head", head);
691: req.setAttribute("sakai.html.head.css", headCss);
692: req.setAttribute("sakai.html.head.css.base", headCssToolBase);
693: req.setAttribute("sakai.html.head.css.skin", headCssToolSkin);
694: req.setAttribute("sakai.html.head.js", headJs);
695: req.setAttribute("sakai.html.body.onload", bodyonload
696: .toString());
697: req.setAttribute(ToolURL.MANAGER, new ToolURLManagerImpl(res));
698:
699: tool.forward(req, res, p, toolContextPath, toolPathInfo);
700: }
701:
702: /**
703: * Output some session information
704: *
705: * @param out
706: * The print writer
707: * @param html
708: * If true, output in HTML, else in text.
709: */
710: protected void showSession(PrintWriter out, boolean html) {
711: // get the current user session information
712: Session s = SessionManager.getCurrentSession();
713: if (s == null) {
714: out.println("no session established");
715: if (html)
716: out.println("<br />");
717: } else {
718: out.println("session: "
719: + s.getId()
720: + " user id: "
721: + s.getUserId()
722: + " enterprise id: "
723: + s.getUserEid()
724: + " started: "
725: + DateFormat.getDateInstance().format(
726: new Date(s.getCreationTime()))
727: + " accessed: "
728: + DateFormat.getDateInstance().format(
729: new Date(s.getLastAccessedTime()))
730: + " inactive after: " + s.getMaxInactiveInterval());
731: if (html)
732: out.println("<br />");
733: }
734:
735: ToolSession ts = SessionManager.getCurrentToolSession();
736: if (ts == null) {
737: out.println("no tool session established");
738: if (html)
739: out.println("<br />");
740: } else {
741: out.println("tool session: "
742: + ts.getId()
743: + " started: "
744: + DateFormat.getDateInstance().format(
745: new Date(ts.getCreationTime()))
746: + " accessed: "
747: + DateFormat.getDateInstance().format(
748: new Date(ts.getLastAccessedTime())));
749: if (html)
750: out.println("<br />");
751: }
752: }
753:
754: /**
755: * Format the tool's configuration parameters
756: *
757: * @param t
758: * The tool.
759: * @return The tool's configuration parameters, formatted for HTML display.
760: */
761: protected String printConfiguration(Properties config) {
762: StringBuilder buf = new StringBuilder();
763: boolean first = true;
764: for (Enumeration names = config.propertyNames(); names
765: .hasMoreElements();) {
766: if (!first) {
767: buf.append("<br />");
768: }
769: first = false;
770:
771: String name = (String) names.nextElement();
772: String value = config.getProperty(name);
773: buf.append(name);
774: buf.append("=");
775: buf.append(value);
776: }
777:
778: return buf.toString();
779: }
780:
781: /**
782: * Format the tool's categories
783: *
784: * @param categories
785: * The categories set.
786: * @return The tool's categories, formatted for HTML display.
787: */
788: protected String printCategories(Set categories) {
789: StringBuilder buf = new StringBuilder();
790: boolean first = true;
791: for (Iterator i = categories.iterator(); i.hasNext();) {
792: if (!first) {
793: buf.append("<br />");
794: }
795: first = false;
796:
797: buf.append((String) i.next());
798: }
799:
800: return buf.toString();
801: }
802:
803: /**
804: * Format the tool's keywords
805: *
806: * @param keywords
807: * The keywords set.
808: * @return The tool's keywords, formatted for HTML display.
809: */
810: protected String printKeywords(Set keywords) {
811: StringBuilder buf = new StringBuilder();
812: boolean first = true;
813: for (Iterator i = keywords.iterator(); i.hasNext();) {
814: if (!first) {
815: buf.append("<br />");
816: }
817: first = false;
818:
819: buf.append((String) i.next());
820: }
821:
822: return buf.toString();
823: }
824: }
|