View Javadoc

1   /*
2    * @(#)GameMarket.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.Iterator;
19  import java.util.Set;
20  
21  import javax.media.j3d.Bounds;
22  import javax.vecmath.Point2d;
23  import javax.vecmath.Point3d;
24  
25  import nl.tudelft.simulation.actor.messagehandlers.HandleAllMessages;
26  import nl.tudelft.simulation.actor.messagehandlers.MessageHandlerInterface;
27  import nl.tudelft.simulation.content.HandlerInterface;
28  import nl.tudelft.simulation.dsol.experiment.TimeUnit;
29  import nl.tudelft.simulation.dsol.experiment.TimeUnitInterface;
30  import nl.tudelft.simulation.dsol.simulators.AnimatorInterface;
31  import nl.tudelft.simulation.dsol.simulators.DEVSSimulatorInterface;
32  import nl.tudelft.simulation.jstats.distributions.DistConstant;
33  import nl.tudelft.simulation.jstats.distributions.DistContinuous;
34  import nl.tudelft.simulation.jstats.distributions.DistExponential;
35  import nl.tudelft.simulation.jstats.streams.Java2Random;
36  import nl.tudelft.simulation.jstats.streams.StreamInterface;
37  import nl.tudelft.simulation.language.d3.BoundingBox;
38  import nl.tudelft.simulation.language.d3.DirectedPoint;
39  import nl.tudelft.simulation.language.io.URLResource;
40  import nl.tudelft.simulation.logger.Logger;
41  import nl.tudelft.simulation.messaging.devices.reference.FaxDevice;
42  import nl.tudelft.simulation.supplychain.actor.SupplyChainActor;
43  import nl.tudelft.simulation.supplychain.banking.Bank;
44  import nl.tudelft.simulation.supplychain.banking.BankAccount;
45  import nl.tudelft.simulation.supplychain.content.InternalDemand;
46  import nl.tudelft.simulation.supplychain.content.LeanContentStore;
47  import nl.tudelft.simulation.supplychain.demand.Demand;
48  import nl.tudelft.simulation.supplychain.handlers.InternalDemandHandlerRFQ;
49  import nl.tudelft.simulation.supplychain.product.Product;
50  import nl.tudelft.simulation.supplychain.reference.Customer;
51  import nl.tudelft.simulation.supplychain.reference.Retailer;
52  import nl.tudelft.simulation.supplychain.roles.BuyingRole;
53  import nl.tudelft.simulation.supplychain.roles.DemandGenerationRole;
54  
55  import org.gscg.common.GameActorInterface;
56  import org.gscg.common.geo.CalculateLatLonDistance;
57  import org.gscg.experiment.DistTriangularDiscrete;
58  import org.gscg.experiment.HandlerParser;
59  import org.gscg.gameleader.animation2D.GisActorAnimation;
60  import org.jdom.Element;
61  import org.jdom.input.SAXBuilder;
62  
63  /***
64   * The GameMarket extends a Customer from the supplychain project and provides
65   * additional game-specific functionalities. <br>
66   * Copyright (c) 2003-2005 Delft University of Technology, Jaffalaan 5, 2628 BX
67   * Delft, the Netherlands. All rights reserved.
68   * 
69   * See for project information <a href="http://www.simulation.tudelft.nl/">
70   * www.simulation.tudelft.nl </a>.
71   * 
72   * The source code and binary code of this software is proprietary information
73   * of Delft University of Technology.
74   * 
75   * @author <a
76   *         href="http://www.tbm.tudelft.nl/webstaf/alexandv/index.htm">Alexander
77   *         Verbraeck </a>
78   * @version $Revision: 1.1 $ $Date: 2005/08/03 08:52:50 $
79   * @since 1.0.0 <br>
80   */
81  
82  public class GameMarket extends Customer implements GameActorInterface
83  {
84  	/*** builder the xerces parser with validation turned on */
85  	private static SAXBuilder builder = new SAXBuilder(
86  			"org.apache.xerces.parsers.SAXParser", true);
87  
88  	static
89  	{
90  		// turns on Schema Validation with Xerces
91  		GameMarket.builder.setFeature("http://xml.org/sax/features/validation",
92  				true);
93  		GameMarket.builder.setFeature(
94  				"http://apache.org/xml/features/validation/schema", true);
95  
96  		// Let's find the XSD file
97  		String xsd = URLResource.getResource("/handler.xsd").toExternalForm();
98  		GameMarket.builder
99  				.setProperty(
100 						"http://apache.org/xml/properties/schema/external-schemaLocation",
101 						"http://www.simulation.tudelft.nl/dsol " + xsd);
102 	}
103 
104 	/*** the serial version uid */
105 	private static final long serialVersionUID = 12L;
106 
107 	/*** the stream to use */
108 	private transient static StreamInterface defaultStream = new Java2Random();
109 
110 	/*** the product that PCMarket wants to buy */
111 	private Product[] product;
112 
113 	/*** the fixed retailer where PCMarket buys */
114 	private Retailer[] retailer;
115 
116 	/*** the location on the small map */
117 	private DirectedPoint smallMapLocation = new DirectedPoint();
118 
119 	/*** the demand generators */
120 	private Demand[] demand = null;
121 
122 	/*** the animation used for serialization */
123 	private GisActorAnimation animation = null;
124 
125 	/*** true for debug mode */
126 	private boolean debug = false;
127 
128 	/***
129 	 * constructs a new GameMarket; used when dragging and dropping an actor
130 	 * 
131 	 * @param name the name
132 	 * @param simulator the simulator
133 	 * @param position the position
134 	 * @param bank the bank
135 	 */
136 	public GameMarket(final String name,
137 			final DEVSSimulatorInterface simulator, final Point3d position,
138 			final Bank bank)
139 	{
140 		super(name, simulator, position, bank, 0.0);
141 		this.initAnimation();
142 	}
143 
144 	/***
145 	 * constructs a new GameMarket
146 	 * 
147 	 * @param name the name
148 	 * @param simulator the simulator
149 	 * @param position the position
150 	 * @param bank the bank
151 	 * @param initialBankAccount the initial bank account
152 	 * @param product the product
153 	 * @param demand the demand generators for the products
154 	 * @param retailer the retailer
155 	 * @throws RemoteException thrown in case of a network exception
156 	 */
157 	public GameMarket(final String name,
158 			final DEVSSimulatorInterface simulator, final Point3d position,
159 			final Bank bank, final double initialBankAccount,
160 			final Product[] product, final Demand[] demand,
161 			final Retailer[] retailer) throws RemoteException
162 	{
163 		super(name, simulator, position, bank, initialBankAccount);
164 		super.setContentStore(new LeanContentStore(this, simulator));
165 		this.product = (Product[]) product.clone();
166 		this.demand = demand;
167 		this.retailer = retailer;
168 		this.init();
169 
170 		// may be initialized earlier during modeling of supply chain game
171 		if (this.animation == null)
172 		{
173 			this.initAnimation();
174 		}
175 	}
176 
177 	/***
178 	 * @throws RemoteException thrown in case of a network error
179 	 */
180 	public void init() throws RemoteException
181 	{
182 		double hour = TimeUnit.convert(1.0, TimeUnitInterface.HOUR,
183 				this.simulator);
184 		DistContinuous hourDist = new DistConstant(GameMarket.defaultStream,
185 				hour);
186 		double minute = TimeUnit.convert(1.0, TimeUnitInterface.MINUTE,
187 				super.simulator);
188 		//
189 		// give the actor a fax device which is checked every hour
190 		FaxDevice fax = new FaxDevice("Fax-" + this.name, this.simulator);
191 		super.addSendingDevice(fax);
192 		MessageHandlerInterface secretary = new HandleAllMessages(this);
193 		super.addReceivingDevice(fax, secretary, hourDist);
194 
195 		//
196 		// create the buying role for PCMarket
197 		BuyingRole buyingRole = new BuyingRole(this, super.simulator,
198 				super.bankAccount);
199 		super.setBuyingRole(buyingRole);
200 
201 		//
202 		// create the internal demand for PCs
203 		DemandGenerationRole dgRole = new DemandGenerationRole(this,
204 				super.simulator, new DistExponential(GameMarket.defaultStream,
205 						2.0 * minute));
206 
207 		for (int i = 0; i < this.demand.length; i++)
208 		{
209 			dgRole.addDemandGenerator(this.demand[i].getProduct(),
210 					this.demand[i]);
211 		}
212 		super.setDemandGenerationRole(dgRole);
213 
214 		// look for our personal xml file with handler description
215 		URL url = URLResource.getResource("/" + this.name
216 				+ "_computer_controlled.xml");
217 		if (url == null)
218 		{
219 			url = URLResource.getResource("/market_default_handler.xml");
220 		}
221 		Logger
222 				.info(
223 						this,
224 						"init",
225 						"Using: "
226 								+ url.toExternalForm()
227 								+ " as the file containing the configuration for the handlers.");
228 		try
229 		{
230 			// let's parse the xml file data to handlers
231 			Element rootElement = GameDistributor.builder.build(url)
232 					.getRootElement();
233 			HandlerParser.parseAndAddHandler(this, rootElement);
234 		} catch (Exception exception)
235 		{
236 			Logger.severe(this, "init", exception);
237 		}
238 
239 		if (this.contentHandlers.containsKey(InternalDemand.class))
240 		{
241 			Set resolvedhandlers = (Set) this.contentHandlers
242 					.get(InternalDemand.class);
243 
244 			for (Iterator it = resolvedhandlers.iterator(); it.hasNext();)
245 			{
246 				HandlerInterface handler = (HandlerInterface) it.next();
247 				if (handler instanceof InternalDemandHandlerRFQ)
248 				{
249 					for (int i = 0; i < this.product.length; i++)
250 					{
251 						for (int ii = 0; ii < this.retailer.length; ii++)
252 						{
253 							((InternalDemandHandlerRFQ) handler).addSupplier(
254 									this.product[i], this.retailer[ii]);
255 						}
256 					}
257 				}
258 			}
259 		}
260 
261 		//
262 		// CHARTS
263 		//
264 		if (this.simulator instanceof AnimatorInterface)
265 		{
266 			nl.tudelft.simulation.dsol.statistics.charts.XYChart bankChart = new nl.tudelft.simulation.dsol.statistics.charts.XYChart(
267 					this.simulator, "BankAccount " + this.name);
268 			bankChart.add("bank account", this.bankAccount,
269 					BankAccount.BANK_ACCOUNT_CHANGED_EVENT);
270 		}
271 	}
272 
273 	/***
274 	 * Initializes the animation.
275 	 */
276 	private void initAnimation()
277 	{
278 		// Let's give PCMarket its corresponding image
279 		this.animation = new GisActorAnimation(
280 				this,
281 				this.simulator,
282 				GameMarket.class
283 						.getResource("/nl/tudelft/simulation/supplychain/images/Market.gif"));
284 	}
285 
286 	/***
287 	 * @see nl.tudelft.simulation.dsol.animation.LocatableInterface#getBounds()
288 	 */
289 	public Bounds getBounds()
290 	{
291 		// return new BoundingBox(50.0, 50.0, 0.0);
292 		return new BoundingBox(1.0, 1.0, 0.0);
293 	}
294 
295 	/***
296 	 * @return Returns the smallMapLocation.
297 	 */
298 	public DirectedPoint getSmallMapLocation()
299 	{
300 		return this.smallMapLocation;
301 	}
302 
303 	/***
304 	 * @param smallMapLocation The smallMapLocation to set.
305 	 */
306 	public void setSmallMapLocation(final DirectedPoint smallMapLocation)
307 	{
308 		this.smallMapLocation = smallMapLocation;
309 	}
310 
311 	/***
312 	 * @see nl.tudelft.simulation.actor.ActorInterface#getName()
313 	 */
314 	public String getName()
315 	{
316 		return this.name;
317 	}
318 
319 	/***
320 	 * @return Returns the animation
321 	 */
322 	protected GisActorAnimation getAnimation()
323 	{
324 		return this.animation;
325 	}
326 
327 	/***
328 	 * @see nl.tudelft.simulation.supplychain.actor.SupplyChainActor#calculateDistance(nl.tudelft.simulation.supplychain.actor.SupplyChainActor)
329 	 */
330 	public double calculateDistance(final SupplyChainActor actor)
331 	{
332 		return new CalculateLatLonDistance().getDistance(new Point2d(
333 				this.location.x, this.location.y), new Point2d(actor
334 				.getLocation().x, actor.getLocation().y));
335 	}
336 
337 	/***
338 	 * Method changeDemand changes the demand of a PCMarket for the specified
339 	 * product.
340 	 * 
341 	 * @param product the product to change the demand for
342 	 * @param up if true, demand will increase, if false, the demand will
343 	 *        decrease
344 	 * @param percentage the percentage to change the demand with
345 	 */
346 	public void changeDemand(final Product product, final boolean up,
347 			final double percentage)
348 	{
349 		Demand demand = super.getDemandGenerationRole().getDemandGenerator(
350 				product);
351 		if (demand != null)
352 		{
353 			DistContinuous amount = demand.getAmount();
354 			if (amount instanceof org.gscg.experiment.DistTriangularDiscrete)
355 			{
356 				DistTriangularDiscrete oldAmount = (DistTriangularDiscrete) amount;
357 				DistTriangularDiscrete newAmount = null;
358 
359 				if (up)
360 				{
361 					double newB = oldAmount.getB() * (1 + (percentage / 100));
362 
363 					// we keep the original difference between a - b - c
364 					newAmount = new DistTriangularDiscrete(oldAmount
365 							.getStream(), newB
366 							- (oldAmount.getB() - oldAmount.getA()), newB, newB
367 							+ (oldAmount.getC() - oldAmount.getB()));
368 					if (this.debug)
369 					{
370 						System.out.println("DEBUG -- PCMarket: "
371 								+ oldAmount.getA() + " _ " + newAmount.getA());
372 						System.out.println("DEBUG -- PCMarket: "
373 								+ oldAmount.getB() + " _ " + newAmount.getB());
374 						System.out.println("DEBUG -- PCMarket: "
375 								+ oldAmount.getC() + " _ " + newAmount.getC());
376 					}
377 				} else
378 				{
379 					newAmount = new DistTriangularDiscrete(oldAmount
380 							.getStream(), oldAmount.getA()
381 							* (1 - (percentage / 100)), oldAmount.getB()
382 							* (1 - (percentage / 100)), oldAmount.getC()
383 							* (1 - (percentage / 100)));
384 				}
385 
386 				Demand newDemand = new Demand(product, demand.getInterval(),
387 						newAmount, demand.getEarliestDeliveryDate(), demand
388 								.getLatestDeliveryDate());
389 				// we remove the old demand generator
390 				super.getDemandGenerationRole().removeDemandGenerator(product);
391 
392 				// and add the new one...
393 				super.getDemandGenerationRole().addDemandGenerator(
394 						newDemand.getProduct(), newDemand);
395 			}
396 		} else
397 		{
398 			Logger.severe(this, "changeDemand",
399 					"Could not find demand for product: " + product.getName());
400 		}
401 	}
402 }