Admin-password.txt --host localhost --port 4848 --restype
javax.jms.Queue --enabled=true --property Name=PhysicalQueue
Jms/Exаmple1Queue
Как и в случае с ConnectionFactory,созданный объект доступен в административной консоли.
Теперь, после того как все необходимые ресурсы созданы, можно приступить к созданию приложения. В качестве первого примера мы разработаем простое приложение, которое состоит из двух компонентов, обменивающихся текстовыми сообщениями в синхронном режиме.
JMSClient
Класс JMSClient (листинг 1)после своего запуска создает соединение с JMS -провайдером, создает сессию и MessageProducer, после чего в ответ на каждый ввод пользователя посылает в очередь текстовое сообщение. Работа завершается, если пользователь ввел символ q (или Q).
Листинг 1
import javax.jms.ConnectionFactory;import javax.jms.Destination;import javax.jms.Queue;import javax.jms.Topic;import javax.jms.Connection;import javax.jms.Session;import javax.jms.MessageProducer;import javax.jms.TextMessage;import javax.jms.JMSException;import javax.annotation.Resource;import java.io.InputStreamReader;import java.io.IOException; public class JMSClient { @Resource(mappedName = "jms/Example1ConnectionFactory") private static ConnectionFactory connectionFactory; @Resource(mappedName = "jms/Example1Queue") private static Queue queue; public static void main(String[] args) { Connection connection = null; Destination dest = (Destination) queue; try { connection = connectionFactory.createConnection(); Session session = connection.createSession(false,Session.AUTO_ACKNOWLEDGE); MessageProducer producer = session.createProducer(dest); TextMessage message = session.createTextMessage(); InputStreamReader inputStreamReader = new InputStreamReader(System.in); char c = 'n'; int i = 0; while (!((c == 'q') || (c == 'Q'))) { try { c = (char) inputStreamReader.read(); message.setText("This is message " + (i + 1)); System.out.println("Sending message: " + message.getText()); producer.send(message); i++; } catch (IOException e) { System.err.println("I/O exception: " + e.toString()); } } } catch (JMSException e) { System.err.println("Exception occurred: " + e.toString()); } finally { if (connection!= null) { try { connection.close(); } catch (JMSException e) { } } } }}
Программа демонстрирует весь цикл создания типичного JMS -приложения.
|
Сначала определяются необходимые ресурсы - в данном случае ConnectionFactory и Queue (эти ресурсы с соответствующими именами были ранее созданы).
Затем создаются соединение с JMS -провайдером и сессия.
Следующим шагом является создание MessageProducer и текстового сообщения.
Цикл работы программы состоит в ожидании ввода пользователя, формировании тела сообщения и его отправки в очередь.
В конце работы программа закрывает соединение с JMS -провайдером.
JMSServer
Существует два пути получения сообщений:
1. Синхронное затребование сообщений из queue, используя метод receive() интерфейса javax.jms.QueueReceiver.
2. Асинхронное получение сообщений как только они становятся доступны – используя интерфейс javax.jms.MessageListener.
Используем первый способ. В этом случае класс JMSServer (листинг 2)служит для обработки сообщений, отправляемых для JMSClient. Он синхронным образом считывает сообщения из очереди и печатает их.
import javax.jms.ConnectionFactory;import javax.jms.Destination;import javax.jms.Queue;import javax.jms.Connection;import javax.jms.Session;import javax.jms.MessageConsumer;import javax.jms.Message;import javax.jms.TextMessage;import javax.jms.JMSException;import javax.annotation.Resource; public class JMSServer { @Resource(mappedName = "jms/Example1ConnectionFactory") private static ConnectionFactory connectionFactory; @Resource(mappedName = "jms/Example1Queue") private static Queue queue; public static void main(String[] args) { String destType = null; Connection connection = null; Session session = null; Destination dest = (Destination) queue;; MessageConsumer consumer = null; TextMessage message = null; try { connection = connectionFactory.createConnection(); session = connection.createSession(false, Session.AUTO_ACKNOWLEDGE); consumer = session.createConsumer(dest); connection.start(); while (true) { Message m = consumer.receive(1); if (m!= null) { if (m instanceof TextMessage) { message = (TextMessage) m; System.out.println("Reading message: " + message.getText()); } } } } catch (JMSException e) { System.err.println("Exception occurred: " + e.toString()); } finally { if (connection!= null) { try { connection.close(); } catch (JMSException e) { } } } }}Отличие от предыдущего класса заключается в том, что создается не MessageProducer, а MessageConsumer, поскольку мы собираемся не отправлять сообщения, а принимать их.
|
Для того чтобы начать обработку сообщений, необходимо вызвать метод start.
Цикл работы программы состоит в ожидании прихода нового сообщения. В данном случае ожидание продолжается 1 миллисекунду.
Если пришедшее сообщение имеет текстовый тип (именно такие сообщения мы ожидаем получить), оно извлекается и печатается тело сообщения.
Компиляция и запуск
Компиляция приложений JMS не имеет особенностей, единственное, что нужно сделать, - указать соответствующие библиотеки в classpath:
javac –classpath.;activation.jar;appserv-ws.jar;javaee.jar; jsfimpl.jar;appserv-jstl.jar; -d build JMSClient.java
Затем нужно собрать соответствующие пакеты (jar):
jar -cvfm server.jar manifest2.mf -C./build. jar -cvfm client.jar manifest.mf -C./build.
При этом файлы манифеста имеют следующий вид:
manifest.mf
Manifest-Version: 1.0 Ant-Version: Apache Ant 1.6.5 Created-By: aswMain-Class: JMSClient
manifest2.mf
Manifest-Version: 1.0 Ant-Version: Apache Ant 1.6.5 Created-By: asw Main-Class: JMSServer
В результате будут созданы два пакета: server.jar и client.jar.
Запуск приложения производится с помощью утилиты appclient, соответственно:
appclient -client client.jar
для клиента (отправителя сообщений) и
appclient -client server.jar
для сервера (обработчика сообщений).
После запуска клиент в ответ на ввод пользователя будет посылать сообщения в очередь, сервер будет их принимать и печатать.
Следует обратить внимание, что сервер и клиент не обязательно должны быть запущены одновременно. Так, клиент, будучи запущенным, может сгенерировать несколько сообщений и закончить работу. Сервер, будучи запущенным позднее, эти сообщения получит, поскольку JMS -провайдер их сохранил.
|
Ниже приведен пример работы системы.
appclient -client client.jar
Запуск клиента приведет к выводу сообщений об отправке.
Sending message: This is message 1Sending message: This is message 2Sending message: This is message 3Sending message: This is message 4Sending message: This is message 5Sending message: This is message 6Sending message: This is message 7Sending message: This is message 8Sending message: This is message 9Sending message: This is message 10
Запуск сервера:
appclient -client server.jar
приведет к выводу сообщений о приеме.
Reading message: This is message 1Reading message: This is message 2Reading message: This is message 3Reading message: This is message 4Reading message: This is message 5Reading message: This is message 6Reading message: This is message 7Reading message: This is message 8Reading message: This is message 9Reading message: This is message 10
Пример создания JMS -базированной КИС
Теперь, после того как основные концепции JMS проиллюстрированы, мы можем приступить к реализации системы, обеспечивающей решение поставленной нами задачи с использованием механизмов JMS.
Как обычно, система будет состоять из двух компонентов:
- клиентского, передающего данные о новых картах и операциях над ними;
- серверного, принимающего и обрабатывающего эти данные.
Для передачи данных мы воспользуемся сообщениями типа ObjectMessage и транспортными классами, которые будут поддерживать механизм сериализации. Кроме этого, в серверном компоненте будет реализован асинхронный механизм обработки сообщений, с использованием соответствующего листенера.
Перед компиляцией и выполнением примера необходимо создать соответствующие ресурсы: ConnectionFctory и Queue с именами jms/ConnectionFactory и jms/Queue соответственно.
Клиентский класс BillingClient
1 package com.asw.jms.ex1;2 3 import javax.jms.*;4 import javax.annotation.Resource;5 import java.util.Date;6 7 public class BillingClient {8 @Resource(mappedName = "jms/ConnectionFactory")9 private static ConnectionFactory connectionFactory;10 @Resource(mappedName = "jms/Queue")11 private static Queue queue;12 13 public static void main(String[] args) {14 Connection connection = null;15 Destination dest = (Destination) queue;16 try {17 connection = connectionFactory.createConnection();18 Session session = connection.createSession(false,19 Session.AUTO_ACKNOWLEDGE);20 MessageProducer producer = session.createProducer(dest);21 ObjectMessage message = session.createObjectMessage();22 Card c = new Card ("Piter",new Date(),"1",0.0);23 message.setObject(c);24 producer.send(message);25 c = new Card("Stefan",new Date(),"2",0.0);26 message.setObject(c);27 producer.send(message);28 c = new Card("Nataly",new Date(),"3",0.0);29 message.setObject(c);30 producer.send(message);31 int cnt = 1000;32 for (int i = 0; i < cnt; i++) {33 CardOperation co = new CardOperation ((i%3+1)+"",10+i,new Date());34 message.setObject(co);35 System.out.println("Sending message: " + message.getObject());36 producer.send(message);37 }38 /*39 * Send a non-text control message indicating end of40 * messages.41 */42 producer.send(session.createMessage());43 } catch (JMSException e) {44 System.err.println("Exception occurred: " + e.toString());45 } finally {46 if (connection!= null) {47 try {48 connection.close();49 } catch (JMSException e) {50 }51 }52 }53 }54 }
Отличие от рассмотренного ранее примера состоит в том, что создается сообщение типа ObjectMessage (строка 21). Для помещения объекта в тело этого сообщения необходимо вызвать метод setObject (конечно, класс, объект которого помещается в сообщение, должен быть объявлен как реализующий интерфейс Serializable).
Транспортный класс Card
Транспортные классы Card и CardOperation полностью аналогичны рассматриваемым ранее.
Класс Card
1 package com.asw.jms.ex1;2 3 import java.io.Serializable;4 import java.util.*;5 6 7 public class Card implements Serializable{8 public Card(String person, Date createDate, String cardNumber,double balance){9 this.person = person;10 this.createDate = createDate;11 this.cardNumber = cardNumber;12 this.balance = balance;13 }14 public String person;15 public Date createDate;16 public String cardNumber;17 public double balance;18 public String toString(){19 return "Card: cardNumber = "+cardNumber+"\tBalance="+balance+ "\tPerson="+person+"\tCreateDate="+createDate+"";20 }21 }Транспортный класс CardOperation
1 package com.asw.jms.ex1;2 3 import java.util.*;4 import java.io.*;5 6 public class CardOperation implements Serializable {7 public CardOperation(String card,double amount,Date operationDate){8 this.card = card;9 this.amount = amount;10 this.operationDate = operationDate;11 }12 public String card;13 public double amount;14 public Date operationDate;15 }Серверный класс BillingService
Серверный класс содержит методы, обеспечивающие выполнение операций с картами, и является контейнером для хранения карт.Для обработки (получения) сообщений он регистрирует Objectlistener.
Класс BillingService
1 package com.asw.jms.ex1;2 3 import javax.jms.*;4 import javax.annotation.Resource;5 import java.io.InputStreamReader;6 import java.io.IOException;7 import java.util.Hashtable;8 import java.util.Enumeration;9 10 public class BillingService {11 @Resource(mappedName = "jms/ConnectionFactory")12 private static ConnectionFactory connectionFactory;13 @Resource(mappedName = "jms/Queue")14 private static Queue queue;15 16 Hashtable hash = new Hashtable();17 public void addNewCard(Card c) {18 hash.put(c.cardNumber, c); 19 };20 21 public void performCardOperation(CardOperation co){22 Card c = (Card)hash.get(co.card);23 if (c==null) return;24 c.balance+=co.amount;25 hash.put(co.card,c);26 };27 28 public void printCards(){29 for(Enumeration e = hash.elements();e.hasMoreElements();)30 System.out.println(e.nextElement());31 }32 33 public static void main(String[] args) {34 String destType = null;35 Connection connection = null;36 Session session = null;37 Destination dest = (Destination) queue;38 MessageConsumer consumer = null;39 ObjectListener listener = null;40 TextMessage message = null;41 InputStreamReader inputStreamReader = null;42 char answer = '\0';43 try {44 connection = connectionFactory.createConnection();45 session = connection.createSession(false, Session.AUTO_ACKNOWLEDGE);46 consumer = session.createConsumer(dest);47 listener = new ObjectListener(new BillingService());48 consumer.setMessageListener(listener);49 connection.start();50 System.out.println(51 "To end program, type Q or q, " + "then <return>");52 inputStreamReader = new InputStreamReader(System.in);53 while (!((answer == 'q') || (answer == 'Q'))) {54 try {55 answer = (char) inputStreamReader.read();56 } catch (IOException e) {57 System.err.println("I/O exception: " + e.toString());58 }59 }60 } catch (JMSException e) {61 System.err.println("Exception occurred: " + e.toString());62 } finally {63 if (connection!= null) {64 try {65 connection.close();66 } catch (JMSException e) {67 }68 }69 }70 }71 }
После создания соединения с JMS-провайдером (строка 44) и создания сессии (строка 45) создается MessageConsumer (строка 46). Затем создается ObjectListener (строка 47) и регистрируется в MessageConsumer как принимающий сообщения (строка 48). Таким образом, при приходе нового сообщения в очередь будет вызываться метод onMessage листенера, который и будет обрабатывать сообщение. Метод start (строка 49) запускает обработку сообщений.
Серверный листенер ObjectListener
ObjectListener обрабатывает поступающие сообщения. При приходе нового сообщения он проверяет его тип (сообщение должно быть типа ObjectMessage,приход текстового сообщения интерпретируется как команда выдать балансы всех карт), извлекает объект, переданный в теле сообщения, проверяет его тип (ожидается, что пришедшие объекты могут быть двух типов - Card и CardOperation),после чего вызывает соответствующий метод BillingService,выполняющий нужную операцию.
Класс ObjectListener
1 package com.asw.jms.ex1;2 3 import javax.jms.*;4 5 6 public class ObjectListener implements MessageListener {7 BillingService bs;8 public ObjectListener (BillingService bs){9 this.bs = bs;10 }11 public void onMessage(Message message) {12 ObjectMessage msg = null;13 14 try {15 if (message instanceof ObjectMessage) {16 msg = (ObjectMessage) message;17 Object o = msg.getObject();18 System.out.println("Reading message: " + o);19 if (o instanceof Card) bs.addNewCard((Card)o);20 else if (o instanceof CardOperation) bs.performCardOperation((CardOperation)o);21 } else {22 System.err.println("Message is not a ObjectMessage");23 bs.printCards();24 }25 } catch (JMSException e) {26 System.err.println("JMSException in onMessage(): " + e.toString());27 } catch (Throwable t) {28 System.err.println("Exception in onMessage():" + t.getMessage());29 }30 }31 }Компиляция и запуск
Компиляция и выполнение не отличаются от рассмотренного ранее примера. Ниже приведен пример работы системы. Запуск клиента:
appclient -client BillingClient.jar
Результат выполнения клиентской программы приведен ниже:
Sending message: com.asw.jms.ex1.CardOperation@1e0bf98....Sending message: com.asw.jms.ex1.CardOperation@11fb8c6Sending message: com.asw.jms.ex1.CardOperation@35378dSending message: com.asw.jms.ex1.CardOperation@190c5c0Sending message: com.asw.jms.ex1.CardOperation@1681629Sending message: com.asw.jms.ex1.CardOperation@1c39aa6Sending message: com.asw.jms.ex1.CardOperation@44c4a4Sending message: com.asw.jms.ex1.CardOperation@469729
Запуск сервера:
appclient -client BillingService.jar
Результат выполнения серверной программы приведен ниже:
To end program, type Q or q, then <return>Reading message: Card: cardNumber=1 Balance=0.0 Person=PiterCreateDate=Sun Dec 24 13:13:15 MSK 2006Reading message: Card: cardNumber=2 Balance=0.0 Person=StefanCreateDate=Sun Dec 24 13:13:15 MSK 2006Reading message: Card: cardNumber=3 Balance=0.0 Person=NatalyCreateDate=Sun Dec 24 13:13:15 MSK 2006Reading message: com.asw.jms.ex1.CardOperation@1dbe72fReading message: com.asw.jms.ex1.CardOperation@26efd3Reading message: com.asw.jms.ex1.CardOperation@1c20611Reading message: com.asw.jms.ex1.CardOperation@11c5c88... Reading message: com.asw.jms.ex1.CardOperation@11ce4fe Reading message: com.asw.jms.ex1.CardOperation@1fe0d66 Card: cardNumber=3Balance=169830.0 Person=Nataly CreateDate=SunDec 24 13:13:15 MSK 2006Card: cardNumber=2Balance=169497.0 Person=Stefan CreateDate=SunDec 24 13:13:15 MSK 2006Card: cardNumber=1Balance=170173.0 Person=PiterCreateDate=Sun Dec24 13:13:15 MSK 2006
План выполнения лабораторной работы:
Часть 1.
1. Ознакомиться с принципами удаленного взаимодействия объектов Java в рамках RMI.
2. Ознакомиться и разобрать предлагаемый пример Simple Time, использующий передачу примитивных типов Java.
3. Реализовать пример на локальной машине.
4. Определить состав файлов, необходимый для клиента и сервера.
5. Реализовать пример в сети (используя п. 4).
6. Ознакомиться с файлами политик безопасности и добиться запуска примера в «ограниченном» режиме (факультативно).
Часть 2.
1. Ознакомиться с понятием сериализации объектов Java.
2. Изучить предлагаемый пример, использующий передачу пользовательского сериализуемого типа.
3. Реализовать пример в сети.
4. Создать клиент-серверную систему, использующую RMI для передачи объектов (объекты выбрать произвольно) в виде пары консольных приложений.
5. Реализовать пример в сети.
Часть 3.
1. Ознакомиться с понятием активизации серверных объектов в RMI.
2. Изучить предлагаемый пример клиент-серверной системы, использующей активизацию серверного объекта.
3. Реализовать пример в сетевом режиме.
Часть 4 (факультативно).
Реализовать графическую оболочку для клиентской части клиент-серверной системы в соответствии с индивидуальным заданием. В качестве среды для построения графического приложения предлагается использовать NetBeans IDE.
Задание - создать оригинальное приложение на основе Java JMS, имеющее следующие минимальные возможности:
- подключение источника данных к приложению средствами Microsoft Visual Studio 2010;
- установка и разрыв соединения с существующей БД КИС программным способом;
- работа с БД КИС в соединённом режиме программным способом: просмотр записей выбранной таблицы БД, выполнение команд-запросов на получение данных таблицы БД.
- работа с БД КИС в разъединённом режиме программным способом: просмотр схемы выбранной таблицы БД, выполнение запросов, не возвращающих результат, редактирование выбранной таблицы БД;
- работа с БД КИС программным способом с использованием механизмов: транзакций, триггеров и хранимых процедур.
Указания и рекомендации:
1. Рекомендуется использование ОС Windows 7 Ultimate RTM Russian + Service Pack 1.
2. Обязательно использование языка программирования Java.
3. Рекомендуется использование системы программирования SUN ONE STUDIO 5.1 и NetBeans IDE.
4. Рекомендуется создание консольного приложения.
Контрольные вопросы:
1. Дайте определение JMS.
2. Что представляет собой корпоративная информационная система типа MOM?
3. Что называется JMS-клиентом?
4. Что называется JMS-поставщиком?
5. Что называется JMS-потребителем?
6. Что называется JMS-провайдеом?
7. Что называется JMS-приложением?
8. Что называется JMS-сообщением?
9. Какую роль выполняют управляющие объекты JMS?
10. Зачем нужны средства администрирования JMS?
11. Дайте определение термину расположение.
12. Какую роль выполняет фабрика соединения в JMS?
13. Какую роль выполняет JNDI в JMS?
14. Опишите трехуровневую архитектуру JMS.
15. Что называется JMS-провайдером?
16. Перечислите типы сообщений JMS.
17. Из каких частей состоит сообщение JMS?
18. Что означает термин несохраняемое сообщение JMS?
19. Что означает термин сохраняемое сообщение JMS?
20. Что такое Уведомления о доставке сообщений JMS?
21. Какую роль выполняет селектор сообщений JMS?
22. Для чего в JMS используются транзакции?
23. Какие разновидности механизма транзакций используются в JMS?
24. Опишите модель передачи сообщений «издание - подписка».
25. Какую роль выполняет тема в модели передачи сообщений «издание - подписка»?
26. Что означает термин прочная подписка?
27. Что означает термин непрочная подписка?
28. Опишите модель передачи сообщений «точка - точка».
29. Какую роль выполняет очередь в модели передачи сообщений «точка - точка»?
30. Кратко опишите схему применения JMS при разработке КИС.
[1] один и тот же JMS -клиент может быть одновременно и поставщиком, и потребителем в разных актах взаимодействия
[2] концепция ESB - E nterprise S ervice B us
[3] JTA - J ava T ransaction API