View Javadoc

1   /*
2    *  
3    *  author nambi sankaran
4    *  copyright (C) 2009 nambi sankaran.
5    *
6    *  This program is free software: you can redistribute it and/or modify
7    *  it under the terms of the GNU General Public License as published by
8    *  the Free Software Foundation, either version 3 of the License, or
9    *  (at your option) any later version.
10   *
11   *  This program is distributed in the hope that it will be useful,
12   *  but WITHOUT ANY WARRANTY; without even the implied warranty of
13   *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
14   *  GNU General Public License for more details.
15   *
16   *  You should have received a copy of the GNU General Public License
17   *  along with this program.  If not, see <http://www.gnu.org/licenses/>.
18   *
19   */
20  package net.sf.emarket.order.service;
21  
22  import java.util.ArrayList;
23  import java.util.Collections;
24  import java.util.Comparator;
25  import java.util.HashMap;
26  import java.util.List;
27  import java.util.Map;
28  import java.util.logging.Logger;
29  
30  import net.sf.emarket.account.domain.Account;
31  import net.sf.emarket.account.domain.AcctPosition;
32  import net.sf.emarket.account.domain.AcctPositionTransfer;
33  import net.sf.emarket.account.domain.CashBalance;
34  import net.sf.emarket.account.domain.CashTransfer;
35  import net.sf.emarket.account.service.AccountNotActiveException;
36  import net.sf.emarket.account.service.IAccountManagerService;
37  import net.sf.emarket.account.service.InSufficientCashBalanceException;
38  import net.sf.emarket.account.service.NotEnoughCashException;
39  import net.sf.emarket.account.service.NotEnoughPositionsException;
40  import net.sf.emarket.account.service.NotValidAccountException;
41  import net.sf.emarket.order.domain.Order;
42  import net.sf.emarket.order.domain.TimeComparator;
43  import net.sf.emarket.order.repository.IOrderDao;
44  import net.sf.emarket.quote.domain.Instrument;
45  import net.sf.emarket.quote.domain.Quote;
46  import net.sf.emarket.quote.domain.Instrument;
47  import net.sf.emarket.quote.service.IQuoteManagerService;
48  import net.sf.emarket.system.service.IMailSenderService;
49  import net.sf.emarket.trade.domain.OrderFill;
50  import net.sf.emarket.trade.domain.OrderMatch;
51  import net.sf.emarket.trade.service.IOrderExecutorService;
52  import net.sf.emarket.user.domain.User;
53  import net.sf.emarket.user.service.IUserManagerService;
54  import net.sf.emarket.user.service.UserNotFoundException;
55  
56  import org.springframework.beans.factory.annotation.Autowired;
57  import org.springframework.mail.SimpleMailMessage;
58  import org.springframework.transaction.annotation.Propagation;
59  import org.springframework.transaction.annotation.Transactional;
60  
61  
62  public class OrderManagerServiceImpl implements IOrderManagerService  {
63  	
64  	private static final long serialVersionUID = 6143050250286605772L;
65  
66  	private static Logger logger = Logger.getLogger( OrderManagerServiceImpl.class.getName() );
67  	
68  	private IOrderDao orderDao = null;
69  	private IUserManagerService userMgr =null;
70  	private IAccountManagerService acctMgr = null;
71  	private IQuoteManagerService quoteMgr = null;
72  	private IOrderExecutorService orderExecutor = null;
73      private IMailSenderService mailSender;
74      private SimpleMailMessage templateMessage;
75  
76  
77  	@Autowired
78  	public void setOrderDao( IOrderDao dao){
79  		orderDao = dao;
80  	}
81  	
82  	@Autowired
83  	public void setUserManager( IUserManagerService mgr){
84  		userMgr = mgr;
85  	}
86  	
87  	@Autowired
88  	public void setAccountManager( IAccountManagerService acctMgrSvc ){
89  		acctMgr = acctMgrSvc;
90  	}
91  	
92  	@Autowired
93  	public void setQuoteManager( IQuoteManagerService quoteMgrSvr ){
94  		quoteMgr = quoteMgrSvr;
95  	}
96  	
97  	@Autowired
98  	public void setOrderExecutor( IOrderExecutorService executor){
99  		orderExecutor = executor;
100 	}
101 	
102     @Autowired
103     public void setMailSender(IMailSenderService mailSender) {
104         this.mailSender = mailSender;
105     }
106 
107     @Autowired
108     public void setTemplateMessage(SimpleMailMessage templateMessage) {
109         this.templateMessage = templateMessage;
110     }
111 		
112 
113 	@Transactional(propagation = Propagation.REQUIRED, readOnly = false)
114 	public Order placeOrder(Order order) throws AccountNotActiveException, InSufficientCashBalanceException, NotEnoughPositionsException, InstrumentCannotTradeException, WrongLimitPriceExeption {
115 	
116 		// verify the order, if it is not done before
117 		Order verifiedOrder = null;
118 		if( order.getId() == null || order.getId().trim().equals("") ){
119 			verifiedOrder = verifyOrder(order);
120 		}else{
121 			// TODO: need better logic to figure out whether the order is verified and it is still valid
122 			verifiedOrder =order;
123 		}
124 		
125 		//Sometimes, the verification was done long ago.
126 		// TODO: we need to check whether it is still valid
127 		
128 	
129 		// change the status 
130 		verifiedOrder.setStatus(Order.STATUS_OPEN);
131 		
132 		// place the order, with order management system
133 		orderDao.updateOrder(verifiedOrder);
134 		
135 		// send the order to the trading engine
136 		orderExecutor.execute(verifiedOrder);
137 		
138 		return verifiedOrder;
139 	}
140 	
141 	@Transactional(propagation = Propagation.REQUIRED, readOnly = false)
142 	public Order verifyOrder( Order order )
143             throws AccountNotActiveException, InSufficientCashBalanceException, NotEnoughPositionsException, InstrumentCannotTradeException, WrongLimitPriceExeption {
144 		
145 		// TODO: determine the type of "trade" by looking at the order
146 		
147 		
148 		// get the account status
149 		Account account = acctMgr.getAccountById(order.getAcctId());
150 		
151 		String acctStatus = account.getStatus();
152 		if( !acctStatus.equals( Account.STATUS_ACTIVE) ){
153 			throw new AccountNotActiveException( "Account  "+  account.getAcctId() + " not active");
154 		}
155 		
156 		// TODO: check whether the account is enabled for this type of trading
157 		
158 		// get the quote
159 		Quote quote = quoteMgr.getQuote(order.getSymbol());
160 
161 
162         //Check whether the instrument is allowed to trade
163         if( !quote.getInstrument().getStatus().equals( Instrument.STATUS_ACTIVE )){
164              throw new InstrumentCannotTradeException("Symbol "+ quote.getSymbol() + " is not allowed trade" );
165         }
166 		
167 		// Store the quote Id in order
168 		order.setQuoteId(quote.getId());
169 
170 /*        // if it is a limit order, the limit price should be within a range
171         if( order.isLimitOrder() ){
172             if( order.isBuy() ){
173                // limit price cannot be higher than the best bid price
174                 if( order.getLimitPrice() > quote.getAskPrice() ){
175                         throw new WrongLimitPriceExeption("Buy limit price " + order.getLimitPrice() + " is greater than ask price " + quote.getAskPrice());
176                 }
177 
178             }else if( order.isSell() ){
179                 // limit price cannot be lower than the best ask price
180                 if( order.getLimitPrice() < quote.getBidPrice() ){
181                         throw new WrongLimitPriceExeption("Sell limit price " + order.getLimitPrice() + " is lesser than bid price "+ quote.getBidPrice() );
182                 }
183             }
184         }*/
185 		
186 		// calculate the cost 
187 		float cost = calculateCost(order, quote);
188 		
189 		// determine commission
190 		float commission = calculateCommision(account, order);
191 		order.setCommission(commission);
192 		
193 		// compute total
194 		// total = cost + commission
195 		float totalCost = cost + commission;
196 		order.setTotalCost(totalCost);
197 		
198 		
199 		// check whether account has enough money to BUY 
200 		// or
201 		// whether the account has enough shares to SELL
202 		if( order.getOrderType().equals( Order.TYPE_BUY) ){
203 			CashBalance balance = acctMgr.getCashBalance(account);
204 			if( balance.getAmount() < order.getTotalCost() ){
205 				throw new InSufficientCashBalanceException("Account "+ account.getAcctId()
206                         + " doesn't have enough cash balance.");
207 			}
208 
209             float totalCashNeeded = 0f;
210             // check whether there are any other "BUY" orders that need the cash
211             List<Order> openOrders = orderDao.getOrdersForAcctIdWithStatusAndSymbol( account.getAcctId(),
212                                                                                                                                                     Order.STATUS_OPEN,
213                                                                                                                                                     order.getSymbol());
214 
215             for( Order o : openOrders ){
216                 totalCashNeeded += ( o.getQuantity() * o.getLimitPrice() );
217             }
218 
219             // get all partialy filled orders for this account and symbol
220             List<Order> partiallyFilledOrders =  orderDao.getOrdersForAcctIdWithStatusAndSymbol( account.getAcctId(),
221                                                                                                                                                     Order.STATUS_PARTIALLY_FILLED ,
222                                                                                                                                                     order.getSymbol());
223 
224             for( Order o : partiallyFilledOrders ){
225                 totalCashNeeded += ((o.getQuantity() - o.getFilledQuantity())) * o.getLimitPrice();
226             }
227 
228             if( balance.getAmount() < ( totalCashNeeded + order.getTotalCost() ) ){
229                     throw new InSufficientCashBalanceException("Account "+ account.getAcctId()
230                             + " doesn't have enough cash balance, because there are other BUY orders.");
231             }
232 
233 
234 		}else if(order.getOrderType().equals( Order.TYPE_SELL)){
235 			
236 			List<AcctPosition> positions = acctMgr.getAccountPositions(account.getAcctId(), order.getSymbol());
237 			
238 			//calculate the total number of positions owned by the user
239 			long total = 0;
240 			for( AcctPosition pos : positions ){
241 				total = total + pos.getQuantity();
242 			}
243 			
244 			if( total < order.getQuantity() ){
245 				throw new NotEnoughPositionsException("Account "+ account.getAcctId()
246                         + " doesn't have enough positions to sell");
247 			}
248 
249             int totalPositionsOpen = 0;
250 
251             //  make sure the positions are not part of a sell order already
252             // get all open orders for this account and symbol
253             List<Order> openOrders = orderDao.getOrdersForAcctIdWithStatusAndSymbol( account.getAcctId(),
254                                                                                                                                                     Order.STATUS_OPEN ,
255                                                                                                                                                     order.getSymbol());
256 
257             for( Order o : openOrders ){
258                     totalPositionsOpen += o.getQuantity();
259             }
260 
261             // get all partialy filled orders for this account and symbol
262             List<Order> partiallyFilledOrders =  orderDao.getOrdersForAcctIdWithStatusAndSymbol( account.getAcctId(),
263                                                                                                                                                     Order.STATUS_PARTIALLY_FILLED ,
264                                                                                                                                                     order.getSymbol());
265 
266             for( Order o : partiallyFilledOrders ){
267                 totalPositionsOpen += (o.getQuantity() - o.getFilledQuantity());
268             }
269 
270             if( total < ( order.getQuantity() + totalPositionsOpen) ){
271                 throw new NotEnoughPositionsException("Account "+ account.getAcctId() + " doesn't have enough positions to sell, since "
272                                     + totalPositionsOpen + " shares are already on sale");  
273             }
274 
275         }
276 		
277 		
278 		// set status of the order to "VERIFIED"
279 		order.setStatus(Order.STATUS_VERIFIED);
280 	
281 		// generate order Id
282 		long orderId = orderDao.generateOrderId();
283 		order.setId( Long.toString(orderId) );
284 		
285 		// add to EM_ORDER table
286 		orderDao.addOrder(order);
287 		
288 		// retreive the order, with order created time
289 		Order verifiedOrder = orderDao.getOrderById(order.getId());
290 		
291 		// TODO: generate order_history_id
292 		
293 		// TODO: record EM_ORDER_HISTORY table
294 		
295 		return verifiedOrder;
296 	}
297 	
298 	public float calculateCommision( Account account, Order order ){
299 		
300 		float commission = 0f;
301 		
302 		return commission;
303 	}
304 
305 	public List<Order> getOpenOrdersForAcctId(String acctId) {
306         
307 		List<Order> openorders =orderDao.getOrdersForAcctIdWithStatus( acctId , Order.STATUS_OPEN);
308         List<Order> partiallFilledOrders = orderDao.getOrdersForAcctIdWithStatus(acctId,  Order.STATUS_PARTIALLY_FILLED);
309 
310         openorders.addAll(partiallFilledOrders);
311         
312         // FIXME : only for pridict.com
313         Comparator reverseTimeComparator = Collections.reverseOrder( new TimeComparator());
314         Collections.sort(openorders, reverseTimeComparator);
315         
316 		return openorders;
317 	}
318 
319     public List<Order> getExecutedOrdersForAcctId(String acctId) {
320 
321         List<Order> filledOrders  = orderDao.getOrdersForAcctIdWithStatus(acctId, Order.STATUS_FILLED);
322         List<Order> partiallyFilledOrders  = orderDao.getOrdersForAcctIdWithStatus(acctId, Order.STATUS_PARTIALLY_FILLED);
323         filledOrders.addAll(partiallyFilledOrders);
324         
325         // FIXME : only for pridict,com
326         Comparator reverseTimeComparator = Collections.reverseOrder( new TimeComparator());
327         Collections.sort( filledOrders, reverseTimeComparator);
328 
329         return filledOrders;
330     }
331 
332     private float calculateCost( Order order, Quote quote){
333 		
334 		float cost = 0f;
335 
336         if( order.getPriceType().equals( Order.PRICE_TYPE_LIMIT) ){
337 			    cost = order.getQuantity() * order.getLimitPrice();
338         }else if( order.getPriceType().equals( Order.PRICE_TYPE_MARKET)  ){
339                 if( order.getOrderType().equals( Order.TYPE_BUY )){
340                     // calculate based on lowest ask price
341                    cost = order.getQuantity() * quote.getAskPrice();
342                 }
343                 if( order.getOrderType().equals(Order.TYPE_SELL)){
344                     // calculate based on highest bid price
345                     cost = order.getQuantity() * quote.getBidPrice();
346                 }           
347         }
348 		
349 		return cost;
350 	}
351 
352 	/***
353 	 * <code>fillOrders</code> .
354 	 * <OL>
355 			<li>determine how many cash transfers are needed</li>
356 			<li>collect money from BUY accounts</li>
357 			<li>collect positions from SELL accounts</li>
358 			<li>Transfer cash from BUY account to SELL account</li>
359 			<li>Transfer position from SELL account from BUY account</li>
360 		</OL>
361 
362 	 */
363 	@Transactional(propagation = Propagation.REQUIRED, readOnly = false)
364 	public void fillOrders(List<OrderFill> fills) throws OrderCannotBeFilledException, OrderFillQuantityMismatchException {
365 		
366 		// TODO: order fills must be recorded by OMS, when it receives them
367 		// now updating the order directly for the sake of time... not correct
368 		
369 		// retrieve the orders from OMS
370 		Map<String, Order> orders = new HashMap<String,Order>();
371 		
372 		for( OrderFill fill : fills ){
373 			Order order = orderDao.getOrderById(fill.getOrderId());
374 			
375 			// to receive a fill, order must be "open" or "partially filled"
376 			if( !order.getStatus().equalsIgnoreCase(Order.STATUS_OPEN) || 
377 					!order.getStatus().equalsIgnoreCase(Order.STATUS_PARTIALLY_FILLED) ){
378 				throw new OrderCannotBeFilledException("Order Id : "+ fill.getOrderId() + " cannot be filled");
379 			}
380 			
381 			if( fill.getMatchedQuantity() > order.getQuantity() ){
382 				// this is an error condition, something is wrong, it could be bug or system inconsistency
383 				throw new OrderFillQuantityMismatchException("Order fill quantity exceeds the order quantity for Order Id: "
384 																									+ fill.getOrderId() + ", fillId: "+ fill.getId() );
385 			}
386 			
387 			orders.put(fill.getOrderId(), order);
388 		}
389 		
390 
391 
392 		
393 		// STEP :1
394 		// determine how many cash transfers are needed.
395 		// all order fill method invocation, will have one side will be just one.
396 		// i.e., one BUY fill matching many SELLs or
397 		//        one SELL fill with many matching BUY fills
398 		// if not there is an error
399 		int buys = 0;
400 		int sells =0;
401 		for( OrderFill fill : fills){
402 			if( fill.getOrderType().equals(Order.TYPE_BUY) ){
403 				buys += 1;
404 			}
405 			if( fill.getOrderType().equals(Order.TYPE_SELL) ){
406 				sells +=1;
407 			}
408 		}
409 		
410 		// either "buys" or "sells" must be 1, or error
411 		if( buys == 0 && sells == 0){
412 			// ERROR
413 		}else if( buys > 1 && sells > 1){
414 			// ERROR
415 		}
416 		
417 		boolean moreSells = false;
418 		if( buys == 1 && sells > 1 ){
419 			moreSells = true;
420 		}else if( buys > 1 && sells == 1 ){
421 			moreSells = false;
422 		}
423 		
424 		List<CashTransfer> cashTransfers = new ArrayList<CashTransfer>();
425 		List<AcctPositionTransfer> acctPosTransfers = new ArrayList<AcctPositionTransfer>();
426 		
427 		if( moreSells ){
428 			for( OrderFill fill : fills ){
429 				if( fill.getOrderType().equals(Order.TYPE_SELL ) ){
430 					
431 						Order order = orders.get(fill.getOrderId());
432 						CashTransfer cashTransfer = new CashTransfer();
433 						cashTransfer.setReceiverAcctId(order.getAcctId());
434 						cashTransfer.setAmount(cashTransfer.getAmount());						
435 						cashTransfers.add(cashTransfer);
436 						
437 						AcctPositionTransfer posTransfer = new AcctPositionTransfer();
438 						posTransfer.setSenderAcctId(order.getAcctId());
439 						posTransfer.setQuantity(fill.getMatchedQuantity());
440 						acctPosTransfers.add(posTransfer);
441 				}
442 			}
443 			
444 		}else if( !moreSells ){
445 			
446 			for( OrderFill fill : fills ){
447 				if( fill.getOrderType().equals(Order.TYPE_BUY ) ){
448 			
449 						Order order = orders.get(fill.getOrderId());
450 						CashTransfer cashTransfer = new CashTransfer();
451 						cashTransfer.setSenderAcctId(order.getAcctId());
452 						cashTransfer.setAmount(cashTransfer.getAmount());
453 						cashTransfers.add(cashTransfer);
454 						
455 						AcctPositionTransfer posTransfer = new AcctPositionTransfer();
456 						posTransfer.setReceiverAcctId( order.getAcctId() );
457 						posTransfer.setQuantity(fill.getMatchedQuantity());
458 						acctPosTransfers.add( posTransfer);
459 				}
460 			}			
461 		}
462 		
463 		//
464 	}
465 
466 
467 	
468 	/***
469 	 * 
470 	 * <code>executeMatches()</code> transfers the positions and cash after order execution.
471 	 * This method is a short term hack. 
472 	 * This will be replaced by fillOrder() and a corresponding clearing system.
473 	 * @param matches
474 	 * @throws OrderCannotBeFilledException 
475 	 * @throws NotValidAccountException 
476 	 * @throws NotEnoughCashException 
477 	 * @throws NotEnoughPositionsException 
478 	 */
479 	public void executeMatches( List<OrderMatch> matches) 
480         throws OrderCannotBeFilledException, NotEnoughCashException, NotValidAccountException, NotEnoughPositionsException{
481 		
482 		// each match results in one cash transfer and one position transfer
483 		for( OrderMatch match : matches ){
484 			
485 			Order buyOrder = orderDao.getOrderById( match.getBuyOrderId() );
486 			Order sellOrder = orderDao.getOrderById(match.getSellOrderId());
487 			
488 			// to receive a fill, order must be "open" or "partially filled"
489 			if( !buyOrder.getStatus().equalsIgnoreCase(Order.STATUS_OPEN) &&
490 					!buyOrder.getStatus().equalsIgnoreCase(Order.STATUS_PARTIALLY_FILLED) ){
491 				throw new OrderCannotBeFilledException("Order Id : "+ match.getBuyFillId() + " cannot be filled");
492 			}
493 			if( !sellOrder.getStatus().equalsIgnoreCase(Order.STATUS_OPEN) &&
494 					!sellOrder.getStatus().equalsIgnoreCase(Order.STATUS_PARTIALLY_FILLED) ){
495 				throw new OrderCannotBeFilledException("Order Id : "+ match.getSellFillId() + " cannot be filled");
496 			}
497 			
498 			CashTransfer cashTransfer = new CashTransfer();
499 			float amount = match.getMatchPrice() * match.getMatchedQuantity();
500 			cashTransfer.setAmount(amount);
501 			cashTransfer.setSenderAcctId(buyOrder.getAcctId());
502 			cashTransfer.setReceiverAcctId(sellOrder.getAcctId());
503 			// TODO :  price received should be minus commissions, fees etc
504 			acctMgr.tranferCash(cashTransfer);
505 			
506 			AcctPositionTransfer positionTransfer = new AcctPositionTransfer();
507 			positionTransfer.setSenderAcctId( sellOrder.getAcctId());
508 			positionTransfer.setReceiverAcctId( buyOrder.getAcctId() );
509 			positionTransfer.setQuantity(match.getMatchedQuantity());
510             positionTransfer.setPrice( match.getMatchPrice());
511 			positionTransfer.setSymbol(match.getSymbol());
512 			
513 			acctMgr.transferPosition(positionTransfer);
514 
515 			// at this point update the 'OPEN' orders to 'FILLED' or 'PARTIALLY_FILLED'
516 			if( match.getBuyMatchType().equals(OrderMatch.TYPE_FULL)){
517 				buyOrder.setStatus(Order.STATUS_FILLED);
518                 buyOrder.setFilledQuantity(match.getMatchedQuantity());
519 			}else if(match.getBuyMatchType().equals(OrderMatch.TYPE_PARTIAL)){
520 				buyOrder.setStatus(Order.STATUS_PARTIALLY_FILLED);
521                 int matchedQuantity = match.getMatchedQuantity() + buyOrder.getFilledQuantity();
522                 buyOrder.setFilledQuantity(matchedQuantity);
523 			}
524 			
525 			orderDao.updateOrder(buyOrder);
526 
527 			
528 			if(match.getSellMatchType().equals(OrderMatch.TYPE_FULL)){
529 				sellOrder.setStatus(Order.STATUS_FILLED);
530                 sellOrder.setFilledQuantity(match.getMatchedQuantity());
531 			}else if(match.getSellMatchType().equals(OrderMatch.TYPE_PARTIAL)){
532 				sellOrder.setStatus(Order.STATUS_PARTIALLY_FILLED);
533                 int matchedQuantity = match.getMatchedQuantity() + sellOrder.getFilledQuantity();
534                 sellOrder.setFilledQuantity(matchedQuantity);
535 			}
536 			
537 			orderDao.updateOrder(sellOrder);
538 			
539 			Account buyerAcct = acctMgr.getAccountById( buyOrder.getAcctId() );
540 			Account sellerAcct = acctMgr.getAccountById(sellOrder.getAcctId());
541 			try {
542 
543 				User buyer = userMgr.getUserById( buyerAcct.getId());
544 				logger.info("sending mail to buyer");
545 				sendMail( buyer.getId(), buyOrder);
546 				User seller = userMgr.getUserById( sellerAcct.getId());
547 				logger.info("sending mail to seller");
548 				sendMail( seller.getId(), sellOrder);
549 				
550 			} catch (UserNotFoundException e) {
551 				e.printStackTrace();
552 				logger.severe("User not found exception: "  + e.getMessage());
553 			}
554 		}
555 	}
556 	
557 	private void sendMail( String email, Order order){
558 		
559         SimpleMailMessage msg = new SimpleMailMessage(this.templateMessage);
560         
561         msg.setTo(email);
562         msg.setSubject("Re: order no. "+ order.getId());
563         
564         StringBuilder sb = new StringBuilder();
565         sb.append("your ");
566         
567         if( order.isBuy() ){
568         	sb.append("buy ");
569         }else if( order.isSell()){
570         	sb.append("sell ");
571         }
572         
573         sb.append(" order for "+ order.getQuantity() );
574         sb.append(" shares of " + order.getSymbol());
575         sb.append(" is ");
576         
577         if( order.getStatus().equals(Order.STATUS_FILLED) ){
578         	sb.append("filled completely");
579         }
580         if( order.getStatus().equals(Order.STATUS_PARTIALLY_FILLED) ){
581         	sb.append("filled partially");
582         }        
583         
584         msg.setText(sb.toString());
585 
586         logger.info("sending message : \n"+ msg.toString());
587         this.mailSender.sendMail(msg);       
588 	}
589 	
590 /*	public static void main(String[] args){
591 		
592 		XmlBeanFactory beanFactory = new XmlBeanFactory(new ClassPathResource("WEB-INF/applicationContext.xml"));
593 		IOrderManagerService svc = (IOrderManagerService) beanFactory.getBean("IOrderManagerService");
594 		
595 		SimpleMailMessage msg = (SimpleMailMessage) beanFactory.getBean("templateMessage");
596 		MailSender mailSender = (MailSender) beanFactory.getBean("mailSender");
597 		
598         
599         msg.setTo("snambi@gmail.com");
600         msg.setSubject("Re: order no. "+ 100);
601         
602         StringBuilder sb = new StringBuilder();
603         sb.append("your message ");
604 
605         msg.setText(sb.toString());
606 
607         try{
608             mailSender.send(msg);
609         }catch(MailException ex) {
610             ex.printStackTrace();
611         }		
612 		
613 	}*/
614 
615 }