View Javadoc

1   /*
2    * @(#)GameDelayProductionService.java Mar 14, 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.singleuser.production;
15  
16  import java.util.HashMap;
17  import java.util.Iterator;
18  import java.util.Map;
19  
20  import org.gscg.singleuser.interactionlayer.dataobjects.ProductionStartedData;
21  
22  import nl.tudelft.simulation.dsol.experiment.TimeUnit;
23  import nl.tudelft.simulation.dsol.experiment.TimeUnitInterface;
24  import nl.tudelft.simulation.dsol.formalisms.devs.SimEvent;
25  import nl.tudelft.simulation.event.Event;
26  import nl.tudelft.simulation.event.EventInterface;
27  import nl.tudelft.simulation.event.EventProducer;
28  import nl.tudelft.simulation.event.EventType;
29  import nl.tudelft.simulation.jstats.distributions.DistContinuous;
30  import nl.tudelft.simulation.logger.Logger;
31  import nl.tudelft.simulation.supplychain.actor.Trader;
32  import nl.tudelft.simulation.supplychain.content.ProductionOrder;
33  import nl.tudelft.simulation.supplychain.product.Cargo;
34  import nl.tudelft.simulation.supplychain.product.Product;
35  import nl.tudelft.simulation.supplychain.production.ProductionService;
36  import nl.tudelft.simulation.supplychain.stock.StockInterface;
37  
38  
39  /***
40   * The GameDelayProductionService starts production at the latest possible
41   * moment to meet the delivery date of the production order. Two versions are
42   * available: one that waits till all the raw materials are available. If not,
43   * production is delayed until all materials of the BoM are available in the
44   * right quantities. The other version is a greedy one, it takes all the
45   * materials it needs from the moment production should start, and delays if
46   * necessary to get the missing materials. <br>
47   * <br>
48   * Copyright (c) 2003-2005 Delft University of Technology, Jaffalaan 5, 2628 BX
49   * Delft, the Netherlands. All rights reserved.
50   * 
51   * See for project information <a href="http://www.simulation.tudelft.nl/">
52   * www.simulation.tudelft.nl </a>.
53   * 
54   * The source code and binary code of this software is proprietary information
55   * of Delft University of Technology.
56   * 
57   * @author <a
58   *         href="http://www.tbm.tudelft.nl/webstaf/alexandv/index.htm">Alexander
59   *         Verbraeck </a>
60   * @version $$Revision: 1.3 $$ $$Date: 2005/08/10 11:23:30 $$
61   */
62  public class GameDelayProductionService extends ProductionService
63  {
64  	/*** the EVENT_PRODUCTION_STARTED event */
65  	public static final EventType EVENT_PRODUCTION_STARTED = new EventType(
66  			"EVENT_PRODUCTION_STARTED");
67  
68  	/*** the serial version uid */
69  	private static final long serialVersionUID = 12L;
70  
71  	/*** the time distribution to produce products */
72  	protected DistContinuous productionTime;
73  
74  	/*** fixed time, independent of order size; otherwise time is per unit */
75  	protected boolean fixedTime;
76  
77  	/*** if true, immediately start picking raw materials */
78  	protected boolean greedy;
79  
80  	/*** the fraction that is added to the cost of the materials */
81  	protected double profitMargin;
82  
83  	/*** the event producer */
84  	private MyEventProducer eventProducer = null;
85  
86  	/***
87  	 * Constructs a new production service for one product.
88  	 * 
89  	 * @param owner the actor that owns the production service.
90  	 * @param stock the stock for getting and storing materials.
91  	 * @param product the product of the production service.
92  	 * @param productionTime the time distribution to produce products.
93  	 * @param fixedTime fixed time, independent of order size; otherwise, the
94  	 *        time is per unit.
95  	 * @param greedy if true, immediately start picking raw materials when
96  	 *        production has to start.
97  	 * @param profitMargin the fraction that is added to the cost of the
98  	 *        materials.
99  	 */
100 	public GameDelayProductionService(final Trader owner,
101 			final StockInterface stock, final Product product,
102 			final DistContinuous productionTime, final boolean fixedTime,
103 			final boolean greedy, final double profitMargin)
104 	{
105 		super(owner, stock, product);
106 		this.eventProducer = new MyEventProducer();
107 		this.productionTime = productionTime;
108 		this.fixedTime = fixedTime;
109 		this.greedy = greedy;
110 		this.profitMargin = profitMargin;
111 	}
112 
113 	/***
114 	 * Accept the production order, and delay till the start of production
115 	 * (equals delivery time minus production time minus transportation time) to
116 	 * get the raw materials to produce. Acquire the materials either greedy or
117 	 * all-at-once.
118 	 * 
119 	 * @see nl.tudelft.simulation.supplychain.production.ProductionServiceInterface#acceptProductionOrder(nl.tudelft.simulation.supplychain.content.ProductionOrder)
120 	 */
121 	public void acceptProductionOrder(final ProductionOrder productionOrder)
122 	{
123 		// calculate production time
124 		double ptime = this.productionTime.draw();
125 		if (!this.fixedTime)
126 		{
127 			ptime *= productionOrder.getAmount();
128 		}
129 		double startTime = productionOrder.getDateReady() - ptime;
130 		startTime = Math.max(super.owner.getSimulatorTime(), startTime);
131 		// determine the needed raw materials
132 		Product product = productionOrder.getProduct();
133 		Map bom = product.getBillOfMaterials().getMaterials();
134 		HashMap availableMaterials = new HashMap();
135 		Iterator bomIter = bom.keySet().iterator();
136 		while (bomIter.hasNext())
137 		{
138 			Product raw = (Product) (bomIter.next());
139 			double amount = ((Double) (bom.get(raw))).doubleValue();
140 			amount *= productionOrder.getAmount();
141 			availableMaterials.put(raw, new Double(amount));
142 		}
143 		// don't do anyting before production has to start
144 		Object[] args = new Object[]{productionOrder, new Double(ptime),
145 				availableMaterials};
146 		try
147 		{
148 			SimEvent simEvent = new SimEvent(startTime, this, this,
149 					"startProduction", args);
150 			System.out.println("GameDelayProductionService: actor: "
151 					+ this.owner.getName()
152 					+ " production started for product: "
153 					+ productionOrder.getProduct());
154 			super.owner.getSimulator().scheduleEvent(simEvent);
155 		} catch (Exception e)
156 		{
157 			Logger.severe(this, "acceptProductionOrder", e);
158 		}
159 	}
160 
161 	/***
162 	 * Start the production at the latest possible time. When raw materials are
163 	 * 
164 	 * @param productionOrder the production order.
165 	 * @param ptime the production time.
166 	 * @param availableMaterials the gathered raw materials.
167 	 */
168 	protected void startProduction(final ProductionOrder productionOrder,
169 			final double ptime, final HashMap availableMaterials)
170 	{
171 		// implement production: look if raw materials available in stock
172 		boolean ready = pickRawMaterials(productionOrder, availableMaterials,
173 				false);
174 		if (ready)
175 		{
176 			pickRawMaterials(productionOrder, availableMaterials, true);
177 			// wait for the production time to put the final products together
178 			Object[] args = new Object[]{productionOrder};
179 			try
180 			{
181 				SimEvent simEvent = new SimEvent(super.owner.getSimulatorTime()
182 						+ ptime, this, this, "endProduction", args);
183 				super.owner.getSimulator().scheduleEvent(simEvent);
184 			} catch (Exception e)
185 			{
186 				Logger.severe(this, "startProduction", e);
187 			}
188 
189 			// fire the event that production has started
190 			this.eventProducer.fireEvent(new Event(
191 					GameDelayProductionService.EVENT_PRODUCTION_STARTED,
192 					this.eventProducer, new ProductionStartedData(
193 							productionOrder,
194 							(super.owner.getSimulatorTime() + ptime))));
195 		} else
196 		{
197 			if (this.greedy)
198 			{
199 				pickRawMaterials(productionOrder, availableMaterials, true);
200 			}
201 			// try again in one day
202 			Object[] args = new Object[]{productionOrder, new Double(ptime),
203 					availableMaterials};
204 			try
205 			{
206 				SimEvent simEvent = new SimEvent(super.owner.getSimulatorTime()
207 						+ TimeUnit.convert(1.0, TimeUnitInterface.DAY,
208 								super.owner.getSimulator()), this, this,
209 						"startProduction", args);
210 				super.owner.getSimulator().scheduleEvent(simEvent);
211 			} catch (Exception e)
212 			{
213 				Logger.severe(this, "startProduction", e);
214 			}
215 		}
216 	}
217 
218 	/***
219 	 * @param productionOrder the order that has to be produced
220 	 * @param availableMaterials the materials we already have picked
221 	 * @param pick pick materials (true) or just check availability (false)
222 	 * @return success meaning that all materials were available
223 	 */
224 	protected boolean pickRawMaterials(final ProductionOrder productionOrder,
225 			final HashMap availableMaterials, final boolean pick)
226 	{
227 		boolean ready = true;
228 		Iterator materialIter = availableMaterials.keySet().iterator();
229 		while (materialIter.hasNext())
230 		{
231 			Product rawProduct = (Product) (materialIter.next());
232 			double neededAmount = ((Double) (availableMaterials.get(rawProduct)))
233 					.doubleValue();
234 			double pickAmount = Math.min(super.stock
235 					.getActualAmount(rawProduct), neededAmount);
236 			if (pickAmount == 0)
237 			{
238 				ready = false;
239 			}
240 			if (pick)
241 			{
242 				Cargo cargo = super.stock.getStock(rawProduct, pickAmount);
243 				productionOrder.addMaterialCost(cargo.getValue());
244 				System.out.println("GameDelayProductionService: owner: "
245 						+ this.owner.getName() + " products taken from stock: "
246 						+ cargo);
247 			}
248 		}
249 		return ready;
250 	}
251 
252 	/***
253 	 * endProduction is scheduled after the production time, which starts when
254 	 * all raw materials are available. The task of this scheduled method is to
255 	 * store the finished products in stock.
256 	 * 
257 	 * @param productionOrder the original production order
258 	 */
259 	protected void endProduction(final ProductionOrder productionOrder)
260 	{
261 		Product product = productionOrder.getProduct();
262 		double amount = productionOrder.getAmount();
263 		double cost = productionOrder.getMaterialCost();
264 		super.stock.addStock(product, amount, cost * this.profitMargin);
265 	}
266 
267 
268 	/***
269 	 * Method getEventProducer
270 	 * 
271 	 * @return returns the event producer used to fire events
272 	 */
273 	public EventProducer getEventProducer()
274 	{
275 		return this.eventProducer;
276 	}
277 
278 	/***
279 	 * 
280 	 * <p>
281 	 * (c) copyright 2005 <a href="http://www.simulation.tudelft.nl">Delft
282 	 * University of Technology </a>, the Netherlands. <br>
283 	 * See for project information <a
284 	 * href="http://www.simulation.tudelft.nl">www.simulation.tudelft.nl </a>
285 	 * <br>
286 	 * 
287 	 * Copyright (c) 2003-2005 Delft University of Technology, Jaffalaan 5, 2628
288 	 * BX Delft, the Netherlands. All rights reserved.
289 	 * 
290 	 * See for project information <a href="http://www.simulation.tudelft.nl/">
291 	 * www.simulation.tudelft.nl </a>.
292 	 * 
293 	 * The source code and binary code of this software are proprietary
294 	 * information of Delft University of Technology.
295 	 * 
296 	 * @author <a
297 	 *         href="http://www.tbm.tudelft.nl/webstaf/stijnh/index.htm">Stijn-Pieter
298 	 *         van Houten </a>
299 	 * @version $Revision: 1.3 $ $Date: 2005/08/10 11:23:30 $
300 	 * @since 1.1.12
301 	 */
302 	private class MyEventProducer extends EventProducer
303 	{
304 		/***
305 		 * constructs a new MyEventProducer
306 		 */
307 		public MyEventProducer()
308 		{
309 			super();
310 		}
311 
312 		/***
313 		 * @see nl.tudelft.simulation.event.EventProducer#fireEvent(nl.tudelft.simulation.event.EventInterface)
314 		 */
315 		protected synchronized EventInterface fireEvent(
316 				final EventInterface event)
317 		{
318 			return super.fireEvent(event);
319 		}
320 	}
321 }