/* * Copyright (c) 2004-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 net.jxta.endpoint; import net.jxta.peergroup.PeerGroupID; /** * A Channel Messenger provides an exclusive interface to the shared messenger. * <p/> * What is typically exclusive is the message queue, addressing parameters * that are not usefully shared (serviceName, serviceParam), and if needed * cross-group address rewriting parameters. * <p/> * This class is provided as a base for implementing such channel messengers, * which are typically what Messenger.getChannelMessenger() needs to return. * * @see net.jxta.endpoint.EndpointService * @see net.jxta.endpoint.EndpointAddress * @see net.jxta.endpoint.Message */ public abstract class ChannelMessenger extends AbstractMessenger implements Messenger { /** * insertedServicePrefix This is how all valid inserted services start. This * lets us recognize if a message already has an inserted service. Then we * must not add another one. Only the top-most one counts. Since insertion * is only done here, the constant is defined here. Even if historically it * was done within the endpoint implementation, it has become a protocol now. */ public static final String InsertedServicePrefix = "EndpointService:"; private String insertedService; /** * The worker that implements sendMessage-with-listener for this channel. If * there's none, sendMessage-with-listener will throw an exception. Channels * returned by getMessenger methods all have one already. It is up to the * invoker of getChannelMessenger to supply one or not. */ private ListenerAdaptor messageWatcher; protected String origService; protected String origServiceParam; /** * Figure out what the service string will be after mangling (if required) * and applying relevant defaults. * * @param service The service name in the unmangled address. * @return String The service name in the mangled address. */ protected String effectiveService(String service) { // No redirection required. Just apply the default service. if (insertedService == null) { return (service == null) ? origService : service; } // Check if redirection is applicable. return ((service != null) && service.startsWith(InsertedServicePrefix)) ? service : insertedService; } /** * Figure out what the param string will be after mangling (if required) and * applying relevant defaults. * * @param service The service name in the unmangled address. * @param serviceParam The service parameter in the unmangled address. * @return String The service parameter in the mangled address. */ protected String effectiveParam(String service, String serviceParam) { // No redirection required. Or not applicable. Just apply the default param. if ((insertedService == null) || ((service != null) && service.startsWith(InsertedServicePrefix))) { return (serviceParam == null) ? origServiceParam : serviceParam; } // Apply redirection. We need the effective service, now. if (service == null) { service = origService; } if (serviceParam == null) { serviceParam = origServiceParam; } return ((null != service) && (null != serviceParam)) ? (service + "/" + serviceParam) : service; } /** * Give this channel the watcher that it must use whenever sendMessage(...,listener) is used. If not set, * sendMessage(..., listener) will throw. * * @param messageWatcher the listener */ public void setMessageWatcher(ListenerAdaptor messageWatcher) { this.messageWatcher = messageWatcher; } /** * Create a new ChannelMessenger * * @param baseAddress The network address messages go to; regardless of service, param, or group. * @param groupRedirection Group to which the messages must be redirected. This is used to implement the automatic group * segregation which has become a de-facto standard. If not null, the unique portion of the specified groupID is * prepended with {@link #InsertedServicePrefix} and inserted in every message's destination address in place of the * the original service name, which gets shifted into the beginning of the service parameter. The opposite is done * on arrival to restore the original destination address before the message is delivered to the listener in the * the specified group. Messages that already bear a group redirection are not affected. * @param origService The default destination service for messages sent without specifying a different service. * @param origServiceParam The default destination service parameter for messages sent without specifying a different service * parameter. */ public ChannelMessenger(EndpointAddress baseAddress, PeerGroupID groupRedirection, String origService, String origServiceParam) { // FIXME: The inserted service business is really messy. Group seggregation does not have to be the endpoint service's // business. It should be specified by the app as part of the destination address. What we're doing here // is simply enforcing what could just be a convention. super(baseAddress); if (groupRedirection == null) { insertedService = null; } else { insertedService = InsertedServicePrefix + groupRedirection.getUniqueValue().toString(); } this.origService = origService; this.origServiceParam = origServiceParam; } /** * {@inheritDoc} * <p/> * By default a channel refuses to make a channel. */ public Messenger getChannelMessenger(PeerGroupID redirection, String service, String serviceParam) { return null; } /** * {@inheritDoc} * */ @Override public void sendMessage(Message msg, String service, String serviceParam, OutgoingMessageEventListener listener) { if (messageWatcher == null) { throw new UnsupportedOperationException("This channel was not configured to emulate this legacy method."); } // Cleanup the message from any existing result prop since we're going to use select. msg.setMessageProperty(Messenger.class, null); // Tell the watcher to select that message. messageWatcher.watchMessage(listener, msg); sendMessageN(msg, service, serviceParam); } }