1
2
3
4
5
6
7
8
9
10
11
12
13
14 package org.gscg.singleuser.interactionlayer;
15
16 import java.io.IOException;
17 import java.io.ObjectOutputStream;
18 import java.rmi.RemoteException;
19 import java.rmi.server.UnicastRemoteObject;
20 import java.util.ArrayList;
21 import java.util.HashMap;
22 import java.util.HashSet;
23 import java.util.Map;
24 import java.util.Set;
25 import java.util.TreeSet;
26
27 import nl.tudelft.simulation.dsol.simulators.SimulatorInterface;
28 import nl.tudelft.simulation.event.Event;
29 import nl.tudelft.simulation.event.EventInterface;
30 import nl.tudelft.simulation.event.EventListenerInterface;
31 import nl.tudelft.simulation.event.EventType;
32 import nl.tudelft.simulation.event.remote.RemoteEventListener;
33 import nl.tudelft.simulation.event.remote.RemoteEventListenerInterface;
34 import nl.tudelft.simulation.event.remote.RemoteEventProducerInterface;
35 import nl.tudelft.simulation.logger.Logger;
36 import nl.tudelft.simulation.naming.InitialEventContext;
37 import nl.tudelft.simulation.supplychain.actor.SupplyChainActor;
38 import nl.tudelft.simulation.supplychain.actor.Trader;
39 import nl.tudelft.simulation.supplychain.stock.StockInterface;
40
41 import org.gscg.common.gui.ClientInterface;
42 import org.gscg.common.gui.exceptions.ReceivedUnknownEventException;
43 import org.gscg.common.interactionlayer.AnnounceInterface;
44 import org.gscg.common.interactionlayer.ThreadedEventProducer;
45 import org.gscg.common.interactionlayer.location.YellowPage;
46 import org.gscg.common.interactionlayer.messaging.ScenarioText;
47 import org.gscg.common.interactionlayer.messaging.SocialMessaging;
48 import org.gscg.common.interactionlayer.timecontrol.CurrentRowOrColumnNumber;
49 import org.gscg.common.interactionlayer.timecontrol.GlobalRowOrColumnNumber;
50 import org.gscg.common.interactionlayer.timecontrol.ProgressDateAndTime;
51 import org.gscg.game.GameActorContentStore;
52 import org.gscg.game.GameGlobalData;
53 import org.gscg.gameactors.GameActorInteractiveInterface;
54 import org.gscg.gameactors.GameDistributor;
55 import org.gscg.gameactors.statistics.ContentStatisticsLayer;
56 import org.gscg.gameleader.interactionlayer.util.EventTypeComparator;
57 import org.gscg.singleuser.handlers.CommittedOrderHandler;
58 import org.gscg.singleuser.handlers.ConfirmedOrderHandler;
59 import org.gscg.singleuser.interactionlayer.business.BusinessPurchase;
60 import org.gscg.singleuser.interactionlayer.business.BusinessSales;
61 import org.gscg.singleuser.interactionlayer.business.BusinessStock;
62 import org.gscg.singleuser.interactionlayer.business.statistics.BankStatistics;
63 import org.gscg.singleuser.interactionlayer.business.statistics.StockStatistics;
64 import org.gscg.singleuser.interactionlayer.dataobjects.content.RFQDataSuppliers;
65 import org.gscg.singleuser.interactionlayer.economics.Economics;
66
67 /***
68 * The DistributorSingleUserInteractionLayer takes care of the communication
69 * between the simulation server side and a client side application for a
70 * distributor.
71 *
72 * <p>
73 * Copyright (c) 2003-2005 Delft University of Technology, Jaffalaan 5, 2628 BX
74 * Delft, the Netherlands. All rights reserved.
75 *
76 * See for project information <a href="http://www.simulation.tudelft.nl/">
77 * www.simulation.tudelft.nl </a>.
78 *
79 * The source code and binary code of this software is proprietary information
80 * of Delft University of Technology.
81 *
82 * @author <a
83 * href="http://www.tbm.tudelft.nl/webstaf/stijnh/index.htm">Stijn-Pieter
84 * van Houten </a>
85 * @version $Revision: 1.1 $ $Date: 2005/08/09 15:43:41 $
86 * @since 1.0.0
87 */
88 public class DistributorSingleUserInteractionLayer extends
89 ThreadedEventProducer implements RemoteInteractionLayerInterface,
90 SingleUserInteractionLayerInterface
91 {
92 /*** the serial version uid */
93 private static final long serialVersionUID = 13L;
94
95 /*** the static list of ids in this game for identification mapping */
96 protected static Map idMap = new HashMap();
97
98 /*** the remote event listener */
99 private transient RemoteEventListener remoteEventListener = null;
100
101 /*** the id is used by a client to perform a lookup in de remote context */
102 private String id = "";
103
104 /*** the simulator */
105 private SimulatorInterface simulator = null;
106
107 /*** the owner of the interaction layer */
108 private SupplyChainActor owner = null;
109
110 /*** the event types this layer is subscribed to */
111 private Set eventTypes = new HashSet();
112
113 /*** the event types this layer is subscribed to */
114 private Set eventsSentByClient = new HashSet();
115
116 /*** the semaphore to use for the announce calls */
117 private transient Object semaphore = new Object();
118
119 /*** indicates if all announce events have been processed client side */
120 private boolean clientIsReady = false;
121
122 /*** the event types this layer is subscribed to */
123 private Set statisticEventTypes = new TreeSet(new EventTypeComparator());
124
125 /*** the overall game data */
126 private GameGlobalData globalSupplyChainData;
127
128 /*** the yellowpage */
129 private YellowPage yellowPage = null;
130
131 /*** maps event types and corresponding announce objects */
132 private HashMap announceObjects = new HashMap();
133
134 /***
135 * indicates whether caching is necessary (during initialization of a
136 * client)
137 */
138 private boolean shouldBeCaching = false;
139
140 /*** the cache to store mesages during intialization of a client */
141 private ArrayList cache = new ArrayList();
142
143 /***
144 * constructs a new DistributorSingleUserInteractionLayer
145 *
146 * @param simulator the simulator
147 * @param id the id of the single user interaction layer
148 * @param owner the owner of the interaction layer
149 * @param globalSupplyChainData the global supply chain data
150 */
151 public DistributorSingleUserInteractionLayer(
152 final SimulatorInterface simulator, final String id,
153 final SupplyChainActor owner,
154 final GameGlobalData globalSupplyChainData)
155 {
156 super();
157 try
158 {
159 UnicastRemoteObject.exportObject(this);
160 } catch (RemoteException remoteException)
161 {
162 Logger.severe(this, "<init>", remoteException);
163 }
164 try
165 {
166 this.globalSupplyChainData = globalSupplyChainData;
167 this.remoteEventListener = new RemoteEventListener(this);
168
169 this.simulator = simulator;
170 this.simulator.addListener(this, SimulatorInterface.START_EVENT);
171 this.eventTypes.add(SimulatorInterface.START_EVENT);
172 this.simulator.addListener(this, SimulatorInterface.STOP_EVENT);
173 this.eventTypes.add(SimulatorInterface.STOP_EVENT);
174
175 this.id = id;
176 this.owner = owner;
177 this.yellowPage = this.globalSupplyChainData.getYellowPage();
178
179
180 this.globalSupplyChainData.getYellowPage().addListener(this,
181 YellowPage.UPDATE_ACTORS, false);
182 this.globalSupplyChainData.getYellowPage().addListener(this,
183 YellowPage.UPDATE_INTERACTIVE_PLAYER_STATUS, false);
184
185
186
187
188 new ProgressDateAndTime(this);
189 new CurrentRowOrColumnNumber(this);
190
191 new SocialMessaging(this, this.yellowPage);
192 new Economics(this);
193 new BusinessStock(this);
194 new BusinessPurchase(this);
195 new BusinessSales(this);
196 new BankStatistics(this, (Trader) this.owner,
197 GlobalRowOrColumnNumber.getNumberOfDays());
198 new StockStatistics(this, (Trader) this.owner,
199 GlobalRowOrColumnNumber.getNumberOfDays());
200
201
202 new ContentStatisticsLayer(this);
203
204
205 ((Trader) this.owner).getStock().addListener(this,
206 StockInterface.STOCK_CHANGE_EVENT);
207 this.eventTypes.add(StockInterface.STOCK_CHANGE_EVENT);
208
209
210 new ConfirmedOrderHandler(this);
211 new CommittedOrderHandler(this);
212
213
214
215
216 new InitialEventContext().bind("distributor_" + this.id, this);
217
218
219 ((GameActorInteractiveInterface) this.owner)
220 .setSingleUserInteractionLayer(this);
221 } catch (Exception exception)
222 {
223 Logger.severe(this, "DistributorSingleUserInteractionLayer",
224 exception);
225 }
226 }
227
228 /***
229 * @see org.gscg.singleuser.interactionlayer.SingleUserInteractionLayerInterface#addEventType(nl.tudelft.simulation.event.EventType)
230 */
231 public void addEventType(final EventType eventType)
232 {
233 if (!this.eventTypes.contains(eventType))
234 {
235 this.eventTypes.add((eventType));
236 }
237 }
238
239 /***
240 * @see org.gscg.common.interactionlayer.GlobalInteractionLayerInterface#addEventTypeSentByClient(nl.tudelft.simulation.event.EventType)
241 */
242 public void addEventTypeSentByClient(final EventType eventType)
243 {
244 if (!this.eventsSentByClient.contains(eventType))
245 {
246 this.eventsSentByClient.add((eventType));
247 }
248 }
249
250 /***
251 * @see org.gscg.common.interactionlayer.GlobalInteractionLayerInterface#addEventTypeToAnnounceList(nl.tudelft.simulation.event.EventType,
252 * org.gscg.common.interactionlayer.AnnounceInterface)
253 */
254 public void addEventTypeToAnnounceList(final EventType eventType,
255 final AnnounceInterface announceObject)
256 {
257 String key = eventType.toString();
258 this.announceObjects.put(key, announceObject);
259 }
260
261 /***
262 * @see org.gscg.singleuser.interactionlayer.SingleUserInteractionLayerInterface#addStatisticEventType(nl.tudelft.simulation.event.EventType)
263 */
264 public void addStatisticEventType(final EventType eventType)
265 {
266 if (!this.statisticEventTypes.contains(eventType))
267 {
268 this.statisticEventTypes.add(eventType);
269 }
270 }
271
272 /***
273 * @see org.gscg.common.interactionlayer.GlobalInteractionLayerInterface#getCache(java.lang.Object,
274 * nl.tudelft.simulation.event.EventType, boolean)
275 */
276 public synchronized void getCache(final Object remoteEventProducer,
277 final EventType eventType, final boolean cache)
278 throws RemoteException
279 {
280 if (cache)
281 {
282
283
284
285
286 if (!this.clientIsReady)
287 {
288
289 this.shouldBeCaching = true;
290
291 synchronized (this.semaphore)
292 {
293 if (eventType
294 .equals(ScenarioText.CACHE_LARGE_NEWS_MESSAGE_EVENT))
295 {
296 ScenarioText.getScenarioText().announce(eventType,
297 true, this);
298 return;
299 }
300 if (this.announceObjects.containsKey(eventType.toString()))
301 {
302 AnnounceInterface object = (AnnounceInterface) this.announceObjects
303 .get(eventType.toString());
304 object.announce(eventType, true);
305 return;
306 }
307 if (eventType.equals(YellowPage.UPDATE_ACTORS))
308 {
309
310 this.globalSupplyChainData.getYellowPage().update(true,
311 this);
312
313
314 this.eventTypes.add(YellowPage.UPDATE_ACTORS);
315 this.eventTypes
316 .add(YellowPage.UPDATE_INTERACTIVE_PLAYER_STATUS);
317 return;
318 }
319
320
321 if (eventType
322 .equals(GameActorContentStore.UPDATE_ALL_NUMBER_DATA_EVENT))
323 {
324 this.fireAllNumberData();
325 return;
326 }
327
328
329 if (eventType
330 .equals(ClientInterface.INITIALIZATION_COMPLETED_EVENT))
331 {
332 if (this.simulator.isRunning())
333 {
334 this
335 .notifyAnnounced(new Event(
336 SimulatorInterface.START_EVENT,
337 this, null));
338 }
339
340
341
342
343
344 this.isReady(true);
345
346 try
347 {
348
349
350
351 while (this.cache.size() > 0)
352 {
353 this.notify((EventInterface) this.cache
354 .remove(0));
355 }
356 } catch (RemoteException remoteException)
357 {
358
359
360 this.removeListener(null,
361 SimulatorInterface.TIME_CHANGED_EVENT);
362 }
363
364 this.shouldBeCaching = false;
365
366 Logger.info(this, "getCache",
367 "DistributorSingleUserInteractionLayer: last cache event fired. Player: \""
368 + this.owner.getName()
369 + "\" is ready to play.");
370 return;
371 }
372 new ReceivedUnknownEventException(this, "getCache1",
373 eventType);
374 }
375 }
376 } else
377 {
378
379 if (this.announceObjects.containsKey(eventType.toString()))
380 {
381 AnnounceInterface object = (AnnounceInterface) this.announceObjects
382 .get(eventType.toString());
383 object.announce(eventType, false);
384 return;
385 }
386
387
388 if (this.eventsSentByClient.contains(eventType))
389 {
390 if (remoteEventProducer != null)
391 {
392 ((RemoteEventProducerInterface) remoteEventProducer)
393 .addListener(this.remoteEventListener, eventType,
394 false);
395 System.out.println("eveny sent by client event: "
396 + eventType);
397 }
398 return;
399 }
400 new ReceivedUnknownEventException(this, "getCache2", eventType);
401 }
402 }
403
404 /***
405 * @see nl.tudelft.simulation.event.EventListenerInterface#notify(nl.tudelft.simulation.event.EventInterface)
406 */
407 public void notify(final EventInterface event) throws RemoteException
408 {
409
410 if (this.clientIsReady)
411 {
412
413
414 super.fireEvent(event);
415
416
417
418
419
420
421
422
423 } else
424 {
425
426 if (event.getType().equals(SocialMessaging.RECEIVE_SOCIAL_MESSAGE)
427 || event.getType().equals(
428 SocialMessaging.SOCIAL_MESSAGE_SENT)
429 || event.getType().equals(
430 SocialMessaging.UPDATE_SENT_SOCIAL_MESSAGE)
431 || event.getType().equals(
432 SocialMessaging.UPDATE_RECEIVED_SOCIAL_MESSAGE))
433 {
434 this.fireEvent(new Event(event.getType(), this, event
435 .getContent()));
436 return;
437 }
438 if (this.shouldBeCaching)
439 {
440 Logger.info(this, "notify",
441 "DistributorSingleUserInteractionLayer: player: "
442 + this.owner.getName() + " is caching");
443
444 if (!event.getType().equals(
445 SimulatorInterface.TIME_CHANGED_EVENT))
446 {
447
448
449
450
451
452
453 this.cache.add(event);
454 }
455 return;
456 }
457 }
458 }
459
460 /***
461 * @see org.gscg.singleuser.interactionlayer.SingleUserInteractionLayerInterface#notifyAnnounced(nl.tudelft.simulation.event.EventInterface)
462 */
463 public void notifyAnnounced(final EventInterface event)
464 {
465 this.fireEvent(event);
466 }
467
468
469 /***
470 * @see org.gscg.common.interactionlayer.GlobalInteractionLayerInterface#login(nl.tudelft.simulation.event.remote.RemoteEventListenerInterface)
471 */
472 public synchronized boolean login(final RemoteEventListenerInterface client)
473 throws RemoteException
474 {
475
476
477 if (this.clientIsReady)
478 {
479
480 return true;
481 }
482 if (this.shouldBeCaching)
483 {
484
485 return true;
486 }
487 return false;
488 }
489
490 /***
491 * Method publicFireEvent.
492 *
493 * @param event the event to fire
494 */
495 public void publicFireEvent(final EventInterface event)
496 {
497 super.fireEvent(event);
498 }
499
500 /***
501 * Method fireAllNumberData.
502 */
503 public void fireAllNumberData()
504 {
505 ((GameDistributor) this.owner).fireAllNumberData();
506 }
507
508 /***
509 * @see nl.tudelft.simulation.event.EventProducerInterface#removeListener(nl.tudelft.simulation.event.EventListenerInterface,
510 * nl.tudelft.simulation.event.EventType)
511 */
512 public synchronized boolean removeListener(
513 final EventListenerInterface listener, final EventType eventType)
514 {
515
516
517 if (eventType.equals(SimulatorInterface.TIME_CHANGED_EVENT))
518 {
519
520 this.shouldBeCaching = false;
521 this.cache.clear();
522
523 this.isReady(false);
524 Logger.info(this, "removeListener",
525 "DistributorSingleUserInteractionLayer: status of player: \""
526 + this.owner.getName() + "" + "\" set to "
527 + this.clientIsReady);
528 }
529 boolean result = super.removeListener(listener, eventType);
530 return result;
531 }
532
533
534
535
536
537 /***
538 * @see org.gscg.singleuser.interactionlayer.RemoteInteractionLayerInterface#getContentList(java.lang.Class,
539 * boolean, java.lang.String)
540 */
541 public void getContentList(final Class contentClass, final boolean sent,
542 final String productName) throws RemoteException
543 {
544 ((GameDistributor) this.owner).fireAllContentData(contentClass, sent,
545 productName);
546 }
547
548 /***
549 * @see org.gscg.singleuser.interactionlayer.SingleUserInteractionLayerInterface#getGlobalSupplyChainData()
550 */
551 public GameGlobalData getGlobalSupplyChainData()
552 {
553 return this.globalSupplyChainData;
554 }
555
556 /***
557 * @see org.gscg.common.interactionlayer.GlobalInteractionLayerInterface#getStatisticEventTypes()
558 */
559 public EventType[] getStatisticEventTypes()
560 {
561 return (EventType[]) this.statisticEventTypes
562 .toArray(new EventType[this.statisticEventTypes.size()]);
563 }
564
565 /***
566 * @see org.gscg.singleuser.interactionlayer.RemoteInteractionLayerInterface#getSuppliers(java.lang.String)
567 */
568 public RFQDataSuppliers getSuppliers(final String productName)
569 throws RemoteException
570 {
571 return ((GameDistributor) this.owner).getInitialRFQData(productName);
572 }
573
574 /***
575 * @see org.gscg.common.interactionlayer.GlobalInteractionLayerInterface#getTotalNumberOfDays()
576 */
577 public int getTotalNumberOfDays() throws RemoteException
578 {
579 return GlobalRowOrColumnNumber.getNumberOfDays();
580 }
581
582 /***
583 * @see org.gscg.singleuser.interactionlayer.SingleUserInteractionLayerInterface#getOwner()
584 */
585 public SupplyChainActor getOwner()
586 {
587 return this.owner;
588 }
589
590 /***
591 * @see org.gscg.singleuser.interactionlayer.SingleUserInteractionLayerInterface#getSimulator()
592 */
593 public SimulatorInterface getSimulator()
594 {
595 return this.simulator;
596 }
597
598
599
600
601 /***
602 * Method isReady.
603 *
604 * @param ready true if the client is connected, false otherwise
605 */
606 private void isReady(final boolean ready)
607 {
608 this.clientIsReady = ready;
609 this.yellowPage.updateInteractiveOnlineStatus(this.owner, ready, false);
610 }
611
612 /***
613 * writes a serializable method to stream
614 *
615 * @param out the outputstream
616 * @throws IOException on IOException
617 */
618 private synchronized void writeObject(final ObjectOutputStream out)
619 throws IOException
620 {
621
622 this.yellowPage.updateInteractiveOnlineStatus(this.owner, false, true);
623
624 out.defaultWriteObject();
625 out.writeObject(this.simulator.getReplication().getRunControl()
626 .getTreatment().getProperties());
627
628
629 this.yellowPage.updateInteractiveOnlineStatus(this.owner,
630 this.clientIsReady, true);
631 }
632
633 /***
634 * reads a serializable method from stream
635 *
636 * @param in the inputstream
637 */
638 private synchronized void readObject(final java.io.ObjectInputStream in)
639 {
640 try
641 {
642 in.defaultReadObject();
643 try
644 {
645 UnicastRemoteObject.exportObject(this);
646 } catch (RemoteException remoteException)
647 {
648 Logger.severe(this, "<init>", remoteException);
649 }
650
651 this.remoteEventListener = new RemoteEventListener(this);
652 this.semaphore = new Object();
653 new InitialEventContext().bind(this.id, this);
654
655 this.clientIsReady = false;
656
657 } catch (Exception exception)
658 {
659 Logger.severe(this, "readObject", exception);
660 }
661 }
662 }