001: /*
002: * Copyright 2001-2006 C:1 Financial Services GmbH
003: *
004: * This software is free software; you can redistribute it and/or
005: * modify it under the terms of the GNU Lesser General Public
006: * License Version 2.1, as published by the Free Software Foundation.
007: *
008: * This software is distributed in the hope that it will be useful,
009: * but WITHOUT ANY WARRANTY; without even the implied warranty of
010: * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
011: * Lesser General Public License for more details.
012: *
013: * You should have received a copy of the GNU Lesser General Public
014: * License along with this library; if not, write to the Free Software
015: * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307, USA
016: */
017:
018: package de.finix.contelligent.client.remote;
019:
020: import java.util.logging.Level;
021: import java.util.logging.Logger;
022: import java.util.prefs.PreferenceChangeEvent;
023: import java.util.prefs.PreferenceChangeListener;
024:
025: import javax.swing.JOptionPane;
026: import javax.swing.SwingUtilities;
027:
028: import org.w3c.dom.Element;
029: import org.w3c.dom.Node;
030: import org.w3c.dom.NodeList;
031:
032: import de.finix.contelligent.client.ContelligentClient;
033: import de.finix.contelligent.client.base.ComponentFactory;
034: import de.finix.contelligent.client.base.ComponentPath;
035: import de.finix.contelligent.client.base.ConfigurationManager;
036: import de.finix.contelligent.client.base.ContelligentException;
037: import de.finix.contelligent.client.base.Session;
038: import de.finix.contelligent.client.base.TypeFactory;
039: import de.finix.contelligent.client.base.UserManager;
040: import de.finix.contelligent.client.event.ConfigurationEvent;
041: import de.finix.contelligent.client.event.ContelligentComponentDisplayEvent;
042: import de.finix.contelligent.client.event.ContelligentComponentEvent;
043: import de.finix.contelligent.client.event.ContelligentEvent;
044: import de.finix.contelligent.client.event.ContelligentLockEvent;
045: import de.finix.contelligent.client.event.ContextEvent;
046: import de.finix.contelligent.client.event.LogEvent;
047: import de.finix.contelligent.client.event.LoginEvent;
048: import de.finix.contelligent.client.event.LogoutEvent;
049: import de.finix.contelligent.client.event.MessageEvent;
050: import de.finix.contelligent.client.event.ServerEvent;
051: import de.finix.contelligent.client.event.SessionTimeoutEvent;
052: import de.finix.contelligent.client.event.TypeEvent;
053: import de.finix.contelligent.client.i18n.Resources;
054: import de.finix.contelligent.client.modules.preferences.PreferencesModule;
055: import de.finix.contelligent.client.util.xml.XMLUtil;
056:
057: /**
058: * This class is used to periodically pull related component events by calling
059: * the
060: * {@link de.finix.contelligent.base.component.PullComponentSystemEventsAction}.
061: */
062: public class UpdateManager {
063:
064: private static Logger logger = Logger.getLogger(UpdateManager.class
065: .getName());
066:
067: private java.util.Timer updateTimer = null;
068:
069: public final static String EVENT = "Event";
070:
071: public final static String EVENT_TYPE = "Type";
072:
073: public final static String EVENT_SERVER = "Server";
074:
075: public final static String EVENT_DOMAIN = "domain";
076:
077: public final static String EVENT_TARGET = "Target";
078:
079: public final static String EVENT_OWNER = "owner";
080:
081: public final static String EVENT_OWNERPRINCIPAL = "ownerPrincipal";
082:
083: public final static String EVENT_TIMESTAMP = "timestamp";
084:
085: public final static String EVENT_USER = "user";
086:
087: public final static String EVENT_HOST = "host";
088:
089: public final static String EVENT_MESSAGE = "message";
090:
091: public final static String EVENT_IMPORTANCE = "importance";
092:
093: public final static String EVENT_MESSAGE_TYPE = "message-type";
094:
095: public final static String EVENT_NAME = "name";
096:
097: public final static String EVENT_SESSION = "session";
098:
099: public final static String EVENT_TYPE_NAME = "component-type";
100:
101: public final static String EVENT_PRINCIPAL = "principals";
102:
103: public final static String EVENT_TASKID = "taskId";
104:
105: public final static String EVENT_WFID = "wfId";
106:
107: public final static String EVENT_CM = "cm";
108:
109: public final static String EVENT_SHARED_LOCK = "shared";
110:
111: public final static String EVENT_USERGROUP = "usergroup";
112:
113: public final static String EVENT_ROLEGROUP = "rolegroup";
114:
115: public final static String EVENT_LOGLEVEL = "logLevel";
116:
117: public final static String EVENT_CALLERCLASS = "callerClass";
118:
119: public final static String EVENT_CALLERMETHOD = "callerMethod";
120:
121: public final static String EVENT_CALLERLINE = "callerLine";
122:
123: public final static String EVENT_CALLERFILE = "callerFile";
124:
125: public final static String EVENT_THROWABLE = "throwable";
126:
127: public final static String EVENT_STACKTRACE = "stackTrace";
128:
129: public final static String EVENT_ORIGINTYPE = "originType";
130:
131: // these are the codes for all server generated events
132: private final static int COMPONENT_CHANGE_EVENT = 65;
133:
134: private final static int COMPONENT_REMOVE_EVENT = 66;
135:
136: private final static int COMPONENT_ADD_EVENT = 67;
137:
138: private final static int COMPONENT_LOCK_EVENT = 68;
139:
140: private final static int COMPONENT_UNLOCK_EVENT = 69;
141:
142: private final static int CURRENT_PAGE_EVENT = 70;
143:
144: private final static int CONTEXT_CREATED_EVENT = 71;
145:
146: private final static int CONTEXT_DISCARDED_EVENT = 72;
147:
148: private final static int MESSAGE_EVENT = 73;
149:
150: private final static int LOGIN_EVENT = 74;
151:
152: private final static int LOGOUT_EVENT = 75;
153:
154: private final static int TYPE_CREATED_EVENT = 76;
155:
156: private final static int TASK_ADD_EVENT = 77;
157:
158: private final static int TASK_REMOVE_EVENT = 78;
159:
160: private final static int TYPE_CHANGED_EVENT = 79;
161:
162: private final static int TYPE_DELETED_EVENT = 80;
163:
164: private final static int CONTEXT_SWITCHED_EVENT = 81;
165:
166: private final static int WF_DEFINITION_CHANGED = 82;
167:
168: private final static int COMPONENT_EDIT_EVENT = 83;
169:
170: private final static int CONFIGURATION_ADDED = 84;
171:
172: private final static int CONFIGURATION_CHANGED = 85;
173:
174: private final static int CONFIGURATION_REMOVED = 86;
175:
176: private final static int CLIENT_EVENT_MASK = 64;
177:
178: private final static int PRINCIPALGROUP_EVENT_MASK = 128;
179:
180: private final static int SESSION_TIMEOUT_EVENT = (23 | CLIENT_EVENT_MASK);
181:
182: private final static int LOG_EVENT = (24 | CLIENT_EVENT_MASK);
183:
184: private final static int PRINCIPALGROUP_CREATE_EVENT = (1 | CLIENT_EVENT_MASK | PRINCIPALGROUP_EVENT_MASK);
185:
186: private final static int PRINCIPALGROUP_CHANGE_EVENT = (2 | CLIENT_EVENT_MASK | PRINCIPALGROUP_EVENT_MASK);
187:
188: private final static int PRINCIPALGROUP_REMOVE_EVENT = (3 | CLIENT_EVENT_MASK | PRINCIPALGROUP_EVENT_MASK);
189:
190: public final static int UPDATE_MODE_NONE = 0;
191:
192: public final static int UPDATE_MODE_PUSH = 1;
193:
194: public final static int UPDATE_MODE_POLL = 2;
195:
196: private int updateMode;
197:
198: /**
199: * How many seconds do we allow the update to be late until we decide to
200: * skip it.
201: */
202: /*
203: * Updates can be delayed and bunched up when the server is realy slow. Do
204: * not allow too many updates, as the event-dispatch thread hangs as well,
205: * when actions are performed
206: */
207: private final static int MAX_TARDINESS_SECS = 1;
208:
209: // give server this many seconds before checking if it actually has
210: // connected us
211: private final static int MAX_WAIT_BEFORE_NOTIFY_SECS = 5;
212:
213: private static UpdateManager instance = null;
214:
215: private boolean pushUpdateStarted = false;
216:
217: private boolean pollUpdateStarted = false;
218:
219: private int updateInterval;
220:
221: private int port;
222:
223: private boolean keepAlive;
224:
225: private boolean pushTried = false;
226:
227: private boolean isStarted = false;
228:
229: public final static void handleComponentEvents(NodeList events,
230: final Object source) {
231: for (int i = 0; i < events.getLength(); i++) {
232: final Node event = events.item(i);
233: try {
234: final int type = Integer.parseInt(XMLUtil
235: .getElementValue((Element) event,
236: UpdateManager.EVENT_TYPE));
237: SwingUtilities.invokeLater(new Runnable() {
238: public void run() {
239: try {
240: UpdateManager.generateComponentEvent(type,
241: event, source);
242: } catch (EventParserException parserException) {
243: logger.log(Level.SEVERE,
244: "Could not generate event",
245: parserException);
246: }
247: }
248: });
249: } catch (ClassCastException cce) {
250: logger.log(Level.SEVERE,
251: "Illegal event data format. Event ignored!",
252: cce);
253: break;
254: } catch (NumberFormatException nfe) {
255: logger.log(Level.SEVERE, "Element '"
256: + UpdateManager.EVENT_TYPE
257: + "' is not an int. Event ignored!", nfe);
258: break;
259: }
260: }
261: }
262:
263: public final static void generateComponentEvent(int type,
264: Node eventNode, Object source) throws EventParserException {
265: ContelligentEvent event = null;
266: boolean alreadySentToSessions = false;
267:
268: if (type == COMPONENT_ADD_EVENT) {
269: event = new ContelligentComponentEvent(source,
270: ComponentPath.toComponentPath(getEventAttribute(
271: eventNode, UpdateManager.EVENT_TARGET)),
272: ContelligentComponentEvent.COMPONENT_ADDED);
273: ComponentFactory.getInstance().fireComponentAddEvent(
274: (ContelligentComponentEvent) event);
275: } else if (type == COMPONENT_CHANGE_EVENT) {
276: event = new ContelligentComponentEvent(source,
277: ComponentPath.toComponentPath(getEventAttribute(
278: eventNode, UpdateManager.EVENT_TARGET)),
279: ContelligentComponentEvent.COMPONENT_CHANGED);
280: ComponentFactory.getInstance().fireComponentChangeEvent(
281: (ContelligentComponentEvent) event);
282: } else if (type == COMPONENT_REMOVE_EVENT) {
283: event = new ContelligentComponentEvent(source,
284: ComponentPath.toComponentPath(getEventAttribute(
285: eventNode, UpdateManager.EVENT_TARGET)),
286: ContelligentComponentEvent.COMPONENT_REMOVED);
287: ComponentFactory.getInstance().fireComponentRemoveEvent(
288: (ContelligentComponentEvent) event);
289:
290: } else if (type == COMPONENT_LOCK_EVENT
291: || type == COMPONENT_UNLOCK_EVENT) {
292: try {
293: long timestamp = Long.parseLong(getEventAttribute(
294: eventNode, UpdateManager.EVENT_TIMESTAMP));
295: String context = getEventAttribute(eventNode,
296: UpdateManager.EVENT_SERVER);
297: if (type == COMPONENT_LOCK_EVENT) {
298: event = new ContelligentLockEvent(
299: source,
300: ComponentPath
301: .toComponentPath(getEventAttribute(
302: eventNode,
303: UpdateManager.EVENT_TARGET)),
304: getEventAttribute(eventNode,
305: UpdateManager.EVENT_OWNER),
306: getEventAttribute(eventNode,
307: UpdateManager.EVENT_OWNERPRINCIPAL),
308: timestamp,
309: context,
310: getEventAttribute(eventNode,
311: UpdateManager.EVENT_WFID),
312: Boolean
313: .valueOf(
314: getEventAttribute(
315: eventNode,
316: UpdateManager.EVENT_SHARED_LOCK))
317: .booleanValue(),
318: ContelligentLockEvent.COMPONENT_LOCKED);
319: ComponentFactory.getInstance()
320: .fireComponentLockEvent(
321: (ContelligentLockEvent) event);
322: } else {
323: event = new ContelligentLockEvent(
324: source,
325: ComponentPath
326: .toComponentPath(getEventAttribute(
327: eventNode,
328: UpdateManager.EVENT_TARGET)),
329: getEventAttribute(eventNode,
330: UpdateManager.EVENT_OWNER),
331: getEventAttribute(eventNode,
332: UpdateManager.EVENT_OWNERPRINCIPAL),
333: timestamp,
334: context,
335: getEventAttribute(eventNode,
336: UpdateManager.EVENT_WFID),
337: Boolean
338: .valueOf(
339: getEventAttribute(
340: eventNode,
341: UpdateManager.EVENT_SHARED_LOCK))
342: .booleanValue(),
343: ContelligentLockEvent.COMPONENT_UNLOCKED);
344: ComponentFactory.getInstance()
345: .fireComponentUnlockEvent(
346: (ContelligentLockEvent) event);
347: }
348: } catch (NumberFormatException nfe) {
349: throw new EventParserException(
350: "Could not parse timestamp!");
351: }
352:
353: } else if (type == CURRENT_PAGE_EVENT) {
354: event = new ContelligentComponentDisplayEvent(
355: source,
356: ComponentPath.toComponentPath(getEventAttribute(
357: eventNode, UpdateManager.EVENT_TARGET)),
358: ContelligentComponentDisplayEvent.COMPONENT_FOLLOW_SERVER);
359: ComponentFactory.getInstance().fireComponentSelectEvent(
360: (ContelligentComponentDisplayEvent) event);
361: } else if (type == COMPONENT_EDIT_EVENT) {
362: event = new ContelligentComponentDisplayEvent(source,
363: ComponentPath.toComponentPath(getEventAttribute(
364: eventNode, UpdateManager.EVENT_TARGET)),
365: ContelligentComponentDisplayEvent.COMPONENT_EDIT);
366: ComponentFactory.getInstance().fireComponentEditEvent(
367: (ContelligentComponentDisplayEvent) event);
368: } else if (type == MESSAGE_EVENT) {
369: String user = getEventAttribute(eventNode,
370: UpdateManager.EVENT_USER);
371: String message = getEventAttribute(eventNode,
372: UpdateManager.EVENT_MESSAGE);
373: String importance = getEventAttribute(eventNode,
374: UpdateManager.EVENT_IMPORTANCE);
375: String messageType = getEventAttribute(eventNode,
376: UpdateManager.EVENT_MESSAGE_TYPE);
377:
378: event = new MessageEvent(source, user, message, importance,
379: messageType);
380: Session.getInstance()
381: .fireMessageEvent((MessageEvent) event);
382: alreadySentToSessions = true;
383:
384: } else if (type == LOGIN_EVENT) {
385: String user = getEventAttribute(eventNode,
386: UpdateManager.EVENT_USER);
387: String host = getEventAttribute(eventNode,
388: UpdateManager.EVENT_HOST);
389: String session = getEventAttribute(eventNode,
390: UpdateManager.EVENT_SESSION);
391:
392: event = new LoginEvent(source, user, host, session);
393: Session.getInstance().fireLoginEvent((LoginEvent) event);
394: alreadySentToSessions = true;
395:
396: } else if (type == LOGOUT_EVENT
397: || type == SESSION_TIMEOUT_EVENT) {
398: String session = getEventAttribute(eventNode,
399: UpdateManager.EVENT_SESSION);
400:
401: if (type == LOGOUT_EVENT) {
402: event = new LogoutEvent(source, session);
403: Session.getInstance().fireLogoutEvent(
404: (LogoutEvent) event);
405: } else if (type == SESSION_TIMEOUT_EVENT) {
406: event = new SessionTimeoutEvent(source, session);
407: Session.getInstance().fireSessionTimeoutEvent(
408: (SessionTimeoutEvent) event);
409: }
410: alreadySentToSessions = true;
411:
412: } else if (type == CONTEXT_CREATED_EVENT) {
413: event = new ContextEvent(source, getEventAttribute(
414: eventNode, EVENT_NAME),
415: ContextEvent.CONTEXT_CREATED);
416: ComponentFactory.getInstance().fireContextCreateEvent(
417: (ContextEvent) event);
418: } else if (type == CONTEXT_DISCARDED_EVENT) {
419: event = new ContextEvent(source, getEventAttribute(
420: eventNode, EVENT_NAME),
421: ContextEvent.CONTEXT_DISCARDED);
422: ComponentFactory.getInstance().fireContextDiscardEvent(
423: (ContextEvent) event);
424: } else if (type == CONTEXT_SWITCHED_EVENT) {
425: String context;
426: try {
427: context = getEventAttribute(eventNode,
428: UpdateManager.EVENT_CM);
429: } catch (EventParserException epe) {
430: context = "";
431: }
432: event = new ContextEvent(source, context,
433: ContextEvent.CONTEXT_SWITCHED);
434: ComponentFactory.getInstance().fireContextSwitchEvent(
435: (ContextEvent) event);
436:
437: } else if (type == TYPE_CREATED_EVENT
438: || type == TYPE_CHANGED_EVENT
439: || type == TYPE_DELETED_EVENT) {
440: String typeName = getEventAttribute(eventNode,
441: UpdateManager.EVENT_TYPE_NAME);
442: if (type == TYPE_CREATED_EVENT) {
443: event = new TypeEvent(source, typeName,
444: TypeEvent.TYPE_CREATED);
445: TypeFactory.getInstance().fireTypeCreateEvent(
446: (TypeEvent) event);
447: } else if (type == TYPE_CHANGED_EVENT) {
448: event = new TypeEvent(source, typeName,
449: TypeEvent.TYPE_CHANGED);
450: TypeFactory.getInstance().fireTypeChangeEvent(
451: (TypeEvent) event);
452: } else {
453: event = new TypeEvent(source, typeName,
454: TypeEvent.TYPE_DELETED);
455: TypeFactory.getInstance().fireTypeDeleteEvent(
456: (TypeEvent) event);
457: }
458: } else if (type == CONFIGURATION_ADDED) {
459: String domain = getEventAttribute(eventNode,
460: UpdateManager.EVENT_DOMAIN);
461: String target = getEventAttribute(eventNode,
462: UpdateManager.EVENT_TARGET);
463: event = new ConfigurationEvent(source, target, domain,
464: ConfigurationEvent.CONFIGURATION_ADDED);
465: ConfigurationManager.getInstance().fireConfigurationEvent(
466: (ConfigurationEvent) event);
467: } else if (type == CONFIGURATION_REMOVED) {
468: String domain = getEventAttribute(eventNode,
469: UpdateManager.EVENT_DOMAIN);
470: String target = getEventAttribute(eventNode,
471: UpdateManager.EVENT_TARGET);
472: event = new ConfigurationEvent(source, target, domain,
473: ConfigurationEvent.CONFIGURATION_REMOVED);
474: ConfigurationManager.getInstance().fireConfigurationEvent(
475: (ConfigurationEvent) event);
476: } else if (type == CONFIGURATION_CHANGED) {
477: String domain = getEventAttribute(eventNode,
478: UpdateManager.EVENT_DOMAIN);
479: String target = getEventAttribute(eventNode,
480: UpdateManager.EVENT_TARGET);
481: event = new ConfigurationEvent(source, target, domain,
482: ConfigurationEvent.CONFIGURATION_CHANGED);
483: ConfigurationManager.getInstance().fireConfigurationEvent(
484: (ConfigurationEvent) event);
485: } else if (type == LOG_EVENT) {
486: String level = getEventAttribute(eventNode,
487: UpdateManager.EVENT_LOGLEVEL);
488: String callerClass = getEventAttribute(eventNode,
489: UpdateManager.EVENT_CALLERCLASS);
490: String callerMethod = getEventAttribute(eventNode,
491: UpdateManager.EVENT_CALLERMETHOD);
492: String callerLine = getEventAttribute(eventNode,
493: UpdateManager.EVENT_CALLERLINE);
494: String callerFile = getEventAttribute(eventNode,
495: UpdateManager.EVENT_CALLERFILE);
496: String timestamp = getEventAttribute(eventNode,
497: UpdateManager.EVENT_TIMESTAMP);
498: String message = getEventAttribute(eventNode,
499: UpdateManager.EVENT_MESSAGE);
500: String originType = getEventAttribute(eventNode,
501: UpdateManager.EVENT_ORIGINTYPE);
502: String throwable = null;
503: try {
504: throwable = getEventAttribute(eventNode,
505: UpdateManager.EVENT_THROWABLE);
506: } catch (EventParserException epe) {
507: // ignore
508: }
509: String stackTrace = null;
510: try {
511: stackTrace = getEventAttribute(eventNode,
512: UpdateManager.EVENT_STACKTRACE);
513: } catch (EventParserException epe) {
514: // ignore
515: }
516: event = new LogEvent(level, callerClass, callerMethod,
517: callerLine, callerFile, timestamp, message,
518: throwable, stackTrace, originType);
519: Session.getInstance().fireLogEvent((LogEvent) event);
520: alreadySentToSessions = true;
521: } else if ((type & PRINCIPALGROUP_EVENT_MASK) != 0) {
522: String groupId = XMLUtil.getElementValue(
523: (Element) eventNode, UpdateManager.EVENT_USERGROUP);
524: if (groupId == null) {
525: groupId = XMLUtil.getElementValue((Element) eventNode,
526: UpdateManager.EVENT_ROLEGROUP);
527: try {
528: UserManager.getInstance().reloadRoleGroup(groupId);
529: } catch (RemoteActionException rae) {
530: logger.log(Level.WARNING,
531: "Could not reload role group data", rae);
532: }
533: } else {
534: try {
535: UserManager.getInstance().reloadUserGroup(groupId);
536: } catch (RemoteActionException rae) {
537: logger.log(Level.WARNING,
538: "Could not reload user group data", rae);
539: }
540: }
541: } else {
542: throw new EventParserException("Unknown type: " + type);
543: }
544:
545: // XXX design flaw forces me to check if this has already been sent to
546: // Session.
547: // Otherwise this may result in events dispatched twice, as type of
548: // event stays the same
549: //
550: if (event != null && !alreadySentToSessions) {
551: Session.getInstance().fireRawEvent(event);
552: }
553: }
554:
555: private final static String getEventAttribute(Node node,
556: String nodeName) throws EventParserException {
557: String attributeValue = XMLUtil.getElementValue((Element) node,
558: nodeName);
559: if (attributeValue == null) {
560: throw new EventParserException("Could not find attribute '"
561: + nodeName + "' for event!");
562: }
563: return attributeValue;
564: }
565:
566: /**
567: * Gets the singleton instance. If it has been killed before you will always
568: * get null
569: */
570: public static UpdateManager getInstance() {
571: if (instance == null) {
572: instance = new UpdateManager();
573: }
574: return instance;
575: }
576:
577: public static void dropInstance() {
578: if (instance != null) {
579: instance.stop();
580: instance = null;
581: }
582: }
583:
584: public static void clearAllEventDispatchers() {
585: Session.getInstance().clear();
586: ComponentFactory.getInstance().clear();
587: TypeFactory.getInstance().clear();
588: }
589:
590: /**
591: * If you want to use push mode, you will have to call this before start().
592: * <em>IMPORTANT</em>: Between this call and the call to start you must
593: * have logged into server
594: */
595: public void tryPush() {
596: if (getUpdateMode() == UPDATE_MODE_PUSH) {
597: startPushUpdate();
598: pushTried = true;
599: }
600: }
601:
602: /** Start update. Can only be called once prior to {@link #stop}. */
603: public void start() {
604: if (!isStarted) {
605: // if a push has been tried, let's see if it was successful
606: if (pushTried) {
607: UpdateThread ut = UpdateThread.getInstance();
608: if (ut != null) {
609: // wait for call back as it might take some time
610: // XXX: this implementation is a bit ugly, but who knows a
611: // better solution?
612: for (int i = 0; i < MAX_WAIT_BEFORE_NOTIFY_SECS; i++) {
613: if (ut.isReachable())
614: break;
615: try {
616: Thread.sleep(1000);
617: } catch (InterruptedException ie) {
618: // who cares?
619: }
620: }
621: // now we have waited long enough, see if server came
622: // through
623: if (!ut.isReachable()) {
624: logger
625: .log(Level.WARNING,
626: "Events can not be pushed from server! Using poll by client instead! ");
627: JOptionPane
628: .showMessageDialog(
629: ContelligentClient
630: .getActiveFrame(),
631: Resources
632: .getLocalString("push_not_possible"),
633: Resources
634: .getLocalString("push_not_possible_title"),
635: JOptionPane.ERROR_MESSAGE);
636:
637: updateMode = UPDATE_MODE_POLL;
638: stopPushUpdate();
639: startPollUpdate();
640: }
641: }
642: } else if (getUpdateMode() == UPDATE_MODE_POLL) {
643: startPollUpdate();
644: }
645: isStarted = true;
646: }
647: }
648:
649: /** Stop update. */
650: public void stop() {
651: if (isStarted) {
652: stopPollUpdate();
653: stopPushUpdate();
654: isStarted = false;
655: }
656: }
657:
658: public int getCallBackPort() {
659: if (updateMode == UPDATE_MODE_POLL) {
660: return -1;
661: } else if (port != 0) {
662: return port;
663: } else if (UpdateThread.getInstance() != null) {
664: return UpdateThread.getInstance().getActualPort();
665: } else {
666: return -1;
667: }
668: }
669:
670: public boolean isKeepAlive() {
671: return keepAlive;
672: }
673:
674: public int getUpdateMode() {
675: return updateMode;
676: }
677:
678: protected void pollUpdateFromServer() {
679: try {
680: // call action and get response content
681: ActionResult result = Actions.pollEvents();
682: if (result.getState().equals(ActionResult.ERROR)) {
683: logger
684: .log(Level.WARNING,
685: "Could not poll update from server, action returned error");
686: result.showErrors();
687: return;
688: }
689: Element response = result.getContent();
690: Session.getInstance().fireServerEvent(
691: new ServerEvent(this , response.toString(),
692: ServerEvent.PULL_EVENT));
693: // decompose response content
694: NodeList events = response
695: .getElementsByTagName(UpdateManager.EVENT);
696: if (events.getLength() > 0) {
697: logger.log(Level.FINEST, "Event: " + response);
698: UpdateManager.handleComponentEvents(events, this );
699: }
700: } catch (RemoteActionException rae) {
701: logger.log(Level.WARNING,
702: "Could not poll update from server", rae);
703: stop();
704: if (JOptionPane
705: .showOptionDialog(
706: ContelligentClient.getActiveFrame(),
707: Resources.getLocalString("server_down"),
708: Resources
709: .getLocalString("server_down_title"),
710: JOptionPane.YES_NO_OPTION,
711: JOptionPane.WARNING_MESSAGE,
712: null,
713: new String[] {
714: Resources
715: .getLocalString("exit_client"),
716: Resources
717: .getLocalString("reload_session") },
718: Resources.getLocalString("exit_client")) == JOptionPane.YES_OPTION) {
719: ContelligentClient.getFrame().exit();
720: } else {
721: ContelligentClient.getFrame().getMainPanel()
722: .reloadSession();
723: }
724: }
725: }
726:
727: /**
728: * registers listener for preference change
729: */
730: private UpdateManager() {
731: updateInterval = PreferencesModule.getServerPreferences()
732: .getInt(PreferencesModule.UPDATE_INTERVAL,
733: PreferencesModule.DEFAULT_UPDATE_INTERVAL) * 1000;
734: updateMode = PreferencesModule.getServerPreferences().getInt(
735: PreferencesModule.UPDATE_MODE,
736: PreferencesModule.DEFAULT_UPDATE_MODE);
737: if (updateMode > UPDATE_MODE_POLL)
738: updateMode = UPDATE_MODE_POLL;
739: port = PreferencesModule.getServerPreferences().getInt(
740: PreferencesModule.CALLBACK_PORT,
741: PreferencesModule.DEFAULT_CALLBACK_PORT);
742: if (port < 0)
743: port = 0;
744: keepAlive = PreferencesModule.getServerPreferences()
745: .getBoolean(PreferencesModule.KEEP_ALIVE,
746: PreferencesModule.DEFAULT_KEEP_ALIVE);
747:
748: registerPreferenceChangeListeners();
749: }
750:
751: private void registerPreferenceChangeListeners() {
752: PreferencesModule.getServerPreferences()
753: .addPreferenceChangeListener(
754: new PreferenceChangeListener() {
755: public void preferenceChange(
756: PreferenceChangeEvent property) {
757: if (property
758: .getKey()
759: .equals(
760: PreferencesModule.UPDATE_INTERVAL)) {
761: updateInterval = Integer.valueOf(
762: property.getNewValue())
763: .intValue() * 1000;
764: logger.log(Level.FINE,
765: "Update interval for polling component events is set to "
766: + updateInterval
767: + " milliseconds");
768: if (getUpdateMode() == UPDATE_MODE_POLL
769: && pollUpdateStarted) {
770: stopPollUpdate();
771: startPollUpdate();
772: }
773: }
774: }
775: });
776:
777: PreferencesModule.getServerPreferences()
778: .addPreferenceChangeListener(
779: new PreferenceChangeListener() {
780: public void preferenceChange(
781: PreferenceChangeEvent property) {
782: if (property.getKey().equals(
783: PreferencesModule.UPDATE_MODE)) {
784: int requestedMode = Integer
785: .valueOf(
786: property
787: .getNewValue())
788: .intValue();
789: logger.log(Level.INFO,
790: "Request to switch mode "
791: + updateMode
792: + " to "
793: + requestedMode);
794: if (requestedMode > UPDATE_MODE_POLL)
795: requestedMode = UPDATE_MODE_POLL;
796: if (requestedMode == updateMode)
797: return;
798: updateMode = requestedMode;
799: if (isStarted) {
800: switch (requestedMode) {
801: case UPDATE_MODE_PUSH:
802: logger
803: .log(Level.WARNING,
804: "Switch to push mode needs reload to take effect");
805: // client needs a reload to actually do that, so
806: // tell user and do not stop current update mode!
807: // stopPollUpdate();
808: // startPushUpdate();
809: JOptionPane
810: .showMessageDialog(
811: ContelligentClient
812: .getActiveFrame(),
813: Resources
814: .getLocalString("push_needs_reload"),
815: Resources
816: .getLocalString("push_needs_reload_title"),
817: JOptionPane.WARNING_MESSAGE);
818: break;
819: case UPDATE_MODE_NONE:
820: stopPushUpdate();
821: stopPollUpdate();
822: logger
823: .log(Level.INFO,
824: "Switched mode to none");
825: break;
826: case UPDATE_MODE_POLL:
827: stopPushUpdate();
828: startPollUpdate();
829: logger
830: .log(Level.INFO,
831: "Switched mode to poll");
832: break;
833: }
834: } else if (pushTried
835: && getUpdateMode() == UPDATE_MODE_POLL) {
836: // stop unwanted push if it has been tried, but not
837: // terminated, yet
838: stopPushUpdate();
839: }
840: }
841: }
842: });
843: }
844:
845: private void startPushUpdate() {
846: if (getUpdateMode() == UPDATE_MODE_PUSH && !pushUpdateStarted) {
847: try {
848: UpdateThread ut = UpdateThread.initInstance(port);
849: ut.start();
850: pushUpdateStarted = true;
851: } catch (Exception e) {
852: logger.log(Level.SEVERE, "Could not start push update",
853: e);
854: UpdateThread.dropInstance();
855: }
856: }
857: }
858:
859: private boolean stopPushUpdate() {
860: if (pushUpdateStarted) {
861: pushUpdateStarted = !UpdateThread.dropInstance();
862: return pushUpdateStarted;
863: }
864: return true;
865: }
866:
867: private void startPollUpdate() {
868: if (!pollUpdateStarted) {
869: updateTimer = new java.util.Timer(true); // generate a timer
870: // using a daemon thread
871: updateTimer.scheduleAtFixedRate(new java.util.TimerTask() {
872: public void run() {
873: logger.log(Level.FINE,
874: "Timer call back NOW by Thread "
875: + Thread.currentThread().getName());
876:
877: if (System.currentTimeMillis()
878: - scheduledExecutionTime() >= MAX_TARDINESS_SECS * 1000) {
879: logger.log(Level.WARNING,
880: "Timer task late. Skipping...");
881: return; // Too late; skip this execution.
882: }
883: pollUpdateFromServer();
884: }
885: }, updateInterval, updateInterval);
886: pollUpdateStarted = true;
887: }
888: }
889:
890: private void stopPollUpdate() {
891: if (pollUpdateStarted) {
892: updateTimer.cancel();
893: updateTimer = null;
894: pollUpdateStarted = false;
895: }
896: }
897:
898: private final static class EventParserException extends
899: ContelligentException {
900: public EventParserException(String message) {
901: super(message);
902: }
903: }
904: }
|