Source code: net/jxta/ext/config/Util.java
1 /*
2 * Copyright (c) 2001 Sun Microsystems, Inc. All rights
3 * reserved.
4 *
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions
7 * are met:
8 *
9 * 1. Redistributions of source code must retain the above copyright
10 * notice, this list of conditions and the following disclaimer.
11 *
12 * 2. Redistributions in binary form must reproduce the above copyright
13 * notice, this list of conditions and the following disclaimer in
14 * the documentation and/or other materials provided with the
15 * distribution.
16 *
17 * 3. The end-user documentation included with the redistribution,
18 * if any, must include the following acknowledgment:
19 * "This product includes software developed by the
20 * Sun Microsystems, Inc. for Project JXTA."
21 * Alternately, this acknowledgment may appear in the software itself,
22 * if and wherever such third-party acknowledgments normally appear.
23 *
24 * 4. The names "Sun", "Sun Microsystems, Inc.", "JXTA" and "Project JXTA"
25 * must not be used to endorse or promote products derived from this
26 * software without prior written permission. For written
27 * permission, please contact Project JXTA at http://www.jxta.org.
28 *
29 * 5. Products derived from this software may not be called "JXTA",
30 * nor may "JXTA" appear in their name, without prior written
31 * permission of Sun.
32 *
33 * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED
34 * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
35 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
36 * DISCLAIMED. IN NO EVENT SHALL THE APACHE SOFTWARE FOUNDATION OR
37 * ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
38 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
39 * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
40 * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
41 * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
42 * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
43 * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
44 * SUCH DAMAGE.
45 * ====================================================================
46 *
47 * This software consists of voluntary contributions made by many
48 * individuals on behalf of Project JXTA. For more
49 * information on Project JXTA, please see
50 * <http://www.jxta.org/>.
51 *
52 * This license is based on the BSD license adopted by the Apache Foundation.
53 *
54 * $Id: Util.java,v 1.19 2004/11/30 22:42:11 gonzo Exp $
55 */
56 package net.jxta.ext.config;
57
58 import java.io.IOException;
59 import java.net.BindException;
60 import java.net.InetAddress;
61 import java.net.ServerSocket;
62 import java.net.UnknownHostException;
63 import java.net.URI;
64 import java.net.URISyntaxException;
65 import java.util.Iterator;
66
67 import java.io.File;
68 import java.io.FileNotFoundException;
69 import java.io.FileReader;
70
71 import org.apache.log4j.Level;
72 import org.apache.log4j.Logger;
73
74 /**
75 * Description of the Class
76 *
77 * @author james todd [gonzo at jxta dot org]
78 * @version $Id: Util.java,v 1.19 2004/11/30 22:42:11 gonzo Exp $
79 */
80
81 public class Util {
82
83 private final static String MACRO_PREFIX = "${";
84 private final static String MACRO_POSTFIX = "}";
85 private final static String MACRO_ESCAPE = "\\";
86 private final static String NEW_LINE = "\n";
87 private final static String EMPTY_STRING = "";
88 private final static Logger LOG = Logger.getLogger(Util.class.getName());
89
90
91 /**
92 * Description of the Method
93 *
94 * @param s Description of the Parameter
95 * @return Description of the Return Value
96 */
97 public static String expand(String s) {
98 StringBuffer sb = null;
99
100 if (s != null) {
101 sb = new StringBuffer(s);
102 int i = -1;
103 int j = -1;
104
105 while ((i = sb.indexOf(MACRO_PREFIX)) > -1 &&
106 (i - MACRO_ESCAPE.length() < 0 ||
107 (i - MACRO_ESCAPE.length() >= 0 &&
108 !sb.substring(i - MACRO_ESCAPE.length(), i).equals(MACRO_ESCAPE))) &&
109 (j = sb.indexOf(MACRO_POSTFIX, i + MACRO_PREFIX.length())) > -1) {
110 String p = expand(sb.substring(i + MACRO_PREFIX.length(), j));
111
112 sb.replace(i, j + MACRO_POSTFIX.length(), System.getProperty(p, ""));
113 }
114 }
115
116 return sb != null ? sb.toString() : null;
117 }
118
119
120 /**
121 * Gets the local address.
122 *
123 * @return The local address
124 */
125 public static String getLocalHost() {
126 String s = null;
127
128 try {
129 s = InetAddress.getLocalHost().getHostAddress();
130 } catch (UnknownHostException uhe) {
131 if (LOG.isEnabledFor(Level.ERROR)) {
132 LOG.error("can't resolve local host", uhe);
133 }
134 }
135
136 return s;
137 }
138
139 /**
140 * Description of the Method
141 *
142 * @param address Description of the Parameter
143 * @return Description of the Return Value
144 */
145 public static String validateAddress(URI address) {
146 return validateAddress(address, (boolean)true);
147 }
148
149 public static String validateAddress(URI address, int minimumPort) {
150 return validateAddress(address, (String)null, minimumPort);
151 }
152
153 /**
154 * Description of the Method
155 *
156 * @param address Description of the Parameter
157 * @param requireHost Description of the Parameter
158 * @return Description of the Return Value
159 */
160 public static String validateAddress(URI address, boolean requireHost) {
161 return validateAddress(address, (String)null, requireHost);
162 }
163
164
165 /**
166 * Validate address against the provided scheme.
167 *
168 * @param address Description of the Parameter
169 * @param scheme scheme
170 * @return Validation state
171 */
172 public static String validateAddress(URI address, String scheme) {
173 return validateAddress(address, scheme, (boolean)false);
174 }
175
176
177 /**
178 * Validate address against the provided scheme and host requirement.
179 *
180 * @param address addresss
181 * @param scheme scheme
182 * @param requireHost Description of the Parameter
183 * @return Validation state
184 */
185 public static String validateAddress(URI address, String scheme, boolean requireHost) {
186 return validateAddress(address, scheme, requireHost, Default.MINIMUM_DYNAMIC_PORT);
187 }
188
189
190 /**
191 * Validate address against the provided scheme and host requirement.
192 *
193 * @param address addresss
194 * @param scheme scheme
195 * @param minimumPort minimum port
196 * @return Validation state
197 */
198 public static String validateAddress(URI address, String scheme, int minimumPort) {
199 return validateAddress(address, scheme, (boolean)false, minimumPort);
200 }
201
202
203 /**
204 * Validate address against the provided scheme and host requirement.
205 *
206 * @param address addresss
207 * @param scheme scheme
208 * @param requireHost Description of the Parameter
209 * @param minimumPort minimum port
210 * @return Validation state
211 */
212 public static String validateAddress(URI address, String scheme, boolean requireHost,
213 int minimumPort) {
214 StringBuffer b = new StringBuffer();
215
216 if (address != null) {
217 if (scheme != null &&
218 !address.getScheme().equalsIgnoreCase(scheme)) {
219 b.append((b.length() > 0 ? NEW_LINE : EMPTY_STRING) + "invalid scheme: " +
220 scheme);
221 }
222
223 if (requireHost) {
224 String h = address.getHost();
225
226 if (h == null ||
227 h.trim().length() == 0) {
228 b.append((b.length() > 0 ? NEW_LINE : EMPTY_STRING) + "invalid host: " + h);
229 }
230
231 // xxx: don't validate the adress for now.
232 // it would be nice to validate fqn addresses (eg www.jxta.org) and ip addresses
233 // (eg 123.123.123.123) alike without requiring resolution.
234 /*
235 if (h != null &&
236 Protocol.isValid(address.getScheme())) {
237 InetAddress ia = null;
238
239 try {
240 ia = InetAddress.getByName(h);
241 } catch (UnknownHostException uhe) {
242 if (LOG.isEnabledFor(Level.ERROR)) {
243 LOG.error("invalid address", uhe);
244 }
245 }
246
247 if (ia == null) {
248 b.append((b.length() > 0 ? NEW_LINE : EMPTY_STRING) + "invalid host: " + h);
249 }
250 }
251 */
252
253 if (address.getPort() < minimumPort ||
254 address.getPort() > Default.MAXIMUM_PORT) {
255 b.append((b.length() > 0 ? NEW_LINE : EMPTY_STRING) + "invalid port: " + address.getPort());
256 }
257 }
258 } else {
259 b.append((b.length() > 0 ? NEW_LINE : EMPTY_STRING) + "null address");
260 }
261
262 return b.toString();
263 }
264
265
266 /**
267 * Description of the Method
268 *
269 * @param address Description of the Parameter
270 * @return Description of the Return Value
271 */
272 public static URI normalize(Address address) {
273 return normalize(address, true);
274 }
275
276 /**
277 * Description of the Method
278 *
279 * @param address Description of the Parameter
280 * @param portScan port scan
281 * @return Description of the Return Value
282 */
283
284 public static URI normalize(Address address, boolean portScan) {
285 URI u = address != null ? address.getAddress() : null;
286
287 return normalize(address, portScan,
288 model(u != null ? u.getScheme() : null));
289 }
290
291 /**
292 * Address normalizer.
293 *
294 * @param address base address
295 * @param portScan port scan
296 * @param model model address
297 * @return Resultant address
298 */
299 public static URI normalize(Address address, boolean portScan, URI model) {
300 URI u = address != null ? address.getAddress() : null;
301
302 if (u != null) {
303 String s = u.getScheme();
304 String h = u.getHost();
305 int p = u.getPort();
306
307 if (model != null) {
308 if (s == null ||
309 s.trim().length() == 0) {
310 s = model.getScheme();
311 }
312
313 if (h == null ||
314 h.trim().length() == 0) {
315 h = model.getHost();
316 }
317
318 if (p == Default.INVALID_PORT) {
319 p = model.getPort();
320 }
321 }
322
323 try {
324 address.setAddress(new URI(u.getScheme(), u.getUserInfo(),
325 h, p, u.getPath(), u.getQuery(),
326 u.getFragment()));
327
328 u = new URI(u.getScheme(), u.getUserInfo(), h,
329 portScan ? getNextAvailablePort(address, p) : p,
330 u.getPath(), u.getQuery(), u.getFragment());
331 } catch (URISyntaxException use) {
332 if (LOG.isEnabledFor(Level.ERROR)) {
333 LOG.error("invalid transformation", use);
334 }
335 }
336 }
337
338 return u;
339 }
340
341
342 /**
343 * Description of the Method
344 *
345 * @param scheme Description of the Parameter
346 * @param host Description of the Parameter
347 * @param port Description of the Parameter
348 * @return Description of the Return Value
349 */
350 public static URI toURI(String scheme, String host, int port) {
351 URI u = null;
352
353 try {
354 u = new URI(scheme, EMPTY_STRING,
355 host == null || host.trim().length() == 0 ? getLocalHost() : host,
356 port, EMPTY_STRING, EMPTY_STRING, EMPTY_STRING);
357 } catch (URISyntaxException use) {
358 if (LOG.isEnabledFor(Level.ERROR)) {
359 LOG.error("invalid transformation", use);
360 }
361 }
362
363 return u;
364 }
365
366
367 /**
368 * Description of the Method
369 *
370 * @param scheme Description of the Parameter
371 * @return Description of the Return Value
372 */
373 public static URI model(String scheme) {
374 return model(scheme, Default.INVALID_PORT);
375 }
376
377 public static URI model(String scheme, int port) {
378 URI u = null;
379
380 if (Protocol.TCP.equalsIgnoreCase(scheme)) {
381 u = toURI(Default.ANY_TCP_ADDRESS.getScheme(), null,
382 port != Default.INVALID_PORT ?
383 port : Default.TCP_PORT);
384 } else if (Protocol.HTTP.equalsIgnoreCase(scheme)) {
385 u = toURI(Default.ANY_HTTP_ADDRESS.getScheme(), null,
386 port != Default.INVALID_PORT ?
387 port : Default.HTTP_PORT);
388 } else if (Protocol.UDP.equalsIgnoreCase(scheme)) {
389 u = toURI(Default.ANY_UDP_ADDRESS.getScheme(),
390 Default.MULTICAST_ADDRESS.getHost(),
391 port != Default.INVALID_PORT ?
392 port : Default.MULTICAST_PORT);
393 }
394
395 return u;
396 }
397
398 /**
399 * Checks for the specified port availability.
400 *
401 * @param address target system address
402 * @param port target port
403 * @return The availability indicator
404 */
405 public static boolean isPortAvailable(InetAddress address, int port) {
406 ServerSocket ss = getServerSocket(address, port);
407 boolean isAvailable = ss != null;
408
409 if (ss != null) {
410 try {
411 ss.close();
412 } catch (IOException ioe) {}
413 }
414
415 ss = null;
416
417 return isAvailable;
418 }
419
420 public static ServerSocket getServerSocket(InetAddress address, int port) {
421 ServerSocket ss = null;
422
423 try {
424 ss = new ServerSocket(port, 0,
425 address != null &&
426 ! address.getHostAddress().equals(Env.ALL_ADDRESSES.getHostAddress()) ?
427 address : null);
428 } catch (BindException be) {}
429 catch (IOException ioe) {}
430
431 return ss;
432 }
433
434 public static String getProxyFromUserAgent() {
435 String p = null;
436
437 return p;
438 }
439
440 public static boolean isNonRoutable(URI u) {
441 boolean isNonRoutable = false;
442 String a = u != null ? u.getHost() : null;
443
444 if (a != null) {
445 for (Iterator r = Env.NON_ROUTABLE_ADDRESSES.iterator();
446 ! isNonRoutable && r.hasNext(); ) {
447 if (a.startsWith((String)r.next())) {
448 isNonRoutable = true;
449 }
450 }
451 }
452
453 return isNonRoutable;
454 }
455
456 public static boolean isMulticast(URI u) {
457 String h = u != null ? u.getHost() : null;
458 InetAddress ia = null;
459
460 if (h != null) {
461 try {
462 ia = InetAddress.getByAddress(h, inetAddressToBytes(h));
463 } catch (UnknownHostException uhe) {
464 if (LOG.isEnabledFor(Level.ERROR)) {
465 LOG.error("invalid address", uhe);
466 }
467 }
468 }
469
470 return ia != null ? ia.isMulticastAddress() : false;
471 }
472
473 public static byte[] inetAddressToBytes(String ipAddr) {
474 byte[] bytes = new byte[4];
475 int bit = 0;
476
477 for(int i = 0; i < ipAddr.length(); i++) {
478 char c = ipAddr.charAt(i);
479
480 switch(c) {
481 case '.':
482 bit++;
483 break;
484 default:
485 bytes[bit] = (byte)(bytes[bit]*10 + Character.digit(c, 10));
486 break;
487 }
488 }
489
490 return bytes;
491 }
492
493 /**
494 * Gets the nextAvailablePort attribute of the Configurator object
495 *
496 * @param a Description of the Parameter
497 * @param defaultPort Description of the Parameter
498 * @return The nextAvailablePort value
499 */
500 private static int getNextAvailablePort(Address a, int defaultPort) {
501 URI u = a != null ? a.getAddress() : null;
502 String h = u != null ? u.getHost() : null;
503 int p = u != null ? u.getPort() : Default.INVALID_PORT;
504 int port = p != Default.INVALID_PORT ? p : defaultPort;
505 int pr = a != null ? a.getPortRange() : Default.PORT_RANGE;
506 InetAddress ia = null;
507
508 if (h != null) {
509 try {
510 ia = InetAddress.getByAddress(h, inetAddressToBytes(h));
511 } catch (UnknownHostException uhe) {
512 if (LOG.isEnabledFor(Level.ERROR)) {
513 LOG.error("invalid address", uhe);
514 }
515 }
516
517 if (ia != null &&
518 p != Default.INVALID_PORT) {
519 for (int i = p; i <= p + pr; i++) {
520 if (isPortAvailable(ia, i)) {
521 port = i;
522
523 break;
524 }
525 }
526 }
527 }
528
529 return port;
530 }
531 }