Jini – это название распределенной вычислительной среды, которая может предложить принцип «network plug and play». Устройство или программная служба может быть подключена к сети, может известить о своем присутствии, и клиенты, желающие использовать такой сервис, могут разместить его для дальнейших вызовов. Jini также можно использовать для мобильных вычислительных задач, когда сервис подключается в сеть на короткое время.
Технология Jini™ – это сервис-ориентированная архитектура, которая определяет программную модель, испоьзующую и расширяющую технологию Java ™ с целью построения безопасных распределенных систем, состоящих из федераций сетевых сервисов и клиентов.
Подробнее, можно прочесть на
официальном сайтеДля создания простого приложения, необходимо:
1)
jini 
как не странно
2)
jdk (я использую 1.5.0_12) (можно скачать с
http://www.java.sun.com)3) (не обязательное условие)
IDE - IntelliJ IDEA 7.0.1
К проекту необходимо подключить
jdk, два .jar файла
jsk-lib.jar и
jsk-platform.jar (их нужно взять в папочке jini2_1\lib\)
Итак, приложение будет предоставлять информацию по различным туристическим направлениям (в виде направление/количество дней/цена тура/вид транспорта), а также позволять ее добавлять, удалять и редактировать по направлениям.
Итак, начнем:
Клиент и реализация сервиса должны разделять некоторые общие классы. Для нашего задания общими классами будут класс, определяющий хранение информации
TourInfo и интерфейс сервиса
TourInfoService.
Если сервис выполняется удаленно и запускается на отдельной JVM, то объект
TourInfo должен быть сериализован для транспортировки на клиентскую машину, реализуя интерфейс
Serializable.
Определим класс
TourInfo, который представляет совокупность данных по одному направлению. В классе реализованы метод добавления (сеттер) и взятия (геттер) информации. Она представлена в виде массива.
Код |
package common;
import java.util.ArrayList; import java.io.Serializable; /** * класс базы данных турфирмы * info - | направление | цена | количество дней | вид тура | * records - совокупность информации (info) по разным направлениям */ public class TourInfo implements Serializable { private ArrayList info;
public TourInfo() { }
public ArrayList getInfo() { return info; }
public void setInfo(ArrayList info) { this.info = info; } }
|
Если мы желаем сделать сервис
TourInfoService, доступным по сети, наилучшим выходом будет отделить реализацию от интерфейса. Затем сделать интерфейс доступным с клиента и загружать реализацию со службы поиска.
Определим интерфейс нашего сервиса –
TourInfoService, куда запишем объявления методов, которые будут реализовывать сервис.
Код |
package common;
import java.rmi.RemoteException; import java.util.ArrayList;
/** * сервис по работе с информацией о турах представлен * в виде Jini-сервиса */
public interface TourInfoService { // получение информации public ArrayList getTourInfo() throws RemoteException; // добавление нового тура public void addTourInfo(String dir,int price,int days,String type) throws RemoteException; // удаление тура по существующему направлению public void delTourInfo(String direction) throws RemoteException; // редактирование тура по данному направлению public void editTourInfo(String direction,String dir, int price, int days, String type) throws RemoteException; }
|
Все методы интерфейса выбрасывают java.rmi.RemoteException на случай сетевой ошибки (потерянное соединение, несуществующий сервер, незагружаемый класс и т.д.).
- Компиляция общих классов.
- Компиляция совершенно обычна, не используются никакие опции.
javac src/common/*.java КлиентСоздадим две версии клиента – для одноадресного и многоадресного поиска. Клиентов будем создавать в пакете(папке)
client.
Одноадресный клиент(
Unicast Client)
Если имеется известный локатор сервиса, который нет необходимости искать, то клиент использует одноадресный механизм.
Код |
package client;
import net.jini.core.discovery.LookupLocator; import net.jini.core.lookup.ServiceRegistrar; import net.jini.core.lookup.ServiceTemplate; import common.TourInfoService;
import java.net.MalformedURLException; import java.rmi.RMISecurityManager; import java.rmi.RemoteException; import java.io.IOException; import java.io.UnsupportedEncodingException; import java.io.BufferedReader; import java.io.InputStreamReader; import java.util.ArrayList;
public class UnicastTourInfoService {
LookupLocator lookup = null; ServiceRegistrar registrar = null; TourInfoService infoService = null;
public UnicastTourInfoService(){
// подготовка к обнаружению try { lookup = new LookupLocator("jini://127.0.0.1"); } catch (MalformedURLException e) { e.printStackTrace(); }
System.setSecurityManager(new RMISecurityManager()); // обнаружение службы поиска
/*клиент получает регистратор от JVM локатора сервиса. Локатор выполняет ServiceRegistrar, используя реализацию, которая неизвестна ни клиентам, ни дургим сервисам. Классы-реализаторы содержатся в reggie-dl.jar и загружаются клиентам и сервисам из HTTP сервера */
try { registrar = lookup.getRegistrar(); } catch (IOException e) { e.printStackTrace(); } catch (ClassNotFoundException e) { e.printStackTrace(); } // подготовка шаблона для поиска в службе Class[] classes = new Class[] {TourInfoService.class}; ServiceTemplate template = new ServiceTemplate(null,classes,null); // ищем наш Jini-сервис try { infoService = (TourInfoService) registrar.lookup(template); } catch (RemoteException e) { e.printStackTrace(); } if (infoService == null){ System.out.println("info service null"); System.exit(2); } // запускаем меню, а вместе с ним и всю логику menu(); }
private void menu() {
BufferedReader br = new BufferedReader(new InputStreamReader(System.in)); int option=1; while (true){ System.out.println("**************************"); System.out.println("\t1-Добавить "); System.out.println("\t\t| направление | цена |" "+ количество дней | вид тура |"); System.out.println("\t2-Удалить (по направлению)"); System.out.println("\t3-Редактировать (по направлению)"); System.out.println("\t4-Просмотреть"); System.out.println("\t5-Выход"); System.out.println("**************************"); String line="5";
try { line = br.readLine(); } catch (IOException e) { e.printStackTrace(); } option = Integer.parseInt(line); switch(option){ case 1: try { System.out.println("Направление: "); String d = br.readLine(); System.out.println("Цена: "); String pr = br.readLine(); int price = Integer.parseInt(pr); System.out.println("Количество дней: "); String days = br.readLine(); int day = Integer.parseInt(days); System.out.println("Тип тура: "); String tp = br.readLine(); // вызов метода сервиса для добавления infoService.addTourInfo(d,price,day,tp); } catch (RemoteException e) { e.printStackTrace(); } catch (IOException e) { e.printStackTrace; } break; case 2: try { String dest = br.readLine(); // вызов метода сервиса для удаления infoService.delTourInfo(dest); } catch (IOException e) { e.printStackTrace(); } break; case 3: try { System.out.println("Направление: "); String dest = br.readLine(); System.out.println("Новое направление: "); String d = br.readLine(); System.out.println("Новая цена: "); String pr = br.readLine(); int price = Integer.parseInt(pr); System.out.println("Новое количество дней: "); String days = br.readLine(); int day = Integer.parseInt(days); System.out.println("Новый тип тура: "); String tp = br.readLine();
// вызов метода сервиса для редактирования infoService.editTourInfo(dest, d, price, day, tp); } catch (IOException e) { e.printStackTrace(); } break; case 4: try { // вызов метода сервиса для просмотра ArrayList records = infoService.getTourInfo(); for (int i=0;i<records.size();i++){ ArrayList inf = (ArrayList)records.get(i); for (int j=0; j<inf.size(); j++) System.out.print(inf.get(j)+" "); System.out.println(); } } catch (RemoteException e) { e.printStackTrace(); } break; case 5: System.exit(0); break; } } }
public static void main(String[] args) { new UnicastTourInfoService(); } }
|
Компиляция клиента.
Клиент использует ряд Jini-классов. Эти классы нужно указать в CLASSPATH компилятора.
set JINI_HOME=D:\work\jini2_1\lib
set CLASSPATH="D:\work\jini\turizm\src;%JINI_HOME%\jsk-platform.jar;%JINI_HOME%\jsk-lib.jar"
javac -classpath %CLASSPATH% src/client/*.java
где пути необходимо поменять на свои.
Многоадресный клиент (Multicast Client)Более вероятно, что клиенту понадобится искать по всем локаторам сервиса, пока не найдет искомый. Для этого используется многоадресный поиск. Клиенту не нужен пользовательский поток, чтобы остаться существующим достаточное время для поиска локаторов сервиса и нахождения подходящего сервиса. Поэтому в функции main() пользовательский потом «засыпает» на короткий период (10 секунд).
Код |
package client; import net.jini.discovery.DiscoveryListener; import net.jini.discovery.DiscoveryEvent; import net.jini.discovery.LookupDiscovery; import net.jini.core.lookup.ServiceRegistrar; import net.jini.core.lookup.ServiceTemplate; import common.TourInfoService;
import java.rmi.RemoteException; import java.rmi.RMISecurityManager; import java.io.BufferedReader; import java.io.InputStreamReader; import java.io.IOException; import java.io.UnsupportedEncodingException; import java.util.ArrayList;
public class MulticastTourInfoService implements DiscoveryListener {
TourInfoService infoService = null;
public MulticastTourInfoService(){ System.setSecurityManager(new RMISecurityManager()); LookupDiscovery discover = null; try { discover = new LookupDiscovery(LookupDiscovery.ALL_GROUPS); } catch (IOException e) { e.printStackTrace(); System.exit(1); } discover.addDiscoveryListener(this); } public void discovered(DiscoveryEvent discoveryEvent) { ServiceRegistrar[] registrars = discoveryEvent.getRegistrars(); Class[] classes = new Class[] {TourInfoService.class}; ServiceTemplate template = new ServiceTemplate(null,classes,null);
for (int n=0; n<registrars.length; n++){ System.out.println("Найдена служба LookUp"); ServiceRegistrar registrar = registrars[n]; try { infoService = (TourInfoService) registrar.lookup(template); } catch (RemoteException e) { e.printStackTrace(); continue; } if (infoService == null){ System.out.println("infoService null"); continue; }
menu(); } }
public void discarded(DiscoveryEvent discoveryEvent) { }
private void menu() { // метод такой же как и в одноадресном клиенте (копируем оттуда). }
public static void main(String[] args) { new MulticastTourInfoService(); try { Thread.currentThread().sleep(100000L); } catch (InterruptedException e) { e.printStackTrace(); } } }
|
Компиляция клиента.
Клиент использует ряд Jini-классов. Эти классы нужно указать в CLASSPATH компилятора.
set JINI_HOME=D:\work\jini2_1\lib
set CLASSPATH="D:\work\jini\turizm\src;%JINI_HOME%\jsk-platform.jar;%JINI_HOME%\jsk-lib.jar"
javac -classpath %CLASSPATH% src/client/*.javaгде пути необходимо поменять на свои.
Загрузка сервиса полностью
Сервис не использует какое-либо конкретное свойство хоста – он не зависим ни от оборудования, ни от операционной системы. В таком случае возможна загрузка сервиса целиком на клиент и запуск его там. Сервис является прокси.
Реализация сервиса – файл TourInfoService.java в пакете complete.
Код |
ackage complete;
// использует общие файлы import common.TourInfoService; import common.TourInfo;
import java.io.Serializable; import java.rmi.RemoteException; import java.util.ArrayList;
public class TourInfoServiceImpl implements TourInfoService, Serializable {
public TourInfo tourInfo = new TourInfo(); public ArrayList records = new ArrayList();
// получение информации public ArrayList getTourInfo() throws RemoteException { return records; }
// добавление нового тура public void addTourInfo(String dir, int price, int days, String type) throws RemoteException { ArrayList al = new ArrayList();
al.add(dir); al.add(price); al.add(days); al.add(type);
tourInfo.setInfo(al); records.add(tourInfo.getInfo()); }
// удаление тура по существующему направлению public void delTourInfo(String direction) throws RemoteException {
for (int i=0;i<records.size();i++){ ArrayList inf = (ArrayList)records.get(i); if (inf.get(0).equals(direction)) records.remove(i); } }
// редактирование тура по данному направлению public void editTourInfo(String direction,String dir, int price, int days, String type) throws RemoteException {
for (int i=0;i<records.size();i++){ ArrayList inf = (ArrayList)records.get(i); if (inf.get(0).equals(direction)){ inf.set(0,dir); inf.set(1,price); inf.set(2,days); inf.set(3,type); } } } }
|
Компиляция реализации сервиса.
set JINI_HOME=D:\work\jini2_1\lib
set CLASSPATH="D:\work\jini\turizm\src;%JINI_HOME%\jsk-platform.jar;%JINI_HOME%\jsk-lib.jar"
javac -classpath %CLASSPATH% src/complete/*.java
где пути меняем на свои.
СерверПомещается в пакет
complete.
Сервис-провайдеру необходимо создать экземпляр экспортируемого объекта сервиса, зарегистрировать его и поддерживать аренду в жизнеспособном состоянии (alive). В методе
discovered() он не только регистрирует сервис, но также и добавляет его в LeaseRenewalManager для поддержания вечной (FOREVER) аренды. Это менеджер запускает свои собственные потоки для перерегистрации аренды, эти потоки являются демонами (т.е. фоновые процессы). Поэтому в методе
main() пользовательский поток «засыпает» на столько, на сколько мы хотим, чтобы действовал сервер (server to stay around). Заметьте, что если сервер завершает работу, то аренда больше не сможет возобновляться (renew).
serviceID первоначально равняется
null. Как только служба поиска назначит ID сервиса, он сохраняется в файле
FileClassifier.id. Если сервер падает, то при рестарте он восстанавливает ID и использует.
Код |
package complete;
import net.jini.discovery.DiscoveryListener; import net.jini.discovery.DiscoveryEvent; import net.jini.discovery.LookupDiscovery; import net.jini.lease.LeaseListener; import net.jini.lease.LeaseRenewalEvent; import net.jini.lease.LeaseRenewalManager; import net.jini.core.lookup.ServiceID; import net.jini.core.lookup.ServiceRegistrar; import net.jini.core.lookup.ServiceItem; import net.jini.core.lookup.ServiceRegistration; import net.jini.core.lease.Lease;
import java.io.*; import java.rmi.RMISecurityManager; import java.rmi.RemoteException;
public class TourInfoServiceServer implements DiscoveryListener, LeaseListener {
protected LeaseRenewalManager leaseManager = new LeaseRenewalManager(); protected ServiceID serviceID = null; protected TourInfoServiceImpl impl;
public static void main(String[] args) {
TourInfoServiceServer s = new TourInfoServiceServer(); Object keepAlive = new Object(); synchronized(keepAlive){ try { keepAlive.wait(); } catch (InterruptedException e) { e.printStackTrace(); } } }
public TourInfoServiceServer() { impl = new TourInfoServiceImpl(); DataInputStream din = null; try { din = new DataInputStream(new FileInputStream("TourInfoService.id")); serviceID = new ServiceID(din); } catch (FileNotFoundException e) { e.printStackTrace(); } catch (IOException e) { e.printStackTrace(); } System.setSecurityManager(new RMISecurityManager()); LookupDiscovery discover = null; try { discover = new LookupDiscovery(LookupDiscovery.ALL_GROUPS); } catch (IOException e) { e.printStackTrace(); System.exit(1); } discover.addDiscoveryListener(this); }
public void discovered(DiscoveryEvent discoveryEvent) { ServiceRegistrar[] registrars = discoveryEvent.getRegistrars(); for (int n=0; n<registrars.length; n++){ ServiceRegistrar registrar = registrars[n]; ServiceItem item = new ServiceItem(serviceID,impl,null); ServiceRegistration reg; try { reg = registrar.register(item, Lease.FOREVER); // reg = registrar.register(item, 20000); } catch (RemoteException e) { e.printStackTrace(); continue; } System.out.println("--------------------------------------"); System.out.println("Service is registered with ID="+ reg.getServiceID()); System.out.println("--------------------------------------");
leaseManager.renewUntil(reg.getLease(),Lease.FOREVER,this); //leaseManager.renewUntil(reg.getLease(),20000,this);
if (serviceID == null){ serviceID = reg.getServiceID(); DataOutputStream dout = null; try { dout = new DataOutputStream(new FileOutputStream("TourInfoService.id")); serviceID.writeBytes(dout); dout.flush(); } catch (FileNotFoundException e) { e.printStackTrace(); } catch (IOException e) { e.printStackTrace(); } } } }
public void discarded(DiscoveryEvent discoveryEvent) {
}
public void notify(LeaseRenewalEvent leaseRenewalEvent) { System.out.println("Leasing is expired "+ leaseRenewalEvent.toString()); } }
|
Компиляция сервера
set JINI_HOME=D:\work\jini2_1\lib
set CLASSPATH="D:\work\jini\turizm\src;%JINI_HOME%\jsk-platform.jar;%JINI_HOME%\jsk-lib.jar"
javac -classpath %CLASSPATH% src/complete/*.java запуск проекта:1)создадим jar файл с именем TourInfoService-dl.jar
cd src
jar cf TourInfoServiceImpl-dl.jar common/TourInfo.class common/TourInfoService.class complete/TourInfoServiceImpl.class
2)поместим его в папку lib-dl внутри директории с Jini.
3)Запустим jini2_1\installverify\Launch-All.lnk
4)Запустим сервер:
cd src
title Server
set JINI_HOME=D:\work\jini2_1\lib
set CLASSPATH=".;%JINI_HOME%\jsk-platform.jar;%JINI_HOME%\jsk-lib.jar"
java -Djava.rmi.server.codebase=http://xata:8081/TourInfoServiceImpl-dl.jar -Djava.security.policy=policy.all complete.TourInfoServiceServer
5)Запустим клиента.
Одноадресного:
cd src
title Unicast client
set JINI_HOME=D:\work\jini2_1\lib
set CLASSPATH=".;D:\work\jini\turizm\src;%JINI_HOME%\jsk-platform.jar;%JINI_HOME%\jsk-lib.jar"
java -classpath %CLASSPATH% -Djava.security.policy=policy.all client.UnicastTourInfoService
Или многоадресного:
cd src
title Multicast Client
set JINI_HOME=D:\work\jini2_1\lib
set CLASSPATH=".;D:\work\jini\turizm\src;%JINI_HOME%\jsk-platform.jar;%JINI_HOME%\jsk-lib.jar"
java -classpath %CLASSPATH% -Djava.security.policy=policy.all client.MulticastTourInfoServiceВсе

готово, буду рад, если этот материал кому - нибудь пригодится
Это сообщение отредактировал(а) Samotnik - 4.5.2008, 04:14