Package org.tinyradius.attribute

Source Code of org.tinyradius.attribute.VendorSpecificAttribute

/**
* $Id: VendorSpecificAttribute.java,v 1.7 2005/11/22 10:18:38 wuttke Exp $
* Created on 10.04.2005
* @author Matthias Wuttke
* @version $Revision: 1.7 $
*/
package org.tinyradius.attribute;

import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.util.ArrayList;
import java.util.Iterator;
import java.util.LinkedList;
import java.util.List;

import org.tinyradius.dictionary.AttributeType;
import org.tinyradius.dictionary.Dictionary;
import org.tinyradius.util.RadiusException;

/**
* This class represents a "Vendor-Specific" attribute.
*/
public class VendorSpecificAttribute extends RadiusAttribute {

  /**
   * Radius attribute type code for Vendor-Specific
   */
  public static final int VENDOR_SPECIFIC = 26;

  /**
   * Constructs an empty Vendor-Specific attribute that can be read from a
   * Radius packet.
   */
  public VendorSpecificAttribute() {
    super();
  }

  /**
   * Constructs a new Vendor-Specific attribute to be sent.
   * @param vendorId vendor ID of the sub-attributes
   */
  public VendorSpecificAttribute(int vendorId) {
    setAttributeType(VENDOR_SPECIFIC);
    setChildVendorId(vendorId);
  }

  /**
   * Sets the vendor ID of the child attributes.
   * @param childVendorId
   */
  public void setChildVendorId(int childVendorId) {
    this.childVendorId = childVendorId;
  }

  /**
   * Returns the vendor ID of the sub-attributes.
   * @return vendor ID of sub attributes
   */
  public int getChildVendorId() {
    return childVendorId;
  }

  /**
   * Also copies the new dictionary to sub-attributes.
   * @param dictionary dictionary to set
   * @see org.tinyradius.attribute.RadiusAttribute#setDictionary(org.tinyradius.dictionary.Dictionary)
   */
  public void setDictionary(Dictionary dictionary) {
    super.setDictionary(dictionary);
    for (Iterator i = subAttributes.iterator(); i.hasNext();) {
      RadiusAttribute attr = (RadiusAttribute) i.next();
      attr.setDictionary(dictionary);
    }
  }

  /**
   * Adds a sub-attribute to this attribute.
   * @param attribute sub-attribute to add
   */
  public void addSubAttribute(RadiusAttribute attribute) {
    if (attribute.getVendorId() != getChildVendorId())
      throw new IllegalArgumentException(
          "sub attribut has incorrect vendor ID");

    subAttributes.add(attribute);
  }

  /**
   * Adds a sub-attribute with the specified name to this attribute.
   * @param name name of the sub-attribute
   * @param value value of the sub-attribute
   * @exception IllegalArgumentException invalid sub-attribute name or value
   */
  public void addSubAttribute(String name, String value) {
    if (name == null || name.length() == 0)
      throw new IllegalArgumentException("type name is empty");
    if (value == null || value.length() == 0)
      throw new IllegalArgumentException("value is empty");

    AttributeType type = getDictionary().getAttributeTypeByName(name);
    if (type == null)
      throw new IllegalArgumentException("unknown attribute type '"
          + name + "'");
    if (type.getVendorId() == -1)
      throw new IllegalArgumentException("attribute type '" + name
          + "' is not a Vendor-Specific sub-attribute");
    if (type.getVendorId() != getChildVendorId())
      throw new IllegalArgumentException("attribute type '" + name
          + "' does not belong to vendor ID " + getChildVendorId());

    RadiusAttribute attribute = createRadiusAttribute(getDictionary(),
        getChildVendorId(), type.getTypeCode());
    attribute.setAttributeValue(value);
    addSubAttribute(attribute);
  }

