001: /* *****************************************************************************
002: * Application.java
003: * ****************************************************************************/
004:
005: /* J_LZ_COPYRIGHT_BEGIN *******************************************************
006: * Copyright 2001-2004 Laszlo Systems, Inc. All Rights Reserved. *
007: * Use is subject to license terms. *
008: * J_LZ_COPYRIGHT_END *********************************************************/
009:
010: package org.openlaszlo.connection;
011:
012: import java.io.*;
013: import java.util.*;
014: import javax.servlet.http.*;
015: import javax.servlet.*;
016: import org.openlaszlo.auth.*;
017: import org.openlaszlo.utils.*;
018: import org.apache.log4j.*;
019:
020: public class Application {
021: private static final int RANGE_ALL = 0;
022: private static final int RANGE_USER = 1;
023: private static final int RANGE_AGENT = 2;
024:
025: private static Hashtable mApplications = new Hashtable();
026: static private Logger mLogger = Logger.getLogger(Application.class);
027:
028: static public Application getApplication(String name) {
029: return getApplication(name, true);
030: }
031:
032: synchronized static public Application getApplication(String name,
033: boolean create) {
034: Application application = (Application) mApplications.get(name);
035: if (application == null && create) {
036: application = new Application(name);
037: mApplications.put(name, application);
038: }
039: return application;
040: }
041:
042: synchronized static public void removeApplication(
043: Application application) {
044: ConnectionGroup group = application.getConnectionGroup();
045: if (group != null) {
046: group.unregisterApplication(application);
047: }
048: mApplications.remove(application);
049: }
050:
051: private String mName;
052: private long mLastModifiedTime = 0;
053: private long mHeartbeat = 0;
054: private Authentication mAuthenticator = null;
055: private boolean mSendUserDisconnect = false;
056: private ConnectionGroup mGroup = null;
057:
058: /** Username lookup */
059: private MultiMap mUsers = new MultiMap();
060:
061: /** Connections */
062: private Hashtable mConnections = new Hashtable();
063:
064: /** Agents */
065: private Hashtable mAgents = new Hashtable();
066:
067: private Application(String name) {
068: mName = name;
069: }
070:
071: public String getName() {
072: return mName;
073: }
074:
075: public long getLastModifiedTime() {
076: return mLastModifiedTime;
077: }
078:
079: public void setLastModifiedTime(long lmt) {
080: mLastModifiedTime = lmt;
081: }
082:
083: public long getHeartbeat() {
084: return mHeartbeat;
085: }
086:
087: public void setHeartbeat(long heartbeat) {
088: mHeartbeat = heartbeat;
089: }
090:
091: public Authentication getAuthenticator() {
092: return mAuthenticator;
093: }
094:
095: public void setAuthenticator(Authentication authenticator) {
096: mAuthenticator = authenticator;
097: }
098:
099: public boolean doSendUserDisconnect() {
100: return mSendUserDisconnect;
101: }
102:
103: public void setSendUserDisconnect(boolean sud) {
104: mSendUserDisconnect = sud;
105: }
106:
107: public ConnectionGroup getConnectionGroup() {
108: return mGroup;
109: }
110:
111: public void setConnectionGroup(ConnectionGroup group) {
112: if (mGroup != null) {
113: mGroup.unregisterApplication(this );
114: }
115: group.registerApplication(this );
116: mGroup = group;
117: }
118:
119: //------------------------------------------------------------
120: // Application wrappers for connection group method calls.
121: //------------------------------------------------------------
122: private void checkGroup() {
123: if (mGroup == null)
124: throw new RuntimeException(
125: /* (non-Javadoc)
126: * @i18n.test
127: * @org-mes="connection group not set"
128: */
129: org.openlaszlo.i18n.LaszloMessages.getMessage(
130: Application.class.getName(), "051018-131"));
131: }
132:
133: public void register(HTTPConnection connection) {
134: synchronized (mUsers) {
135: mUsers.put(connection.getUsername(), connection);
136: mConnections.put(connection.getCID(), connection);
137: }
138: }
139:
140: public void unregister(HTTPConnection connection) {
141: synchronized (mUsers) {
142: mUsers.remove(connection.getUsername(), connection);
143: mConnections.remove(connection.getCID());
144: }
145: }
146:
147: public void setAgents(Set agentSet) {
148: mAgents = new Hashtable();
149: if (agentSet != null) {
150: synchronized (mAgents) {
151: Iterator iter = agentSet.iterator();
152: while (iter.hasNext()) {
153: ConnectionAgent agent = ConnectionAgent
154: .getAgent((String) iter.next());
155: mAgents.put(agent.getURL(), agent);
156: }
157: }
158: }
159: }
160:
161: /**
162: * Send message to a list of users
163: * @param userList list of users to send message or '*' for everyone on the system
164: * @param mesg message to send
165: * @return number of messages sent
166: */
167: public int sendMessage(String users, String mesg, String range,
168: StringBuffer xmlResult) {
169: mLogger.debug(
170: /* (non-Javadoc)
171: * @i18n.test
172: * @org-mes="sendMessage(users=" + p[0] + ",range=" + p[1] + ",mesg=" + p[2] + ")"
173: */
174: org.openlaszlo.i18n.LaszloMessages.getMessage(Application.class
175: .getName(), "051018-179", new Object[] { users, range,
176: mesg }));
177:
178: if (users == null || users.equals(""))
179: return 0;
180:
181: int r = RANGE_ALL;
182: if (range == null || range.equals("")) {
183: r = RANGE_ALL;
184: } else if (range.equals("user")) {
185: r = RANGE_USER;
186: } else if (range.equals("agent")) {
187: r = RANGE_AGENT;
188: }
189:
190: if (users.equals("*")) {
191: return sendAllMessage(mesg, r, xmlResult);
192: }
193:
194: int count = 0;
195: StringTokenizer st = new StringTokenizer(users, ", ");
196: while (st.hasMoreTokens()) {
197: String username = (String) st.nextToken();
198:
199: if (r == RANGE_ALL || r == RANGE_USER) {
200: synchronized (mUsers) {
201: Set usernameSet = (Set) mUsers.get(username);
202: if (usernameSet != null) {
203: Iterator iter = usernameSet.iterator();
204:
205: while (iter.hasNext()) {
206: HTTPConnection connection = (HTTPConnection) iter
207: .next();
208: try {
209: mLogger
210: .debug(
211: /* (non-Javadoc)
212: * @i18n.test
213: * @org-mes="send to " + p[0]
214: */
215: org.openlaszlo.i18n.LaszloMessages
216: .getMessage(
217: Application.class
218: .getName(),
219: "051018-218",
220: new Object[] { connection
221: .getUsername() }));
222: connection.send(mesg);
223: ++count;
224: } catch (IOException e) {
225: mLogger
226: .debug(
227: /* (non-Javadoc)
228: * @i18n.test
229: * @org-mes="user " + p[0] + " not connected"
230: */
231: org.openlaszlo.i18n.LaszloMessages
232: .getMessage(
233: Application.class
234: .getName(),
235: "051018-229",
236: new Object[] { connection
237: .getUsername() }));
238: iter.remove();
239: }
240: }
241:
242: if (usernameSet.size() == 0)
243: mUsers.remove(username);
244: }
245: }
246: }
247:
248: if (r == RANGE_ALL || r == RANGE_AGENT) {
249: ConnectionAgent agent = null;
250: try {
251: synchronized (mAgents) {
252: agent = (ConnectionAgent) mAgents.get(username);
253: }
254: if (agent != null) {
255: if (xmlResult != null) {
256: StringBuffer tmp = new StringBuffer(
257: "<agent url=\"" + agent.getURL()
258: + "\" >");
259: tmp.append(agent.send(mesg));
260: tmp.append("</agent>");
261: xmlResult.append(tmp.toString());
262: } else {
263: agent.send(mesg);
264: }
265: ++count;
266: }
267: } catch (IOException e) {
268: mLogger.warn(
269: /* (non-Javadoc)
270: * @i18n.test
271: * @org-mes="IOException: agent " + p[0]
272: */
273: org.openlaszlo.i18n.LaszloMessages.getMessage(
274: Application.class.getName(), "051018-266",
275: new Object[] { agent.getURL() }));
276: }
277: }
278:
279: }
280: return count;
281: }
282:
283: private int sendAllMessage(String mesg, int range,
284: StringBuffer xmlResult) {
285: int count = 0;
286: Iterator iter;
287:
288: if (range == RANGE_ALL || range == RANGE_USER) {
289: synchronized (mUsers) {
290: iter = mConnections.entrySet().iterator();
291: while (iter.hasNext()) {
292: Map.Entry entry = (Map.Entry) iter.next();
293: HTTPConnection connection = (HTTPConnection) entry
294: .getValue();
295: try {
296: connection.send(mesg);
297: ++count;
298: mLogger.debug(
299: /* (non-Javadoc)
300: * @i18n.test
301: * @org-mes=p[0] + " sent message"
302: */
303: org.openlaszlo.i18n.LaszloMessages.getMessage(
304: Application.class.getName(),
305: "051018-295", new Object[] { connection
306: .getUsername() }));
307: } catch (IOException e) {
308: iter.remove();
309: mLogger.debug(
310: /* (non-Javadoc)
311: * @i18n.test
312: * @org-mes=p[0] + " not connected"
313: */
314: org.openlaszlo.i18n.LaszloMessages.getMessage(
315: Application.class.getName(),
316: "051018-305", new Object[] { connection
317: .getUsername() }));
318: }
319: }
320: }
321: }
322:
323: if (range == RANGE_ALL || range == RANGE_AGENT) {
324: synchronized (mAgents) {
325: iter = mAgents.entrySet().iterator();
326: while (iter.hasNext()) {
327: Map.Entry entry = (Map.Entry) iter.next();
328: ConnectionAgent agent = (ConnectionAgent) entry
329: .getValue();
330: try {
331: if (xmlResult != null) {
332: String result = agent.send(mesg);
333: StringBuffer tmp = new StringBuffer(
334: "<agent url=\"" + agent.getURL()
335: + "\" >");
336: tmp.append(result);
337: tmp.append("</agent>");
338: xmlResult.append(tmp.toString());
339: } else {
340: agent.send(mesg);
341: }
342: ++count;
343: } catch (IOException e) {
344: mLogger.warn(
345: /* (non-Javadoc)
346: * @i18n.test
347: * @org-mes="IOException: agent " + p[0]
348: */
349: org.openlaszlo.i18n.LaszloMessages.getMessage(
350: Application.class.getName(),
351: "051018-337", new Object[] { agent
352: .getURL() }));
353: }
354: }
355: }
356: }
357:
358: if (xmlResult != null) {
359: xmlResult.insert(0, "<send count=\"" + count + "\" >");
360: xmlResult.append("</send>");
361: }
362:
363: return count;
364: }
365:
366: /**
367: * Return an xml string list of connected users. Agents are not considered
368: * users.
369: */
370: public Set list(String users) {
371: synchronized (mUsers) {
372: Set set = new HashSet();
373: mLogger.debug(
374: /* (non-Javadoc)
375: * @i18n.test
376: * @org-mes="list(users=" + p[0] + ")"
377: */
378: org.openlaszlo.i18n.LaszloMessages.getMessage(
379: Application.class.getName(), "051018-366",
380: new Object[] { users }));
381:
382: if (users.equals("*")) {
383: Iterator iter = mUsers.keySet().iterator();
384: while (iter.hasNext()) {
385: set.add((String) iter.next());
386: }
387: } else {
388: StringTokenizer st = new StringTokenizer(users, ", ");
389: while (st.hasMoreTokens()) {
390: String username = (String) st.nextToken();
391: if (mUsers.containsKey(username))
392: set.add(username);
393: }
394: }
395: return set;
396: }
397: }
398:
399: public HTTPConnection getConnection(String cid) {
400: synchronized (mUsers) {
401: if (cid == null || cid.equals(""))
402: return null;
403: return (HTTPConnection) mConnections.get(cid);
404: }
405: }
406:
407: //----------------------------------------------------------------------
408: // Info functions
409: //----------------------------------------------------------------------
410:
411: synchronized static public void dumpApplicationsXML(
412: StringBuffer buf, boolean details) {
413: Set s = mApplications.entrySet();
414: Iterator iter = s.iterator();
415: buf.append("<applications>");
416: while (iter.hasNext()) {
417: Map.Entry e = (Map.Entry) iter.next();
418: Application app = (Application) e.getValue();
419: app.dumpXML(buf, details);
420: }
421: buf.append("</applications>");
422: }
423:
424: public void dumpXML(StringBuffer buf, boolean details) {
425: Authentication a = mAuthenticator;
426: ConnectionGroup g = mGroup;
427: buf.append("<application ").append(" name=\"").append(mName)
428: .append("\"").append(" group=\"").append(
429: (g != null ? g.getName() : "none"))
430: .append("\"").append(" heartbeat=\"")
431: .append(mHeartbeat).append("\"").append(
432: " authenticator=\"").append(
433: (a != null ? a.getClass().toString() : "none"))
434: .append("\"").append(" senduserdisconnect=\"").append(
435: mSendUserDisconnect).append("\"").append(" >");
436: // dumpUsersXML(buf, details);
437: dumpConnectionsXML(buf, details);
438: dumpAgentsXML(buf, details);
439: buf.append("</application>");
440: }
441:
442: public void dumpConnectionsXML(StringBuffer buf, boolean details) {
443: synchronized (mUsers) {
444: dumpTableXML("connection", mConnections, buf, details);
445: }
446: }
447:
448: public void dumpAgentsXML(StringBuffer buf, boolean details) {
449: synchronized (mAgents) {
450: dumpTableXML("agent", mAgents, buf, details);
451: }
452: }
453:
454: public void dumpUsersXML(StringBuffer buf, boolean details) {
455: synchronized (mUsers) {
456: dumpMultiTableXML("user", mUsers, buf, details);
457: }
458: }
459:
460: public static void dumpMultiTableXML(String table, Map map,
461: StringBuffer buf, boolean details) {
462: Set s = map.entrySet();
463: Iterator iter = s.iterator();
464: buf.append("<").append(table).append("-table>");
465: while (iter.hasNext()) {
466: Map.Entry e = (Map.Entry) iter.next();
467: String k = (String) e.getKey();
468: if (details) {
469: buf.append("<" + table + " name=\"" + k + "\">");
470: Set set = (Set) e.getValue();
471: Iterator iter1 = set.iterator();
472: while (iter1.hasNext()) {
473: Object o = iter1.next();
474: buf.append(o.toString());
475: }
476: buf.append("</" + table + ">\n");
477: } else {
478: buf.append("<" + table + " name=\"").append(k).append(
479: "\" />\n");
480: }
481:
482: }
483: buf.append("</").append(table).append("-table>\n");
484: }
485:
486: public static void dumpTableXML(String table, Map map,
487: StringBuffer buf, boolean details) {
488: Set s = map.entrySet();
489: Iterator iter = s.iterator();
490: buf.append("<").append(table).append("-table>");
491: while (iter.hasNext()) {
492: Map.Entry e = (Map.Entry) iter.next();
493: String k = (String) e.getKey();
494: if (details) {
495: Object v = e.getValue();
496: buf.append(v.toString());
497: } else {
498: buf.append("<" + table + " name=\"").append(k).append(
499: "\" />");
500: }
501:
502: }
503: buf.append("</").append(table).append("-table>\n");
504: }
505: }
|