2 * Copyright (c) 2001-2007 Sun Microsystems, Inc. All rights reserved.
4 * The Sun Project JXTA(TM) Software License
6 * Redistribution and use in source and binary forms, with or without
7 * modification, are permitted provided that the following conditions are met:
9 * 1. Redistributions of source code must retain the above copyright notice,
10 * this list of conditions and the following disclaimer.
12 * 2. Redistributions in binary form must reproduce the above copyright notice,
13 * this list of conditions and the following disclaimer in the documentation
14 * and/or other materials provided with the distribution.
16 * 3. The end-user documentation included with the redistribution, if any, must
17 * include the following acknowledgment: "This product includes software
18 * developed by Sun Microsystems, Inc. for JXTA(TM) technology."
19 * Alternately, this acknowledgment may appear in the software itself, if
20 * and wherever such third-party acknowledgments normally appear.
22 * 4. The names "Sun", "Sun Microsystems, Inc.", "JXTA" and "Project JXTA" must
23 * not be used to endorse or promote products derived from this software
24 * without prior written permission. For written permission, please contact
25 * Project JXTA at http://www.jxta.org.
27 * 5. Products derived from this software may not be called "JXTA", nor may
28 * "JXTA" appear in their name, without prior written permission of Sun.
30 * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED WARRANTIES,
31 * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
32 * FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL SUN
33 * MICROSYSTEMS OR ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
34 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
35 * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA,
36 * OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
37 * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
38 * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE,
39 * EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
41 * JXTA is a registered trademark of Sun Microsystems, Inc. in the United
42 * States and other countries.
44 * Please see the license information page at :
45 * <http://www.jxta.org/project/www/license.html> for instructions on use of
46 * the license in source files.
48 * ====================================================================
50 * This software consists of voluntary contributions made by many individuals
51 * on behalf of Project JXTA. For more information on Project JXTA, please see
52 * http://www.jxta.org.
54 * This license is based on the BSD license adopted by the Apache Foundation.
57 package net.jxta.impl.peergroup;
60 import java.net.InetAddress;
62 import java.util.Enumeration;
63 import java.util.Iterator;
65 import java.util.logging.Level;
66 import net.jxta.logging.Logging;
67 import java.util.logging.Logger;
69 import net.jxta.document.AdvertisementFactory;
70 import net.jxta.document.MimeMediaType;
71 import net.jxta.document.StructuredDocumentFactory;
72 import net.jxta.document.StructuredDocumentUtils;
73 import net.jxta.document.XMLDocument;
74 import net.jxta.document.XMLElement;
75 import net.jxta.peergroup.PeerGroup;
76 import net.jxta.protocol.TransportAdvertisement;
78 import net.jxta.exception.ConfiguratorException;
80 import net.jxta.impl.endpoint.IPUtils;
81 import net.jxta.impl.protocol.HTTPAdv;
82 import net.jxta.impl.protocol.PlatformConfig;
83 import net.jxta.impl.protocol.PSEConfigAdv;
84 import net.jxta.impl.protocol.RdvConfigAdv;
85 import net.jxta.impl.protocol.RelayConfigAdv;
86 import net.jxta.impl.protocol.TCPAdv;
90 * A simple platform configurator. This implementation provides reasonable
91 * automatic configuration for edge peers on the JXTA public network.
93 * This implementation will read default values from several Java system
94 * properties as appropriate:
96 * jxta.peer.name -- The peer name to use.
97 * jxta.http.port -- The http port to use.
98 * jxta.tcp.port -- The tcp port to use.
100 * @see net.jxta.peergroup.Configurator
102 public class AutomaticConfigurator extends NullConfigurator {
107 private final static transient Logger LOG = Logger.getLogger(AutomaticConfigurator.class.getName());
110 * Configures the platform using the specified directory.
111 * @param jxtaHome store home URI
112 * @throws net.jxta.exception.ConfiguratorException if a configuration error occurs
114 public AutomaticConfigurator(URI jxtaHome) throws ConfiguratorException {
122 public PlatformConfig getPlatformConfig() throws ConfiguratorException {
123 super.getPlatformConfig();
128 reconf = buildPlatformConfig();
129 } catch (RuntimeException serious) {
130 if (Logging.SHOW_SEVERE && LOG.isLoggable(Level.SEVERE)) {
131 LOG.log(Level.SEVERE, "Trouble while fixing PlatformConfig. Hope for the best.", serious);
137 // See if we need a reconf
139 throw new IncompleteConfigurationException("Damaged platform configuration.");
142 // Save the updated config.
145 return advertisement;
149 * Makes sure a PlatformConfig is present and if not, creates one.
151 * Performs some checking of PlatformConfig values and will fix some
152 * minor configuration problems automatically.
154 * @return If <tt>true</tt> then manual reconfiguration (of some form) is required.
156 private boolean buildPlatformConfig() {
158 boolean reconf = false;
160 if (advertisement == null) {
161 if (Logging.SHOW_CONFIG && LOG.isLoggable(Level.CONFIG)) {
162 LOG.config("New PlatformConfig Advertisement");
164 advertisement = (PlatformConfig) AdvertisementFactory.newAdvertisement(PlatformConfig.getAdvertisementType());
165 advertisement.setDescription("Platform Config Advertisement created by : " + AutomaticConfigurator.class.getName());
169 String peerName = advertisement.getName();
171 if ((null == peerName) || (0 == peerName.trim().length())) {
172 String jpn = System.getProperty("jxta.peer.name", "");
174 if (0 != jpn.trim().length()) {
175 advertisement.setName(jpn);
179 // Check the HTTP Message Transport parameters.
180 XMLDocument http = (XMLDocument) advertisement.getServiceParam(PeerGroup.httpProtoClassID);
181 HTTPAdv httpAdv = null;
182 boolean httpEnabled = true;
186 httpEnabled = advertisement.isSvcEnabled(PeerGroup.httpProtoClassID);
188 XMLElement param = null;
190 Enumeration httpChilds = http.getChildren(TransportAdvertisement.getAdvertisementType());
192 // get the HTTPAdv from TransportAdv
193 if (httpChilds.hasMoreElements()) {
194 param = (XMLElement) httpChilds.nextElement();
198 httpAdv = (HTTPAdv) AdvertisementFactory.newAdvertisement(param);
201 // check if the interface address is still valid.
202 String intf = httpAdv.getInterfaceAddress();
204 if ((null != intf) && !isValidInetAddress(intf)) {
207 if (Logging.SHOW_CONFIG && LOG.isLoggable(Level.CONFIG)) {
208 LOG.config("Reconfig requested - invalid interface address");
213 } catch (RuntimeException advTrouble) {
214 if (Logging.SHOW_WARNING && LOG.isLoggable(Level.WARNING)) {
215 LOG.log(Level.WARNING, "HTTP advertisement corrupted", advTrouble);
222 if (httpAdv == null) {
223 if (Logging.SHOW_CONFIG && LOG.isLoggable(Level.CONFIG)) {
224 LOG.config("HTTP advertisement missing, making a new one.");
228 // get the port from a property
229 String httpPort = System.getProperty("jxta.http.port");
231 if (httpPort != null) {
233 int propertyPort = Integer.parseInt(httpPort);
235 if ((propertyPort < 65536) && (propertyPort >= 0)) {
238 if (Logging.SHOW_WARNING && LOG.isLoggable(Level.WARNING)) {
239 LOG.warning("Property \'jxta.http.port\' is not a valid port number : " + propertyPort);
242 } catch (NumberFormatException ignored) {
243 if (Logging.SHOW_WARNING && LOG.isLoggable(Level.WARNING)) {
244 LOG.warning("Property \'jxta.http.port\' was not an integer : " + http);
249 httpAdv = (HTTPAdv) AdvertisementFactory.newAdvertisement(HTTPAdv.getAdvertisementType());
250 httpAdv.setProtocol("http");
251 httpAdv.setPort(port);
252 httpAdv.setServerEnabled(false);
255 // Create new param docs that contain the updated adv
256 http = (XMLDocument) StructuredDocumentFactory.newStructuredDocument(MimeMediaType.XMLUTF8, "Parm");
257 XMLDocument httAdvDoc = (XMLDocument) httpAdv.getDocument(MimeMediaType.XMLUTF8);
259 StructuredDocumentUtils.copyElements(http, http, httAdvDoc);
261 http.appendChild(http.createElement("isOff"));
263 advertisement.putServiceParam(PeerGroup.httpProtoClassID, http);
265 // Check the TCP Message Transport parameters.
266 XMLDocument tcp = (XMLDocument) advertisement.getServiceParam(PeerGroup.tcpProtoClassID);
267 TCPAdv tcpAdv = null;
268 boolean tcpEnabled = true;
272 tcpEnabled = advertisement.isSvcEnabled(PeerGroup.tcpProtoClassID);
274 XMLElement param = null;
276 Enumeration tcpChilds = tcp.getChildren(TransportAdvertisement.getAdvertisementType());
278 // get the TransportAdv
279 if (tcpChilds.hasMoreElements()) {
280 param = (XMLElement) tcpChilds.nextElement();
284 tcpAdv = (TCPAdv) AdvertisementFactory.newAdvertisement(param);
287 String intf = tcpAdv.getInterfaceAddress();
289 if ((null != intf) && !isValidInetAddress(intf)) {
292 if (Logging.SHOW_CONFIG && LOG.isLoggable(Level.CONFIG)) {
293 LOG.config("Reconfig requested - invalid interface address");
298 } catch (RuntimeException advTrouble) {
299 if (Logging.SHOW_WARNING && LOG.isLoggable(Level.WARNING)) {
300 LOG.log(Level.WARNING, "TCP advertisement corrupted", advTrouble);
307 if (tcpAdv == null) {
308 if (Logging.SHOW_CONFIG && LOG.isLoggable(Level.CONFIG)) {
309 LOG.config("TCP advertisement missing, making a new one.");
313 // get the port from a property
314 String tcpPort = System.getProperty("jxta.tcp.port");
316 if (tcpPort != null) {
318 int propertyPort = Integer.parseInt(tcpPort);
320 if ((propertyPort < 65536) && (propertyPort >= 0)) {
323 if (Logging.SHOW_WARNING && LOG.isLoggable(Level.WARNING)) {
324 LOG.warning("Property \'jxta.tcp.port\' is not a valid port number : " + propertyPort);
327 } catch (NumberFormatException ignored) {
328 if (Logging.SHOW_WARNING && LOG.isLoggable(Level.WARNING)) {
329 LOG.warning("Property \'jxta.tcp.port\' was not an integer : " + tcpPort);
334 tcpAdv = (TCPAdv) AdvertisementFactory.newAdvertisement(TCPAdv.getAdvertisementType());
336 tcpAdv.setProtocol("tcp");
337 tcpAdv.setPort(port);
338 tcpAdv.setMulticastAddr("224.0.1.85");
339 tcpAdv.setMulticastPort(1234);
340 tcpAdv.setMulticastSize(16384);
341 tcpAdv.setMulticastState(true);
344 tcp = (XMLDocument) StructuredDocumentFactory.newStructuredDocument(MimeMediaType.XMLUTF8, "Parm");
346 StructuredDocumentUtils.copyElements(tcp, tcp, (XMLDocument) tcpAdv.getDocument(MimeMediaType.XMLUTF8));
348 tcp.appendChild(tcp.createElement("isOff"));
350 advertisement.putServiceParam(PeerGroup.tcpProtoClassID, tcp);
352 // Check the relay config
353 RelayConfigAdv relayConfig = null;
356 XMLElement param = (XMLElement) advertisement.getServiceParam(PeerGroup.relayProtoClassID);
359 // XXX 20041027 backwards compatibility
360 param.addAttribute("type", RelayConfigAdv.getAdvertisementType());
362 relayConfig = (RelayConfigAdv) AdvertisementFactory.newAdvertisement(param);
364 } catch (Exception failure) {
365 if (Logging.SHOW_WARNING && LOG.isLoggable(Level.WARNING)) {
366 LOG.log(Level.WARNING, "Problem reading relay configuration", failure);
370 if (null == relayConfig) {
371 if (Logging.SHOW_CONFIG && LOG.isLoggable(Level.CONFIG)) {
372 LOG.config("Relay Config advertisement missing, making a new one.");
375 // restore default values.
376 relayConfig = (RelayConfigAdv) AdvertisementFactory.newAdvertisement(RelayConfigAdv.getAdvertisementType());
378 // Enable relay if any transport doesn't support incoming.
379 if (!tcpAdv.isServerEnabled() || !httpAdv.isServerEnabled()) {
380 relayConfig.setClientEnabled(true);
385 if( (0 == relayConfig.getSeedingURIs().length) && (0 == relayConfig.getSeedRelays().length) && !relayConfig.isServerEnabled() ) {
386 // add the default relay seeding peer.
387 relayConfig.addSeedingURI( "http://rdv.jxtahosts.net/cgi-bin/relays.cgi?3" );
391 XMLDocument relayDoc = (XMLDocument) relayConfig.getDocument(MimeMediaType.XMLUTF8);
393 advertisement.putServiceParam(PeerGroup.relayProtoClassID, relayDoc);
395 // Check Rendezvous Configuration
396 RdvConfigAdv rdvAdv = null;
399 XMLElement param = (XMLElement) advertisement.getServiceParam(PeerGroup.rendezvousClassID);
402 // XXX 20041027 backwards compatibility
403 param.addAttribute("type", RdvConfigAdv.getAdvertisementType());
405 rdvAdv = (RdvConfigAdv) AdvertisementFactory.newAdvertisement(param);
407 } catch (Exception failure) {
408 if (Logging.SHOW_WARNING && LOG.isLoggable(Level.WARNING)) {
409 LOG.log(Level.WARNING, "Problem reading rendezvous configuration", failure);
413 if (null == rdvAdv) {
414 if (Logging.SHOW_CONFIG && LOG.isLoggable(Level.CONFIG)) {
415 LOG.config("Rdv Config advertisement missing, making a new one.");
418 // restore default values.
419 rdvAdv = (RdvConfigAdv) AdvertisementFactory.newAdvertisement(RdvConfigAdv.getAdvertisementType());
423 if( (0 == rdvAdv.getSeedingURIs().length) &&
424 (0 == rdvAdv.getSeedRendezvous().length) &&
425 (RdvConfigAdv.RendezVousConfiguration.RENDEZVOUS != rdvAdv.getConfiguration()) &&
426 (RdvConfigAdv.RendezVousConfiguration.AD_HOC != rdvAdv.getConfiguration()) &&
427 !relayConfig.isClientEnabled() ) {
428 // add the default rendezvous seeding peer if we don't know of any rendezvous, aren't a rendezvous ourselves, aren't in ad-hoc mode or using a relay.
429 rdvAdv.addSeedingURI( "http://rdv.jxtahosts.net/cgi-bin/rendezvous.cgi?3" );
432 XMLDocument rdvDoc = (XMLDocument) rdvAdv.getDocument(MimeMediaType.XMLUTF8);
434 advertisement.putServiceParam(PeerGroup.rendezvousClassID, rdvDoc);
436 // if no proxy param section, disable it.
437 XMLDocument proxy = (XMLDocument) advertisement.getServiceParam(PeerGroup.proxyClassID);
440 if (Logging.SHOW_CONFIG && LOG.isLoggable(Level.CONFIG)) {
441 LOG.config("Proxy config advertisement missing, making a new one.");
444 proxy = (XMLDocument) StructuredDocumentFactory.newStructuredDocument(MimeMediaType.XMLUTF8, "Parm");
445 proxy.appendChild(proxy.createElement("isOff"));
446 advertisement.putServiceParam(PeerGroup.proxyClassID, proxy);
449 // Check the PSE Configuration
450 PSEConfigAdv pseConfig = null;
453 XMLElement param = (XMLElement) advertisement.getServiceParam(PeerGroup.membershipClassID);
456 // XXX 20041027 backwards compatibility
457 param.addAttribute("type", PSEConfigAdv.getAdvertisementType());
459 pseConfig = (PSEConfigAdv) AdvertisementFactory.newAdvertisement(param);
461 } catch (Exception failure) {
462 if (Logging.SHOW_WARNING && LOG.isLoggable(Level.WARNING)) {
463 LOG.log(Level.WARNING, "Problem reading pse configuration", failure);
467 if (null == pseConfig) {
468 if (Logging.SHOW_CONFIG && LOG.isLoggable(Level.CONFIG)) {
469 LOG.config("PSE Config advertisement missing, making a new one.");
472 // restore default values.
473 pseConfig = (PSEConfigAdv) AdvertisementFactory.newAdvertisement(PSEConfigAdv.getAdvertisementType());
474 XMLDocument pseDoc = (XMLDocument) pseConfig.getDocument(MimeMediaType.XMLUTF8);
476 advertisement.putServiceParam(PeerGroup.membershipClassID, pseDoc);
479 // If we did not modify anything of importance or see anything wrong,
480 // leave the adv alone.
485 private boolean isValidInetAddress(String address) {
486 boolean found = false;
492 ias = InetAddress.getAllByName(address);
493 } catch (java.net.UnknownHostException notfound) {
497 for (Iterator la = IPUtils.getAllLocalAddresses(); la.hasNext() && !found;) {
498 for (InetAddress ia1 : ias) {
499 found |= ia1.equals(la.next());
505 for (InetAddress ia1 : ias) {
506 loopback &= ia1.isLoopbackAddress();
509 return found || loopback;