1
2
3
4
5
6
7
8
9
10
11
12
13 package org.gscg.gameleader.interactionlayer;
14
15 import java.awt.Dimension;
16 import java.io.FileOutputStream;
17 import java.io.IOException;
18 import java.io.ObjectOutputStream;
19 import java.io.Serializable;
20 import java.rmi.RemoteException;
21 import java.rmi.server.UnicastRemoteObject;
22 import java.text.DateFormat;
23 import java.util.ArrayList;
24 import java.util.Calendar;
25 import java.util.Collections;
26 import java.util.HashMap;
27 import java.util.HashSet;
28 import java.util.Iterator;
29 import java.util.List;
30 import java.util.Map;
31 import java.util.Set;
32 import java.util.SortedSet;
33 import java.util.Timer;
34 import java.util.TimerTask;
35 import java.util.TreeSet;
36
37 import javax.naming.Binding;
38 import javax.naming.NamingEnumeration;
39 import javax.naming.event.EventContext;
40 import javax.naming.event.NamespaceChangeListener;
41 import javax.naming.event.NamingEvent;
42 import javax.naming.event.NamingExceptionEvent;
43
44 import nl.tudelft.simulation.actor.ActorInterface;
45 import nl.tudelft.simulation.dsol.SimRuntimeException;
46 import nl.tudelft.simulation.dsol.animation.D2.ImageRenderable;
47 import nl.tudelft.simulation.dsol.animation.D2.Renderable2DInterface;
48 import nl.tudelft.simulation.dsol.animation.D2.SingleImageRenderable;
49 import nl.tudelft.simulation.dsol.experiment.Experiment;
50 import nl.tudelft.simulation.dsol.experiment.Replication;
51 import nl.tudelft.simulation.dsol.experiment.TimeUnit;
52 import nl.tudelft.simulation.dsol.experiment.TimeUnitInterface;
53 import nl.tudelft.simulation.dsol.simulators.AnimatorInterface;
54 import nl.tudelft.simulation.dsol.simulators.DESSSimulatorInterface;
55 import nl.tudelft.simulation.dsol.simulators.SimulatorInterface;
56 import nl.tudelft.simulation.event.Event;
57 import nl.tudelft.simulation.event.EventInterface;
58 import nl.tudelft.simulation.event.EventListenerInterface;
59 import nl.tudelft.simulation.event.EventType;
60 import nl.tudelft.simulation.event.remote.RemoteEventListenerInterface;
61 import nl.tudelft.simulation.language.d3.DirectedPoint;
62 import nl.tudelft.simulation.language.swing.SwingWorker;
63 import nl.tudelft.simulation.logger.Logger;
64 import nl.tudelft.simulation.naming.InitialEventContext;
65 import nl.tudelft.simulation.supplychain.actor.SupplyChainActor;
66 import nl.tudelft.simulation.supplychain.animation.ContentAnimation;
67
68 import org.gscg.common.GameAnimator;
69 import org.gscg.common.gui.exceptions.ReceivedUnknownEventException;
70 import org.gscg.common.interactionlayer.AnnounceInterface;
71 import org.gscg.common.interactionlayer.ThreadedEventProducer;
72 import org.gscg.common.interactionlayer.dataobjects.ProgressionData;
73 import org.gscg.common.interactionlayer.location.YellowPage;
74 import org.gscg.common.interactionlayer.messaging.ScenarioText;
75 import org.gscg.common.interactionlayer.messaging.SocialMessaging;
76 import org.gscg.common.interactionlayer.timecontrol.CurrentRowOrColumnNumber;
77 import org.gscg.common.interactionlayer.timecontrol.GlobalProgressDateAndTime;
78 import org.gscg.common.interactionlayer.timecontrol.GlobalRowOrColumnNumber;
79 import org.gscg.common.interactionlayer.timecontrol.ProgressDateAndTime;
80 import org.gscg.game.GameGlobalData;
81 import org.gscg.gameactors.GameMarket;
82 import org.gscg.gameleader.animation2D.GisActorAnimation;
83 import org.gscg.gameleader.animation2D.GisActorImageDataElement;
84 import org.gscg.gameleader.animation2D.GisGraphicsRenderable;
85 import org.gscg.gameleader.animation2D.GisRenderable2D;
86 import org.gscg.gameleader.animation2D.ImageDataElement;
87 import org.gscg.gameleader.animation2D.ImageDataInterface;
88 import org.gscg.gameleader.animation2D.SingleImageDataElement;
89 import org.gscg.gameleader.animation2D.mouse.IntrospectionData;
90 import org.gscg.gameleader.interactionlayer.experiment.ExperimentParser;
91 import org.gscg.gameleader.interactionlayer.experiment.ExperimentParsingThread;
92 import org.gscg.gameleader.interactionlayer.statistics.DemandStatistics;
93 import org.gscg.gameleader.interactionlayer.util.EventTypeComparator;
94 import org.gscg.gameleader.interactionlayer.util.IntrospectionUtil;
95 import org.jdom.Element;
96
97 /***
98 * The game leader interaction layer is the layer between server-side game
99 * control logic and a client-side game administrator application.
100 * <p>
101 * Copyright (c) 2003-2005 Delft University of Technology, Jaffalaan 5, 2628 BX
102 * Delft, the Netherlands. All rights reserved.
103 *
104 * See for project information <a href="http://www.simulation.tudelft.nl/">
105 * www.simulation.tudelft.nl </a>.
106 *
107 * The source code and binary code of this software is proprietary information
108 * of Delft University of Technology.
109 *
110 * @author <a
111 * href="http://www.tbm.tudelft.nl/webstaf/stijnh/index.htm">Stijn-Pieter
112 * van Houten </a>
113 * @version $Revision: 1.2 $ $Date: 2005/08/03 08:52:50 $
114 * @since 1.0.0 <br>
115 */
116 public class GameLeaderInteractionLayer extends ThreadedEventProducer implements
117 RemoteInteractionLayerInterface, NamespaceChangeListener
118 {
119 /*** the serial version uid */
120 private static final long serialVersionUID = 13L;
121
122 /*** the object added event */
123 public static final EventType OBJECT_ADDED_EVENT = new EventType(
124 "OBJECT_ADDED_EVENT");
125
126 /*** the object removed event */
127 public static final EventType OBJECT_REMOVED_EVENT = new EventType(
128 "OBJECT_REMOVED_EVENT");
129
130 /*** the animation changed event */
131 public static final EventType ANIMATION_UPDATE_EVENT = new EventType(
132 "ANIMATION_UPDATE_EVENT");
133
134 /*** indicates whether this class has been deserialized */
135 private static boolean deserialized = false;
136
137 /*** indicates whether the bindings have already been looked up */
138 private static boolean bindingsLookedUp = false;
139
140 /*** the simulator events types for the interaction layer to subscribe to */
141 private EventType[] simulatorEventTypes = {
142 AnimatorInterface.ANIMATION_DELAY_CHANGED_EVENT,
143 AnimatorInterface.UPDATE_ANIMATION_EVENT,
144 SimulatorInterface.STOP_EVENT, SimulatorInterface.START_EVENT};
145
146 /*** the experiment */
147 private Experiment experiment = null;
148
149 /*** the client side event listeners */
150 private transient List clients = new ArrayList();
151
152 /*** indicates whether the client side game administrator is online */
153 private int numberLoggedIn = 0;
154
155 /*** the id of the interaction layer */
156 private String id = null;
157
158 /*** the event types this layer is subscribed to */
159 private Set eventsSentByClient = new HashSet();
160
161 /*** the elements of the animation panel */
162 private transient Set elements = Collections.synchronizedSet(new HashSet());
163
164 /*** contains the changed elements during an animation refreshment */
165 private transient Map changedElements = Collections
166 .synchronizedMap(new HashMap());
167
168 /*** the map with data elements of the images */
169 private transient Map imageDataElements = Collections
170 .synchronizedMap(new HashMap());
171
172 /*** a map with a key - source mappings */
173 private transient Map keySourceMap = Collections
174 .synchronizedMap(new HashMap());
175
176 /*** maps a remote event listener to its refresh rate */
177 private transient Map listenersRefreshRates = Collections
178 .synchronizedMap(new HashMap());
179
180 /*** maps a remote event listener to its timer */
181 private transient Map listenersTimers = Collections
182 .synchronizedMap(new HashMap());
183
184 /*** the map with actor keys */
185 private transient Map actorKeys = new HashMap();
186
187 /*** the timed animation refresher */
188 private TimedAnimationRefresher timedAnimationRefresher = null;
189
190 /*** we use this for persistency reasons */
191 private int numberOfTreatment = 0;
192
193 /*** we use this for persistency reasons */
194 private int numberOfReplication = 0;
195
196 /*** we use this for persistency reasons */
197 private String run = null;
198
199 /*** maps event types and corresponding announce objects */
200 private HashMap announceObjects = new HashMap();
201
202 /*** the event types this layer is subscribed to */
203 private Set statisticEventTypes = new TreeSet(new EventTypeComparator());
204
205 /*** the global supply chain data */
206 private GameGlobalData globalSupplyChainData = null;
207
208 /*** the scenario text */
209 private ScenarioText scenarioText = null;
210
211 /*** the social messaging */
212 private SocialMessaging socialMessaging = null;
213
214 /*** the yellowpage */
215 private YellowPage yellowPage = null;
216
217 /***
218 * constructs a new GameLeaderInteractionLayer
219 *
220 * @param id the id of the game administrator
221 */
222 public GameLeaderInteractionLayer(final String id)
223 {
224 super();
225 this.id = id;
226 try
227 {
228 UnicastRemoteObject.exportObject(this);
229 } catch (RemoteException remoteException)
230 {
231 Logger.severe(this, "<init>", remoteException);
232 }
233
234 try
235 {
236
237 new InitialEventContext().bind(this.id, this);
238 } catch (Exception exception)
239 {
240 Logger.severe(this, "<init>", exception);
241 }
242 }
243
244 /***
245 * @see nl.tudelft.simulation.event.EventListenerInterface#notify(nl.tudelft.simulation.event.EventInterface)
246 */
247 public void notify(final EventInterface event) throws RemoteException
248 {
249 if (this.numberLoggedIn > 0)
250 {
251 if (event.getType()
252 .equals(AnimatorInterface.UPDATE_ANIMATION_EVENT))
253 {
254 synchronized (this.elements)
255 {
256 for (Iterator i = this.elements.iterator(); i.hasNext();)
257 {
258 Renderable2DInterface renderable = ((Renderable2DInterface) i
259 .next());
260 ImageDataInterface element = (ImageDataInterface) this.imageDataElements
261 .get(renderable.getSource().toString()
262 + renderable.getSource().hashCode());
263 try
264 {
265 if (element != null)
266 {
267 if (!renderable.getSource().getLocation()
268 .equals(
269 new DirectedPoint(element
270 .getPoint()[0], element
271 .getPoint()[1], element
272 .getPoint()[2])))
273 {
274 synchronized (this.changedElements)
275 {
276
277 element.setPoints(new double[]{
278 renderable.getSource()
279 .getLocation().x,
280 renderable.getSource()
281 .getLocation().y,
282 renderable.getSource()
283 .getLocation().z});
284
285
286
287
288
289 for (Iterator it = this.changedElements
290 .keySet().iterator(); it
291 .hasNext();)
292 {
293 ((List) this.changedElements.get(it
294 .next())).add(element);
295 }
296 }
297 }
298 }
299 } catch (NullPointerException nullPointerException)
300 {
301 Logger.severe(this, "notify", nullPointerException);
302 }
303 }
304 return;
305 }
306 }
307 super.fireEvent(event);
308 }
309 }
310
311 /***
312 * Method addStatisticEventType adds an event to a set with event types only
313 * used for statistical updates. Upon initialization, a remote game leader
314 * graphical user interface asks for this set. EventTypes which are added to
315 * this set should follow the following convention ACTORROLE_ + description
316 * of eventtype. E.g. CUSTOMER_DEMAND_CHANGED_EVENT.
317 *
318 * @param eventType the event type to add
319 */
320 public void addStatisticEventType(final EventType eventType)
321 {
322 if (!this.statisticEventTypes.contains(eventType))
323 {
324 this.statisticEventTypes.add(eventType);
325 }
326 }
327
328 /***
329 * @see org.gscg.common.interactionlayer.GlobalInteractionLayerInterface#getCache(java.lang.Object,
330 * nl.tudelft.simulation.event.EventType, boolean)
331 */
332 public void getCache(final Object remoteEventListener,
333 final EventType eventType, final boolean cache)
334 throws RemoteException
335 {
336
337 if (cache)
338 {
339 if (eventType.equals(YellowPage.UPDATE_ACTORS))
340 {
341
342 this.globalSupplyChainData.getYellowPage().update(true, this);
343 return;
344 }
345
346
347
348 if (eventType
349 .equals(SocialMessaging.UPDATE_RECEIVED_SOCIAL_MESSAGES))
350 {
351 for (int i = 0; i < this.socialMessaging
352 .getReceivedSocialMessages().size(); i++)
353 {
354 ((RemoteEventListenerInterface) remoteEventListener)
355 .notify(new Event(
356 SocialMessaging.UPDATE_RECEIVED_SOCIAL_MESSAGE,
357 this, this.socialMessaging
358 .getReceivedSocialMessages().get(i)));
359 }
360 return;
361 }
362 if (eventType.equals(SocialMessaging.UPDATE_SENT_SOCIAL_MESSAGES))
363 {
364 for (int i = 0; i < this.socialMessaging
365 .getSentSocialMessages().size(); i++)
366 {
367 ((RemoteEventListenerInterface) remoteEventListener)
368 .notify(new Event(
369 SocialMessaging.UPDATE_SENT_SOCIAL_MESSAGE,
370 this, this.socialMessaging
371 .getSentSocialMessages().get(i)));
372 }
373 return;
374 }
375 if (eventType.equals(SimulatorInterface.TIME_CHANGED_EVENT))
376 {
377 ProgressionData data = new ProgressionData(
378 GlobalProgressDateAndTime.getDate(),
379 GlobalProgressDateAndTime.getTime(),
380 GlobalProgressDateAndTime.getStopTime(),
381 GlobalProgressDateAndTime.getProgress(),
382 GlobalProgressDateAndTime.getProgressTime());
383 ((RemoteEventListenerInterface) remoteEventListener)
384 .notify(new Event(
385 SimulatorInterface.TIME_CHANGED_EVENT, this,
386 data));
387 return;
388 }
389 new ReceivedUnknownEventException(this, "getCache", eventType);
390 } else
391 {
392
393 if (this.announceObjects.containsKey(eventType.toString()))
394 {
395 AnnounceInterface object = (AnnounceInterface) this.announceObjects
396 .get(eventType.toString());
397 object.announce(eventType, false);
398 return;
399 }
400 new ReceivedUnknownEventException(this, "getCache", eventType);
401 }
402 }
403
404 /***
405 * @see org.gscg.common.interactionlayer.GlobalInteractionLayerInterface#login(nl.tudelft.simulation.event.remote.RemoteEventListenerInterface)
406 */
407 public synchronized boolean login(final RemoteEventListenerInterface client)
408 {
409 if (!GameLeaderInteractionLayer.bindingsLookedUp)
410 {
411 GameLeaderInteractionLayer.bindingsLookedUp = true;
412 this.resolveBindings(GameLeaderInteractionLayer.deserialized);
413 }
414 boolean loggedIn = false;
415 if (this.numberLoggedIn > 0)
416 {
417 loggedIn = true;
418 }
419 this.numberLoggedIn++;
420 this.clients.add(client);
421 this.globalSupplyChainData.getYellowPage()
422 .updateInteractiveOnlineStatus(this, true, false);
423 return loggedIn;
424 }
425
426 /***
427 * @see org.gscg.gameleader.interactionlayer.experiment.ExperimentInterface#parseExperiment(org.jdom.Element)
428 */
429 public void parseExperiment(final Element experimentElement)
430 throws RemoteException
431 {
432 if (this.experiment != null)
433 {
434 try
435 {
436
437 if (!this.experiment.getSimulator().isRunning())
438 {
439 this.experiment.getSimulator().stop();
440 }
441 } catch (Exception exception)
442 {
443 Logger.severe(this, "parseExperiment", exception);
444 }
445 }
446
447 try
448 {
449 this.experiment = ExperimentParser
450 .parseExperiment(experimentElement);
451
452 if (this.experiment != null)
453 {
454 this.experiment.setSimulator(new GameAnimator());
455 this.experiment.start();
456 this.experiment.getSimulator().stop();
457
458
459 for (int i = 0; i < this.simulatorEventTypes.length; i++)
460 {
461 this.experiment.getSimulator().addListener(this,
462 this.simulatorEventTypes[i], false);
463 }
464
465
466 this.elements.clear();
467 this.changedElements.clear();
468 this.imageDataElements.clear();
469 this.keySourceMap.clear();
470 this.listenersRefreshRates.clear();
471 this.listenersTimers.clear();
472
473
474 this.timedAnimationRefresher = new TimedAnimationRefresher(this);
475
476
477 this.numberOfTreatment = this.experiment.getSimulator()
478 .getReplication().getRunControl().getTreatment()
479 .getNumber();
480 this.numberOfReplication = this.experiment.getSimulator()
481 .getReplication().getNumber();
482 this.run = this.experiment.getRun();
483
484
485 this.globalSupplyChainData = (GameGlobalData) new InitialEventContext()
486 .lookup(GameGlobalData.CONTEXT_NAME);
487
488
489 new ProgressDateAndTime(this);
490 new CurrentRowOrColumnNumber(this);
491
492 this.socialMessaging = new SocialMessaging(this,
493 this.globalSupplyChainData.getYellowPage());
494
495
496 this.yellowPage = this.globalSupplyChainData.getYellowPage();
497 this.yellowPage.addGameLeader(this);
498
499
500 this.yellowPage.addListener(this, YellowPage.UPDATE_ACTORS,
501 false);
502 this.globalSupplyChainData.getYellowPage().addListener(this,
503 YellowPage.UPDATE_INTERACTIVE_PLAYER_STATUS, false);
504
505
506 this.scenarioText = (ScenarioText) new InitialEventContext()
507 .lookup(ScenarioText.CONTEXT_NAME);
508 this.scenarioText.addInteractionLayer(this);
509
510
511
512 for (Iterator it = this.globalSupplyChainData
513 .getSupplyChainActors().iterator(); it.hasNext();)
514 {
515 Object obj = it.next();
516 if (obj instanceof GameMarket)
517 {
518 new DemandStatistics(this, (GameMarket) obj);
519 }
520 }
521
522
523 for (int i = 0; i < this.clients.size(); i++)
524 {
525 ((RemoteEventListenerInterface) this.clients.get(i))
526 .notify(new Event(
527 ExperimentParsingThread.EXPERIMENT_PARSED_EVENT,
528 this, null));
529 }
530
531
532
533
534 }
535 } catch (Exception exception)
536 {
537 exception.printStackTrace();
538 }
539 }
540
541 /***
542 * @see nl.tudelft.simulation.dsol.simulators.SimulatorInterface#getSimulatorTime()
543 */
544 public double getSimulatorTime() throws RemoteException
545 {
546 return this.experiment.getSimulator().getSimulatorTime();
547 }
548
549 /***
550 * @see nl.tudelft.simulation.dsol.simulators.SimulatorInterface#getReplication()
551 */
552 public Replication getReplication() throws RemoteException
553 {
554 return this.experiment.getTreatments()[0].getRunControl()
555 .getReplications()[0];
556 }
557
558 /***
559 * @see nl.tudelft.simulation.dsol.simulators.SimulatorInterface#initialize(nl.tudelft.simulation.dsol.experiment.Replication)
560 */
561 public void initialize(final Replication replication)
562 throws RemoteException, SimRuntimeException
563 {
564 this.experiment.getSimulator().initialize(replication);
565 }
566
567 /***
568 * @see nl.tudelft.simulation.dsol.simulators.SimulatorInterface#isRunning()
569 */
570 public boolean isRunning() throws RemoteException
571 {
572 if (this.experiment != null)
573 {
574 return this.experiment.getSimulator().isRunning();
575 }
576 return false;
577 }
578
579 /***
580 * @see nl.tudelft.simulation.dsol.simulators.SimulatorInterface#start()
581 */
582 public void start() throws RemoteException, SimRuntimeException
583 {
584 this.experiment.getSimulator().start();
585 }
586
587 /***
588 * @see nl.tudelft.simulation.dsol.simulators.SimulatorInterface#step()
589 */
590 public void step() throws RemoteException, SimRuntimeException
591 {
592 this.experiment.getSimulator().step();
593 }
594
595 /***
596 * @see nl.tudelft.simulation.dsol.simulators.SimulatorInterface#stop()
597 */
598 public void stop() throws RemoteException, SimRuntimeException
599 {
600 this.experiment.getSimulator().stop();
601 }
602
603 /***
604 * @see nl.tudelft.simulation.event.EventProducerInterface#removeListener(nl.tudelft.simulation.event.EventListenerInterface,
605 * nl.tudelft.simulation.event.EventType)
606 */
607 public synchronized boolean removeListener(
608 final EventListenerInterface listener, final EventType eventType)
609 {
610 SwingWorker worker = new SwingWorker()
611 {
612 /***
613 * @see nl.tudelft.simulation.language.swing.SwingWorker#construct()
614 */
615 public Object construct()
616 {
617 Logger.info(this, "removeListener",
618 "Listener removed for event type: " + eventType);
619
620 return null;
621 }
622 };
623 worker.start();
624
625
626 if (eventType.equals(SimulatorInterface.TIME_CHANGED_EVENT))
627 {
628 this.numberLoggedIn--;
629 if (this.clients.remove(listener))
630 {
631 Logger.info(this, "removeListener", "Game leader is offline");
632 }
633 if (this.numberLoggedIn == 0)
634 {
635 this.yellowPage.updateInteractiveOnlineStatus(this, false,
636 false);
637 }
638 }
639 return super.removeListener(listener, eventType);
640 }
641
642
643 /***
644 * @return Returns the id
645 */
646 public String getId()
647 {
648 return this.id;
649 }
650
651 /***
652 * @see nl.tudelft.simulation.dsol.simulators.DESSSimulatorInterface#getTimeStep()
653 */
654 public double getTimeStep() throws RemoteException
655 {
656 return ((DESSSimulatorInterface) this.experiment.getSimulator())
657 .getTimeStep();
658 }
659
660 /***
661 * @see nl.tudelft.simulation.dsol.simulators.DESSSimulatorInterface#setTimeStep(double)
662 */
663 public void setTimeStep(final double arg0) throws RemoteException
664 {
665 ((DESSSimulatorInterface) this.experiment.getSimulator())
666 .setTimeStep(arg0);
667 }
668
669 /***
670 * @see org.gscg.gameleader.interactionlayer.RemoteInteractionLayerInterface#getAnimationDelay()
671 */
672 public long getAnimationDelay() throws RemoteException
673 {
674 return ((AnimatorInterface) this.experiment.getSimulator())
675 .getAnimationDelay();
676 }
677
678 /***
679 * @see org.gscg.gameleader.interactionlayer.RemoteInteractionLayerInterface#setAnimationDelay(long)
680 */
681 public void setAnimationDelay(final long arg0) throws RemoteException
682 {
683 ((AnimatorInterface) this.experiment.getSimulator())
684 .setAnimationDelay(arg0);
685 }
686
687 /***
688 * @see org.gscg.gameleader.interactionlayer.RemoteInteractionLayerInterface#getActorKeys()
689 */
690 public Map getActorKeys() throws RemoteException
691 {
692 return this.actorKeys;
693 }
694
695 /***
696 * @see org.gscg.common.interactionlayer.GlobalInteractionLayerInterface#getTotalNumberOfDays()
697 */
698 public int getTotalNumberOfDays() throws RemoteException
699 {
700 return GlobalRowOrColumnNumber.getNumberOfDays();
701 }
702
703 /***
704 * @see javax.naming.event.NamespaceChangeListener#objectAdded(javax.naming.event.NamingEvent)
705 */
706 public void objectAdded(final NamingEvent namingEvent)
707 {
708 Renderable2DInterface element = null;
709 ImageDataElement dataElement = null;
710 try
711 {
712 element = (Renderable2DInterface) namingEvent.getNewBinding()
713 .getObject();
714 this.elements.add(element);
715 SingleImageRenderable object = (SingleImageRenderable) element;
716 String imagePath = null;
717 if (ContentAnimation.class.isAssignableFrom(object.getSource()
718 .getClass()))
719 {
720 imagePath = ((ContentAnimation) object.getSource())
721 .getImageURLlName();
722 String[] array = imagePath.split("!");
723 if (array.length == 1)
724 {
725 array = imagePath.split("classes");
726 }
727 imagePath = array[1];
728 dataElement = new SingleImageDataElement(element.getClass()
729 .getName(), element.getSource().toString()
730 + element.getSource().hashCode(), imagePath, object
731 .getSource().getLocation(), new Dimension(25, 25),
732 object.isFlip(), object.getOrientation(), object
733 .isRotate(), object.isScale(), object
734 .isTranslate());
735
736 this.keySourceMap.put(element.getSource().toString()
737 + element.getSource().hashCode(),
738 ((ContentAnimation) element.getSource()).getContent());
739 } else
740 {
741 if (SingleImageRenderable.class.isAssignableFrom(element
742 .getClass()))
743 {
744 if (object.getImages() != null)
745 {
746 imagePath = object.getImages()[0].toString();
747 String[] array = imagePath.split("!");
748 if (array.length == 1)
749 {
750 array = imagePath.split("classes");
751 }
752
753
754 dataElement = new SingleImageDataElement(element
755 .getClass().getName(), element.getSource()
756 .toString()
757 + element.getSource().hashCode(), array[1],
758 object.getSource().getLocation(),
759 new Dimension(object.getImages()[0]
760 .getIconWidth(), object.getImages()[0]
761 .getIconHeight()), object.isFlip(),
762 object.getOrientation(), object.isRotate(),
763 object.isScale(), object.isTranslate());
764 }
765
766 this.keySourceMap.put(element.getSource().toString()
767 + element.getSource().hashCode(), element
768 .getSource());
769 } else
770 {
771 Logger.severe(this, "objectAdded",
772 "GameLeaderInteractionLayer object.getSource().getClass(): "
773 + object.getSource().getClass());
774 }
775 }
776 } catch (Exception exception)
777 {
778 Logger.severe(this, "objectAdded", exception);
779 }
780
781 if (dataElement != null)
782 {
783 this.imageDataElements.put(element.getSource().toString()
784 + element.getSource().hashCode(), dataElement);
785 super.fireEvent(new Event(
786 GameLeaderInteractionLayer.OBJECT_ADDED_EVENT, this,
787 dataElement));
788 }
789 }
790
791 /***
792 * @see javax.naming.event.NamespaceChangeListener#objectRemoved(javax.naming.event.NamingEvent)
793 */
794 public void objectRemoved(final NamingEvent namingEvent)
795 {
796 try
797 {
798 synchronized (this.elements)
799 {
800 this.elements.remove(namingEvent.getOldBinding().getObject());
801
802 ImageDataInterface element = (ImageDataInterface) this.imageDataElements
803 .remove(((Renderable2DInterface) namingEvent
804 .getOldBinding().getObject()).getSource()
805 .toString()
806 + ((Renderable2DInterface) namingEvent
807 .getOldBinding().getObject())
808 .getSource().hashCode());
809
810 this.keySourceMap.remove(((Renderable2DInterface) namingEvent
811 .getOldBinding().getObject()).getSource().toString()
812 + namingEvent.getOldBinding().getObject().hashCode());
813
814 synchronized (this.changedElements)
815 {
816 if (element != null)
817 {
818 for (Iterator it = this.changedElements.keySet()
819 .iterator(); it.hasNext();)
820 {
821 List list = (List) this.changedElements.get(it
822 .next());
823 list.remove(element);
824 }
825 }
826 }
827 }
828 super.fireEvent(new Event(
829 GameLeaderInteractionLayer.OBJECT_REMOVED_EVENT, this,
830 new SingleImageDataElement("",
831 ((Renderable2DInterface) namingEvent
832 .getOldBinding().getObject()).getSource()
833 .toString()
834 + ((Renderable2DInterface) namingEvent
835 .getOldBinding().getObject())
836 .getSource().hashCode(), null,
837 new DirectedPoint(0.0, 0.0, 0.0), null, false,
838 ImageRenderable.CC, false, false, false)));
839 } catch (Exception exception)
840 {
841 Logger.severe(this, "objectRemoved", exception);
842 }
843 }
844
845 /***
846 * @see javax.naming.event.NamespaceChangeListener#objectRenamed(javax.naming.event.NamingEvent)
847 */
848 public void objectRenamed(final NamingEvent evt)
849 {
850
851 }
852
853 /***
854 * @see javax.naming.event.NamingListener#namingExceptionThrown(javax.naming.event.NamingExceptionEvent)
855 */
856 public void namingExceptionThrown(final NamingExceptionEvent evt)
857 {
858
859 }
860
861 /***
862 * @see org.gscg.gameleader.interactionlayer.RemoteInteractionLayerInterface#getBindings()
863 */
864 public Map getBindings() throws RemoteException
865 {
866 return this.imageDataElements;
867 }
868
869
870 /***
871 * @see org.gscg.gameleader.interactionlayer.RemoteInteractionLayerInterface#getIntrospectedObjectData(java.lang.String)
872 */
873 public IntrospectionData getIntrospectedObjectData(final String key)
874 throws RemoteException
875 {
876 return IntrospectionUtil.introspectObject(this.keySourceMap.get(key),
877 key);
878 }
879
880 /***
881 * @see org.gscg.gameleader.interactionlayer.RemoteInteractionLayerInterface#updateIntrospectedObject(org.gscg.gameleader.animation2D.mouse.IntrospectionData)
882 */
883 public void updateIntrospectedObject(final IntrospectionData data)
884 throws RemoteException
885 {
886 IntrospectionUtil.updateIntrospectedObject(this.keySourceMap.get(data
887 .getKey()), data);
888 }
889
890 /***
891 * @see org.gscg.gameleader.interactionlayer.RemoteInteractionLayerInterface#setAnimationRefreshDelay(int,
892 * nl.tudelft.simulation.event.remote.RemoteEventListenerInterface)
893 */
894 public void setAnimationRefreshDelay(final double times,
895 final RemoteEventListenerInterface listener) throws RemoteException
896 {
897 synchronized (this.changedElements)
898 {
899 if (!this.listenersRefreshRates.containsKey(listener))
900 {
901 this.changedElements.put(listener, Collections
902 .synchronizedList(new ArrayList()));
903 this.listenersRefreshRates.put(listener, new Double(times));
904
905
906 if (this.timedAnimationRefresher == null)
907 {
908 this.timedAnimationRefresher = new TimedAnimationRefresher(
909 this);
910 }
911 this.timedAnimationRefresher.scheduleTask(listener, times);
912 } else
913 {
914 this.listenersRefreshRates.put(listener, new Double(times));
915 }
916 }
917 }
918
919 /***
920 * @see org.gscg.gameleader.interactionlayer.RemoteInteractionLayerInterface#removeAnimationRefreshDelayListener(nl.tudelft.simulation.event.remote.RemoteEventListenerInterface)
921 */
922 public void removeAnimationRefreshDelayListener(
923 final RemoteEventListenerInterface listener) throws RemoteException
924 {
925 synchronized (this.changedElements)
926 {
927
928
929 this.changedElements.remove(listener);
930 this.listenersRefreshRates.remove(listener);
931 this.listenersTimers.remove(listener);
932 }
933 }
934
935 /***
936 * @see org.gscg.gameleader.interactionlayer.RemoteInteractionLayerInterface#saveSimulation()
937 */
938 public void saveSimulation() throws RemoteException
939 {
940 boolean running = false;
941
942 try
943 {
944 if (this.experiment.getSimulator().isRunning())
945 {
946 running = true;
947 try
948 {
949 this.experiment.getSimulator().stop();
950 } catch (Exception exception)
951 {
952 Logger.severe(this, "saveSimulation", exception);
953 }
954 }
955 } catch (RemoteException remoteException)
956 {
957 remoteException.printStackTrace();
958 }
959
960 try
961 {
962 SaveSimulationRunnable runnable = new SaveSimulationRunnable();
963 Thread thread = new Thread(runnable, "Save Simulation Thread");
964 thread.setPriority(Thread.MAX_PRIORITY);
965
966 thread.start();
967
968
969 thread.join();
970 } catch (Throwable throwable)
971 {
972 Logger.severe(this, "saveSimulation", throwable);
973 }
974
975 if (running)
976 {
977 try
978 {
979 this.experiment.getSimulator().start();
980 } catch (Exception exception)
981 {
982 Logger.severe(this, "saveSimulation", exception);
983 }
984 }
985 }
986
987 /***
988 * @see org.gscg.common.interactionlayer.GlobalInteractionLayerInterface#getStatisticEventTypes()
989 */
990 public EventType[] getStatisticEventTypes()
991 {
992 return (EventType[]) this.statisticEventTypes
993 .toArray(new EventType[this.statisticEventTypes.size()]);
994 }
995
996 /***
997 * @see org.gscg.common.interactionlayer.GlobalInteractionLayerInterface#addEventTypeSentByClient(nl.tudelft.simulation.event.EventType)
998 */
999 public void addEventTypeSentByClient(final EventType eventType)
1000 {
1001 if (!this.eventsSentByClient.contains(eventType))
1002 {
1003 this.eventsSentByClient.add((eventType));
1004 }
1005 }
1006
1007 /***
1008 * @see org.gscg.common.interactionlayer.GlobalInteractionLayerInterface#addEventTypeToAnnounceList(nl.tudelft.simulation.event.EventType,
1009 * org.gscg.common.interactionlayer.AnnounceInterface)
1010 */
1011 public void addEventTypeToAnnounceList(final EventType eventType,
1012 final AnnounceInterface announceObject)
1013 {
1014 String key = eventType.toString();
1015 this.announceObjects.put(key, announceObject);
1016 }
1017
1018
1019
1020
1021
1022 /***
1023 * Resolves the bindings present in the context
1024 *
1025 * @param deserialized indicates whether the simulation has been
1026 * deserialized
1027 */
1028 private void resolveBindings(final boolean deserialized)
1029 {
1030 try
1031 {
1032 String contextName = this.run + "/treatment("
1033 + this.numberOfTreatment + ")/replication("
1034 + this.numberOfReplication + ")/animation/2D";
1035 EventContext context = (EventContext) new InitialEventContext()
1036 .lookup(contextName);
1037 NamingEnumeration list = context.listBindings("");
1038 while (list.hasMore())
1039 {
1040 Binding binding = (Binding) list.next();
1041 Renderable2DInterface element = (Renderable2DInterface) binding
1042 .getObject();
1043 this.elements.add(element);
1044
1045 Object obj = binding.getObject();
1046 if (GisActorAnimation.class.isAssignableFrom(obj.getClass()))
1047 {
1048 GisActorAnimation object = (GisActorAnimation) obj;
1049 String imagePath = object.getImages()[0].toString();
1050 String[] array = imagePath.split("!");
1051 if (array.length == 1)
1052 {
1053 array = imagePath.split("classes");
1054 }
1055
1056
1057 this.imageDataElements.put(element.getSource().toString()
1058 + element.getSource().hashCode(),
1059 new GisActorImageDataElement(element.getClass()
1060 .getName(), element.getSource().toString()
1061 + element.getSource().hashCode(), array[1],
1062 object.getSource().getLocation(),
1063 new Dimension(object.getImages()[0]
1064 .getIconWidth(),
1065 object.getImages()[0]
1066 .getIconHeight()), element
1067 .getSource().getClass().getName(),
1068 ((ActorInterface) element.getSource())
1069 .getName()));
1070 this.keySourceMap.put(element.getSource().toString()
1071 + element.getSource().hashCode(), element
1072 .getSource());
1073 } else if (SingleImageRenderable.class.isAssignableFrom(obj
1074 .getClass()))
1075 {
1076 SingleImageRenderable object = (SingleImageRenderable) obj;
1077 String imagePath = object.getImages()[0].toString();
1078 String[] array = imagePath.split("!");
1079 if (array.length == 1)
1080 {
1081 array = imagePath.split("classes");
1082 }
1083
1084
1085 this.imageDataElements.put(element.getSource().toString()
1086 + element.getSource().hashCode(),
1087 new SingleImageDataElement(element.getClass()
1088 .getName(), element.getSource().toString()
1089 + element.getSource().hashCode(), array[1],
1090 object.getSource().getLocation(),
1091 new Dimension(object.getImages()[0]
1092 .getIconWidth(),
1093 object.getImages()[0]
1094 .getIconHeight()), object
1095 .isFlip(), object.getOrientation(),
1096 object.isRotate(), object.isScale(), object
1097 .isTranslate()));
1098 if (ContentAnimation.class.isAssignableFrom(object
1099 .getSource().getClass()))
1100 {
1101 this.keySourceMap.put(element.getSource().toString()
1102 + element.getSource().hashCode(),
1103 ((ContentAnimation) element.getSource())
1104 .getContent());
1105 } else
1106 {
1107 this.keySourceMap.put(element.getSource().toString()
1108 + element.getSource().hashCode(), element
1109 .getSource());
1110 }
1111 } else if (GisRenderable2D.class.isAssignableFrom(obj
1112 .getClass()))
1113 {
1114 this.imageDataElements.put(element.getSource().toString()
1115 + element.getSource().hashCode(),
1116 new ImageDataElement(element.getClass().getName(),
1117 element.getSource().toString()
1118 + element.getSource().hashCode(),
1119 element.getSource().getLocation(),
1120 "/world.map.xml"));
1121 this.keySourceMap.put(element.getSource().toString()
1122 + element.getSource().hashCode(), element
1123 .getSource());
1124 } else if (GisGraphicsRenderable.class.isAssignableFrom(obj
1125 .getClass()))
1126 {
1127 this.imageDataElements.put(element.getSource().toString()
1128 + element.getSource().hashCode(),
1129 new ImageDataElement(element.getClass().getName(),
1130 element.getSource().toString()
1131 + element.getSource().hashCode(),
1132 element.getSource().getLocation(),
1133 "undefined"));
1134 this.keySourceMap.put(element.getSource().toString()
1135 + element.getSource().hashCode(), element
1136 .getSource());
1137 } else
1138 {
1139 Logger.severe(this, "resolveBindings",
1140 "GameLeaderInteractionLayer: unknown renderable implementation: "
1141 + obj.getClass());
1142 }
1143
1144
1145
1146 if (element.getSource() instanceof SupplyChainActor)
1147 {
1148 String actorKey = element.getSource().toString()
1149 + element.getSource().hashCode();
1150
1151
1152 String[] split = element.getSource().getClass().getName()
1153 .split("//.");
1154 String mapKey = split[split.length - 1];
1155
1156 if (this.actorKeys.get(mapKey) == null)
1157 {
1158
1159 SortedSet set = new TreeSet();
1160 this.actorKeys.put(mapKey, set);
1161 }
1162 ((Set) this.actorKeys.get(mapKey)).add(actorKey);
1163 }
1164 }
1165
1166
1167 context.addNamingListener("", EventContext.SUBTREE_SCOPE, this);
1168
1169 if (!deserialized)
1170 {
1171
1172 this.experiment.getSimulator().addListener(this,
1173 AnimatorInterface.UPDATE_ANIMATION_EVENT, false);
1174 }
1175 } catch (Exception exception)
1176 {
1177 Logger.severe(this, "resolveBindings", exception);
1178 }
1179 }
1180
1181 /***
1182 * writes a serializable method to stream
1183 *
1184 * @param out the outputstream
1185 * @throws IOException on IOException
1186 */
1187 private synchronized void writeObject(final ObjectOutputStream out)
1188 throws IOException
1189 {
1190
1191 this.yellowPage.updateInteractiveOnlineStatus(this, false, true);
1192
1193 this.numberOfTreatment = this.experiment.getSimulator()
1194 .getReplication().getRunControl().getTreatment().getNumber();
1195 this.numberOfReplication = this.experiment.getSimulator()
1196 .getReplication().getNumber();
1197 out.defaultWriteObject();
1198
1199 if (this.numberLoggedIn > 0)
1200 {
1201 this.yellowPage.updateInteractiveOnlineStatus(this, false, true);
1202 }
1203 }
1204
1205 /***
1206 * reads a serializable method from stream
1207 *
1208 * @param in the inputstream
1209 */
1210 private synchronized void readObject(final java.io.ObjectInputStream in)
1211 {
1212 try
1213 {
1214 in.defaultReadObject();
1215
1216
1217 this.clients = new ArrayList();
1218 this.listenersRefreshRates = Collections
1219 .synchronizedMap(new HashMap());
1220 this.listenersTimers = Collections.synchronizedMap(new HashMap());
1221 this.actorKeys = new HashMap();
1222
1223 try
1224 {
1225 UnicastRemoteObject.exportObject(this);
1226 } catch (RemoteException remoteException)
1227 {
1228 Logger.severe(this, "<readObject>", remoteException);
1229 }
1230
1231 new InitialEventContext().bind(this.id, this);
1232
1233
1234 this.elements = Collections.synchronizedSet(new HashSet());
1235 this.changedElements = Collections.synchronizedMap(new HashMap());
1236 this.imageDataElements = Collections.synchronizedMap(new HashMap());
1237 this.keySourceMap = Collections.synchronizedMap(new HashMap());
1238
1239 GameLeaderInteractionLayer.deserialized = true;
1240
1241
1242 this.timedAnimationRefresher = new TimedAnimationRefresher(this);
1243
1244
1245 this.numberLoggedIn = 0;
1246
1247 } catch (Exception exception)
1248 {
1249 Logger.severe(this, "readObject", exception);
1250 }
1251 }
1252
1253 /***
1254 * A Runnable used for saving the simulation.
1255 * <p>
1256 * (c) copyright 2005 <a href="http://www.simulation.tudelft.nl">Delft
1257 * University of Technology </a>, the Netherlands. <br>
1258 * See for project information <a
1259 * href="http://www.simulation.tudelft.nl">www.simulation.tudelft.nl </a>
1260 * <br>
1261 *
1262 * Copyright (c) 2003-2005 Delft University of Technology, Jaffalaan 5, 2628
1263 * BX Delft, the Netherlands. All rights reserved.
1264 *
1265 * See for project information <a href="http://www.simulation.tudelft.nl/">
1266 * www.simulation.tudelft.nl </a>.
1267 *
1268 * The source code and binary code of this software is proprietary
1269 * information of Delft University of Technology.
1270 *
1271 * @author <a
1272 * href="http://www.tbm.tudelft.nl/webstaf/stijnh/index.htm">Stijn-Pieter
1273 * van Houten </a>
1274 * @version $Revision: 1.2 $ $Date: 2005/08/03 08:52:50 $
1275 * @since 1.1.3
1276 */
1277 private class SaveSimulationRunnable implements Runnable
1278 {
1279 /***
1280 * constructs a new SaveSimulationRunnable
1281 */
1282 public SaveSimulationRunnable()
1283 {
1284 super();
1285 }
1286
1287 /***
1288 * @see java.lang.Runnable#run()
1289 */
1290 public void run()
1291 {
1292
1293
1294
1295 try
1296 {
1297 Thread.sleep(1000);
1298 } catch (InterruptedException interruptedException)
1299 {
1300 Logger.severe(this, "run", interruptedException);
1301 }
1302
1303
1304
1305 synchronized (((GameAnimator) GameLeaderInteractionLayer.this.experiment
1306 .getSimulator()).gameSemaphore)
1307 {
1308 try
1309 {
1310 ThreadedEventProducer.DIJKSTRASEMAPHORE.acquireAll();
1311
1312 double time = Math.round(TimeUnit.convert(
1313 GameLeaderInteractionLayer.this.experiment
1314 .getSimulator().getSimulatorTime(),
1315 GameLeaderInteractionLayer.this.experiment
1316 .getSimulator().getReplication()
1317 .getRunControl().getTreatment()
1318 .getTimeUnit(), TimeUnitInterface.DAY));
1319
1320
1321
1322 String doubleAsString = "" + time;
1323 String[] split = doubleAsString.split("//.");
1324 String toFormat = split[0];
1325 while (toFormat.length() <= 3)
1326 {
1327 toFormat = "0" + toFormat;
1328 }
1329 doubleAsString = toFormat + "." + split[1];
1330
1331
1332 Calendar calendar = Calendar.getInstance();
1333 calendar.setTimeInMillis(System.currentTimeMillis());
1334 String date = DateFormat.getDateTimeInstance().format(
1335 calendar.getTime());
1336
1337 String[] dates = date.split(":");
1338 date = dates[0] + "_" + dates[1] + "_" + dates[2];
1339
1340 FileOutputStream file = new FileOutputStream(
1341 GameLeaderInteractionLayer.this.experiment
1342 .getProperty(Experiment.EXPERIMENT_NAME)
1343 + " time in days "
1344 + doubleAsString
1345 + " wallclock " + date + ".ids");
1346
1347
1348
1349 GameLeaderInteractionLayer.this.experiment.getSimulator()
1350 .getReplication().getRunControl().getTreatment()
1351 .getProperties().put("animationPanel.extent", "");
1352
1353 ObjectOutputStream fos = new ObjectOutputStream(file);
1354
1355
1356 try
1357 {
1358 fos
1359 .writeObject(GameLeaderInteractionLayer.this.experiment);
1360 fos
1361 .writeObject(GameLeaderInteractionLayer.this.experiment
1362 .getSimulator().getReplication()
1363 .getRunControl());
1364 } catch (Exception exception)
1365 {
1366 fos.reset();
1367 fos.flush();
1368 fos.close();
1369 file.close();
1370 exception.printStackTrace();
1371 } finally
1372 {
1373 try
1374 {
1375
1376 fos.flush();
1377 fos.close();
1378 file.close();
1379 fos = null;
1380 file = null;
1381 } catch (Exception exception2)
1382 {
1383
1384 exception2 = null;
1385 }
1386 }
1387
1388 Logger
1389 .info(
1390 this,
1391 "saveSimulation",
1392 "GameLeaderInteractionLayer: succesfully saved simulation to persistent storage");
1393 ThreadedEventProducer.DIJKSTRASEMAPHORE.releaseAll();
1394 } catch (Throwable exception)
1395 {
1396 ThreadedEventProducer.DIJKSTRASEMAPHORE.releaseAll();
1397
1398
1399
1400
1401
1402
1403
1404 exception.printStackTrace();
1405 }
1406 }
1407 }
1408 }
1409
1410 /***
1411 *
1412 * The TimedAnimationRefresher manages refreshing the client side animation
1413 * panels.
1414 * <p>
1415 * Copyright (c) 2003-2005 Delft University of Technology, Jaffalaan 5, 2628
1416 * BX Delft, the Netherlands. All rights reserved.
1417 *
1418 * See for project information <a href="http://www.simulation.tudelft.nl/">
1419 * www.simulation.tudelft.nl </a>.
1420 *
1421 * The source code and binary code of this software is proprietary
1422 * information of Delft University of Technology.
1423 *
1424 * @author <a
1425 * href="http://www.tbm.tudelft.nl/webstaf/stijnh/index.htm">Stijn-Pieter
1426 * van Houten </a>
1427 * @version $Revision: 1.2 $ $Date: 2005/08/03 08:52:50 $
1428 * @since 1.0.6 <br>
1429 */
1430 private class TimedAnimationRefresher implements Serializable
1431 {
1432 /*** the serial version uid */
1433 private static final long serialVersionUID = 13L;
1434
1435 /*** the timer */
1436 private Timer timer = null;
1437
1438 /*** the owner */
1439 private GameLeaderInteractionLayer owner = null;
1440
1441 /***
1442 * constructs a new TimedAnimationRefresher
1443 *
1444 * @param owner the owner
1445 */
1446 public TimedAnimationRefresher(final GameLeaderInteractionLayer owner)
1447
1448 {
1449 this.timer = new Timer();
1450 this.owner = owner;
1451 }
1452
1453 /***
1454 * Method scheduleTask schedules a new timer task
1455 *
1456 * @param listener the listener
1457 * @param times the number of times
1458 */
1459 protected void scheduleTask(
1460 final RemoteEventListenerInterface listener, final double times)
1461 {
1462 AnimationRefreshTask task = new AnimationRefreshTask(this,
1463 listener, times);
1464 this.timer.schedule(task, (long) ((1 / times) * 1000),
1465
1466 (long) ((1 / times) * 1000));
1467 this.owner.listenersTimers.put(listener, task);
1468 }
1469
1470 /***
1471 * writes a serializable method to stream
1472 *
1473 * @param out the outputstream
1474 * @throws IOException on IOException
1475 */
1476 private synchronized void writeObject(final ObjectOutputStream out)
1477 throws IOException
1478 {
1479 out.writeObject(this.owner);
1480 }
1481
1482 /***
1483 * reads a serializable method from stream
1484 *
1485 * @param in the inputstream
1486 */
1487 private synchronized void readObject(final java.io.ObjectInputStream in)
1488 {
1489 try
1490 {
1491 this.owner = (GameLeaderInteractionLayer) in.readObject();
1492 this.timer = new Timer();
1493 } catch (Exception exception)
1494 {
1495 Logger.severe(this, "readObject", exception);
1496 }
1497 }
1498
1499 /***
1500 * <p>
1501 * Copyright (c) 2003-2005 Delft University of Technology, Jaffalaan 5,
1502 * 2628 BX Delft, the Netherlands. All rights reserved.
1503 *
1504 * See for project information <a
1505 * href="http://www.simulation.tudelft.nl/"> www.simulation.tudelft.nl
1506 * </a>.
1507 *
1508 * The source code and binary code of this software is proprietary
1509 * information of Delft University of Technology.
1510 *
1511 * @author <a
1512 * href="http://www.tbm.tudelft.nl/webstaf/stijnh/index.htm">Stijn-Pieter
1513 * van Houten </a>
1514 * @version $Revision: 1.2 $ $Date: 2005/08/03 08:52:50 $
1515 * @since 1.0.0 <br>
1516 */
1517 class AnimationRefreshTask extends TimerTask
1518 {
1519 /*** the owner */
1520 private TimedAnimationRefresher owner = null;
1521
1522 /*** the listener */
1523 private RemoteEventListenerInterface listener = null;
1524
1525 /***
1526 * constructs a new RemindTask
1527 *
1528 * @param owner the owner
1529 * @param listener the listener
1530 * @param times the number of times
1531 */
1532 public AnimationRefreshTask(final TimedAnimationRefresher owner,
1533 final RemoteEventListenerInterface listener,
1534 final double times)
1535 {
1536 super();
1537 this.owner = owner;
1538 this.listener = listener;
1539 }
1540
1541 /***
1542 * @see java.lang.Runnable#run()
1543 */
1544 public void run()
1545 {
1546 try
1547 {
1548 synchronized (this.owner.owner.changedElements)
1549 {
1550 List changes = (List) this.owner.owner.changedElements
1551 .get(this.listener);
1552
1553 if (changes.size() > 0)
1554 {
1555
1556
1557
1558
1559 this.listener
1560 .notify(new Event(
1561 GameLeaderInteractionLayer.ANIMATION_UPDATE_EVENT,
1562 this.owner.owner, changes));
1563
1564 changes.clear();
1565 }
1566
1567 this.cancel();
1568
1569
1570 this.owner
1571 .scheduleTask(
1572 this.listener,
1573 ((Double) this.owner.owner.listenersRefreshRates
1574 .get(this.listener))
1575 .doubleValue());
1576 }
1577 } catch (Exception exception)
1578 {
1579
1580 this.cancel();
1581 synchronized (this.owner.owner.changedElements)
1582 {
1583 try
1584 {
1585
1586
1587 this.owner.owner.changedElements
1588 .remove(this.listener);
1589 this.owner.owner.listenersRefreshRates
1590 .remove(this.listener);
1591 this.owner.owner.listenersTimers
1592 .remove(this.listener);
1593 } catch (Exception exception2)
1594 {
1595
1596 exception2 = null;
1597 }
1598 }
1599 Logger.info(this, "AnimationRefreshTask",
1600 "RemoteListener removed from timer task");
1601 }
1602 }
1603 }
1604 }
1605 }