?? pdu.java
字號:
/*
* Copyright (c) 1996-2001
* Logica Mobile Networks Limited
* All rights reserved.
*
* This software is distributed under Logica Open Source License Version 1.0
* ("Licence Agreement"). You shall use it and distribute only in accordance
* with the terms of the License Agreement.
*
*/
package org.smpp.pdu;
import java.util.Dictionary;
import java.util.Enumeration;
import java.util.Vector;
import org.smpp.Data;
import org.smpp.pdu.tlv.TLV;
import org.smpp.pdu.tlv.TLVException;
import org.smpp.pdu.tlv.TLVOctets;
import org.smpp.util.*;
/**
* Class <code>PDU</code> is abstract base class for all classes which
* represent a PDU. It contains methods for manipulating PDU header,
* checking validity of PDU, automatic parsing and generation of optional
* part of PDU, methods for creating instance of proper class representing
* certain PDU based only in command id, methods for detection if the
* PDU is request or response PDU, automatic sequence number
* assignment, etc. It also implements <code>setData</code> and
* <code>getData</code> methods as the header and optional params
* parsing and composition is the same for all PDUs. The derived
* classes on turn implement functions <code>setBody</code> and
* <code>getBody</code>.
* <p>
* The <code>PDU</code> has two descendants, <code>Request</code> and
* <code>Response</code>, which serve as a base classes for concrete
* PDU classes like SubmitSM, SubmitSMResp etc.
*
* @author Logica Mobile Networks SMPP Open Source Team
* @version $Revision: 1.7 $
*/
public abstract class PDU extends ByteData {
/**
* This constant indicates that parsing of the buffer failed
* parsing of the header of PDU.
*
* @see #setData(ByteBuffer)
* @see #valid
*/
public static final byte VALID_NONE = 0;
/**
* This constant indicates that parsing of the buffer passed
* parsing of the header of PDU but failed parsing of mandatory
* part of body.
*
* @see #setData(ByteBuffer)
* @see #valid
*/
public static final byte VALID_HEADER = 1;
/**
* This constant indicates that parsing of the buffer passed
* parsing of the mandatory part of body of PDU but failed parsing
* of optional parameters.
*
* @see #setData(ByteBuffer)
* @see #valid
*/
public static final byte VALID_BODY = 2;
/**
* This constant indicates that parsing of the buffer passed
* all parts of the PDU, i.e. headet, mandator and optional
* parameters.
*
* @see #setData(ByteBuffer)
* @see #valid
*/
public static final byte VALID_ALL = 3;
/**
* This vector contains instances of all possible PDUs whic can be
* received and sent. It is used to create new instance of
* class based only on command id.
*
* @see #createPDU(int)
* @see #createPDU(ByteBuffer)
*/
private static Vector pduList = null;
/**
* This is counter of sequence numbers. Each time the method
* <code>assignSequenceNumber</code> is called, this counter
* is increased and the it's value is assigned as a sequence number
* of th PDU.
*
* @see #assignSequenceNumber()
*/
private static int sequenceNumber = 0;
/**
* Indicates that the sequence number has been changed either by setting
* by method <code>setSequenceNumber(int) or by reading from buffer by
* method <code>setHeader</code>.
*
* @see #setSequenceNumber(int)
* @see #assignSequenceNumber()
*/
private boolean sequenceNumberChanged = false;
/**
* This is the header of the PDU. It's only created when necessary.
* <code>PDU</code> class implements accessor methdos for setting
* and getting parameters of header like comand id, sequence
* number etc.
*
* @see #checkHeader()
* @see #setHeader(ByteBuffer)
* @see #getHeader()
*/
private PDUHeader header = null;
/**
* This contains all optional parameters defined for particular
* concrete PDU. E.g. for submit_sm class <code>SubmitSM</code>
* puts here all it's possible optional parameters. It is used
* to build a byte buffer from optional parameters as well as
* fill them from a buffer.
*
* @see #registerOptional(TLV)
* @see TLV
*/
private Vector optionalParameters = new Vector(10, 2);
/**
* Contains optional parameters which aren't defined in the SMPP spec.
*
* @see #setExtraOptional(TLV)
* @see #setExtraOptional(short,ByteBuffer)
* @see #getExtraOptional(short)
* @see #registerExtraOptional(TLV)
*/
private Vector extraOptionalParameters = new Vector(1, 1);
/**
* This indicates what stage was reached when parsing byte buffer
* in <code>setData</code> method.
*
* @see #VALID_NONE
* @see #VALID_HEADER
* @see #VALID_BODY
* @see #VALID_ALL
* @see #setData(ByteBuffer)
*/
private byte valid = VALID_ALL;
/**
* Application developers can attach application specific data to an instance
* of PDU or derived class. This facility can be used to carry data
* over different components of the application in the PDU without explicit
* development of PDU to data mapping functionality.
* Typical use would be attaching an information about data from which a
* Request was created and after receiving a Response to that Request
* these data can be used for controling the proper reaction to the Response.
* If you use string gey, be carefull and choose a key which would be expected
* to be unique, fo example your class name qualified with full package name
* and with additional key description name appended.
* @see #setApplicationSpecificInfo(Object,Object)
* @see #getApplicationSpecificInfo(Object)
* @see #removeApplicationSpecificInfo(Object)
*/
private Dictionary applicationSpecificInfo = null;
/**
* Default constructor, what else.
*/
public PDU() {
super();
}
/**
* Initialises PDU with given command id. Derived classes should
* provide correct command id for their type, e.g. SubmitSM should
* provide <code>Data.SUBMIT_SM</code>, which is equal to 4 (as defined
* in SMPP 3.4 spec.)
*
* @param commandId the numerical id of the PDU as specified in SMPP
* specification
*/
public PDU(int commandId) {
super();
checkHeader();
setCommandId(commandId);
}
/**
* Default method for seting mandatory parameters of the PDU.
* Derived classes should overwrite this method if they want
* to fill their member variables with data from the binary
* data buffer.
*
* @param buffer the buffer with the PDU's data as received from SMSC
* @see #setData(ByteBuffer)
*/
public void setBody(ByteBuffer buffer)
throws NotEnoughDataInByteBufferException, TerminatingZeroNotFoundException, PDUException {
}
/**
* Default method for composing binary representation of
* the mandatory part of the PDU. Derived classes should overwrite this
* method with composition of buffer from their member variables.
*
* @see #getData()
*/
public ByteBuffer getBody() throws ValueNotSetException {
return null;
}
/**
* This method indicates that the object represents PDU which can
* and should be responded to. For example for <code>SubmitSM</code>
* class this should return <code>true</code>, while for
* <code>SubmitSMResp</code> or <code>AlertNotification</code> classes
* this should return <code>false</code>. This method is overwritten in
* class <code>Request</code> as most "request" PDUs have response
* counterparts. (Exception to this rule is above mentioned
* <code>AlertNotification</code> which doesn't have response.)
* @return if the PDU can have a response
* @see Request#canResponse()
* @see Response#canResponse()
* @see AlertNotification#canResponse()
*/
public boolean canResponse() {
return false;
}
/**
* Returns if the object represents PDU which is a request.
* E.g. classes derived from <code>Request</code> class return
* <code>true</code>.
* @return if the PDU represents request
*/
public abstract boolean isRequest();
/**
* Returns if the object represents PDU which is response.
* E.g. classes derived from <code>Response</code> class return
* <code>true</code>.
* @return if the PDU represents response
*/
public abstract boolean isResponse();
/**
* Assigns newly generated sequence number if the sequence number
* hasn't been assigned yet. Doesn't have any effect if the sequence
* number was already assigned.
*
* @see #assignSequenceNumber(boolean)
* @see #setSequenceNumber(int)
* @see #setHeader(ByteBuffer)
*/
public void assignSequenceNumber() {
assignSequenceNumber(false);
}
/**
* Assigns newly generated sequence number. If the sequence
* number was previously set by <code>setSequenceNumber</code> method or
* from byte buffer in <code>setHeader</code>, this method only assigns the
* number if the parameter <code>always</code> is true.
*
* @param always if the number has to be assigned even if it was already assigned
* @see #setSequenceNumber(int)
* @see #setHeader(ByteBuffer)
*/
public void assignSequenceNumber(boolean always) {
if ((!sequenceNumberChanged) || always) {
setSequenceNumber(++sequenceNumber);
}
}
/**
* If the sequence number was previously set to a value, this function
* resets that fact. I.e. if the PDU is re-used for another say submit,
* then after calling of this function a new sequence number will
* assigned to it the PDU despite of the fact that there was another one
* assigned to it before.
*/
public void resetSequenceNumber() {
setSequenceNumber(0);
sequenceNumberChanged = false;
}
/**
* Parses the binary buffer to get the PDUs header, fields from mandatory
* part and fields from the optional part.<br>
* The header and optional part are parsed common way for all PDUs
* using functions <code>setHeader</code> and <code>setOptionalBody</code>
* the mandatory body is parsed by the derived classes in
* <code>setBody</code> function. If parsing throws an exception, the PDU's
* <code>getValid</code> function returns the phase which was correct
* last.<br>
* The buffer can contain more than one PDU, then only one PDU is taken
* from the buffer and the rest remains unaltered.
* @param buffer the buffer containg the PDU binary data which are source
* for the content of the fields of this PDU
* @see #setHeader(ByteBuffer)
* @see #setBody(ByteBuffer)
* @see #setOptionalBody(ByteBuffer)
* @see #getValid()
* @see #getData()
*/
public void setData(ByteBuffer buffer) throws InvalidPDUException, PDUException {
int initialBufLen = buffer.length();
try {
setValid(VALID_NONE);
// first try read header
if (buffer.length() < Data.PDU_HEADER_SIZE) {
if (debug.active(DPDU)) {
debug.write(DPDU, "PDU.setData() not enough data for header in the buffer " + buffer.getHexDump());
}
}
// get the header from the buffer
ByteBuffer headerBuf = buffer.removeBytes(Data.PDU_HEADER_SIZE);
if (debug.active(DPDU)) {
debug.write(DPDU, "PDU.setData() parsing header " + headerBuf.getHexDump());
}
setHeader(headerBuf);
setValid(VALID_HEADER);
// now read pdu's body for hex dump
if (debug.active(DPDU)) {
if (getCommandLength() > Data.PDU_HEADER_SIZE) {
ByteBuffer tempBodyBuf = buffer.readBytes(getCommandLength() - Data.PDU_HEADER_SIZE);
debug.write(DPDU, "PDU.setData() parsing body " + tempBodyBuf.getHexDump());
} else {
debug.write(DPDU, "PDU.setData() no data for body");
}
}
// parse the body
setBody(buffer);
setValid(VALID_BODY);
if ((initialBufLen - buffer.length()) < getCommandLength()) {
// i.e. parsed less than indicated by command length =>
// must have optional parameters
int optionalLength = getCommandLength() + buffer.length() - initialBufLen;
try {
debug.write(DPDU, "have " + optionalLength + " bytes left.");
ByteBuffer optionalBody = buffer.removeBuffer(optionalLength);
setOptionalBody(optionalBody);
} catch(Exception e) {
debug.write(DPDU, "Parsing optional parameters failed: " + e.getMessage());
}
}
setValid(VALID_ALL);
} catch (NotEnoughDataInByteBufferException e) {
?? 快捷鍵說明
復制代碼
Ctrl + C
搜索代碼
Ctrl + F
全屏模式
F11
切換主題
Ctrl + Shift + D
顯示快捷鍵
?
增大字號
Ctrl + =
減小字號
Ctrl + -