⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 pdu.java

📁 Short Message Peer to Peer
💻 JAVA
📖 第 1 页 / 共 3 页
字号:
/*
 * 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 + -