package com.limegroup.gnutella.routing; import java.io.IOException; import java.io.OutputStream; import com.limegroup.gnutella.messages.BadPacketException; import com.limegroup.gnutella.messages.Message; /** * An abstract class representing all variants of the new ROUTE_TABLE_UPDATE * message. Like Message, this has no public constructors. To decode bytes from * call the static read(..) method. To create a new message from scratch, call * one of its subclass' constructors.<p> */ public abstract class RouteTableMessage extends Message { public static final byte RESET_VARIANT=(byte)0x0; public static final byte PATCH_VARIANT=(byte)0x1; private byte variant; //////////////////////////// Encoding ///////////////////////////////////// /** * Creates a new RouteTableMessage from scratch. */ protected RouteTableMessage(byte ttl, int length, byte variant) { super(Message.F_ROUTE_TABLE_UPDATE, ttl, length); this.variant=variant; } protected void writePayload(OutputStream out) throws IOException { out.write(variant); writePayloadData(out); } /** * @modifies out * @effects writes the data following the common variant * to out. Does NOT flush out. */ protected abstract void writePayloadData(OutputStream out) throws IOException; //////////////////////////////// Decoding //////////////////////////////// /** * Creates a new RouteTableMessage from raw bytes read from the network. * The returned value is a subclass of RouteTableMessage depending on * the variant in the payload. (That's why there is no corresponding * constructor in this.) * * @throws BadPacketException the payload is not well-formatted */ public static RouteTableMessage read(byte[] guid, byte ttl, byte hops, byte[] payload) throws BadPacketException { //Parse the common bytes of the payload... if (payload.length<2) throw new BadPacketException("Payload too small"); byte variant=payload[0]; //...and pass them to the subclass' constructor, which will in turn //call this constructor. switch (variant) { case RESET_VARIANT: return new ResetTableMessage(guid, ttl, hops, payload); case PATCH_VARIANT: return new PatchTableMessage(guid, ttl, hops, payload); default: throw new BadPacketException("Unknown table variant"); } } /* * Creates a new RouteTableMessage with data read from the network. This * is called by subclasses after the payload is fully decoded. * * @param variant the type of update message. REQUIRES: one of * RESET_VARIANT or PATCH_VARIANT. * * @see com.limegroup.gnutella.Message */ protected RouteTableMessage(byte[] guid, byte ttl, byte hops, int length, byte variant) { super(guid, Message.F_ROUTE_TABLE_UPDATE, ttl, hops, length); this.variant=variant; } ///////////////////////////// Accessors ////////////////////////////// /** * Returns the variant of this, i.e. one of RESET_VARIANT, * or PATCH_VARIANT. */ public byte getVariant() { return variant; } /** Returns this. */ public Message stripExtendedPayload() { return this; } }