  /**
   * Removes the specified sub-attribute from this attribute.
   * @param attribute RadiusAttribute to remove
   */
  public void removeSubAttribute(RadiusAttribute attribute) {
    if (!subAttributes.remove(attribute))
      throw new IllegalArgumentException("no such attribute");
  }

  /**
   * Returns the list of sub-attributes.
   * @return List of RadiusAttribute objects
   */
  public List getSubAttributes() {
    return subAttributes;
  }

  /**
   * Returns all sub-attributes of this attribut which have the given type.
   * @param attributeType type of sub-attributes to get
   * @return list of RadiusAttribute objects, does not return null
   */
  public List getSubAttributes(int attributeType) {
    if (attributeType < 1 || attributeType > 255)
      throw new IllegalArgumentException(
          "sub-attribute type out of bounds");

    LinkedList result = new LinkedList();
    for (Iterator i = subAttributes.iterator(); i.hasNext();) {
      RadiusAttribute a = (RadiusAttribute) i.next();
      if (attributeType == a.getAttributeType())
        result.add(a);
    }
    return result;
  }

  /**
   * Returns a sub-attribute of the given type which may only occur once in
   * this attribute.
   * @param type sub-attribute type
   * @return RadiusAttribute object or null if there is no such sub-attribute
   * @throws RuntimeException if there are multiple occurences of the
   * requested sub-attribute type
   */
  public RadiusAttribute getSubAttribute(int type) {
    List attrs = getSubAttributes(type);
    if (attrs.size() > 1)
      throw new RuntimeException(
          "multiple sub-attributes of requested type " + type);
    else if (attrs.size() == 0)
      return null;
    else
      return (RadiusAttribute) attrs.get(0);
  }

  /**
   * Returns a single sub-attribute of the given type name.
   * @param type attribute type name
   * @return RadiusAttribute object or null if there is no such attribute
   * @throws RuntimeException if the attribute occurs multiple times
   */
  public RadiusAttribute getSubAttribute(String type) throws RadiusException {
    if (type == null || type.length() == 0)
      throw new IllegalArgumentException("type name is empty");

    AttributeType t = getDictionary().getAttributeTypeByName(type);
    if (t == null)
      throw new IllegalArgumentException("unknown attribute type name '"
          + type + "'");
    if (t.getVendorId() != getChildVendorId())
      throw new IllegalArgumentException("vendor ID mismatch");

    return getSubAttribute(t.getTypeCode());
  }

  /**
   * Returns the value of the Radius attribute of the given type or null if
   * there is no such attribute.
   * @param type attribute type name
   * @return value of the attribute as a string or null if there is no such
   * attribute
   * @throws IllegalArgumentException if the type name is unknown
   * @throws RuntimeException attribute occurs multiple times
   */
  public String getSubAttributeValue(String type) throws RadiusException {
    RadiusAttribute attr = getSubAttribute(type);
    if (attr == null)
      return null;
    else
      return attr.getAttributeValue();
  }

  /**
   * Renders this attribute as a byte array.
   * @see org.tinyradius.attribute.RadiusAttribute#writeAttribute()
   */
  public byte[] writeAttribute() {
    // write vendor ID
    ByteArrayOutputStream bos = new ByteArrayOutputStream(255);
    bos.write(getChildVendorId() >> 24 & 0x0ff);
    bos.write(getChildVendorId() >> 16 & 0x0ff);
    bos.write(getChildVendorId() >> 8 & 0x0ff);
    bos.write(getChildVendorId() & 0x0ff);

    // write sub-attributes
    try {
      for (Iterator i = subAttributes.iterator(); i.hasNext();) {
        RadiusAttribute a = (RadiusAttribute) i.next();
        bos.write(a.writeAttribute());
      }
    } catch (IOException ioe) {
      // occurs never
      throw new RuntimeException("error writing data", ioe);
    }

    // check data length
    byte[] attrData = bos.toByteArray();
    int len = attrData.length;
    if (len > 253)
      throw new RuntimeException("Vendor-Specific attribute too long: "
          + bos.size());

    // compose attribute
    byte[] attr = new byte[len + 2];
    attr[0] = VENDOR_SPECIFIC; // code
    attr[1] = (byte) (len + 2); // length
    System.arraycopy(attrData, 0, attr, 2, len);
    return attr;
  }

