001: /**
002: * Andy John
003: * 2/99
004: * chat room
005: * andy@enhydra.org
006: * www.enhydra.org
007: *
008: * This is a "by hand" presentation object (Enhydra Jolt was not used).
009: * This is because there is so much java code and so little static HTML that
010: * it is easier to write it by hand.
011: * This page and the Discussion business object are the core of the
012: * "on hold push" algorithm (see the Discussion object). The browser has
013: * asked for a snapshot. They may have sent in a state id. If so, then they
014: * already have something on their screen, and they are really asking for
015: * something new. This state id (or 0 if none was sent), is passed on to
016: * the Discussion object when we ask for a snapshot. It uses it to (maybe)
017: * block (not return) until there is some new state (a message has been
018: * added or deleted from the list).
019: * The browser also probably specified a time limit it is willing to wait.
020: * The browser will time out before TCP/IP will, so we use a one minute
021: * timeout. If the browser times out, it breaks the reload cycle, and the
022: * user stops seeing messages.
023: * Becuase the call to the Discussion object might block for up to a
024: * minute, there may be several threads waiting around in this object.
025: */package chat.presentation;
026:
027: import java.util.Vector;
028: import com.lutris.appserver.server.httpPresentation.*;
029: import chat.ChatApplication;
030: import chat.spec.*;
031:
032: /**
033: * Because this page has alot more code than html content, and because
034: * so much of the page is generated in Java anyway, I chose to write this
035: * presentation object by hand, ranther than using Jolt.
036: */
037: public class ContentsPresentation implements HttpPresentation {
038:
039: /*
040: * How long can we make the browsers wait till they time out.
041: * This is a conservative guess (one minute).
042: */
043: private static final int refreshWait = 60;
044:
045: /*
046: * This is used with the "unique" query string parameter. It is a
047: * psued-hack to make every page look unique. Otherwise sometimes the
048: * browser will think that a request looks like an old one and try
049: * to slip you results from the cache. By using the counter, each
050: * request is guarenteed to look unique. The actual value is not
051: * used by the program.
052: */
053: private static long counter = 0;
054:
055: /**
056: * The main body of a presentation object. See the class comments above.
057: */
058: public void run(HttpPresentationComms comms) throws Exception {
059: // Try to get the current state, default to zero.
060: long state = 0;
061: try {
062: String stateStr = comms.request.getParameter("state");
063: if (stateStr != null)
064: state = Long.parseLong(stateStr);
065: } catch (Exception e) {
066: }
067: // Try to get the wait timeout. Default to zero.
068: long wait = 0;
069: try {
070: String waitStr = comms.request.getParameter("wait");
071: if (waitStr != null)
072: wait = Long.parseLong(waitStr);
073: } catch (Exception e) {
074: }
075: /*
076: * Get a snapshot! This may take up to wait seconds.
077: */
078:
079: DiscussionManager discussionManager = DiscussionManagerFactory
080: .getDiscussionManager("chat.business.DiscussionManagerImpl");
081:
082: /*
083: * Start writing out the page.
084: */
085: ChatApplication myApp = (ChatApplication) comms.application;
086:
087: comms.response.setContentType("text/html");
088: comms.response.setHeader("Expires",
089: "Tue, 01 Jan 1980 1:00:00 GMT");
090: comms.response.setHeader("Pragma", "no-cache");
091: HttpPresentationOutputStream out = comms.response
092: .getOutputStream();
093:
094: out.println("<HTML>");
095: out.println("<HEAD></HEAD>");
096: out.println("<BODY onload=\"loadOn();\" BGCOLOR="
097: + myApp.getBgColor() + ">");
098: out.println("<h3><center><font color=purple>"
099: + myApp.getRoomName() + "</font></center></h3>");
100:
101: /*
102: * Catch Null pointer exception ( we canot make a instances of classes from business layer when we run chat_pres )
103: * We need to allow chat_pres to be functional , so if the requested url is /chat_pres/..... the response
104: * will be default HTML page
105: */
106:
107: try {
108: Snapshot snap = discussionManager.getContents(state, wait);
109:
110: if ((snap.getContents() == null)
111: || (snap.getContents().size() == 0)) {
112: out
113: .println("<center><i><br><br><br><font color=purple><b>"
114: + "There are currently no messages."
115: + "</b></font></i></center>\n");
116: } else {
117: for (int i = snap.getContents().size() - 1; i >= 0; i--) {
118: /*
119: * I used to display the messages in the "normal" order,
120: * but ran into browser incompatabilites with scrolling,
121: * named anchors, meta refresh tags etc...
122: * This way it works on all browsers (which is a good
123: * thing for a demo).
124: */
125:
126: Message msg = (Message) snap.getContents()
127: .elementAt(i);
128:
129: if (msg == null)
130: continue;
131: out.print("<b>");
132: if ((msg.getHtmlName() == null)
133: || (msg.getHtmlName().length() == 0))
134: out.print("<i>Anonymous</i>");
135: else
136: out.print(msg.getHtmlName());
137: out.print(":</b> ");
138: if (msg.getHtmlChunks().size() > 1)
139: out.print("<br>\n ");
140: for (int j = 0; j < ((Vector) msg.getHtmlChunks())
141: .size(); j++) {
142: if (j != 0)
143: out.print(" ");
144: out.print((String) ((Vector) msg
145: .getHtmlChunks()).elementAt(j));
146: out.println("<br>");
147: }
148: }
149: }
150:
151: /*
152: * A key part of the "on hold push" algorithm is that the client
153: * asks for a new snapshot as soon as it is done processing the
154: * current snapshot. This synamic Javascript triggers the browser to
155: * reload, passing on the current state id.
156: * I used to use a refresh HTTP header, but IE has problems with
157: * that when you add a query string.
158: */
159:
160: out
161: .println("<SCRIPT TYPE=\"text/javascript\" LANGUAGE=\"JavaScript\" id=\"RealScript\">\n"
162: + "<!--\n"
163: + " function loadOn() {\n"
164: + " window.location.href = \"ContentsPresentation.po?state="
165: + snap.getState()
166: + "&wait="
167: + refreshWait
168: + "&uniqe="
169: + counter
170: + "\"\n"
171: + " }\n"
172: + "//-->\n" + "</SCRIPT>");
173:
174: } catch (NullPointerException e) {
175: }
176: /*
177: * Close out the page.
178: */
179: out.println("</BODY>");
180: out.println("</HTML>");
181: }
182:
183: }
|