/*
* Copyright (c) 2006-2007 Sun Microsystems, Inc. All rights reserved.
*
* The Sun Project JXTA(TM) Software License
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
*
* 1. Redistributions of source code must retain the above copyright notice,
* this list of conditions and the following disclaimer.
*
* 2. Redistributions in binary form must reproduce the above copyright notice,
* this list of conditions and the following disclaimer in the documentation
* and/or other materials provided with the distribution.
*
* 3. The end-user documentation included with the redistribution, if any, must
* include the following acknowledgment: "This product includes software
* developed by Sun Microsystems, Inc. for JXTA(TM) technology."
* Alternately, this acknowledgment may appear in the software itself, if
* and wherever such third-party acknowledgments normally appear.
*
* 4. The names "Sun", "Sun Microsystems, Inc.", "JXTA" and "Project JXTA" must
* not be used to endorse or promote products derived from this software
* without prior written permission. For written permission, please contact
* Project JXTA at http://www.jxta.org.
*
* 5. Products derived from this software may not be called "JXTA", nor may
* "JXTA" appear in their name, without prior written permission of Sun.
*
* THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED WARRANTIES,
* INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
* FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL SUN
* MICROSYSTEMS OR ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
* INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
* LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA,
* OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
* LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
* NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE,
* EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*
* JXTA is a registered trademark of Sun Microsystems, Inc. in the United
* States and other countries.
*
* Please see the license information page at :
* <http://www.jxta.org/project/www/license.html> for instructions on use of
* the license in source files.
*
* ====================================================================
*
* This software consists of voluntary contributions made by many individuals
* on behalf of Project JXTA. For more information on Project JXTA, please see
* http://www.jxta.org.
*
* This license is based on the BSD license adopted by the Apache Foundation.
*/
package tutorial.directmessenger;
import net.jxta.endpoint.EndpointListener;
import net.jxta.endpoint.EndpointService;
import net.jxta.platform.NetworkManager;
import java.io.File;
import java.io.IOException;
import java.util.Date;
import java.util.concurrent.atomic.AtomicInteger;
import net.jxta.document.AdvertisementFactory;
import net.jxta.document.StructuredDocumentFactory;
import net.jxta.document.XMLDocument;
import net.jxta.endpoint.EndpointAddress;
import net.jxta.endpoint.Message;
import net.jxta.endpoint.MessageElement;
import net.jxta.endpoint.MessageSender;
import net.jxta.endpoint.Messenger;
import net.jxta.endpoint.StringMessageElement;
import net.jxta.peergroup.PeerGroup;
import net.jxta.protocol.RouteAdvertisement;
/**
* Simple example to illustrate the use of direct messengers. A direct messenger
* is acquired directly from the a physical message transport and bypasses the
* normal JXTA network virtualization layers. There are several reasons why an
* an application might want to use direct messengers :
* <dl>
* <dt>Dedicated Resource</dt>
* <dd>Each direct messenger is a dedicated resource and is available only to
* the application or service which creates it. The messenger is not shared
* with other uses.</dd>
* <dt>Latency & Throughput</dt>
* <dd>Because the messenger bypasses the JXTA network virtualization layers
* it may offer somewhat better throughput and latency than regular shared
* JXTA virtual messengers.</dd>
* <dt>Presence & Disconnection</dt>
* <dd>Direct messengers are more immediately responsive to connection status
* changes. If the remote side closes the connection the application or
* service can recognize the state change immediately.</dd>
* </dl>
* Using direct messengers is not
* <dl>
* <dt>Not Always Available</dt>
* <dd>Creation of a direct messenger to another peer requires that the remote
* peer be directly reachable. In many cases this will not be possible. This
* usually means that it is necessary to support both direct messengers and
* indirect messengers in your application. Additionally, there may be extra
* overhead introduced into your application as a result of attempting to
* create direct messengers.</dd>
* <dt>Consume Extra Resources</dt>
* <dd>The resources used by direct messengers are not available to other JXTA
* applications and services (nor the rest of the system).</dd>
* <dt>Require More "Maintenance"</dt>
* <dd>If the remote peer's addresses change or the connection is closed your
* application will need to re-open the direct messenger. Normally the JXTA
* network virtualization layer hides all this work from your application.
* HTTP direct messengers (because of proxies) commonly require frequent
* re-creation.</dd>
* </dl>
*/
public class Sender {
/**
* The number of responses after which we will stop.
*/
static final int TOTAL_RESPONSES = 10;
/**
* Our listener for "chatAnnounce" messages.
*/
private static class ChatAnnounceReceiver implements EndpointListener {
/**
* The endpoint with which this listener is registered.
*/
private final EndpointService endpoint;
/**
* The number of responses we have sent.
*/
private final AtomicInteger responses = new AtomicInteger(0);
public ChatAnnounceReceiver(EndpointService endpoint) {
this.endpoint = endpoint;
}
/**
* {@inheritDoc}
* <p/>
* Receive a message sent to "chatAnnounce". We expect that the message
* will contain a "ChatAnnounce" message element containing a JXTA
* Route Advertisement for the peer which wishes us to send a response.
*/
public void processIncomingMessage(Message msg, EndpointAddress source, EndpointAddress destination) {
MessageElement announce = msg.getMessageElement("ChatAnnounce");
if(null == announce) {
// It doesn't seem to be the right kind of message.
return;
}
RouteAdvertisement route;
try {
XMLDocument routeDoc = (XMLDocument) StructuredDocumentFactory.newStructuredDocument(announce);
route = (RouteAdvertisement) AdvertisementFactory.newAdvertisement(routeDoc);
} catch(Exception bad) {
System.err.println("### - Bad Route");
bad.printStackTrace(System.err);
return;
}
System.out.println("Announcement from " + route.getDestPeerID() );
// We have received an announcement from some peer. We will attempt
// to create a direct messenger to respond to the announcement.
// Currently we look for only TCP messengers.
for(EndpointAddress anEA : route.getDestEndpointAddresses()) {
MessageSender tcp = (MessageSender) endpoint.getMessageTransport("tcp");
// Search for "tcp" endpoint addresses.
if("tcp".equals(anEA.getProtocolName())) {
EndpointAddress destAddress;
if(endpoint.getGroup().equals(tcp.getEndpointService().getGroup())) {
// The TCP message transport is in our peer group. We can address the message directly.
destAddress = new EndpointAddress(anEA, "chatService", route.getDestPeerID().getUniqueValue().toString() );
} else {
// When a message transport receives a message it passes it to the endpoint service in it's own
// peer group for processing. If our peer group is not the same as the message transports then
// the endpoint service which will receive the message is not the same message service with
// which we registered our message listener. There is a solution though : Each endpoint service
// which uses message transports from it's parent peer groups will also register a redirection
// listener for messages destined for that endpoint service. The listener is named
// "EndpointService:"<PeerGroupID-unique value>" with the parameter being a concatination of the
// service name and parameter separated by a "/".
destAddress = new EndpointAddress(anEA, "EndpointService:jxta-NetGroup", "chatService" + "/" + route.getDestPeerID().getUniqueValue().toString() );
}
// We have an address be believe is worth trying. We will
// attempt to create a messenger to the address.
Messenger directMessenger = null;
try {
directMessenger = tcp.getMessenger(destAddress, null);
if(null == directMessenger) {
// The current address was unreachable. Try another.
System.err.println("### - getMessenger() failed for " + anEA );
continue;
}
// We have a direct messenger. Try to send a response.
System.out.println("Sending response to " + anEA );
String chatMessage = "Hello from " + endpoint.getGroup().getPeerID() + " via " + anEA + " @ " + new Date();
Message chat = new Message();
chat.addMessageElement(new StringMessageElement("Chat", chatMessage, null));
directMessenger.sendMessageB(chat, null, null);
// The message has been sent.
// Decide if we have sent enough responses.
int totalSent = responses.incrementAndGet();
if(totalSent >= TOTAL_RESPONSES) {
synchronized(shutDown) {
// We have sent all the responses we wanted to. Signal shutdown.
stopped = true;
shutDown.notifyAll();
}
}
break;
} catch(IOException failed) {
failed.printStackTrace(System.err);
} finally {
if(null != directMessenger) {
directMessenger.close();
}
}
}
}
}
}
private static boolean stopped = false;
private static String shutDown = new String("shutdown");
/**
* main
*
* @param args command line args
*/
public static void main(String args[]) {
try {
// Configure and start JXTA.
NetworkManager manager = new NetworkManager(NetworkManager.ConfigMode.ADHOC, "DirectMessengerSender",
new File(new File(".cache"), "DirectMessengerSender").toURI());
manager.startNetwork();
PeerGroup npg = manager.getNetPeerGroup();
// Register an endpoint listener for "chatAnnounce" messages.
EndpointService endpoint = npg.getEndpointService();
EndpointListener chatAnnouncelistener = new ChatAnnounceReceiver(endpoint);
endpoint.addIncomingMessageListener(chatAnnouncelistener, "chatAnnounce", null );
// Continue until shutdown
synchronized(shutDown) {
try {
while(!stopped) {
shutDown.wait(5000);
}
} catch( InterruptedException woken ) {
Thread.interrupted();
}
}
// De-register "chatAnnounce" listener.
endpoint.removeIncomingMessageListener( "chatAnnounce", null );
// Stop JXTA.
manager.stopNetwork();
} catch (Exception e) {
e.printStackTrace();
System.exit(-1);
}
}
}