Опубликован: 18.03.2010 | Уровень: специалист | Доступ: платный
Лекция 3:

Технология Enterprise Java Beans. Часть 1

Удаленный интерфейс OrdersListBean

В удаленном интерфейсе определим два метода:

  • List getOrdersForUser(String username) throws RemoteException, SQLException. Этот метод возвращает список из объектов Order для пользователя с именем username.
  • List getCommodityOrdersForOrder(int orderId) throws RemoteException, SQLException. Этот метод возвращает список из объектов CommodityOrder для заказа с ID = orderId.
public interface OrdersListRemote extends EJBObject  
{
public List getOrdersForUser(String username)   throws RemoteException, SQLException;
public List getCommodityOrdersForOrder(int orderId)   throws RemoteException,   SQLException;
}
Домашний интерфейс OrdersListBean

Этот интерфейс аналогичен домашним интерфейсам из предыдущих примеров.

public interface OrdersListHome extends EJBHome  
{
public OrdersListRemote create()   throws RemoteException,   CreateException;
}
Класс компонента OrdersListBean

Выполнение запроса к базе данных и формирование объектов Order и CommodityOrder выделено шрифтом.

public class OrdersListBean implements SessionBean  
{
private static final long serialVersionUID = 2767604097827994556L; 
private DataSource dataSource = null;
public List getOrdersForUser(String username)   throws SQLException  
	{
	if   (dataSource == null)
	throw new SQLException("Datasource not loaded");
	Connection conn = dataSource.getConnection();
	PreparedStatement p = conn.prepareStatement
		("SELECT * FROM " + "  ORDERS WHERE USERNAME=?");
	p.setString(1, username);
	ResultSet r = p.executeQuery();
	List arrayList = new ArrayList();
	
	while(r.next())   
		{
		Order order = new Order();
		order.setId(r.getInt("ID"));
		order.setName(r.getString("USERNAME"));
		order.setDate(r.getDate("DATE_CREATED"));
		arrayList.add(order);
		}
	conn.close();
	return arrayList;
	}
	
public List getCommodityOrdersForOrder(int orderId) throws SQLException  
	{
	if   (dataSource == null)
	throw new SQLException("Datasource not loaded");
	Connection conn = dataSource.getConnection();
	PreparedStatement p = conn.prepareStatement
		("SELECT * FROM " + "  COMMODITY_ORDER WHERE ORDER_ID=?");
	
	p.setInt(1,  orderId);
	ResultSet r = p.executeQuery();
	List arrayList = new ArrayList();
	while(r.next())   
		{
		CommodityOrder order = new CommodityOrder(); 
		order.setId(r.getInt("ID"));
		order.setCommodityId(r.getInt("COMMODITY_ID"));
		order.setCommodityQuantity(r.getInt("QUANTITY"));
		arrayList.add(order);
		}
	conn.close(); 
	return arrayList;
	}

public void ejbCreate()   {}

public void ejbActivate()   throws EJBException,   RemoteException  {}

public void ejbPassivate()   throws EJBException,   RemoteException  {}

public void ejbRemove()   throws EJBException,   RemoteException  {}
public void setSessionContext(SessionContext arg0)   throws EJBException, RemoteException  
	{
	try 
		{
		InitialContext ctx = new InitialContext(); 
		if   (dataSource == null)
		dataSource =   (DataSource)   ctx.lookup("java:/OracleDS");
		System.out.println("Data source aquired"); 
		}   
	catch   (NamingException ex)   
		{
		throw new EJBException(ex);
		}
	}
}
Тестовый клиент для OrdersListBean

Для того чтобы проверить работоспособность компонента OrdersListBean, было написано тестовое консольное клиентское приложение. В нем выполнялся вызов обеих методов компонента, а результат выводился в консоль. Код этого клиента приводится далее.

