📄 pdu.java
字号:
sequenceNumberChanged = true;
}
/** If the command status of the PDU is ESME_ROK. */
public boolean isOk() {
return getCommandStatus() == Data.ESME_ROK;
}
/**
* If the PDU carries generic_nack despite of the class of the object.<br>
* Under some wierd conditions there is need to "encapsulate" generic
* negative acknowledge information into instance of class different
* from <code>GenericNack</code> class. For example synchronous
* call to the <code>Session</code>'s <code>submit</code> method
* should return instance of <code>SubmitSMResp</code> class.
* If the from some reason the SMSC returns generic_nack as a response
* to the submit_sm, then the library must somehow overcome the type
* checking for the return type and thus it creates instance of
* <code>SubmitSMResp</code> but then it sets the command id
* the id for generic_nack.
* @return of the object carries generic_nack pdu rather than pdu
* as could be indicated from the object's class
* @see org.smpp.Session#checkResponse(PDU,Response)
*/
public boolean isGNack() {
return getCommandId() == Data.GENERIC_NACK;
}
/**
* This method gets the buffer and returns an instance of class
* corresponding to the type of the PDU which was in the buffer; the
* fields of the returned PDU are set to the data from the buffer.<br>
* Cool, isn't it.
* @see #createPDU(int)
*/
public static final PDU createPDU(ByteBuffer buffer)
throws
HeaderIncompleteException,
MessageIncompleteException,
UnknownCommandIdException,
InvalidPDUException,
TLVException,
PDUException {
ByteBuffer headerBuf = null;
try {
// readBytes just reads bytes from the buffer but
// doesn't alter the buffer
headerBuf = buffer.readBytes(Data.PDU_HEADER_SIZE);
} catch (NotEnoughDataInByteBufferException e) {
// incomplete header
throw new HeaderIncompleteException();
}
PDUHeader header = new PDUHeader();
try {
header.setData(headerBuf);
} catch (NotEnoughDataInByteBufferException e) {
// must be enough, we've checked it above
}
if (buffer.length() < header.getCommandLength()) {
// not enough data in the buffer => throwing
// Receiver must wait for more data
throw new MessageIncompleteException();
}
PDU pdu = createPDU(header.getCommandId());
if (pdu != null) {
// paolo@bulksms.com: more consistent & safe to remove whatever we plan
// to read from the buffer here already - stops problems with our parsing,
// for instance, reading _too much_ data from the buffer because of an
// invalid PDU (via, say, removeCString() in ByteBuffer):
ByteBuffer thisMessageBuffer = null;
try {
thisMessageBuffer = buffer.removeBuffer(header.getCommandLength());
} catch (NotEnoughDataInByteBufferException e) {} // can't fail
pdu.setData(thisMessageBuffer);
return pdu;
} else {
// if not found, throw
throw new UnknownCommandIdException(header);
}
}
/**
* Creates an empty instance of class which represents the PDU
* with given command id.
*/
public static final PDU createPDU(int commandId) {
int size = pduList.size();
PDU pdu = null;
PDU newInstance = null;
for (int i = 0; i < size; i++) {
pdu = (PDU) pduList.get(i);
if (pdu != null) {
if (pdu.getCommandId() == commandId) {
try {
newInstance = (PDU) (pdu.getClass().newInstance());
} catch (IllegalAccessException e) {
// can't be illegal access, we initialised
// the list with instances of our classes
} catch (InstantiationException e) {
// can't be instantiation as we already instantiated
// at least once, for both exception see help
// for Class.newInstance()
}
return newInstance;
}
}
}
return null;
}
/**
* Creates a list of instancies of classes which can represent a PDU.
* This list is used in <code>createPDU</code> to create a PDU
* from a binary buffer.
* @see #createPDU(ByteBuffer)
* @see #createPDU(int)
*/
static {
pduList = new Vector(30, 4);
pduList.add(new BindTransmitter());
pduList.add(new BindTransmitterResp());
pduList.add(new BindReceiver());
pduList.add(new BindReceiverResp());
pduList.add(new BindTransciever());
pduList.add(new BindTranscieverResp());
pduList.add(new Unbind());
pduList.add(new UnbindResp());
pduList.add(new Outbind());
pduList.add(new SubmitSM());
pduList.add(new SubmitSMResp());
pduList.add(new SubmitMultiSM());
pduList.add(new SubmitMultiSMResp());
pduList.add(new DeliverSM());
pduList.add(new DeliverSMResp());
pduList.add(new DataSM());
pduList.add(new DataSMResp());
pduList.add(new QuerySM());
pduList.add(new QuerySMResp());
pduList.add(new CancelSM());
pduList.add(new CancelSMResp());
pduList.add(new ReplaceSM());
pduList.add(new ReplaceSMResp());
pduList.add(new EnquireLink());
pduList.add(new EnquireLinkResp());
pduList.add(new AlertNotification());
pduList.add(new GenericNack());
}
public String debugString() {
String dbgs = "(pdu: ";
dbgs += super.debugString();
dbgs += Integer.toString(getCommandLength());
dbgs += " ";
dbgs += Integer.toHexString(getCommandId());
dbgs += " ";
dbgs += Integer.toHexString(getCommandStatus());
dbgs += " ";
if (sequenceNumberChanged) {
dbgs += Integer.toString(getSequenceNumber());
} else {
// it's likely that this will be the assigned seq number
// (in simple cases :-)
dbgs += "[" + (sequenceNumber + 1) + "]";
}
dbgs += ") ";
return dbgs;
}
/** Returns debug string from provided optional parameters. */
protected String debugStringOptional(String label, Vector optionalParameters) {
String dbgs = "";
int size = optionalParameters.size();
if (size > 0) {
dbgs += "(" + label + ": ";
TLV tlv = null;
for (int i = 0; i < size; i++) {
tlv = (TLV) optionalParameters.get(i);
if ((tlv != null) && (tlv.hasValue())) {
dbgs += tlv.debugString();
dbgs += " ";
}
}
dbgs += ") ";
}
return dbgs;
}
/** Returns debug string of all optional parameters. */
protected String debugStringOptional() {
String dbgs = "";
dbgs += debugStringOptional("opt", optionalParameters);
dbgs += debugStringOptional("extraopt", extraOptionalParameters);
return dbgs;
}
/**
* Compares two PDU. Two PDUs are equal if their sequence number is equal
* ( and now, if their command ids match as well).
*/
public boolean equals(Object object) {
if ((object != null) && (object instanceof PDU)) {
PDU pdu = (PDU) object;
return (pdu.getSequenceNumber() == getSequenceNumber() &&
pdu.getCommandId() == getCommandId());
} else {
return false;
}
}
/**
* Sets the PDU extra information <code>value</code> with key
* <code>key</code>.
* This information is not sent anywhere nor the library uses this information
* in any means. It's intended for use by applicaitons to pass
* information about the PDU from one part of the application to another
* without need of extra PDU management.
*/
public void setApplicationSpecificInfo(Object key, Object value) {
if (applicationSpecificInfo == null) {
applicationSpecificInfo = new java.util.Hashtable();
}
debug.write(
DPDU,
"setting app spec info key=\"" + key + "\" value=\"" + (value == null ? "null" : value) + "\"");
applicationSpecificInfo.put(key, value);
}
/**
* Sets the PDU extra information as a copy of existing Dictionary.
* The Dictionary is shallow copied, i.e. new container is created for the PDU
* and elements are put into the new container without copying.
* @see #setApplicationSpecificInfo(Object,Object)
* @see #cloneApplicationSpecificInfo(Dictionary)
*/
public void setApplicationSpecificInfo(Dictionary applicationSpecificInfo) {
this.applicationSpecificInfo = cloneApplicationSpecificInfo(applicationSpecificInfo);
}
/**
* Returns extra information with key <code>key</code>. If the information
* is not found for this PDU, returns <code>null</code>.
* @see #setApplicationSpecificInfo(Object,Object)
*/
public Object getApplicationSpecificInfo(Object key) {
Object value = null;
if (applicationSpecificInfo != null) {
value = applicationSpecificInfo.get(key);
}
debug.write(
DPDU,
"getting app spec info key=\"" + key + "\" value=\"" + (value == null ? "null" : value) + "\"");
return value;
}
/**
* Returns all the extra information related to this PDU. If there is no
* information found for this PDU, returns <code>null</code>.
* @see #setApplicationSpecificInfo(Object,Object)
*/
public Dictionary getApplicationSpecificInfo() {
return cloneApplicationSpecificInfo(applicationSpecificInfo);
}
/**
* Removes an extra information with the given <code>key</code>
* from this PDU.
* @see #setApplicationSpecificInfo(Object,Object)
*/
public void removeApplicationSpecificInfo(Object key) {
if (applicationSpecificInfo != null) {
applicationSpecificInfo.remove(key);
}
}
/**
* Creates a shallow copy of the provided Dictionary, i.e. new container
* structure is created, but the keys and elements from the original
* Dictionary aren't cloned, htey are only put to the new structure.
*/
private Dictionary cloneApplicationSpecificInfo(Dictionary info) {
Dictionary newInfo = null;
if (info != null) {
newInfo = new java.util.Hashtable();
Enumeration keys = info.keys();
Object key;
Object value;
while (keys.hasMoreElements()) {
key = keys.nextElement();
value = info.get(key);
newInfo.put(key, value);
}
}
return newInfo;
}
}
/*
* $Log: PDU.java,v $
* Revision 1.7 2006/02/22 16:40:50 paoloc
* Updated documentation for equals()
*
* Revision 1.6 2005/09/25 10:12:55 paoloc
* Fixed bug 872640, probably introduced during refactoring from original Logica code - bracketing error, which would cause certain code to run only if debugging was active.
*
* Revision 1.5 2004/09/10 23:10:54 sverkera
* Corrected issue with optional parameters
*
* Revision 1.4 2004/09/04 08:55:20 paoloc
* Now immediately removes the amount of data implied by command_length before parsing further - before, it was possible for parsing to read beyond the end of the PDU, via ByteBuffer methods like removeCString(). Of course, this sort of thing only happens when invalid PDUs are being parsed.
*
* Revision 1.3 2003/12/16 15:06:48 sverkera
* Bugfix from smsforum.net
* If an smpp connection established with the SMSC is idle,
* the smsc sends enquire_link to the esme periodically, these
* pdus are queue up in the receiver queue. After a bunch of these
* pdus queue up, if you send a submit and the sequence number of this
* submit request matches any of the sequence numbers of the enquire_link pdus already in the queue, this code returns the wrong pdu as the response to the submit request and gives a false impression that it failed.
*
* Revision 1.2 2003/07/24 14:30:36 sverkera
* Solved a bug which caused exception to be thrown when there are no body
*
* Revision 1.1 2003/07/23 00:28:39 sverkera
* Imported
*
*
* Old changelog:
* 13-07-01 ticp@logica.com added assignSequenceNumber(boolean) to allow
* assigning seq nr even if the seq nr has been
* already changed
* 13-07-01 ticp@logica.com debug of buffer in hex is now printed in setData
* and getData methods
* 23-08-01 ticp@logica.com in setData() added test if the data following
* mandatory params can be optional params, i.e.
* if command length indicates that there are more data
* after parsing mandatory params. before if the buffer
* contained more data (e.g. more than 1 pdu) the
* additional data were parsed as opt params even
* if they were beyond the command length
* 23-08-01 ticp@logica.com cosmetic change: tabs replaced by spaces
* 26-09-01 ticp@logica.com method resetSequenceNumber() added which causes
* that the PDU 'forgets' that it's sequence number
* was already set, so if submitted again it'll get new one
* 02-10-01 ticp@logica.com comments added
* 02-10-01 ticp@logica.com debug now belongs to DPDU and DPDUD groups
* 02-10-01 ticp@logica.com fixed bug in setData which could cause the optional
* params to be read beyond the indicated length of PDU
* 02-10-01 ticp@logica.com equals now checks if the object to be compared to
* is instance of PDU
* 09-10-01 ticp@logica.com added possibility to attach to PDU some application
* specific data
* 16-10-01 ticp@logica.com added checking if debug's group is active when logging
* the buffer's hex dump in setData and getData
* 16-10-01 ticp@logica.com improved parsing of the pdu for the sake of debug
* debug speed improvement (in setData())
* 20-11-01 ticp@logica.com added support for additional (extra) optional
* parameters which aren't defined in the specs
*/
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -