2 * Copyright (c) 2006-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.platform;
60 import javax.security.cert.CertificateException;
62 import java.io.IOException;
64 import java.util.logging.Level;
65 import java.util.logging.Logger;
67 import net.jxta.credential.AuthenticationCredential;
68 import net.jxta.credential.Credential;
69 import net.jxta.exception.PeerGroupException;
70 import net.jxta.exception.ProtocolNotSupportedException;
71 import net.jxta.id.IDFactory;
72 import net.jxta.logging.Logging;
73 import net.jxta.membership.InteractiveAuthenticator;
74 import net.jxta.membership.MembershipService;
75 import net.jxta.peer.PeerID;
76 import net.jxta.peergroup.NetPeerGroupFactory;
77 import net.jxta.peergroup.PeerGroup;
78 import net.jxta.peergroup.PeerGroupID;
79 import net.jxta.rendezvous.RendezVousService;
80 import net.jxta.rendezvous.RendezvousEvent;
81 import net.jxta.rendezvous.RendezvousListener;
83 import net.jxta.impl.membership.pse.StringAuthenticator;
87 * NetworkManager provides a simplified JXTA platform configuration abstraction, and provides a JXTA platform life-cycle
88 * management. The node configuration is created during construction of this object and can be obtained for fine tuning
89 * or alteration. Note that all alterations must be done prior to calling #startNetwork(), otherwise the default
90 * configuration is used. Configuration persistence is on by default and maybe overridden by call to #setEnableConfigPersistence
92 * NetworkManager defines six abstractions of a node configurations as follows :
93 * ADHOC : A node which typically deployed in an ad-hoc network
94 * EDGE : In addition to supporting ADHOC function, an Edge node can attach to a infrastructure (a Rendezvous, Relay, or both)
95 * RENDEZVOUS: provides network bootstrapping services, such as discovery, pipe resolution, etc.
96 * RELAY: provides message relaying services, enabling cross firewall traversal
97 * PROXY: provide JXME JXTA for J2ME proxying services
98 * SUPER: provide the functionality of a Rendezvous, Relay, Proxy node.
100 public class NetworkManager implements RendezvousListener {
105 private final static transient Logger LOG = Logger.getLogger(NetworkManager.class.getName());
107 protected final transient URI publicSeedingRdvURI = URI.create("http://rdv.jxtahosts.net/cgi-bin/rendezvous.cgi?3");
108 protected final transient URI publicSeedingRelayURI = URI.create("http://rdv.jxtahosts.net/cgi-bin/relays.cgi?3");
111 * Define node standard node operating modes
113 public enum ConfigMode {
132 * Rendezvous and a Relay
140 * A Rendezvous, Relay, and JXME Proxy node
145 private final Object networkConnectLock = new String("rendezvous connection lock");
146 private PeerGroup netPeerGroup = null;
147 private volatile boolean started = false;
148 private volatile boolean connected = false;
149 private volatile boolean stopped = false;
150 private RendezVousService rendezvous;
151 private String instanceName = "NA";
152 private ShutdownHook shutdownHook;
153 private ConfigMode mode;
154 private URI instanceHome;
155 private PeerGroupID infrastructureID = PeerGroupID.defaultNetPeerGroupID;
156 private PeerID peerID = IDFactory.newPeerID(PeerGroupID.defaultNetPeerGroupID);
157 private NetworkConfigurator config;
158 private boolean configPersistent = true;
159 private boolean useDefaultSeeds;
162 * Creates NetworkManger instance with default instance home set to "$CWD"/.jxta"
163 * At this point, alternate Infrastructure PeerGroupID maybe specified, as well as a PeerID. if neither are
164 * specified, the default NetPeerGroupID will be used, and a new PeerID will be generated. Also note the default
165 * seeding URIs are the to development. Alternate values must be specified, if desired, prior to a call to {@link #startNetwork}
167 * @param mode Operating mode the node operating {@link ConfigMode}
168 * @param instanceName Node name
169 * @throws IOException if an io error occurs
171 public NetworkManager(ConfigMode mode, String instanceName) throws IOException {
172 this(mode, instanceName, new File(".jxta/").toURI());
176 * Creates NetworkManger instance.
177 * At this point, alternate Infrastructure PeerGroupID maybe specified, as well as a PeerID. if neither are
178 * specified, the default NetPeerGroupID will be used, and a new PeerID will be generated. Also note the default
179 * seeding URIs are the to development. Alternate values must be specified, if desired, prior to a call to {@link #startNetwork}
181 * @param mode Operating mode the node operating {@link ConfigMode}
182 * @param instanceName Node name
183 * @param instanceHome instance home is a uri to the instance persistent store (aka Cache Manager store home)
184 * @throws IOException if an io error occurs
186 public NetworkManager(ConfigMode mode, String instanceName, URI instanceHome) throws IOException {
187 this.instanceName = instanceName;
189 this.instanceHome = instanceHome;
193 * Returns the {@link NetworkConfigurator} for additional tuning
195 * @return the {@link NetworkConfigurator} for additional tuning
196 * @throws java.io.IOException if an io error occurs
198 public synchronized NetworkConfigurator getConfigurator() throws IOException {
199 if (config == null) {
206 * Getter for property 'infrastructureID'.
208 * @return Value for property 'infrastructureID'.
210 public PeerGroupID getInfrastructureID() {
211 return infrastructureID;
215 * Setter for property 'infrastructureID'.
217 * @param infrastructureID Value to set for property 'infrastructureID'.
219 public void setInfrastructureID(PeerGroupID infrastructureID) {
220 this.infrastructureID = infrastructureID;
221 if (config != null) {
222 config.setInfrastructureID(infrastructureID);
227 * Getter for property 'instanceName'.
229 * @return Value for property 'instanceName'.
231 public String getInstanceName() {
236 * Setter for property 'instanceName'.
238 * @param instanceName Value to set for property 'instanceName'.
240 public void setInstanceName(String instanceName) {
241 this.instanceName = instanceName;
245 * Getter for property 'instanceHome'.
247 * @return Value for property 'instanceHome'.
249 public URI getInstanceHome() {
254 * Setter for property 'instanceHome'.
256 * @param instanceHome Value to set for property 'instanceHome'.
258 public void setInstanceHome(URI instanceHome) {
259 this.instanceHome = instanceHome;
263 * Getter for property node operating 'mode'.
265 * @return Value for property 'mode'.
267 public ConfigMode getMode() {
272 * Setter for property 'mode'.
274 * @param mode Value to set for property 'mode'.
275 * @throws IOException if an io error occurs
277 public void setMode(ConfigMode mode) throws IOException {
283 * Getter for property 'peerID'.
285 * @return Value for property 'peerID'.
287 public PeerID getPeerID() {
292 * Setter for property 'peerID'.
294 * @param peerID Value to set for property 'peerID'.
296 public void setPeerID(PeerID peerID) {
297 this.peerID = peerID;
301 * Getter for property 'configPersistent'.
303 * @return Value for property 'configPersistent'.
305 public boolean isConfigPersistent() {
306 return configPersistent;
310 * Setter for property 'configPersistent'. if disabled a PlatformConfig is not persisted. It assumed that
311 * the PeerID is will be set, or a new PeerID will always be generated.
313 * @param persisted Value to set for property 'configPersistent'.
315 public void setConfigPersistent(boolean persisted) {
316 this.configPersistent = persisted;
319 private void configure(ConfigMode mode) throws IOException {
322 config = NetworkConfigurator.newAdHocConfiguration(instanceHome);
326 config = NetworkConfigurator.newEdgeConfiguration(instanceHome);
330 config = NetworkConfigurator.newRdvConfiguration(instanceHome);
334 config = NetworkConfigurator.newRelayConfiguration(instanceHome);
337 case RENDEZVOUS_RELAY:
338 config = NetworkConfigurator.newRdvRelayConfiguration(instanceHome);
342 config = NetworkConfigurator.newProxyConfiguration(instanceHome);
346 config = NetworkConfigurator.newRdvRelayProxyConfiguration(instanceHome);
350 config = NetworkConfigurator.newAdHocConfiguration(instanceHome);
352 if (!config.exists()) {
353 if (Logging.SHOW_INFO && LOG.isLoggable(Level.INFO)) {
354 LOG.log(Level.INFO, "Created new configuration. mode = " + mode.toString());
357 config.setDescription("Created by NetworkManager");
358 config.setPeerID(peerID);
359 config.setInfrastructureID(infrastructureID);
360 config.setName(instanceName);
361 if (useDefaultSeeds) {
362 config.addRdvSeedingURI(publicSeedingRdvURI);
363 config.addRelaySeedingURI(publicSeedingRelayURI);
366 if (Logging.SHOW_INFO && LOG.isLoggable(Level.INFO)) {
367 LOG.log(Level.INFO, "Loading existing configuration. mode = " + mode.toString());
370 File pc = new File(config.getHome(), "PlatformConfig");
373 config.load(pc.toURI());
374 } catch (CertificateException pseFailed) {
375 IOException failure = new IOException("Failure reading membership service certificates.");
377 failure.initCause(pseFailed);
381 // XXX 20070524 bondolo Aren't we completely ignoring the mode? What if it changed?
382 // 20070614 hamada Good question, this feature is postponed due to the difficulty of comparing a stored/requested modes.
387 * Creates and starts the JXTA infrastructure peer group (aka NetPeerGroup) based on the specified mode
388 * template. This class also registers a listener for rendezvous events.
390 * @return The Net Peer Group
391 * @throws net.jxta.exception.PeerGroupException
392 * if the group fails to initialize
393 * @throws java.io.IOException if an io error occurs
395 public synchronized PeerGroup startNetwork() throws PeerGroupException, IOException {
401 if (config == null) {
405 if (Logging.SHOW_INFO && LOG.isLoggable(Level.INFO)) {
406 LOG.log(Level.INFO, "Starting JXTA Network! MODE = " + mode.toString() + ", HOME = " + instanceHome);
409 // create, and Start the default jxta NetPeerGroup
410 NetPeerGroupFactory factory = new NetPeerGroupFactory(config.getPlatformConfig(), instanceHome);
412 netPeerGroup = factory.getInterface();
414 if (configPersistent) {
418 rendezvous = netPeerGroup.getRendezVousService();
419 rendezvous.addListener(this);
422 if (Logging.SHOW_INFO && LOG.isLoggable(Level.INFO)) {
423 LOG.log(Level.INFO, "Started JXTA Network!");
430 * Establishes group credential. This is a required step when planning to
431 * to utilize TLS messengers or secure pipes
433 * @param group peer group to establish credentials in
434 * @param keystore_password The passphrase for the keystore. This is a
435 * char[] rather than a String so that it can be blanked after use.
436 * @param principal_password The passphrase for the identity. This is a
437 * char[] rather than a String so that it can be blanked after use.
438 * @throws net.jxta.exception.PeerGroupException
439 * if group credentials were rejected
440 * @throws net.jxta.exception.ProtocolNotSupportedException
441 * if authenticator rejected the credential
443 public static void login(PeerGroup group, char[] keystore_password, char[] principal_password) throws PeerGroupException, ProtocolNotSupportedException {
444 StringAuthenticator auth;
445 MembershipService membership = group.getMembershipService();
446 Credential cred = membership.getDefaultCredential();
449 AuthenticationCredential authCred = new AuthenticationCredential(group, "StringAuthentication", null);
451 auth = (StringAuthenticator) membership.apply(authCred);
453 auth.setAuth1_KeyStorePassword(keystore_password);
454 auth.setAuth2Identity(group.getPeerID());
455 auth.setAuth3_IdentityPassword(principal_password);
456 if (auth.isReadyForJoin()) {
457 membership.join(auth);
462 cred = membership.getDefaultCredential();
464 AuthenticationCredential authCred = new AuthenticationCredential(group, "InteractiveAuthentication", null);
465 InteractiveAuthenticator iAuth = (InteractiveAuthenticator) membership.apply(authCred);
467 if (iAuth.interact() && iAuth.isReadyForJoin()) {
468 membership.join(iAuth);
474 * Stops and unreferences the NetPeerGroup
476 public synchronized void stopNetwork() {
477 if (stopped || !started) {
481 if (Logging.SHOW_INFO && LOG.isLoggable(Level.INFO)) {
482 LOG.log(Level.INFO, "Stopping JXTA Network!");
486 synchronized(networkConnectLock) {
488 networkConnectLock.notifyAll();
491 rendezvous.removeListener(this);
492 netPeerGroup.stopApp();
493 netPeerGroup.unref();
498 if (Logging.SHOW_INFO && LOG.isLoggable(Level.INFO)) {
499 LOG.log(Level.INFO, "Stopped JXTA Network!");
504 * Gets the netPeerGroup object
506 * @return The netPeerGroup value
508 public PeerGroup getNetPeerGroup() {
513 * Blocks only, if not connected to a rendezvous, or until a connection to rendezvous node occurs.
515 * @param timeout timeout in milliseconds, a zero timeout of waits forever
516 * @return true if connected to a rendezvous, false otherwise
518 public boolean waitForRendezvousConnection(long timeout) {
520 timeout = Long.MAX_VALUE;
523 long timeoutAt = System.currentTimeMillis() + timeout;
525 if (timeoutAt <= 0) {
527 timeoutAt = Long.MAX_VALUE;
530 while (started && !stopped && !rendezvous.isConnectedToRendezVous() && !rendezvous.isRendezVous()) {
532 long waitFor = timeoutAt - System.currentTimeMillis();
535 synchronized (networkConnectLock) {
536 networkConnectLock.wait(timeout);
539 // all done with waiting.
542 } catch (InterruptedException e) {
543 Thread.interrupted();
548 return rendezvous.isConnectedToRendezVous() || rendezvous.isRendezVous();
552 * rendezvousEvent the rendezvous event
554 * @param event rendezvousEvent
556 public void rendezvousEvent(RendezvousEvent event) {
557 if (event.getType() == RendezvousEvent.RDVCONNECT || event.getType() == RendezvousEvent.RDVRECONNECT
558 || event.getType() == RendezvousEvent.BECAMERDV) {
559 synchronized (networkConnectLock) {
561 networkConnectLock.notifyAll();
567 * if true uses the public rendezvous seeding service
569 * @param useDefaultSeeds if true uses the default development seeding service
571 public void setUseDefaultSeeds(boolean useDefaultSeeds) {
572 this.useDefaultSeeds = useDefaultSeeds;
576 * Returns true if useDefaultSeeds is set to true
578 * @return true if useDefaultSeeds is set to true
580 public boolean getUseDefaultSeeds() {
581 return useDefaultSeeds;
585 * Registers a Runtime shutdown hook to cleanly shutdown the JXTA platform
587 public synchronized void registerShutdownHook() {
588 if (shutdownHook != null) {
591 shutdownHook = new NetworkManager.ShutdownHook();
592 Runtime.getRuntime().addShutdownHook(shutdownHook);
596 * Unregisters a Runtime shutdown hook to cleanly shutdown the JXTA platform
598 public synchronized void unregisterShutdownHook() {
600 if (shutdownHook == null) {
603 Runtime.getRuntime().removeShutdownHook(shutdownHook);
607 private class ShutdownHook extends Thread {