  /**
   * Reads a Vendor-Specific attribute and decodes the internal sub-attribute
   * structure.
   * @see org.tinyradius.attribute.RadiusAttribute#readAttribute(byte[], int,
   * int)
   */
  public void readAttribute(byte[] data, int offset, int length)
      throws RadiusException {
    // check length
    if (length < 6)
      throw new RadiusException("Vendor-Specific attribute too short: "
          + length);

    int vsaCode = data[offset];
    int vsaLen = ((int) data[offset + 1] & 0x000000ff) - 6;

    if (vsaCode != VENDOR_SPECIFIC)
      throw new RadiusException("not a Vendor-Specific attribute");

    // read vendor ID and vendor data
    /*
     * int vendorId = (data[offset + 2] << 24 | data[offset + 3] << 16 |
     * data[offset + 4] << 8 | ((int)data[offset + 5] & 0x000000ff));
     */
    int vendorId = (unsignedByteToInt(data[offset + 2]) << 24
        | unsignedByteToInt(data[offset + 3]) << 16
        | unsignedByteToInt(data[offset + 4]) << 8 | unsignedByteToInt(data[offset + 5]));
    setChildVendorId(vendorId);

    // validate sub-attribute structure
    int pos = 0;
    int count = 0;
    while (pos < vsaLen) {
      if (pos + 1 >= vsaLen)
        throw new RadiusException("Vendor-Specific attribute malformed");
      // int vsaSubType = data[(offset + 6) + pos] & 0x0ff;
      int vsaSubLen = data[(offset + 6) + pos + 1] & 0x0ff;
      pos += vsaSubLen;
      count++;
    }
    if (pos != vsaLen)
      throw new RadiusException("Vendor-Specific attribute malformed");

    subAttributes = new ArrayList(count);
    pos = 0;
    while (pos < vsaLen) {
      int subtype = data[(offset + 6) + pos] & 0x0ff;
      int sublength = data[(offset + 6) + pos + 1] & 0x0ff;
      RadiusAttribute a = createRadiusAttribute(getDictionary(),
          vendorId, subtype);
      a.readAttribute(data, (offset + 6) + pos, sublength);
      subAttributes.add(a);
      pos += sublength;
    }
  }

  private static int unsignedByteToInt(byte b) {
    return (int) b & 0xFF;
  }

  /**
   * Returns a string representation for debugging.
   * @see org.tinyradius.attribute.RadiusAttribute#toString()
   */
  public String toString() {
    StringBuffer sb = new StringBuffer();
    sb.append("Vendor-Specific: ");
    int vendorId = getChildVendorId();
    String vendorName = getDictionary().getVendorName(vendorId);
    if (vendorName != null) {
      sb.append(vendorName);
      sb.append(" (");
      sb.append(vendorId);
      sb.append(")");
    } else {
      sb.append("vendor ID ");
      sb.append(vendorId);
    }
    for (Iterator i = getSubAttributes().iterator(); i.hasNext();) {
      RadiusAttribute attr = (RadiusAttribute) i.next();
      sb.append("\n");
      sb.append(attr.toString());
    }
    return sb.toString();
  }

  /**
   * Sub attributes. Only set if isRawData == false.
   */
  private List subAttributes = new ArrayList();

  /**
   * Vendor ID of sub-attributes.
   */
  private int childVendorId;
}
TOP

Related Classes of org.tinyradius.attribute.VendorSpecificAttribute

TOP
Copyright © 2018 www.massapi.com. All rights reserved.
All source code are property of their respective owners. Java is a trademark of Sun Microsystems, Inc and owned by ORACLE Inc. Contact coftware#gmail.com.