/*
* Copyright (c) 2003 University of Murcia. All rights reserved.
* --------------------------------------------------------------
* For more information, please see .
*/
package org.umu.cops.stack;
import java.io.IOException;
import java.io.OutputStream;
import java.net.Socket;
/**
* COPS Handle Object (RFC 2748 pag. 9)
*
* The Handle Object encapsulates a unique value that identifies an
* installed state. This identification is used by most COPS operations.
*
* C-Num = 1
*
* C-Type = 1, Client Handle.
*
* Variable-length field, no implied format other than it is unique from
* other client handles from the same PEP (a.k.a. COPS TCP connection)
* for a particular client-type. It is always initially chosen by the
* PEP and then deleted by the PEP when no longer applicable. The client
* handle is used to refer to a request state initiated by a particular
* PEP and installed at the PDP for a client-type. A PEP will specify a
* client handle in its Request messages, Report messages and Delete
* messages sent to the PDP. In all cases, the client handle is used to
* uniquely identify a particular PEP's request for a client-type.
*
* The client handle value is set by the PEP and is opaque to the PDP.
* The PDP simply performs a byte-wise comparison on the value in this
* object with respect to the handle object values of other currently
* installed requests.
*
* @version COPSHandle.java, v 1.00 2003
*
*/
public class COPSHandle extends COPSObjBase {
private final COPSObjHeader _objHdr;
private final COPSData _id;
private final COPSData _padding;
/**
* Constructor
* @param id - the identifier (must not be null)
* @throws java.lang.IllegalArgumentException when the id parameter is null
*/
public COPSHandle(final COPSData id) {
if (id == null) throw new IllegalArgumentException("COPSData must not be null");
_objHdr = new COPSObjHeader();
_objHdr.setCNum(COPSObjHeader.COPS_HANDLE);
_objHdr.setCType((byte) 1);
_id = id;
if ((_id.length() % 4) != 0) {
final int padLen = 4 - (_id.length() % 4);
_padding = getPadding(padLen);
} else {
_padding = new COPSData();
}
_objHdr.setDataLength((short) _id.length());
}
/**
* Constructor
* @param dataPtr - the data to parse for setting this object's attributes
*/
protected COPSHandle(final byte[] dataPtr) {
if (dataPtr == null || dataPtr.length < 5)
throw new IllegalArgumentException("Data cannot be null or fewer than 5 bytes");
_objHdr = new COPSObjHeader();
_objHdr.parse(dataPtr);
//Get the length of data following the obj header
final int dLen = _objHdr.getDataLength() - 4;
_id = new COPSData(dataPtr, 4, dLen);
if ((_id.length() % 4) != 0) {
final int padLen = 4 - (_id.length() % 4);
_padding = getPadding(padLen);
} else {
_padding = new COPSData();
}
_objHdr.setDataLength((short) _id.length());
}
/**
* Returns size in number of octects, including header
* @return a short
*/
public short getDataLength() {
//Add the size of the header also
final int lpadding;
if (_padding != null) lpadding = _padding.length();
else lpadding = 0;
return ((short) (_objHdr.getDataLength() + lpadding));
}
/**
* Get handle value
* @return a COPSData
*/
public COPSData getId() {
return _id;
}
@Override
public boolean isClientHandle() {
return true;
}
@Override
public void writeData(final Socket socket) throws IOException {
_objHdr.writeData(socket);
COPSUtil.writeData(socket, _id.getData(), _id.length());
if (_padding != null) {
COPSUtil.writeData(socket, _padding.getData(), _padding.length());
}
}
/**
* Write an object textual description in the output stream
* @param os an OutputStream
* @throws IOException
*/
public void dump(final OutputStream os) throws IOException {
_objHdr.dump(os);
os.write(("client-handle: " + _id.str() + "\n").getBytes());
}
@Override
public boolean equals(Object o) {
if (this == o) {
return true;
}
if (!(o instanceof COPSHandle)) {
return false;
}
final COPSHandle that = (COPSHandle) o;
return _id.equals(that._id) && _objHdr.equals(that._objHdr);
}
@Override
public int hashCode() {
int result = _objHdr.hashCode();
result = 31 * result + _id.hashCode();
return result;
}
}