Source code: Message.java

index |  365 lines | javadoc ]

package nl.west.aaa;

import java.util.*;
import java.io.*;

/**
 * A AAA message. 
 * A Messages consists of a type and attributes.
 * The attributes are stored in
 * attributename-attributevalue pairs.
 * A message should at least have the following
 * attributes:
 * <dl>
 *  <li><code>sid</code> - <i>session-id</i>
 *    identifying the session this message belongs to.
 *    Replies are found by mathcing session-ids.</li>
 *  <li><code>uid</code> - <i>user-id</i>
 *    identifying the user of the session (or the
 *    user wishing authentication.</li>
 * </dl>
 */
public class Message
{
    // AUTHENTICATION MESSAGETYPES

    /**
     * Client requests authentication of user.
     */
    public static final int AUTHENTICATION_REQUEST   = 0x0100;
    
    /**
     * Server accepts authentication of user based
     * on sent data.
     */
    public static final int AUTHENTICATION_ACCEPT    = 0x0101;
    
    /**
     * Server rejects authentication of user based
     * on sent data.
     */
    public static final int AUTHENTICATION_REJECT    = 0x0102;
    
    /**
     * Server needs more data to complete authentication
     * of user.
     */
    public static final int AUTHENTICATION_CHALLENGE = 0x0103;
    
    /**
     * Server requests redo of athentication.
     * Client should respond with a request.
     * Session may be suspended depending on 
     * attributes and settings.
     */
    public static final int AUTHENTICATION_REDO      = 0x0104;    

    // AUTHORISATION MESSAGETYPES
    
    public static final int AUTHORISATION_REQUEST    = 0x0200;
    public static final int AUTHORISATION_ACCEPT     = 0x0201;
    public static final int AUTHORISATION_REJECT     = 0x0202;
    public static final int AUTHORISATION_CHALLENGE  = 0x0203;
    public static final int AUTHORISATION_REDO       = 0x0204;
    
    // ACCOUNTING MESSAGETYPES
    
    /**
     * Client has accounting data for server.
     */
    public static final int ACCOUNTING_REQUEST       = 0x0300;
    
    /**
     * Server confirms receiving accounting data.
     * This may be used to transmit a signature over
     * the sent data.
     */
    public static final int ACCOUNTING_REPLY         = 0x0301;
    
    /**
     * The server requests that the client send
     * accounting messages regarding specified
     * (may be all) sessions currently active.
     */
    public static final int ACCOUNTING_POLL          = 0x0302;
    
    /**
     * The server requests that the client send
     * accounting messages regarding specified
     * (may be all) sessions currently active.
     */
    public static final int ACCOUNTING_INDICATION    = 0x0303;

    // OTHER MESSAGETYPES
    
    /**
     * The server requests that all buffered messages be
     * sent.
     */
    public static final int MESSAGES_REQUEST         = 0x0400;
    
    /**
     * Thge client indicates that there are buffered
     * messages waiting to be delivered.
     */
    public static final int MESSAGES_READY           = 0x0401; 

    /**
     * A reject is sent when a received message
     * cannot be processed for any reason.
     */    
    public static final int MESSAGE_REJECT           = 0x0500;
    
    /**
     * The encoded encoded form of the message.
     * This field may be null at any time.
     */
    public transient byte[] data;

    /**
     * The type of the Message. See static fields
     * for possible values.
     */
    private int type;
    
    /**
     * The attributes of the message.
     */
    private Hashtable attrs;

    /**
     * Idicates the used RecordFormat to encode this message.
     * This field may be null and is not part of the content of the
     * Message.
     */
    public RecordFormat recordFormat;
    
    /**
     * Idicates the used TransportProtocol to send this message.
     * This field may be null and is not part of the content of the
     * Message.
     */
    public TransportProtocol transportProtocol;

    /**
     * The sender of the message.
     * This field may be null and is not part of the content of the
     * Message.
     */
    public Identifier sender;
    
    /**
     * The receiver of this message.
     * This field may be null and is not part of the content of the
     * Message.
     */
    public Identifier receiver;
    
    /**
     * Make a new message of the given type
     * with the given attributes.
     */    
    public Message(int type,Hashtable attrs)
    {
        // serviceID should be in attrs
        this.type=type;
        this.attrs=attrs;
    }
    
    /**
     * Make a new message based on the given message.
     */
    protected Message(Message msg)
    {
        this.type=msg.type;
        this.attrs=(Hashtable)msg.attrs.clone();
        this.recordFormat=msg.recordFormat;
        this.transportProtocol=msg.transportProtocol;
        this.sender=msg.sender;
        this.receiver=msg.receiver;
        //this.foundReply=null;
    }
    
