/* * Copyright (c) 2001-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.impl.protocol; import net.jxta.document.Document; import net.jxta.document.Element; import net.jxta.document.MimeMediaType; import net.jxta.document.StructuredDocument; import net.jxta.document.StructuredDocumentFactory; import net.jxta.document.XMLDocument; import net.jxta.document.XMLElement; import net.jxta.id.ID; import net.jxta.id.IDFactory; import net.jxta.logging.Logging; import net.jxta.peer.PeerID; import java.net.URI; import java.net.URISyntaxException; import java.util.Enumeration; import java.util.logging.Level; import java.util.logging.Logger; /** * The LimitedRangeRdv walk header message. * <p/> * <p/><pre><code> * <xs:simpleType name="WalkDirection"> * <xs:restriction base="xs:unsignedInt"> * <!-- UP --> * <xs:enumeration value="1" /> * <!-- DOWN --> * <xs:enumeration value="2" /> * <!-- BOTH --> * <xs:enumeration value="3" /> * </xs:restriction> * </xs:simpleType> * <p/> * <xs:complexType name="LimitedRangeRdvMessage"> * <xs:sequence> * <xs:element name="TTL" type="xs:unsignedInt" /> * <xs:element name="Dir" type="jxta:WalkDirection" /> * <xs:element name="SrcPeerID" type="jxta:JXTAID" /> * <xs:element name="SrcSvcName" type="xs:string" /> * <xs:element name="SrcSvcParams" minOccurs="0" type="xs:string" /> * </xs:sequence> * </xs:complexType> * </code></pre> * * @see net.jxta.impl.rendezvous.limited.LimitedRangeWalk * @see net.jxta.impl.rendezvous.limited.LimitedRangeWalker * @see net.jxta.impl.rendezvous.limited.LimitedRangeGreeter * @since JXTA 2.0 */ public class LimitedRangeRdvMsg { /** * Logger */ private final static transient Logger LOG = Logger.getLogger(LimitedRangeRdvMsg.class.getName()); private final static String TTL_ELEMENT = "TTL"; private final static String DIRECTION_ELEMENT = "Dir"; private final static String SRCPEERID_ELEMENT = "SrcPeerID"; private final static String SRCSVCNAME_ELEMENT = "SrcSvcName"; private final static String SRCSVCPARAM_ELEMENT = "SrcSvcParams"; private int ttl = 0; private WalkDirection direction = null; private PeerID srcPeerID = null; private String srcSvcName = null; private String srcSvcParams = null; /** * Enumeration of possible walk directions. */ public enum WalkDirection { UP(1), DOWN(2), BOTH(3); /** * The protocol integer value associated with this direction. */ private final int proto_direction; private WalkDirection(int direction) { proto_direction = direction; } /** * Convert a walk code as used by the standard walker protocol to a * direction object. * * @param code the protocol code * @return A direction object. * @throws IllegalArgumentException For illegal protocol codes. */ public static WalkDirection toWalkDirection(int code) { switch (code) { case 1: return UP; case 2: return DOWN; case 3: return BOTH; default: throw new IllegalArgumentException("Illegal direction"); } } /** * Return the protocol code used by the standard walker protocol for * this WalkDirection. * * @return the walk direction as a numeric value for use in protocol * messages. */ public int toProtocolCode() { return proto_direction; } } /** * Constructor */ public LimitedRangeRdvMsg() {} /** * Construct from a StructuredDocument * * @param root the element */ public LimitedRangeRdvMsg(Element root) { if (!XMLElement.class.isInstance(root)) { throw new IllegalArgumentException(getClass().getName() + " only supports XMLElement"); } XMLElement doc = (XMLElement) root; if (!doc.getName().equals(getMessageType())) { throw new IllegalArgumentException( "Could not construct : " + getClass().getName() + " from doc containing a '" + doc.getName() + "'. Should be : " + getMessageType()); } Enumeration elements = doc.getChildren(); while (elements.hasMoreElements()) { XMLElement elem = (XMLElement) elements.nextElement(); if (!handleElement(elem)) { if (Logging.SHOW_FINE && LOG.isLoggable(Level.FINE)) { LOG.fine("Unhandled Element: " + elem); } } } // Sanity check time! if (getTTL() < 1) { throw new IllegalArgumentException("Illegal TTL value."); } if (null == getDirection()) { throw new IllegalArgumentException("No Direction specified."); } if (null == getSrcPeerID()) { throw new IllegalArgumentException("No source peer id specified."); } if (null == getSrcSvcName()) { throw new IllegalArgumentException("No source service name specified."); } } /** * {@inheritDoc} */ @Override public LimitedRangeRdvMsg clone() { try { LimitedRangeRdvMsg clone = (LimitedRangeRdvMsg) super.clone(); clone.setSrcPeerID(getSrcPeerID()); clone.setDirection(getDirection()); clone.setTTL(getTTL()); clone.setSrcSvcName(getSrcSvcName()); clone.setSrcSvcParams(getSrcSvcParams()); return clone; } catch (CloneNotSupportedException impossible) { throw new Error("Object.clone() threw CloneNotSupportedException", impossible); } } /** * Get the TTL * * @return Time To Live */ public int getTTL() { return ttl; } /** * set the TTL * * @param ttl TTL */ public void setTTL(int ttl) { this.ttl = ttl; } /** * Get the direction the message will take * * @return UP, DOWN or BOTH */ public WalkDirection getDirection() { return direction; } /** * Set the direction the message will take * * @param dir direction */ public void setDirection(WalkDirection dir) { direction = dir; } /** * Get the Source Service Name (listening for the response) * * @return Source Service Name */ public String getSrcSvcName() { return srcSvcName; } /** * Set the Source Service Name (listening for the response) * * @param srcSvcName Source Service Name */ public void setSrcSvcName(String srcSvcName) { this.srcSvcName = srcSvcName; } /** * Get the Source Service Param (listening for the response) * * @return Source Service Param */ public String getSrcSvcParams() { return srcSvcParams; } /** * Set the Source Service Params (listening for the response) * * @param srcSvcParams Source Service Params */ public void setSrcSvcParams(String srcSvcParams) { this.srcSvcParams = srcSvcParams; } /** * Get the Source PeerID (walk originiator) * * @return Source PeerID */ public ID getSrcPeerID() { return srcPeerID; } /** * Set the Source PeerID (walk originiator) * * @param srcPeerID Source PeerID */ public void setSrcPeerID(ID srcPeerID) { this.srcPeerID = (PeerID) srcPeerID; } /** * Our DOCTYPE * * @return the type of this message. */ public static String getMessageType() { return "jxta:LimitedRangeRdvMessage"; } /** * Process an individual element from the document during parse. Normally, * implementations will allow the base advertisments a chance to handle the * element before attempting ot handle the element themselves. ie. * <p/> * <p/><pre><code> * protected boolean handleElement( Element elem ) { * <p/> * if ( super.handleElement() ) { * // it's been handled. * return true; * } * <p/> * <i>... handle elements here ...</i> * <p/> * // we don't know how to handle the element * return false; * } * </code></pre> * * @param elem the element to be processed. * @return true if the element was recognized, otherwise false. */ protected boolean handleElement(XMLElement elem) { String value = elem.getTextValue(); if (null != value) { value = value.trim(); if (0 == value.length()) { value = null; } } if (null == value) { return false; } if (elem.getName().equals(TTL_ELEMENT)) { setTTL(Integer.parseInt(value)); return true; } if (elem.getName().equals(DIRECTION_ELEMENT)) { int direction = Integer.parseInt(value); setDirection(LimitedRangeRdvMsg.WalkDirection.toWalkDirection(direction)); return true; } if (elem.getName().equals(SRCPEERID_ELEMENT)) { try { URI srcURI = new URI(value); ID srcID = IDFactory.fromURI(srcURI); setSrcPeerID(srcID); } catch (URISyntaxException badID) { IllegalArgumentException iae = new IllegalArgumentException("Bad ID in message"); iae.initCause(badID); throw iae; } return true; } if (elem.getName().equals(SRCSVCNAME_ELEMENT)) { setSrcSvcName(value); return true; } if (elem.getName().equals(SRCSVCPARAM_ELEMENT)) { setSrcSvcParams(value); return true; } return false; } /** * @inheritDoc */ public Document getDocument(MimeMediaType mediaType) { if (getTTL() < 1) { throw new IllegalStateException("Illegal TTL value."); } if (null == getDirection()) { throw new IllegalStateException("No Direction specified."); } if (null == getSrcPeerID()) { throw new IllegalStateException("No source peer id specified."); } if (null == getSrcSvcName()) { throw new IllegalStateException("No source service name specified."); } StructuredDocument msg = StructuredDocumentFactory.newStructuredDocument(mediaType, getMessageType()); if (msg instanceof XMLDocument) { ((XMLDocument) msg).addAttribute("xmlns:jxta", "http://jxta.org"); } Element e = msg.createElement(TTL_ELEMENT, Integer.toString(getTTL())); msg.appendChild(e); e = msg.createElement(DIRECTION_ELEMENT, Integer.toString(getDirection().toProtocolCode())); msg.appendChild(e); e = msg.createElement(SRCPEERID_ELEMENT, getSrcPeerID().toString()); msg.appendChild(e); e = msg.createElement(SRCSVCNAME_ELEMENT, getSrcSvcName()); msg.appendChild(e); if (getSrcSvcParams() != null) { e = msg.createElement(SRCSVCPARAM_ELEMENT, getSrcSvcParams()); msg.appendChild(e); } return msg; } }