Chapter 28: Peer-to-Peer Applications and JXTA
Outline
28.1 Introduction
28.2 Client/Server and Peer-to-Peer Applications
28.3 Centralized vs. Decentralized Network Applications 28.4 Peer Discovery and Searching
28.5 Case Study: Deitel Instant Messenger 28.6 Defining the Service Interface
28.7 Defining the Service implementation 28.8 Registering the Service
28.9 Find Other Peers
28.10 Compiling and Running the Example 28.11 Improving Deitel Instant Messenger
28.12 Deitel Instant Messenger with Multicast Sockets 28.12.1 Registering the Peer
28.12.2 Finding Other Peers 28.13 Introduction to JXTA
28.1 Introduction
• Peer-to-peer (P2P) application
– Each node performs both client and server functions – Distribution of processing responsibilities
28.2 Client/Server and Peer-to-Peer Applications
• Client/Server application
– e.g., Yahoo! search engine
– Server offers common stores of programs and data – Client access the data provided by servers
• Peer-to-peer (P2P) application
– All computers act as both client and server
28.2 Client/Server and Peer-to-Peer Applications (cont.)
Distributed Applications Description
Gnutella A P2P technology that does not use any central servers. There is no authentication, and peers search for files via a distributed-search mechanism.
KaZaA A file-sharing application that is a hybrid between Gnutella and centralized applications. A central server authenticates all users. Certain peers serve as search hubs, which catalog the files of peers connected to them. Searches are distributed to each search hub, which then respond with results that allow direct connections for file transfers.
Instant Messengers Peer-to-peer applications that enable users to send short text messages and files to one another.
Most instant messengers use central servers that authenticate all users and route messages between peers.
Telephone System A peer-to-peer application that enables users to conduct voice conversations remotely.
Fig. 28.1 Common P2P applications.
28.3 Centralized vs. Decentralized Network Applications
• Centralized server
– Weakness: dependency on central server
• If central server fails, so does the entire application
• Decentralized server
– True P2P application
– No dependency on single node
• If one node fails, the application can exist
28.4 Peer Discovery and Searching
• Peer discovery
– Finding peers in P2P application
– Decentralizing an application often slows peer discovery
• Distributed searching
– Peer sends search criteria to several nearby peers – Searching performed by several systems
28.5 Case Study: Deitel Instant Messenger
• Deitel Instant Messenger
– P2P application
– Uses Jini to bootstrap (register) users onto the P2P network
28.5 Case Study: Deitel Instant Messenger (cont.)
Fig. 28.2 Sample windows of Deitel Instant Messenger.
2002 Prentice Hall.
Outline
Fig. 28.3 Interface IMService specifies how service proxy interacts with the service.
Lines 16-17
1 // IMService.java
2 // IMService interface defines the methods 3 // through which the service proxy
4 // communicates with the service.
5 package com.deitel.advjhtp1.jini.IM.service;
6
7 // Java core packages 8 import java.rmi.*;
9
10 // Deitel packages
11 import com.deitel.advjhtp1.jini.IM.IMPeer;
12
13 public interface IMService extends Remote { 14
15 // return RMI reference to a remote IMPeer 16 public IMPeer connect( IMPeer sender ) 17 throws RemoteException;
18 }
Enables users to send a remote reference to an IMPeer
2002 Prentice Hall.
Outline
Fig. 28.4 Interface IMPeer specifies interaction between peers.
Line 9
Lines 12-13
1 // IMPeer.java
2 // Interface that all Peer to Peer apps must implement 3 package com.deitel.advjhtp1.jini.IM;
4
5 //java core packages 6 import java.rmi.*;
7 import java.util.*;
8
9 public interface IMPeer extends Remote 10 {
11 // posts Message to peer
12 public void sendMessage( Message message ) 13 throws RemoteException;
14
15 // information methods
16 public String getName() throws RemoteException;
17 }
Clients send messages to peers by calling sendMessage Specifies the interface for
communicating between peers
2002 Prentice Hall.
Outline
Fig. 28.5 Class Message defines an object for sending and receiving
messages between peers (part 1).
Line 9
Lines 16-21
1 // Message.java
2 // Message represents an object that can be sent to an IMPeer;
3 // contains the sender and content of the message.
4 package com.deitel.advjhtp1.jini.IM;
5
6 // Java core package
7 import java.io.Serializable;
8
9 public class Message implements Serializable 10 {
11 private static final long SerialVersionUID = 20010808L;
12 private String from;
13 private String content;
14
15 // Message constructor
16 public Message( String messageSenderName, 17 String messageContent )
18 {
19 from = messageSenderName;
20 content = messageContent;
21 } 22
23 // get String representation 24 public String toString() 25 {
26 return from + ": " + content + "\n";
27 } 28
29 // get Message sender's name 30 public String getSenderName() 31 {
32 return from;
33 }
Messages must be serialized for delivery over RMI
Message constructor takes as arguments the sender’s name and message content
2002 Prentice Hall.
Outline
Fig. 28.5 Class Message defines an object for sending and receiving
messages between peers (part 2).
34
35 // get Message content 36 public String getContent() 37 {
38 return content;
39 } 40 }
28.7 Defining the Service Implementation
• Define service implementation
– IMServiceImpl
• Implements interface IMService
• Extends UnicastRemoteObject
2002 Prentice Hall.
Outline
Fig. 28.6
IMServiceImpl service
implementation for our case study (part 1).
Line 18 Lines 28-31
1 // IMServiceImpl.java
2 // IMServiceImpl implements IMService interface 3 // is service side of IM application
4 package com.deitel.advjhtp1.jini.IM.service;
5
6 // Java core packages 7 import java.io.*;
8 import java.rmi.server.UnicastRemoteObject;
9 import java.rmi.RemoteException;
10 import java.util.StringTokenizer;
11
12 // Deitel packages
13 import com.deitel.advjhtp1.jini.IM.IMPeer;
14 import com.deitel.advjhtp1.jini.IM.IMPeerImpl;
15 import com.deitel.advjhtp1.jini.IM.Message;
16 import com.deitel.advjhtp1.jini.IM.client.IMPeerListener;
17
18 public class IMServiceImpl extends UnicastRemoteObject 19 implements IMService, Serializable {
20
21 private static final long SerialVersionUID = 20010808L;
22 private String userName = "Anonymous";
23
24 // IMService no-argument constructor
25 public IMServiceImpl() throws RemoteException{}
26
27 // IMService constructor takes userName
28 public IMServiceImpl( String name ) throws RemoteException 29 {
30 userName = name;
31 } 32
Define the service implementation
Second constructor takes as a String argument the user’s name, which appears
in the PeerList window
2002 Prentice Hall.
Outline
Fig. 28.6
IMServiceImpl service
implementation for our case study (part 2).
Line 40 Line 51 Line 54
33 // sets service s userName
34 public void setUserName( String name ) 35 {
36 userName = name;
37 } 38
39 // return RMI reference to an IMPeer on the receiver side 40 public IMPeer connect( IMPeer sender )
41 throws RemoteException 42 {
43 // Make a GUI and IMPeerImpl to be sent to remote peer 44 IMPeerListener listener =
45 new IMPeerListener( userName );
46
47 IMPeerImpl me = new IMPeerImpl( userName );
48 me.addListener( listener );
49
50 // add remote peer to my GUI 51 listener.addPeer( sender );
52
53 //send my IMPeerImpl to him 54 return me;
55
56 } // end method connect 57 }
First peer sends reference of itself to second peer by invoking IMService
method connect
Second Peer stores first peer’s reference for use when conversation starts
Second peer returns reference of itself to first peer
2002 Prentice Hall.
Outline
Fig. 28.7
IMPeerListener is the GUI that starts peer communication (part 1).
Line 20
1 // IMPeerListener.java
2 // IMPeerListener extends JFrame and provides GUI for 3 // conversations with other peers
4 package com.deitel.advjhtp1.jini.IM.client;
5
6 // Java core packages 7 import java.awt.*;
8 import java.awt.event.*;
9 import java.rmi.RemoteException;
10
11 // Java extension packages 12 import javax.swing.*;
13 import javax.swing.text.*;
14 import javax.swing.border.*;
15
16 // Deitel Packages
17 import com.deitel.advjhtp1.jini.IM.IMPeer;
18 import com.deitel.advjhtp1.jini.IM.Message;
19
20 public class IMPeerListener extends JFrame { 21
22 // JTextAreas for displaying and inputting messages 23 private JTextArea messageArea;
24 private JTextArea inputArea;
25
26 // Actions for sending messages, etc.
27 private Action sendAction;
28
29 // userName to add to outgoing messages 30 private String userName = "";
31
32 // IMPeer to send messages to peer 33 private IMPeer remotePeer;
34
GUI for starting peer communication
2002 Prentice Hall.
Outline
Fig. 28.7
IMPeerListener is the GUI that starts peer communication (part 2).
35 // constructor
36 public IMPeerListener( String name ) 37 {
38 super( "Conversation Window" );
39
40 // set user name 41 userName = name;
42
43 // init sendAction
44 sendAction = new SendAction();
45
46 // create JTextArea for displaying messages 47 messageArea = new JTextArea( 15, 15 );
48
49 // disable editing and wrap words at end of line 50 messageArea.setEditable( false );
51 messageArea.setLineWrap( true );
52 messageArea.setWrapStyleWord( true );
53
54 JPanel panel = new JPanel();
55 panel.setLayout( new BorderLayout( 5, 5 ) );
56 panel.add( new JScrollPane( messageArea ), 57 BorderLayout.CENTER );
58
59 // create JTextArea for entering new messages 60 inputArea = new JTextArea( 4, 12 );
61 inputArea.setLineWrap( true );
62 inputArea.setWrapStyleWord( true );
63
64 // map Enter key in inputArea area to sendAction 65 Keymap keyMap = inputArea.getKeymap();
66 KeyStroke enterKey = KeyStroke.getKeyStroke(
67 KeyEvent.VK_ENTER, 0 );
68 keyMap.addActionForKeyStroke( enterKey, sendAction );
69
2002 Prentice Hall.
Outline
Fig. 28.7
IMPeerListener is the GUI that starts peer communication (part 3).
70 // lay out inputArea and sendAction JButton in Box 71 Box box = Box.createVerticalBox();
72 box.add( new JScrollPane( inputArea ) );
73 box.add( new JButton( sendAction ) );
74
75 panel.add( box, BorderLayout.SOUTH );
76
77 // lay out components
78 Container container = getContentPane();
79 container.add( panel, BorderLayout.CENTER );
80 81 setSize( 200, 400 );
82 setVisible( true );
83 } 84
85 // Action for sending messages
86 private class SendAction extends AbstractAction { 87
88 // configure SendAction 89 public SendAction() 90 {
91 putValue( Action.NAME, "Send" );
92 putValue( Action.SHORT_DESCRIPTION, 93 "Send Message" );
94 putValue( Action.LONG_DESCRIPTION, 95 "Send an Instant Message" );
96 } 97
98 // send message and clear inputArea
99 public void actionPerformed( ActionEvent event ) 100 {
101 // send message to server 102 try {
103 Message message = new Message( userName, 104 inputArea.getText() );
2002 Prentice Hall.
Outline
Fig. 28.7
IMPeerListener is the GUI that starts peer communication (part 4).
Line 107
105
106 // use RMI reference to send a Message 107 remotePeer.sendMessage( message );
108
109 // clear inputArea
110 inputArea.setText( "" );
111 displayMessage( message );
112 } 113
114 // catch error sending message
115 catch( RemoteException remoteException ) { 116 JOptionPane.showMessageDialog( null, 117 "Unable to send message." );
118
119 remoteException.printStackTrace();
120 }
121 } // end method actionPerformed 122
123 } // end sendAction inner class 124
125 public void displayMessage( Message message ) 126 {
127 // displayMessage uses SwingUntilities.invokeLater 128 // to ensure thread-safe access to messageArea
129 SwingUtilities.invokeLater(
130 new MessageDisplayer(
131 message.getSenderName(), message.getContent() ) );
132 } 133
134 // MessageDisplayer displays a new message by appending 135 // the message to the messageArea JTextArea. This Runnable 136 // object should be executed only on the event-dispatch 137 // thread, as it modifies a live Swing component.
138 private class MessageDisplayer implements Runnable { 139
When user presses JButton, call method sendMessage of remote peer
2002 Prentice Hall.
Outline
Fig. 28.7
IMPeerListener is the GUI that starts peer communication (part 5).
Lines 167-173
140 private String fromUser;
141 private String messageBody;
142
143 // MessageDisplayer constructor
144 public MessageDisplayer( String from, String body ) 145 {
146 fromUser = from;
147 messageBody = body;
148 } 149
150 // display new message in messageArea 151 public void run()
152 {
153 // append new message
154 messageArea.append( "\n" + fromUser + "> " + 155 messageBody );
156
157 // move caret to end of messageArea to ensure new 158 // message is visible on screen
159 messageArea.setCaretPosition(
160 messageArea.getText().length() );
161 } 162
163 } // end MessageDisplayer inner class 164
165 // addPeer takes IMPeer as arg
166 // associates IMPeer with sendAction to send messages 167 public void addPeer( IMPeer peer ) throws RemoteException 168 {
169 remotePeer = peer;
170
171 // change title of window to name of peer 172 setTitle( remotePeer.getName() );
173 } 174 }
Stores reference to remote IMPeer and set title of conversation window to the
name of remote IMPeer
2002 Prentice Hall.
Outline
Fig. 28.8 Class IMPeerImpl is the IMPeer
implementation (part 1).
Line 17
1 // IMPeerImpl.java
2 // Implements the IMPeer interface 3 package com.deitel.advjhtp1.jini.IM;
4
5 // Java core packages 6 import java.io.*;
7 import java.net.*;
8 import java.rmi.*;
9 import java.rmi.server.*;
10 import java.util.*;
11
12 // Deitel Packages
13 import com.deitel.advjhtp1.jini.IM.Message;
14 import com.deitel.advjhtp1.jini.IM.client.IMPeerListener;
15 16
17 public class IMPeerImpl extends UnicastRemoteObject 18 implements IMPeer {
19
20 private String name;
21 private IMPeerListener output;
22
23 // No argument constructor
24 public IMPeerImpl() throws RemoteException 25 {
26 super();
27 name = "anonymous";
28 }
29 // constructor takes userName
30 public IMPeerImpl( String myName ) throws RemoteException 31 {
32 name = myName;
33 } 34
Define the peer implementation
2002 Prentice Hall.
Outline
Fig. 28.8 Class IMPeerImpl is the IMPeer
implementation (part 2).
Lines 35-38 Lines 41-45
35 public void addListener( IMPeerListener listener ) 36 {
37 output = listener;
38 } 39
40 // send message to this peer
41 public void sendMessage( Message message ) 42 throws RemoteException
43 {
44 output.displayMessage( message );
45 } 46
47 // accessor for name
48 public String getName() throws RemoteException 49 {
50 return name;
51 } 52 }
Override method sendMessage to send message to peer
Add an object of type IMPeer- Listener that will display the
IMPeerImpl’s actions
28.8 Registering the Service
• Register (bootstrap) service with peer group
2002 Prentice Hall.
Outline
Fig. 28.9 Class
IMServiceManager registers
IMServiceImpl with lookup services (part 1).
Line 33
1 // IMServiceManager.java
2 // IMServiceManager uses JoinManager to find Lookup services, 3 // registers the IMService with the Lookup services,
4 // manages lease renewal
5 package com.deitel.advjhtp1.jini.IM;
6
7 // Java core packages
8 import java.rmi.RMISecurityManager;
9 import java.rmi.RemoteException;
10 import java.io.IOException;
11
12 // Jini core packages
13 import net.jini.core.lookup.ServiceID;
14 import net.jini.core.entry.Entry;
15
16 // Jini extension packages
17 import net.jini.lookup.entry.Name;
18 import net.jini.lease.LeaseRenewalManager;
19 import net.jini.lookup.JoinManager;
20 import net.jini.discovery.LookupDiscoveryManager;
21 import net.jini.lookup.ServiceIDListener;
22
23 // Deitel packages
24 import com.deitel.advjhtp1.jini.IM.service.*;
25
26 public class IMServiceManager implements ServiceIDListener { 27
28 JoinManager manager;
29 LookupDiscoveryManager lookupManager;
30 String serviceName;
31
32 // constructor takes name of the service 33 public IMServiceManager( String screenName ) 34 {
35 System.setSecurityManager( new RMISecurityManager() );
Constructor takes a String that specifies the Name
Entry for the service
2002 Prentice Hall.
Outline
Fig. 28.9 Class
IMServiceManager registers
IMServiceImpl with lookup services (part 2).
Line 56
36
37 // sets the serviceName of this service 38 serviceName = screenName;
39
40 // use JoinManager to register SeminarInfo service 41 // and manage lease
42 try { 43
44 // create LookupDiscoveryManager for discovering 45 // lookup services
46 lookupManager =
47 new LookupDiscoveryManager( new String[] { "" }, 48 null, null );
49
50 // create and set Entry name for service 51 // name used from constructor
52 Entry[] entries = new Entry[ 1 ];
53 entries[ 0 ] = new Name( serviceName );
54
55 // create JoinManager
56 manager = new JoinManager( createProxy(), 57 entries, this, lookupManager,
58 new LeaseRenewalManager() );
59 } 60
61 // handle exception creating JoinManager 62 catch ( IOException exception ) {
63 exception.printStackTrace();
64 }
65 } // end SeminarInfoJoinService constructor 66
67 // return the LookupDiscoveryManager created by JoinManager 68 public LookupDiscoveryManager getDiscoveryManager()
69 {
70 return lookupManager;
Use Jini’s JoinManager class to register the service with all known lookup services
2002 Prentice Hall.
Outline
Fig. 28.9 Class
IMServiceManager registers
IMServiceImpl with lookup services (part 3).
71 } 72
73 // create service proxy
74 private IMService createProxy() 75 {
76 // get SeminarProxy for SeminarInfo service 77 try {
78 return( new IMServiceImpl( serviceName ) );
79 } 80
81 // handle exception creating SeminarProxy 82 catch ( RemoteException exception ) { 83 exception.printStackTrace();
84 } 85
86 return null;
87
88 } // end method createProxy 89
90 // receive notification of ServiceID assignment 91 public void serviceIDNotify( ServiceID serviceID ) 92 {
93 System.err.println( "Service ID: " + serviceID );
94 } 95
96 // informs all lookup services that service is ending 97 public void logout()
98 {
99 manager.terminate();
100 } 101 }
28.9 Find Other Peers
• Create GUI enabling user to find other peers
2002 Prentice Hall.
Outline
Fig. 28.10 Class PeerList is the GUI for finding peers
(part 1).
Lines 33-34
1 // PeerList.java
2 // Initializes ServiceManager, starts service discovery 3 // and lists all IM services in a window
4 package com.deitel.advjhtp1.jini.IM;
5
6 // Java core packages 7 import java.awt.*;
8 import java.awt.event.*;
9 import java.net.MalformedURLException;
10 import java.util.*;
11 import java.util.List;
12 import java.io.IOException;
13 import java.rmi.*;
14
15 // Java extension packages 16 import javax.swing.*;
17 import javax.swing.event.*;
18
19 // Jini core packages
20 import net.jini.core.lookup.ServiceItem;
21 import net.jini.core.lookup.ServiceTemplate;
22 import net.jini.lookup.*;
23 import net.jini.discovery.LookupDiscoveryManager;
24 import net.jini.lease.LeaseRenewalManager;
25 import net.jini.lookup.entry.Name;
26 import net.jini.core.entry.Entry;
27 import net.jini.core.discovery.LookupLocator;
28
29 // Deitel Packages
30 import com.deitel.advjhtp1.jini.IM.service.IMService;
31 import com.deitel.advjhtp1.jini.IM.client.IMPeerListener;
32
33 public class PeerList extends JFrame 34 implements ServiceDiscoveryListener { 35
PeerList is the main window of the Deitel Instant Messenger
2002 Prentice Hall.
Outline
Fig. 28.10 Class PeerList is the GUI for finding peers
(part 2).
Line 53 Lines 57-65
36 private DefaultListModel peers;
37 private JList peerList;
38 private List serviceItems;
39 private ServiceDiscoveryManager serviceDiscoveryManager;
40 private LookupCache cache;
41 private IMServiceManager myManager;
42 private LookupDiscoveryManager lookupDiscoveryManager;
43
44 // initialize userName to anonymous 45 private String userName = "anonymous";
46
47 // method called when ServiceDiscoveryManager finds 48 // IM service adds service proxy to serviceItems 49 // adds Service name to ListModel for JList
50 public void serviceAdded( ServiceDiscoveryEvent event ) 51 {
52 // get added serviceItem
53 ServiceItem item = event.getPostEventServiceItem();
54 Entry attributes[] = item.attributeSets;
55
56 // iterates through attributes to find name 57 for( int i = 0; i < attributes.length; i++ ) 58
59 if ( attributes[ i ] instanceof Name ) { 60 System.out.println( "Added: " + item );
61 serviceItems.add( item.service );
62 peers.addElement(
63 ( ( Name )attributes[ i ] ).name );
64 break;
65 }
66 } // end method serviceAdded 67
68 // empty method ignores seviceChanged event
69 public void serviceChanged( ServiceDiscoveryEvent event ) 70 {}
Obtain a ServiceItem that represents the added service
Add service proxy to List and add Name to Default-
ListModel if Name entry
2002 Prentice Hall.
Outline
Fig. 28.10 Class PeerList is the GUI for finding peers
(part 3).
71
72 // removes services from PeerList GUI and data structure 73 // when serviceRemoved event occurs
74 public void serviceRemoved( ServiceDiscoveryEvent event ) 75 {
76 // getPreEvent because item has been removed 77 // getPostEvent would return null
78 ServiceItem item = event.getPreEventServiceItem();
79 Entry attributes[ ] = item.attributeSets;
80
81 // debug
82 System.out.println( "Remove Event!" );
83
84 // remove from arraylist and DefaultListModel 85 int index = serviceItems.indexOf( item.service );
86
87 // print name of person removed 88 if ( index >= 0 )
89 {
90 System.out.println( "Removing from List:" + 91 serviceItems.remove( index ));
92
93 System.out.println( "Removing from DefList" + 94 peers.elementAt( index ) );
95
96 peers.removeElementAt( index );
97 }
98 } // end method ServiceRemoved 99
100 // constructor 101 public PeerList() 102 {
103 super( "Peer List" );
104
105 System.setSecurityManager( new RMISecurityManager() );
2002 Prentice Hall.
Outline
Fig. 28.10 Class PeerList is the GUI for finding peers
(part 4).
Lines 135-138
106
107 // get desired userName
108 userName = JOptionPane.showInputDialog(
109 PeerList.this, "Please enter your name: " );
110
111 // change title of window
112 setTitle( userName + "'s Peer List Window" );
113
114 // Init Lists
115 serviceItems = new ArrayList();
116
117 Container container = getContentPane();
118 peers = new DefaultListModel();
119
120 // init components
121 peerList = new JList( peers );
122 peerList.setVisibleRowCount( 5 );
123 JButton connectButton = new JButton( "Connect" );
124
125 // do not allow multiple selections 126 peerList.setSelectionMode(
127 ListSelectionModel.SINGLE_SELECTION );
128
129 // set up event handler for connectButton 130 connectButton.addActionListener(
131 new ActionListener() { 132
133 public void actionPerformed( ActionEvent event ) 134 {
135 int itemIndex = peerList.getSelectedIndex();
136
137 Object selectedService =
138 serviceItems.get( itemIndex );
139 IMService peerProxy =
140 ( IMService )selectedService;
Use index of selected JList item to retrieve
IMService proxy
2002 Prentice Hall.
Outline
Fig. 28.10 Class PeerList is the GUI for finding peers
(part 5).
Lines 147-151 Lines 154-155
141
142 // send info to remote peer 143 // get RMI reference
144 try { 145
146 // set up gui and my peerImpl 147 IMPeerListener gui =
148 new IMPeerListener( userName );
149 IMPeerImpl me =
150 new IMPeerImpl( userName );
151 me.addListener( gui );
152
153 // Connect myGui to remote IMPeer object 154 IMPeer myPeer = peerProxy.connect( me );
155 gui.addPeer( myPeer );
156 } 157
158 // connecting may cause RemoteException 159 catch( RemoteException re ) {
160 JOptionPane.showMessageDialog 161 ( null, "Couldn't Connect" );
162 re.printStackTrace();
163 } 164 } 165 }
166 ); // end connectButton actionListener 167
168 // set up File menu
169 JMenu fileMenu = new JMenu( "File" );
170 fileMenu.setMnemonic( 'F' );
171
Create IMPeerListener for IMPeerImpl
IMPeerImpl will post all messages sent by remote peer
to IMPeerListener
2002 Prentice Hall.
Outline
Fig. 28.10 Class PeerList is the GUI for finding peers
(part 6).
Lines 189-223
172 // about Item
173 JMenuItem aboutItem = new JMenuItem( "About..." );
174 aboutItem.setMnemonic( 'A' );
175 aboutItem.addActionListener(
176 new ActionListener() {
177 public void actionPerformed( ActionEvent event ) 178 {
179 JOptionPane.showMessageDialog( PeerList.this, 180 "Deitel Instant Messenger" ,
181 "About", JOptionPane.PLAIN_MESSAGE );
182 } 183 } 184 );
185
186 fileMenu.add( aboutItem );
187
188 // AddLocator item
189 JMenuItem federateItem =
190 new JMenuItem( "Add Locators" );
191 federateItem.setMnemonic( 'L' );
192 federateItem.addActionListener(
193
194 new ActionListener() {
195 public void actionPerformed( ActionEvent event ) 196 {
197 // get LookupService url to be added 198 String locator =
199 JOptionPane.showInputDialog(
200 PeerList.this,
201 "Please enter locator in this" + 202 "form: jini://host:port/" );
203 204 try {
205 LookupLocator newLocator =
206 new LookupLocator( locator );
Create dialog box to prompt user for Jini-lookup-service URL
2002 Prentice Hall.
Outline
Fig. 28.10 Class PeerList is the GUI for finding peers
(part 7).
Line 212
207
208 // make one element LookupLocator array 209 LookupLocator[] locators = { newLocator };
210
211 // because addLocators takes array
212 lookupDiscoveryManager.addLocators( locators );
213 } 214
215 catch( MalformedURLException urlException) { 216
217 JOptionPane.showMessageDialog(
218 PeerList.this, "invalid url" );
219 } 220 } 221 } 222 );
223 fileMenu.add( federateItem );
224
225 // set up JMenuBar and attach File menu 226 JMenuBar menuBar = new JMenuBar();
227 menuBar.add ( fileMenu );
228 setJMenuBar( menuBar );
229
230 // handow window closing event 231 addWindowListener(
232 new WindowAdapter(){
233 public void windowClosing( WindowEvent w ) 234 {
235 System.out.println( "CLOSING WINDOW" );
236
237 // disconnects from lookup services 238 myManager.logout();
239 System.exit( 0 );
240 } 241 }
Client registers with newly added lookup service;
PeerList window lists all other peers registered with new lookup service
2002 Prentice Hall.
Outline
Fig. 28.10 Class PeerList is the GUI for finding peers
(part 8).
Line 263
242 );
243
244 // lay out GUI components 245 peerList.setFixedCellWidth( 100 );
246 JPanel inputPanel = new JPanel();
247 inputPanel.add( connectButton );
248
249 container.add( new JScrollPane( peerList ) , 250 BorderLayout.NORTH );
251 container.add( inputPanel, BorderLayout.SOUTH );
252
253 setSize( 100, 170 );
254 setVisible( true );
255
256 // peer list displays only other IMServices
257 Class[] types = new Class[] { IMService.class };
258 ServiceTemplate IMTemplate =
259 new ServiceTemplate( null, types, null );
260
261 // Initialize IMServiceManager, ServiceDiscoveryManager 262 try {
263 myManager = new IMServiceManager( userName );
264
265 // store LookupDiscoveryManager 266 // generated by IMServiceManager
267 lookupDiscoveryManager = myManager.getDiscoveryManager();
268
269 // ServiceDiscoveryManager uses lookupDiscoveryManager 270 serviceDiscoveryManager =
271 new ServiceDiscoveryManager( lookupDiscoveryManager, 272 null );
273
274 // create a LookupCache
275 cache = serviceDiscoveryManager.createLookupCache(
276 IMTemplate, null, this );
Create the IMServiceManager, using userName to name the peer
2002 Prentice Hall.
Outline
Fig. 28.10 Class PeerList is the GUI for finding peers
(part 9).
277 } 278
279 // catch all exceptions and inform user of problem 280 catch ( Exception managerException) {
281 JOptionPane.showMessageDialog( null, 282 "Error initializing IMServiceManger" + 283 "or ServiceDisoveryManager" );
284 managerException.printStackTrace();
285 } 286 } 287
288 public static void main( String args[] ) 289 {
290 new PeerList();
291 } 292 }
28.10 Compiling and Running the Example
• 1. Compile classes
• 2. Compile remote classes via rmic
• 3. Start rmid
• 4. Start HTTP server
• 5. Start lookup service
28.11 Improving Deitel Instant Messenger
• Limitations
– Not secure – Not scalable
• Solutions
– Filters
• limit the number of service proxies that
ServiceDiscoveryManager downloads
– Distributed searches
• Facilitate locating peers
28.12 Deitel Instant Messenger with Multicast Sockets
• True P2P application
– Each node must run lookup service
• Requires significant amounts of memory and processor time
– Solution:
• Use Multicast sockets
– Advertise and find peers in network
28.12.1 Registering the Peer
• Jini implementation
– provided mechanism to register and find peers
– We must implement this mechanism via multicast sockets
2002 Prentice Hall.
Outline
Fig. 28.11
MulticastSending Thread broadcasts DatagramPackets (part 1).
Line 17
1 // MulticastSendingThread.java
2 // Sends a multicast periodically containing a remote reference 3 // to the IMServiceImpl object
4 package com.deitel.advjhtp1.p2p;
5
6 // Java core packages
7 import java.net.MulticastSocket;
8 import java.net.*;
9 import java.rmi.*;
10 import java.rmi.registry.*;
11 import java.io.*;
12
13 // Deitel core packages
14 import com.deitel.advjhtp1.jini.IM.service.IMServiceImpl;
15 import com.deitel.advjhtp1.jini.IM.service.IMService;
16
17 public class MulticastSendingThread extends Thread 18 implements IMConstants {
19
20 // InetAddress of group for messages 21 private InetAddress multicastNetAddress;
22
23 // MulticastSocket for multicasting messages 24 private MulticastSocket multicastSocket;
25
26 // Datagram packet to be reused
27 private DatagramPacket multicastPacket;
28
29 // stub of local peer
30 private IMService peerStub;
31
32 // flag for terminating MulticastSendingThread 33 private boolean keepSending = true;
34
35 private String userName;
MulticastSendingThread multicasts a peer’s presence
2002 Prentice Hall.
Outline
Fig. 28.11
MulticastSending Thread broadcasts DatagramPackets (part 2).
Lines 47-48 Line 49 Lines 59-60
36
37 // MulticastSendingThread constructor
38 public MulticastSendingThread( String myName ) 39 {
40 // invoke superclass constructor to name Thread 41 super( "MulticastSendingThread" );
42
43 userName = myName;
44
45 // create a registry on default port 1099 46 try {
47 Registry registry =
48 LocateRegistry.createRegistry( 1099 );
49 peerStub = new IMServiceImpl( userName );
50 registry.rebind( BINDING_NAME, peerStub );
51 }
52 catch ( RemoteException remoteException ) { 53 remoteException.printStackTrace();
54 } 55
56 try { 57
58 // create MulticastSocket for sending messages 59 multicastSocket =
60 new MulticastSocket ( MULTICAST_SENDING_PORT );
61
62 // set TTL for Multicast Socket
63 multicastSocket.setTimeToLive( MULTICAST_TTL );
64
65 // use InetAddress reserved for multicast group 66 multicastNetAddress = InetAddress.getByName(
67 MULTICAST_ADDRESS );
68
69 // create greeting packet
70 String greeting = new String( HELLO_HEADER + userName );
Call createRegistry to instantiate an RMI registry on port 1099 Rebind IMServiceImpl
to RMI registry
Instantiate MulticastSocket for sending messages to peers
2002 Prentice Hall.
Outline
Fig. 28.11
MulticastSending Thread broadcasts DatagramPackets (part 3).
Lines 72-74 Lines 100
71
72 multicastPacket = new DatagramPacket(
73 greeting.getBytes(), greeting.getBytes().length, 74 multicastNetAddress, MULTICAST_LISTENING_PORT );
75 }
76
77 // MULTICAST_ADDRESS IS UNKNOWN HOST
78 catch ( java.net.UnknownHostException unknownHostException ) 79 {
80 System.err.println( "MULTICAST_ADDRESS is unknown" );
81 unknownHostException.printStackTrace();
82 } 83
84 // any other exception
85 catch ( Exception exception ) 86 {
87 exception.printStackTrace();
88 } 89 } 90
91 // deliver greeting message to peers 92 public void run()
93 {
94 while ( keepSending ) { 95
96 // deliver greeting 97 try {
98
99 // send greeting packet
100 multicastSocket.send( multicastPacket );
101
102 Thread.sleep( MULTICAST_INTERVAL );
103 } 104
Create message packet containing peer’s name
Send message via MulticastSocket
2002 Prentice Hall.
Outline
Fig. 28.11
MulticastSending Thread broadcasts DatagramPackets (part 4).
Lines 123-130
105 // handle exception delivering message 106 catch ( IOException ioException ) { 107 ioException.printStackTrace();
108 continue;
109 }
110 catch ( InterruptedException interruptedException ) { 111 interruptedException.printStackTrace();
112 } 113
114 } // end while 115
116 multicastSocket.close();
117
118 } // end method run 119
120 // send goodbye message 121 public void logout() 122 {
123 String goodbye = new String( GOODBYE_HEADER + userName );
124 System.out.println( goodbye );
125 multicastPacket = new DatagramPacket(
126 goodbye.getBytes(), goodbye.getBytes().length, 127 multicastNetAddress, MULTICAST_LISTENING_PORT );
128
129 try {
130 multicastSocket.send( multicastPacket );
131
132 Naming.unbind( BINDING_NAME );
133 } 134
135 // error multicasting
136 catch ( IOException ioException ) {
137 System.err.println( "Could not Say Goodbye“ );
138 ioException.printStackTrace();
139 }
Send message indicating that the peer is leaving network
2002 Prentice Hall.
Outline
Fig. 28.11
MulticastSending Thread broadcasts DatagramPackets (part 5).
140
141 // unbinding may cause many possible exceptions 142 catch ( Exception unbindingException ) {
143 unbindingException.printStackTrace();
144 } 145
146 keepSending = false;
147
148 } 149 }