    /**
     * Return a string representation of the messageType.
     */
    private static String typeString(int type)
    {
        switch(type)
        {
        case Message.AUTHENTICATION_REQUEST:
            return "AUTHENTICATION_REQUEST";
        case Message.AUTHENTICATION_ACCEPT:
            return "AUTHENTICATION_ACCEPT";
        case Message.AUTHENTICATION_REJECT:
            return "AUTHENTICATION_REJECT";
        case Message.AUTHENTICATION_CHALLENGE:
            return "AUTHENTICATION_CHALLENGE";
        case Message.AUTHENTICATION_REDO:
            return "AUTHENTICATION_REDO";
        case Message.AUTHORISATION_REQUEST:
            return "AUTHORISATION_REQUEST";
        case Message.AUTHORISATION_ACCEPT:
            return "AUTHORISATION_ACCEPT";
        case Message.AUTHORISATION_REJECT:
            return "AUTHORISATION_REJECT";
        case Message.AUTHORISATION_CHALLENGE:
            return "AUTHORISATION_CHALLENGE";
        case Message.AUTHORISATION_REDO:
            return "AUTHORISATION_REDO";
        case Message.ACCOUNTING_REQUEST:
            return "ACCOUNTING_REQUEST";
        case Message.ACCOUNTING_REPLY:
            return "ACCOUNTING_REPLY";
        case Message.ACCOUNTING_POLL:
            return "ACCOUNTING_POLL";
        case Message.MESSAGES_REQUEST:
            return "MESSAGES_REQUEST";
        case Message.MESSAGES_READY:
            return "MESSAGES_READY";
        case Message.MESSAGE_REJECT:
            return "MESSAGE_REJECT";
        default:
            // return a numeric representation
            return ""+type;
        }
    }
    
    /**
     * Produces a string representation of 
     * the message for debug purposes.
     */
    public String toString()
    {
        return "Message{type="+typeString(type)+
              ",sender="+sender+
              ",receiver="+receiver+
              ",attrs="+attrs+"}";
    }
    
    /**
     * Checks if this message is a valid reply
     * to the given message.
     * Subclasses could check signatures.
     * This class compares session ids (sid attributes)
     * and messagetypes.
     */
     // TODO: realy change to something like a ReplyMatcher interface
     //       because reply-matching is very service dependant
     // TODO: change to something with a factory thingy
     //       where this is delegated to the factory
    public boolean isReplyTo(Message msg)
    {
        // first check the messagetype
        switch(msg.type)
        {
        case Message.AUTHENTICATION_REQUEST:
            switch(this.type)
            {
            case Message.AUTHENTICATION_ACCEPT:
            case Message.AUTHENTICATION_REJECT:
            case Message.AUTHENTICATION_CHALLENGE:
                break;
            default:
                return false;
            }
            break;
        case Message.AUTHENTICATION_CHALLENGE:
            switch(this.type)
            {
            case Message.AUTHENTICATION_REQUEST:
                break;
            default:
                return false;
            }
            break;
        case Message.AUTHORISATION_REQUEST:
            switch(this.type)
            {
            case Message.AUTHORISATION_ACCEPT:
            case Message.AUTHORISATION_REJECT:
            case Message.AUTHORISATION_CHALLENGE:
                break;
            default:
                return false;
            }
            break;
        case Message.AUTHORISATION_CHALLENGE:
            switch(this.type)
            {
            case AUTHORISATION_REQUEST:
                break;
            default:
                return false;
            }
            break;
        case Message.ACCOUNTING_REQUEST:
            switch(this.type)
            {
            case ACCOUNTING_REPLY:
                break;
            default:
                return false;
            }
            break;
        }
        // every message should have a session id
        String osid=(String)msg.attrs.get("sid");
        String tsid=(String)this.attrs.get("sid");
        if((osid==null)||(tsid==null))
            return true;
        if(!osid.equals(tsid))
            return false;
        return true;
        // TODO: improve reply-matching
    }

    /**
     * Make a reply to this message
     * with given messageType and attributes.
     */
    public Message reply(int type,Hashtable attrs)
    {
        Message msg=new Message(type,attrs);
        msg.recordFormat=this.recordFormat;
        msg.transportProtocol=this.transportProtocol;
        msg.sender=this.receiver;
        msg.receiver=this.sender;
        // copy session id (any message should have one)
        if (this.attrs.get("sid")!=null)
          msg.attrs.put("sid",this.attrs.get("sid"));
        //msg.attrs.put("uid",this.attrs.get("uid"));
        //msg.replyTo=this;
        return msg;
    }        
    
    /**
     * Make a new message to forward to
     * the specified destination.
     * The attributes and messageType are not
     * modified.
     */
    public Message forward(Identifier to)
    {
        Message msg=new Message(this);
        msg.sender=msg.receiver;
        msg.receiver=to;
        return msg;
    }

    public int getMessageType()
    {
        return type;
    }
    
    public Object getAttribute(String attname)
    {
        return attrs.get(attname);
    }
    
    public Hashtable getAttributes()
    {
        return attrs;
    }
}


Arthur <arthur@ch.twi.tudelft.nl> http://ch.twi.tudelft.nl/~arthur/
2002-05-27