public class TestClient3  
{
public static void main(String args[])   
	{
	try 
		{
		Context jndiContext = createJBossContext();
		
		Object ref = jndiContext.lookup("OrdersListBean"); 
		OrdersListHome home =   (OrdersListHome) PortableRemoteObject.narrow(ref, OrdersListHome.class);
		OrdersListRemote remote = home.create();
		List orders = remote.getOrdersForUser("Boris");
		System.out.println("Orders  for user Boris");
		
		for   (Iterator iter = orders.iterator();  iter.hasNext();)   
			{ 
			Order order =   (Order)   iter.next();
			List commodityList =remote.
			getCommodityOrdersForOrder(order.getId()); 
			System.out.println("Commodities  for order " +
			order.getId()   + "  " + order.getDate().toString());
			
			for   (Iterator iter2 = commodityList.iterator(); iter2.hasNext();)   
				{ 
				CommodityOrder cOrder = (CommodityOrder) iter2.next(); 
				System.out.println(cOrder.getCommodityId() + "  " + cOrder.getCommodityQuantity());
				}
			}
		}   
	catch (RemoteException e)   
		{
		e.printStackTrace(); 
		}   
	catch   (NamingException e)   
		{
		e.printStackTrace(); 
		}   
	catch   (CreateException e)   
		{
		e.printStackTrace(); 
		}   
	catch   (SQLException e)   
		{
		e.printStackTrace();
		}
	}

public static Context createJBossContext()   throws NamingException  
	{ 
	Properties p = new Properties(); 
	p.put("java.naming.factory.initial", "org.jnp.interfaces.NamingContextFactory"); 
	p.put("java.naming.provider.url", "jnp://127.0.0.1:1099"); 
	p.put("java.naming.factory.url.pkgs",
	"org.jboss.naming:org.jnp.interfaces"); 
	Context jndiContext = new InitialContext(p); 
	return jndiContext;
	}
}
Консольный вывод тестового клиента

Рис. 3.39. Консольный вывод тестового клиента

Вывод тестового клиента показан на Рис. 3.39.

Удаленный интерфейс ShoppingBasketBean

Интерфейс этого сеансового компонента с состоянием отражает те возможные опреации, которые пользователь может производить с корзиной. Эти методы перечислены далее:

  • public List getCurrentCommoditiesList() throws RemoteException. Этот метод возвращает список из объектов CommodityOrder, соответствующих товарам в корзине.
  • public boolean isEmpty() throws RemoteException. Этот метод возвращает булевское значение true, если корзина пуста.
  • public addCommodity(int commodityId) throws RemoteException. Этот метод добавляет одну единицу товара с ID = commodityId в корзину.
  • public recalculateCommodity(int commodityId, int newCount) throws RemoteException. Этот метод изменяет количество товаров с ID = commodityId в корзине на newCount.
  • public deleteCommodity(int commodityId) throws RemoteException. Этот метод удаляет товар из корзины.
  • public void processOrder() throws RemoteException, SQLException. Этот метод создает новый объект в таблице ORDERS базы данных, а затем добавляет записи с ORDERID, соответствущему только что добавленному заказу, в таблицу COMMODITYORDERS.

Как вы уже, наверное, успели убедиться, вызов каждого из этих методов может менять состояние компонента ShoppingBasketBean.

public interface ShoppingBasketRemote extends EJBObject  
{
public List getCurrentCommoditiesList()   throws RemoteException; 
public boolean isEmpty()   throws RemoteException;
public void addCommodity(int commodityId)   throws RemoteException; 
public void recalculateCommodity(int commodityId,   int newCount)
throws RemoteException; 
public void deleteCommodity(int commodityId)   throws RemoteException; 
public void processOrder()   throws RemoteException,   SQLException;
}
Домашний интерфейс OrdersListBean

Этот интерфейс отличается от домашних интерфейсов предыдущих компонентов. Компонент ShoppingBasketBean создается отдельно для каждого пользователя, поэтому удобно в него передать имя пользователя. Имя пользователя будет использоваться при выполнении запроса в методе processOrder (). В метод create(String username) домашнего интерфейса передается имя пользователя.

public interface ShoppingBasketHome extends EJBHome  
{
public ShoppingBasketRemote create(String username)   throws RemoteException,   CreateException;

}
Класс компонента ShoppingBasketBean

Компонент ShoppingBasketBean должен постоянно поддерживать текущий список товаров. В классе компонента это делается посредством списка из объектов класса CommodityOrder. Все операции по добавлению, пересчету, и удалению товаров из списка текущих товаров в корзине сводятся к операциям поиска, удаления и добавления соответствующего объекта CommodityOrder в этом списке. Определен дополнительный вспомогательный метод private CommodityOrder findOrderById(int commodityId). Он ищет соответствующий объект в списке и возвращает либо его, либо значение null, если он найден не был. Код метода, осуществляющий поиск по commodityId представлен далее.

Iterator iter = commodityOrderList.iterator(); 
CommodityOrder order = null; 
while   (iter.hasNext())   
{
CommodityOrder currentOrder =   (CommodityOrder)   iter.next();
if   (currentOrder.getCommodityId()   == commodityId)     
	{ 
	order = currentOrder;
	break;
	}
}
return order;

