View Javadoc

1   //This library is free software; you can redistribute it and/or
2   //modify it under the terms of the GNU Lesser General Public
3   //License as published by the Free Software Foundation; either
4   //version 2.1 of the License, or (at your option) any later version.
5   //
6   //This library is distributed in the hope that it will be useful,
7   //but WITHOUT ANY WARRANTY; without even the implied warranty of
8   //MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
9   //Lesser General Public License for more details.
10  //
11  //You should have received a copy of the GNU Lesser General Public
12  //License along with this library; if not, write to the Free Software
13  //Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
14  
15  /***
16   * Modified on Jun 15, 2005, Copyright UC Regents
17   */
18  package org.telscenter.pas.util;
19  
20  import java.util.logging.Level;
21  import java.util.logging.Logger;
22  
23  import java.awt.BorderLayout;
24  import java.awt.Color;
25  import java.awt.Container;
26  import java.awt.GridLayout;
27  import java.io.IOException;
28  import java.util.Enumeration;
29  import java.util.Vector;
30  
31  import javax.jmdns.JmDNS;
32  import javax.jmdns.ServiceEvent;
33  import javax.jmdns.ServiceInfo;
34  import javax.jmdns.ServiceListener;
35  import javax.jmdns.ServiceTypeListener;
36  import javax.swing.DefaultListModel;
37  import javax.swing.JFrame;
38  import javax.swing.JLabel;
39  import javax.swing.JList;
40  import javax.swing.JPanel;
41  import javax.swing.JScrollPane;
42  import javax.swing.JTextArea;
43  import javax.swing.ListSelectionModel;
44  import javax.swing.SwingUtilities;
45  import javax.swing.border.EmptyBorder;
46  import javax.swing.event.ListSelectionEvent;
47  import javax.swing.event.ListSelectionListener;
48  import javax.swing.table.AbstractTableModel;
49  
50  /***
51   * User Interface for browsing JmDNS services.
52   * 
53   * @author Arthur van Hoff, Werner Randelshofer, turadg
54   */
55  public class JmdnsBrowser extends JPanel implements ServiceListener,
56  		ServiceTypeListener, ListSelectionListener {
57  	/***
58  	 * Logger for this class
59  	 */
60  	private static final Logger logger = Logger.getLogger(JmdnsBrowser.class
61  			.getName());
62  
63  	JmDNS jmdns;
64  
65  	Vector headers;
66  
67  	String type;
68  
69  	DefaultListModel types;
70  
71  	JList typeList;
72  
73  	DefaultListModel services;
74  
75  	JList serviceList;
76  
77  	JTextArea info;
78  
79  	public JmdnsBrowser(JmDNS jmdns) throws IOException {
80  		this.jmdns = jmdns;
81  
82  		Color bg = new Color(230, 230, 230);
83  		EmptyBorder border = new EmptyBorder(5, 5, 5, 5);
84  		Container content = this;
85  		content.setLayout(new GridLayout(1, 3));
86  
87  		types = new DefaultListModel();
88  		typeList = new JList(types);
89  		typeList.setBorder(border);
90  		typeList.setBackground(bg);
91  		typeList.setSelectionMode(ListSelectionModel.SINGLE_SELECTION);
92  		typeList.addListSelectionListener(this);
93  
94  		JPanel typePanel = new JPanel();
95  		typePanel.setLayout(new BorderLayout());
96  		typePanel.add("North", new JLabel("Types"));
97  		typePanel.add("Center", new JScrollPane(typeList,
98  				JScrollPane.VERTICAL_SCROLLBAR_AS_NEEDED,
99  				JScrollPane.HORIZONTAL_SCROLLBAR_AS_NEEDED));
100 		content.add(typePanel);
101 
102 		services = new DefaultListModel();
103 		serviceList = new JList(services);
104 		serviceList.setBorder(border);
105 		serviceList.setBackground(bg);
106 		serviceList.setSelectionMode(ListSelectionModel.SINGLE_SELECTION);
107 		serviceList.addListSelectionListener(this);
108 
109 		JPanel servicePanel = new JPanel();
110 		servicePanel.setLayout(new BorderLayout());
111 		servicePanel.add("North", new JLabel("Services"));
112 		servicePanel.add("Center", new JScrollPane(serviceList,
113 				JScrollPane.VERTICAL_SCROLLBAR_AS_NEEDED,
114 				JScrollPane.HORIZONTAL_SCROLLBAR_AS_NEEDED));
115 		content.add(servicePanel);
116 
117 		info = new JTextArea();
118 		info.setBorder(border);
119 		info.setBackground(bg);
120 		info.setEditable(false);
121 		info.setLineWrap(true);
122 
123 		JPanel infoPanel = new JPanel();
124 		infoPanel.setLayout(new BorderLayout());
125 		infoPanel.add("North", new JLabel("Details"));
126 		infoPanel.add("Center", new JScrollPane(info,
127 				JScrollPane.VERTICAL_SCROLLBAR_AS_NEEDED,
128 				JScrollPane.HORIZONTAL_SCROLLBAR_AS_NEEDED));
129 		content.add(infoPanel);
130 
131 		jmdns.addServiceTypeListener(this);
132 
133 		// register some well known types
134 		String list[] = new String[] { "_http._tcp.local.", "_ftp._tcp.local.",
135 				"_tftp._tcp.local.", "_ssh._tcp.local.", "_smb._tcp.local.",
136 				"_printer._tcp.local.", "_airport._tcp.local.",
137 				"_afpovertcp._tcp.local.", "_ichat._tcp.local.",
138 				"_eppc._tcp.local.", "_presence._tcp.local." };
139 
140 		for (int i = 0; i < list.length; i++) {
141 			jmdns.registerServiceType(list[i]);
142 		}
143 
144 		setVisible(true);
145 	}
146 
147 	/***
148 	 * Add a service.
149 	 */
150 	public void serviceAdded(ServiceEvent event) {
151 		final String name = event.getName();
152 
153 		if (logger.isLoggable(Level.CONFIG)) {
154 			logger.config("ADD: " + name); //$NON-NLS-1$
155 		}
156 		SwingUtilities.invokeLater(new Runnable() {
157 			public void run() {
158 				insertSorted(services, name);
159 			}
160 		});
161 	}
162 
163 	/***
164 	 * Remove a service.
165 	 */
166 	public void serviceRemoved(ServiceEvent event) {
167 		final String name = event.getName();
168 
169 		if (logger.isLoggable(Level.CONFIG)) {
170 			logger.config("REMOVE: " + name); //$NON-NLS-1$
171 		}
172 		SwingUtilities.invokeLater(new Runnable() {
173 			public void run() {
174 				services.removeElement(name);
175 			}
176 		});
177 	}
178 
179 	/***
180 	 * A new service type was <discovered.
181 	 */
182 	public void serviceTypeAdded(ServiceEvent event) {
183 		final String type = event.getType();
184 
185 		if (logger.isLoggable(Level.CONFIG)) {
186 			logger.config("TYPE: " + type); //$NON-NLS-1$
187 		}
188 		SwingUtilities.invokeLater(new Runnable() {
189 			public void run() {
190 				insertSorted(types, type);
191 			}
192 		});
193 	}
194 
195 	void insertSorted(DefaultListModel model, String value) {
196 		for (int i = 0, n = model.getSize(); i < n; i++) {
197 			if (value.compareToIgnoreCase((String) model.elementAt(i)) < 0) {
198 				model.insertElementAt(value, i);
199 				return;
200 			}
201 		}
202 		model.addElement(value);
203 	}
204 
205 	/***
206 	 * Resolve a service.
207 	 */
208 	@SuppressWarnings("unchecked")
209 	public void serviceResolved(ServiceEvent event) {
210 		String name = event.getName();
211 		String type = event.getType();
212 		ServiceInfo info = event.getInfo();
213 
214 		if (name.equals(serviceList.getSelectedValue())) {
215 			if (info == null) {
216 				this.info.setText("service not found");
217 			} else {
218 
219 				StringBuffer buf = new StringBuffer();
220 				buf.append(name);
221 				buf.append('.');
222 				buf.append(type);
223 				buf.append('\n');
224 				buf.append(info.getServer());
225 				buf.append(':');
226 				buf.append(info.getPort());
227 				buf.append('\n');
228 				buf.append(info.getAddress());
229 				buf.append(':');
230 				buf.append(info.getPort());
231 				buf.append('\n');
232 				for (Enumeration names = info.getPropertyNames(); names
233 						.hasMoreElements();) {
234 					String prop = (String) names.nextElement();
235 					buf.append(prop);
236 					buf.append('=');
237 					buf.append(info.getPropertyString(prop));
238 					buf.append('\n');
239 				}
240 
241 				this.info.setText(buf.toString());
242 			}
243 		}
244 	}
245 
246 	/***
247 	 * List selection changed.
248 	 */
249 	public void valueChanged(ListSelectionEvent e) {
250 		if (!e.getValueIsAdjusting()) {
251 			if (e.getSource() == typeList) {
252 				type = (String) typeList.getSelectedValue();
253 				jmdns.removeServiceListener(type, this);
254 				services.setSize(0);
255 				info.setText("");
256 				if (type != null) {
257 					jmdns.addServiceListener(type, this);
258 				}
259 			} else if (e.getSource() == serviceList) {
260 				String name = (String) serviceList.getSelectedValue();
261 				if (name == null) {
262 					info.setText("");
263 				} else {
264 					if (logger.isLoggable(Level.CONFIG)) {
265 						logger
266 								.config(this
267 										+ " valueChanged() type:" + type + " name:" + name); //$NON-NLS-1$ //$NON-NLS-2$
268 					}
269 					System.out.flush();
270 					ServiceInfo service = jmdns.getServiceInfo(type, name);
271 					if (service == null) {
272 						info.setText("service not found");
273 					} else {
274 						jmdns.requestServiceInfo(type, name);
275 					}
276 				}
277 			}
278 		}
279 	}
280 
281 	/***
282 	 * Table data.
283 	 */
284 	class ServiceTableModel extends AbstractTableModel {
285 		public String getColumnName(int column) {
286 			switch (column) {
287 			case 0:
288 				return "service";
289 			case 1:
290 				return "address";
291 			case 2:
292 				return "port";
293 			case 3:
294 				return "text";
295 			}
296 			return null;
297 		}
298 
299 		public int getColumnCount() {
300 			return 1;
301 		}
302 
303 		public int getRowCount() {
304 			return services.size();
305 		}
306 
307 		public Object getValueAt(int row, int col) {
308 			return services.elementAt(row);
309 		}
310 	}
311 
312 	/***
313 	 * Main program.
314 	 */
315 	public static void main(String argv[]) throws IOException {
316 		JFrame browserFrame = new JFrame("JmDNS Browser");
317 		
318 		JPanel browser = new JmdnsBrowser(new JmDNS());
319 		
320 		browserFrame.getContentPane().add(browser);
321 		browserFrame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
322 		browserFrame.setLocation(100, 100);
323 		browserFrame.setSize(600, 400);
324 		browserFrame.setVisible(true);
325 	}
326 }