|
Здравствуйте, подскажите пожалуйста где можно достать материалы по курсу Кросс-платформенные и многозвенные технологии, о которых говориться, к примеру, в Лекции 2. Пример "Служба мгновенных сообщений" |
Технология 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.
Удаленный интерфейс 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);
}
}
}
