View Javadoc

1   /*
2    * @(#)GameDistributor.java Apr 25, 2004
3    * 
4    * Copyright (c) 2003-2005 Delft University of Technology, Jaffalaan 5, 2628 BX
5    * Delft, the Netherlands. All rights reserved.
6    * 
7    * See for project information <a href="http://www.simulation.tudelft.nl/">
8    * www.simulation.tudelft.nl </a>.
9    * 
10   * The source code and binary code of this software is proprietary information
11   * of Delft University of Technology.
12   */
13  
14  package org.gscg.gameactors;
15  
16  import java.net.URL;
17  import java.rmi.RemoteException;
18  import java.util.Collection;
19  import java.util.HashMap;
20  import java.util.HashSet;
21  import java.util.Iterator;
22  import java.util.List;
23  import java.util.Map;
24  import java.util.Set;
25  
26  import javax.media.j3d.Bounds;
27  import javax.vecmath.Point2d;
28  import javax.vecmath.Point3d;
29  
30  import nl.tudelft.simulation.actor.messagehandlers.HandleAllMessages;
31  import nl.tudelft.simulation.actor.messagehandlers.MessageHandlerInterface;
32  import nl.tudelft.simulation.content.HandlerInterface;
33  import nl.tudelft.simulation.dsol.experiment.TimeUnit;
34  import nl.tudelft.simulation.dsol.experiment.TimeUnitInterface;
35  import nl.tudelft.simulation.dsol.simulators.AnimatorInterface;
36  import nl.tudelft.simulation.dsol.simulators.DEVSSimulatorInterface;
37  import nl.tudelft.simulation.dsol.statistics.charts.XYChart;
38  import nl.tudelft.simulation.jstats.distributions.DistConstant;
39  import nl.tudelft.simulation.jstats.distributions.DistContinuous;
40  import nl.tudelft.simulation.jstats.streams.StreamInterface;
41  import nl.tudelft.simulation.language.d3.BoundingBox;
42  import nl.tudelft.simulation.language.d3.DirectedPoint;
43  import nl.tudelft.simulation.language.io.URLResource;
44  import nl.tudelft.simulation.logger.Logger;
45  import nl.tudelft.simulation.messaging.devices.reference.FaxDevice;
46  import nl.tudelft.simulation.supplychain.actor.SupplyChainActor;
47  import nl.tudelft.simulation.supplychain.actor.Trader;
48  import nl.tudelft.simulation.supplychain.banking.Bank;
49  import nl.tudelft.simulation.supplychain.banking.BankAccount;
50  import nl.tudelft.simulation.supplychain.content.InternalDemand;
51  import nl.tudelft.simulation.supplychain.handlers.InternalDemandHandlerRFQ;
52  import nl.tudelft.simulation.supplychain.product.Product;
53  import nl.tudelft.simulation.supplychain.reference.Retailer;
54  import nl.tudelft.simulation.supplychain.roles.Role;
55  import nl.tudelft.simulation.supplychain.stock.Stock;
56  
57  import org.gscg.common.GameActorInterface;
58  import org.gscg.common.geo.CalculateLatLonDistance;
59  import org.gscg.experiment.HandlerParser;
60  import org.gscg.game.GameActorContentStore;
61  import org.gscg.game.GameGlobalData;
62  import org.gscg.gameleader.animation2D.GisActorAnimation;
63  import org.gscg.singleuser.handlers.InteractiveQuoteHandler;
64  import org.gscg.singleuser.interactionlayer.business.statistics.CustomerStatistics;
65  import org.gscg.singleuser.interactionlayer.dataobjects.DateIntData;
66  import org.gscg.singleuser.interactionlayer.dataobjects.content.RFQDataSuppliers;
67  import org.jdom.Element;
68  import org.jdom.input.SAXBuilder;
69  
70  /***
71   * The GameDistributor extends a Distributor from the supplychain project and
72   * provides additional game-specific functionalities. <br>
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/alexandv/index.htm">Alexander
84   *         Verbraeck </a>
85   * @version $Revision: 1.3 $ $Date: 2005/08/09 20:49:45 $
86   * @since 1.0.0 <br>
87   */
88  
89  public class GameDistributor extends Retailer implements GameActorInterface,
90  		GameInteractiveActorRoleInterface
91  {
92  	/*** builder the xerces parser with validation turned on */
93  	protected static SAXBuilder builder = new SAXBuilder(
94  			"org.apache.xerces.parsers.SAXParser", true);
95  
96  	static
97  	{
98  		// turns on Schema Validation with Xerces
99  		GameDistributor.builder.setFeature(
100 				"http://xml.org/sax/features/validation", true);
101 		GameDistributor.builder.setFeature(
102 				"http://apache.org/xml/features/validation/schema", true);
103 
104 		// Let's find the XSD file
105 		String xsd = URLResource.getResource("/handler.xsd").toExternalForm();
106 		GameDistributor.builder
107 				.setProperty(
108 						"http://apache.org/xml/properties/schema/external-schemaLocation",
109 						"http://www.simulation.tudelft.nl/dsol " + xsd);
110 	}
111 
112 	/*** the serial version uid */
113 	private static final long serialVersionUID = 12L;
114 
115 	/*** debug */
116 	private static final boolean DEBUG = false;
117 
118 	/*** the manufacturers where the GameDistributor buys */
119 	protected Trader[] manufacturer;
120 
121 	/*** the global supply chain game data */
122 	protected GameGlobalData globalSupplyChainData = null;
123 
124 	/*** the customer statistisc for this player */
125 	protected CustomerStatistics customerStatistics = null;
126 
127 	/*** the special interactive quotehander */
128 	protected InteractiveQuoteHandler interactiveQuoteHandler = null;
129 
130 	/*** the lat lon distance calculator to use */
131 	protected CalculateLatLonDistance latLonDistanceCalculator = null;
132 
133 	/*** if true than we use any human intervention */
134 	protected boolean humanControlled = false;
135 
136 	/*** true for warming-up */
137 	protected boolean warmingUp = false;
138 
139 	/*** the location on the small map */
140 	private DirectedPoint smallMapLocation = new DirectedPoint();
141 
142 	/*** the animation used for serialization */
143 	private GisActorAnimation animation = null;
144 
145 	/*** the map with product names and their suppliers */
146 	private Map productNameToSuppliers = null;
147 
148 	/***
149 	 * constructs a new GameDistributor; used when dragging and dropping an
150 	 * actor
151 	 * 
152 	 * @param name the name
153 	 * @param simulator the simulator
154 	 * @param position the position
155 	 * @param bank the bank
156 	 */
157 	public GameDistributor(final String name,
158 			final DEVSSimulatorInterface simulator, final Point3d position,
159 			final Bank bank)
160 	{
161 		super(name, simulator, position, new Role[]{}, bank, 0.0);
162 		this.initAnimation();
163 	}
164 
165 
166 	/***
167 	 * constructs a new GameDistributor
168 	 * 
169 	 * @param name the name
170 	 * @param simulator the simulator
171 	 * @param position the position
172 	 * @param roles the roles to implement
173 	 * @param bank the bank
174 	 * @param product the product
175 	 * @param amount the amount
176 	 * @param manufacturer the manufacturer
177 	 * @param globalSupplyChainData the global supply chain data
178 	 */
179 	public GameDistributor(final String name,
180 			final DEVSSimulatorInterface simulator, final Point3d position,
181 			final Role[] roles, final Bank bank, final Product[] product,
182 			final Double[] amount, final Trader[] manufacturer,
183 			final GameGlobalData globalSupplyChainData)
184 	{
185 		this(name, simulator, position, roles, bank, 0.0, product, amount,
186 				manufacturer, globalSupplyChainData);
187 	}
188 
189 	/***
190 	 * Constructs a new GameDistributor
191 	 * 
192 	 * @param name the name
193 	 * @param simulator the simulator
194 	 * @param position the position
195 	 * @param roles the roles to implement
196 	 * @param bank the bank
197 	 * @param initialBankAccount the initial bank account
198 	 * @param product the product
199 	 * @param amount the amount
200 	 * @param manufacturer the manufacturer
201 	 * @param globalSupplyChainData the global supply chain data
202 	 */
203 	public GameDistributor(final String name,
204 			final DEVSSimulatorInterface simulator, final Point3d position,
205 			final Role[] roles, final Bank bank,
206 			final double initialBankAccount, final Product[] product,
207 			final Double[] amount, final Trader[] manufacturer,
208 			final GameGlobalData globalSupplyChainData)
209 	{
210 		super(name, simulator, position, roles, bank, initialBankAccount);
211 		super.setContentStore(new GameActorContentStore(this, simulator));
212 		this.manufacturer = (Trader[]) manufacturer.clone();
213 		this.globalSupplyChainData = globalSupplyChainData;
214 		this.latLonDistanceCalculator = new CalculateLatLonDistance();
215 
216 		// make a map which keeps track which manufacturer supplies what
217 		// products
218 		this.productNameToSuppliers = new HashMap();
219 		for (int i = 0; i < this.manufacturer.length; i++)
220 		{
221 			Trader trader = this.manufacturer[i];
222 			List productsOnStock = trader.getProductsOnStock();
223 			for (int ii = 0; ii < productsOnStock.size(); ii++)
224 			{
225 				Product productOnStock = (Product) productsOnStock.get(ii);
226 
227 				if (!this.productNameToSuppliers.containsKey(productOnStock
228 						.getName()))
229 				{
230 					this.productNameToSuppliers.put(productOnStock.getName(),
231 							new HashSet());
232 				}
233 				Set set = (Set) this.productNameToSuppliers.get(productOnStock
234 						.getName());
235 				set.add(trader);
236 				this.productNameToSuppliers.put(productOnStock.getName(), set);
237 			}
238 		}
239 
240 		// give the retailer some stock
241 		Stock stock = new Stock(this);
242 		for (int i = 0; i < product.length; i++)
243 		{
244 			stock.addStock(product[i], amount[i].doubleValue(), amount[i]
245 					.doubleValue()
246 					* product[i].getUnitMarketPrice());
247 		}
248 		setInitialStock(stock);
249 
250 		// add the devices
251 		this.addDevices();
252 
253 		// add the content handlers
254 		this.init();
255 
256 		// may be initialized earlier during modeling of supply chain game
257 		if (this.animation == null)
258 		{
259 			this.initAnimation();
260 		}
261 	}
262 
263 	/***
264 	 * initializes the content handlers
265 	 */
266 	protected void init()
267 	{
268 		this.addComputerControlledContentHandlers();
269 		try
270 		{
271 			//
272 			// CHARTS
273 			//
274 			if (this.simulator instanceof AnimatorInterface)
275 			{
276 				XYChart bankChart = new XYChart(this.simulator, "BankAccount "
277 						+ this.name);
278 				bankChart.add("bank account", this.bankAccount,
279 						BankAccount.BANK_ACCOUNT_CHANGED_EVENT);
280 			}
281 		} catch (RemoteException remoteException)
282 		{
283 			Logger.severe(this, "init", remoteException);
284 		}
285 
286 		if (GameDistributor.DEBUG)
287 		{
288 			System.out.println("GameDistributor: player: " + this.name
289 					+ " initialized.");
290 		}
291 	}
292 
293 	/***
294 	 * adds computer-controlled interactive content handlers
295 	 */
296 	protected void addComputerControlledContentHandlers()
297 	{
298 		// remove all previous content handlers
299 		this.removeAllContentHandlers();
300 
301 		// look for our personal xml file with handler description
302 		URL url = URLResource.getResource("/" + this.name
303 				+ "_computer_controlled.xml");
304 		if (url == null)
305 		{
306 			url = URLResource.getResource("/distributor_default_handler.xml");
307 		}
308 		Logger
309 				.info(
310 						this,
311 						"addComputerControlledContentHandlers",
312 						"Using: "
313 								+ url.toExternalForm()
314 								+ " as the file containing the configuration for the handlers.");
315 		try
316 		{
317 			// let's parse the xml file data to handlers
318 			Element rootElement = GameDistributor.builder.build(url)
319 					.getRootElement();
320 			HandlerParser.parseAndAddHandler(this, rootElement);
321 		} catch (Exception exception)
322 		{
323 			Logger.severe(this, "addComputerControlledContentHandlers",
324 					exception);
325 		}
326 
327 		// after all handlers have been added we check whether there is an
328 		// internal demand handler for rfq's
329 
330 		if (this.contentHandlers.containsKey(InternalDemand.class))
331 		{
332 			Set resolvedHandlers = (Set) this.contentHandlers
333 					.get(InternalDemand.class);
334 
335 			for (Iterator resolvedHandlersIterator = resolvedHandlers
336 					.iterator(); resolvedHandlersIterator.hasNext();)
337 			{
338 				HandlerInterface handler = (HandlerInterface) resolvedHandlersIterator
339 						.next();
340 
341 				if (handler instanceof InternalDemandHandlerRFQ)
342 				{
343 					Iterator productIterator = this.getStock().iterator();
344 					while (productIterator.hasNext())
345 					{
346 						Product product = (Product) productIterator.next();
347 						Set suppliers = (Set) this.getProductNameToSuppliers()
348 								.get(product.getName());
349 						if (suppliers != null)
350 						{
351 							for (Iterator supplierIterator = suppliers
352 									.iterator(); supplierIterator.hasNext();)
353 							{
354 								((InternalDemandHandlerRFQ) handler)
355 										.addSupplier(product,
356 												(Trader) supplierIterator
357 														.next());
358 							}
359 						} else
360 						{
361 							Logger.warning(this,
362 									"addComputerControlledContentHandlers",
363 									"No suppliers found for product: "
364 											+ product);
365 						}
366 					}
367 				}
368 			}
369 		}
370 	}
371 
372 	/***
373 	 * removes all the content handlers
374 	 */
375 	protected void removeAllContentHandlers()
376 	{
377 		super.contentHandlers.clear();
378 	}
379 
380 	protected void addDevices()
381 	{
382 		try
383 		{
384 			StreamInterface stream = this.simulator.getReplication().getStream(
385 					"default");
386 			double hour = TimeUnit.convert(1.0, TimeUnitInterface.HOUR,
387 					this.simulator);
388 			DistContinuous hourDist = new DistConstant(stream, hour);
389 			//
390 			// give the actor a fax device which is checked every hour
391 			//
392 			FaxDevice fax = new FaxDevice("GameDistributorFax", this.simulator);
393 			addSendingDevice(fax);
394 			MessageHandlerInterface secretary = new HandleAllMessages(this);
395 			addReceivingDevice(fax, secretary, hourDist);
396 		} catch (RemoteException remoteException)
397 		{
398 			Logger.severe(this, "addDevices", remoteException);
399 		}
400 	}
401 
402 	/***
403 	 * Initializes the animation.
404 	 */
405 	private void initAnimation()
406 	{
407 		// Let's give PCMarket its corresponding image
408 		this.animation = new GisActorAnimation(
409 				this,
410 				this.simulator,
411 				URLResource
412 						.getResource("/nl/tudelft/simulation/supplychain/images/Retailer.gif"));
413 	}
414 
415 	/***
416 	 * @see nl.tudelft.simulation.dsol.animation.LocatableInterface#getBounds()
417 	 */
418 	public Bounds getBounds()
419 	{
420 		return new BoundingBox(1.0, 1.0, 0.0);
421 	}
422 
423 	/***
424 	 * Method getContent returns all data objects of type contentClass
425 	 * 
426 	 * @param contentClass the content class to look for
427 	 * @param sent indicates whether the content is sent or received
428 	 * @param productName the name of the product
429 	 */
430 	public void fireAllContentData(final Class contentClass,
431 			final boolean sent, final String productName)
432 	{
433 		getGameContentStore().fireAllProductContentData(contentClass, sent,
434 				productName);
435 	}
436 
437 	/***
438 	 * Method fireAllNumberData.
439 	 */
440 	public void fireAllNumberData()
441 	{
442 		Collection products = this.globalSupplyChainData.getProducts();
443 		Iterator prodIter = products.iterator();
444 		while (prodIter.hasNext())
445 		{
446 			Product product = (Product) prodIter.next();
447 			getGameContentStore().fireAllProductNumberData(product.getName());
448 		}
449 	}
450 
451 	/***
452 	 * @param productName the product we want
453 	 * @return an initialized RFQData object with potential suppliers
454 	 */
455 	public RFQDataSuppliers getInitialRFQData(final String productName)
456 	{
457 		double day = 0;
458 		try
459 		{
460 			day = TimeUnit.convert(1, TimeUnitInterface.DAY, this.simulator);
461 		} catch (Exception exception)
462 		{
463 			Logger.severe(this, "getInitialRFQData", "TimeUnit.convert failed");
464 		}
465 
466 		// TODO the desired earliest and delivery date should not be hard-coded
467 		double earliestDeliveryDate = this.getSimulatorTime() + 14 * day;
468 		double defaultAmount = 100;
469 		double latestDeliveryDate = earliestDeliveryDate + 7.0 * day;
470 
471 		String[] supplierNames = new String[0];
472 		String[] supplierNickNames = new String[0];
473 		Point2d ownLocation = new Point2d(this.getLocation().x, this
474 				.getLocation().y);
475 		Point2d[] suppliersLocations = new Point2d[0];
476 
477 		Set suppliers = (Set) this.productNameToSuppliers.get(productName);
478 		if (suppliers != null)
479 		{
480 			supplierNames = new String[suppliers.size()];
481 			supplierNickNames = new String[suppliers.size()];
482 			suppliersLocations = new Point2d[suppliers.size()];
483 
484 			int counter = 0;
485 			for (Iterator it = suppliers.iterator(); it.hasNext();)
486 			{
487 				Trader trader = (Trader) it.next();
488 				supplierNames[counter] = trader.getName();
489 				supplierNickNames[counter] = trader.getLocationDescription();
490 				suppliersLocations[counter] = new Point2d(
491 						trader.getLocation().x, trader.getLocation().y);
492 				counter++;
493 			}
494 		}
495 		return new RFQDataSuppliers(this.name, supplierNames,
496 				supplierNickNames, DateIntData.makeDateIntData(
497 						earliestDeliveryDate, this.simulator), DateIntData
498 						.makeDateIntData(latestDeliveryDate, this.simulator),
499 				defaultAmount, productName, ownLocation, suppliersLocations);
500 	}
501 
502 	/***
503 	 * @return Returns the smallMapLocation.
504 	 */
505 	public DirectedPoint getSmallMapLocation()
506 	{
507 		return this.smallMapLocation;
508 	}
509 
510 	/***
511 	 * @param smallMapLocation The smallMapLocation to set.
512 	 */
513 	public void setSmallMapLocation(final DirectedPoint smallMapLocation)
514 	{
515 		this.smallMapLocation = smallMapLocation;
516 	}
517 
518 	/***
519 	 * @see org.gscg.gameactors.GameInteractiveActorRoleInterface#getGameContentStore()
520 	 */
521 	public GameActorContentStore getGameContentStore()
522 	{
523 		return (GameActorContentStore) super.getContentStore();
524 	}
525 
526 	/***
527 	 * @see nl.tudelft.simulation.actor.ActorInterface#getName()
528 	 */
529 	public String getName()
530 	{
531 		return this.name;
532 	}
533 
534 	/***
535 	 * sets the interactive quote handler
536 	 * 
537 	 * @param interactiveQuoteHandler the interactive quote handler to set
538 	 */
539 	public void setInteractiveQuoteHandler(
540 			final InteractiveQuoteHandler interactiveQuoteHandler)
541 	{
542 		this.interactiveQuoteHandler = interactiveQuoteHandler;
543 	}
544 
545 	/***
546 	 * @return Returns the animation
547 	 */
548 	protected GisActorAnimation getAnimation()
549 	{
550 		return this.animation;
551 	}
552 
553 	/***
554 	 * @see nl.tudelft.simulation.supplychain.actor.SupplyChainActor#calculateDistance(nl.tudelft.simulation.supplychain.actor.SupplyChainActor)
555 	 */
556 	public double calculateDistance(final SupplyChainActor actor)
557 	{
558 		return new CalculateLatLonDistance().getDistance(new Point2d(
559 				this.location.x, this.location.y), new Point2d(actor
560 				.getLocation().x, actor.getLocation().y));
561 	}
562 
563 	/***
564 	 * @return Returns the productNameToSuppliers.
565 	 */
566 	public Map getProductNameToSuppliers()
567 	{
568 		return this.productNameToSuppliers;
569 	}
570 
571 	/***
572 	 * @return true if human controlled, false otherwise
573 	 */
574 	public boolean isHumanControlled()
575 	{
576 		return this.humanControlled;
577 	}
578 }