Так как теперь компонент при создании должен получать имя пользователя, метод public void ejbCreate(String username) также несколько изменился. Теперь он сохраняет переданное имя пользователя во внутреннее поле String username, а также создает список, в котором в дальнейшем будет храниться текущий список товаров в корзине. Код этого метода представлен далее.

this.username = username; commodityOrderList = new ArrayList();

В методе public void processOrder() throws SQLException выполняется создание заказа в базе данных по товарам, которые есть в корзине на данный момент. Если в корзине нет товаром, то этот метод не делает ничего. В противном случае он сначала создает объект в таблице ORDERS посредством следующего запроса:

PreparedStatement p = conn.prepareStatement("insert into " "ORDERS(DATE_CREATED, USERNAME) values (?, ?)");
p.setDate(1,new java.sql.Date(System.currentTimeMillis()));
p.setString(2,username);
p.executeUpdate();

Теперь необходимо получить ID этого объекта. В Интернете много рекомендаций на тему того, что это необходимо делать путем выборки максимального ID из таблицы в базе данных.

select max(ID) from ORDERS where USERNAME = 'BORIS'

Не используйте этот подход! Во-первых, он будет работать только тогда, когда генерируемый индекс получается путем увеличения предыдущего, а во-вторых, если один пользователь попробует оформить два заказа одновременно, то может быть выбран ID другого оформляемого в этот момент заказа, и список товаров далее будет добавлен не к тому заказу.

Поэтому в базе данных был создан пакет, в который посредством триггера сохранялось значение поля ID последнего добавленного объекта в таблицу ORDERS. Стоит отметить, что пакеты в СУБД Oracle сохраняют свое состояние для каждой сессии (от создания подключения до его закрытия), поэтому можно не опасаться, что в пакете окажется ID другого заказа.

p = conn.prepareStatement("select ORDER_ID_PKG.GET_LAST_ID from dual"); 
ResultSet r = p.executeQuery(); 
int orderId = -1;
if (r.next()) 
{
orderId = r.getInt(1);
}

То есть выбирается максимальное значение ID для текущего пользователя. Учитывая, что в нашем магазине не может быть создано двух корзин одновременно для одного пользователя, такое решение будет корректно работать.

Затем для каждого товара в корзине добавляется по записи в таблице COMMODITYORDER.

while   (iter.hasNext())   
{
CommodityOrder currentOrder =  (CommodityOrder)   iter.next();
p = conn.prepareStatement("insert into COMMODITY_ORDER
	(ORDER_ID,   " + "COMMODITY_ID,  QUANTITY)   values   (?,   ?,   ?)");
p.setInt(1,  orderId);
p.setInt(2,  currentOrder.getCommodityId()); 
p.setInt(3,  currentOrder.getCommodityQuantity()); 
p.execute();
}

Метод void deleteCommdity(int commodityId) сводится к вызову метода recalculateCommodity(commodityId, 0).

Метод void addCommodity(int commodityId) вначале проверяет, есть ли товар с ID=commodityId в корзине, и либо добавляет новый объект CommodityOrder в список, либо просто увеличивает количество экземпляров в корзине товара на один.

CommodityOrder order = findOrderById(commodityId);
if   (order == null)   
	{
	order = new CommodityOrder(); 
	order.setCommodityId(commodityId); 
	order.setCommodityQuantity(1); 
	commodityOrderList.add(order); 
	}  
else  
	{
	order.setCommodityQuantity(order.getCommodityQuantity()   + 1);
	}

Метод void recalculateCommodity(int commodityId,int newCount) изменяет количество экземпляров товара c ID=commodityId на newCount. Если newCount = 0, то товар удаляется из списка. Если товара не было в списке, то он туда добавляется.

CommodityOrder order = findOrderById(commodityId);
if   (order == null)   
	{
	if   (newCount > 0)   
		{
		order = new CommodityOrder(); 
		order.setCommodityId(commodityId); 
		order.setCommodityQuantity(1); 
		commodityOrderList.add(order);
		}
	}  
else  
	{
	if   (newCount > 0)   
		{
		order.setCommodityQuantity(newCount);
		}  
	else  
		{
		commodityOrderList.remove(order);
		}
	}

Код класса компонента ShoppingBasketBean приводится далее.

public class ShoppingBasketBean implements SessionBean  
{
private static final long serialVersionUID = 8173942031447022589L;
private String username = null;
private DataSource dataSource = null;
private List commodityOrderList;
public void ejbCreate(String username)   
	{
	this.username = username;
	commodityOrderList = new ArrayList();
	}
private CommodityOrder findOrderById(int commodityId)   
	{ 
	Iterator iter = commodityOrderList.iterator(); 
	CommodityOrder order = null; 
	while   (iter.hasNext())   
		{
		CommodityOrder currentOrder =   (CommodityOrder)   iter.next(); 
		if   (currentOrder.getCommodityId()  == commodityId)     
			{ 
			order = currentOrder; break;
			}
		}	
	return order;
	}

public List getCurrentCommoditiesList()   
	{ 
	return commodityOrderList;
	}

public boolean isEmpty()     
	{
	return   (commodityOrderList.size()   == 0);
	}
public void addCommodity(int commodityId)   
	{
	CommodityOrder order = findOrderById(commodityId);
	if   (order == null)   
		{
		// Creating new order
		order = new CommodityOrder();
		order.setCommodityId(commodityId);
		order.setCommodityQuantity(1);
		commodityOrderList.add(order); 
		}  
	else  
		{
		order.setCommodityQuantity(order.getCommodityQuantity()   + 1);
		}
	}

public void recalculateCommodity(int commodityId,   int newCount)   
	{
	CommodityOrder order = findOrderById(commodityId);
	if   (order == null)   
		{
		if   (newCount > 0)   
			{
			// Creating new order
			order = new CommodityOrder();
			order.setCommodityId(commodityId);
			order.setCommodityQuantity(1);
			commodityOrderList.add(order);
			}
		}  
	else  
		{
		if   (newCount > 0)   
			{
			order.setCommodityQuantity(newCount); 
			}  
		else  
			{
			commodityOrderList.remove(order);
			}
		}
	}

public void deleteCommodity(int commodityId)   
	{ 
	recalculateCommodity(commodityId,   0);
	}

public void processOrder()   throws SQLException  
	{ 
	if   (dataSource == null)
		throw new SQLException("Datasource not loaded"); 
	Connection conn = dataSource.getConnection();
	
	if   (commodityOrderList.size() == 0) 
		return;
	PreparedStatement p = conn.prepareStatement
		("insert into " + "ORDERS(DATE_CREATED, USERNAME) "  + "values (?,   ?)");
	
	p.setDate(1,  new java.sql.Date(System.currentTimeMillis()));
	p.setString(2,  username);
	p.executeUpdate();
	
	p = conn.prepareStatement("select max(ID) from ORDERS where " + "USERNAME = ?");
	p.setString(1,  username);
	
	ResultSet r = p.executeQuery(); 
	int orderId = -1;
	
	if (r.next()) 
		{
		orderId = r.getInt(1);
		}
	
	Iterator iter = commodityOrderList.iterator(); 
	while   (iter.hasNext())   
		{
		CommodityOrder currentOrder =   (CommodityOrder)   iter.next();
		p = conn.prepareStatement
	      ("insert into COMMODITY_ORDER
	      	(" + " ORDER_ID, COMMODITY_ID, QUANTITY) " + "values (?, ?, ?)");
		
		p.setInt(1,   orderId);
		p.setInt(2,   currentOrder.getCommodityId()); 
		p.setInt(3,   currentOrder.getCommodityQuantity()); 
		p.execute();
		}
	commodityOrderList.clear(); conn.close();
	}
	
public void ejbActivate()   throws EJBException,   RemoteException  
	{}

public void ejbPassivate()   throws EJBException,   RemoteException  
	{}

public void ejbRemove()   throws EJBException,   RemoteException  
	{}

public void setSessionContext(SessionContext arg0)   throws EJBException, RemoteException  
	{
	try 
		{
		InitialContext ctx = new InitialContext(); 
		if   (dataSource == null)
		dataSource =   (DataSource)
		ctx.lookup("java:/OracleDS");
		System.out.println("Data source aquired");
		}   
	catch   (NamingException ex)   
		{
		throw new EJBException(ex);
		}
	}
}
Антон Зубеков
Антон Зубеков

Здравствуйте, подскажите пожалуйста где можно достать материалы по курсу Кросс-платформенные и многозвенные технологии, о которых говориться, к примеру, в Лекции 2. Пример "Служба мгновенных сообщений"

Ярославй Грива
Ярославй Грива
Россия, г. Санкт-Петербург
Ольга Малых
Ольга Малых
Россия, Казань, Университет управления "ТИСБИ"