All Downloads are FREE. Search and download functionalities are using the official Maven repository.

org.smpp.pdu.ByteData Maven / Gradle / Ivy

The newest version!
/*
 * 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.io.UnsupportedEncodingException;
import java.text.SimpleDateFormat;
import java.text.ParseException;

import org.smpp.Data;
import org.smpp.SmppObject;
import org.smpp.util.*;

/**
 * Base class for all object which can be transformed to sequence of bytes
 * and which can be re-read from sequence of bytes. The sequence of bytes
 * is represented by ByteBuffer.
 * Every descendant of this class must implement setData and
 * getData functions.
 * Apart from abstract methods this class contains static methods for checking
 * of validity of certain values like if the length of string is
 * within valid boundary, if the date format is valid etc.
 *
 * @author Logica Mobile Networks SMPP Open Source Team
 * @version $Id: ByteData.java 72 2008-07-15 19:43:00Z sverkera $
 * @see #setData(ByteBuffer)
 * @see #getData()
 */
public abstract class ByteData extends SmppObject {
	/**
	 * Defines a format of part of the smpp defined date format
	 * which is parseable by Java SimpleDateFormat parser.
	 * The rest (nnp) is parsed 'manually'.
	 */
	private static final String SMPP_TIME_DATE_FORMAT = "yyMMddHHmmss";

	/**
	 * The formatter object used for checking if the format of the datetime
	 * string is correct.
	 */
	private static SimpleDateFormat dateFormatter;

	/**
	 * Controls checking of the date-time format in the library.
	 * If this variable to is set to true the library will check if
	 * the date is correctly formated according SMPP spec; if it's
	 * false, then the date will be sent without checking in
	 * the library and the check will be done by the SMSC. Default
	 * is true.
	 * Note that whatever is the setting, the library will still check
	 * the length of the date-time string.
	 */
	private static boolean libraryCheckDateFormat = true;

	/**
	 * Static initialiser initialises the dateFormatter
	 * with format specified for SMPP Date/Time format and sets
	 * other formatter parameters.
	 */
	static {
		dateFormatter = new SimpleDateFormat(SMPP_TIME_DATE_FORMAT);
		dateFormatter.setLenient(false);
	}

	/**
	* This abstract method should parse the buffer with binary data
	* passed as parameter into member variables.
	*
	* @param buffer the data which should contain binary representation of
	*               the class
	* @see #getData()
	* @throws PDUException some data in the buffer were invalid
	* @throws NotEnoughDataInByteBufferException expected more data in
	          the buffer
	* @throws TerminatingZeroNotFoundException the c-string in buffer
	*         wasn't terminated with 0  zero
	*/
	public abstract void setData(ByteBuffer buffer)
		throws PDUException, NotEnoughDataInByteBufferException, TerminatingZeroNotFoundException;

	/**
	* This abstract method should create a binary buffer from it's member
	* variables.
	*
	* @return the binary data buffer created from member variables
	* @see #setData(ByteBuffer)
	* @throws ValueNotSetException thrown from a TLV if the value was
	*         requested but never set
	* @see org.smpp.pdu.tlv.TLV
	* @see org.smpp.pdu.ValueNotSetException
	*/
	public abstract ByteBuffer getData() throws ValueNotSetException;

	/**
	 * Default constructor. Only this is present as this
	 * abstract class doesn't have any member variables.
	 */
	public ByteData() {
	}

	/**
	 * Checks if the length of string is less or equal than the provided
	 * maximum.
	 *
	 * @param string the string to check
	 * @param max    the maximal length of the string
	 * @exception WrongLengthOfStringException thrown if the string is longer
	 *            than the provided max length
	 */
	protected static void checkString(String string, int max) throws WrongLengthOfStringException {
		checkString(string, 0, max);
	}

	/**
	 * Checks if the length of the data of the string is less or equal than
	 * the provided maximum; necessery for multibyte encodings. 
	 * Note that the length checked is the length wfter transforming
	 * the string to series of octets, so two-byte strings will efectively
	 * require space (max size) two-times the length of the string.
	 * @param string the string to check
	 * @param max    the maximal length of the string
	 * @param encoding the encoding of the string
	 * @exception WrongLengthOfStringException thrown if the string is longer
	 *            than the provided max length
	 * @exception UnsupportedEncodingException the required encoding isn't
	 *            supported
	 */
	protected static void checkString(String string, int max, String encoding)
		throws WrongLengthOfStringException, UnsupportedEncodingException {
		checkString(string, 0, max, encoding);
	}

	/**
	 * Checks if the length of string is greater or equal than provided
	 * minimum and less or equal than the provided maximum.
	 *
	 * @param string the string to check
	 * @param min    the minimal length of the string
	 * @param max    the maximal length of the string
	 * @throws WrongLengthOfStringException thrown if the string is shorter
	 *         than min length or longer than max length
	 */
	protected static void checkString(String string, int min, int max) throws WrongLengthOfStringException {
		int length = string == null ? 0 : string.length();
		checkString(min, length, max);
	}

	/**
	 * Checks if the length of the data of the string is greater or equal
	 * than provided minimum and less or equal than the provided maximum;
	 * necessery for multibyte encodings.
	 *
	 * @param string the string to check
	 * @param min    the minimal length of the string
	 * @param max    the maximal length of the string
	 * @param encoding the encoding of the string
	 * @throws WrongLengthOfStringException thrown if the string is shorter
	 *         than min length or longer than max length
	 * @exception UnsupportedEncodingException the required encoding isn't
	 *            supported
	 */
	protected static void checkString(String string, int min, int max, String encoding)
		throws WrongLengthOfStringException, UnsupportedEncodingException {
		byte[] stringBytes = string.getBytes(encoding);
		int length = stringBytes == null ? 0 : stringBytes.length;
		checkString(min, length, max);
	}

	/**
	 * Checks if the integer value representing length is within provided valid
	 * length.
	 *
	 * @param min minimal possible length
	 * @param length the length to check
	 * @param max maximal possible length
	 * @throws  thrown if the value is out of bounds
	 */
	protected static void checkString(int min, int length, int max) throws WrongLengthOfStringException {
		if ((length < min) || (length > max)) {
			throw new WrongLengthOfStringException(min, max, length);
		}
	}

	/**
	 * Checks if the length of the string plus 1 for terminating zero
	 * is less or equal than provided maximum.
	 *
	 * @param string the string to check
	 * @param max    the maximal length of the string with added term. zero
	 * @exception WrongLengthOfStringException thrown if string with added
	 *            terminating zero would be longer than the maximum
	 */
	protected static void checkCString(String string, int max) throws WrongLengthOfStringException {
		checkCString(string, 1, max); // min = empty + 1 for zero
	}

	/**
	 * Checks if the length of the string plus 1 for terminating zero
	 * is greater or equal than provided minimum and less or equal than
	 * provided maximum.
	 *
	 * @param string the string to check
	 
	 * @param min    the minimal length of the string with added term. zero
	 * @param max    the maximal length of the string with added term. zero
	 * @throws WrongLengthOfStringException thrown if string with added
	 *         terminating zero would be shorter than minimum or longer than
	 *         the maximum
	 */
	protected static void checkCString(String string, int min, int max) throws WrongLengthOfStringException {
		int count = string == null ? 1 : (string.length() + 1); // 1 is for terminating zero
		if (count < min || count > max) {
			throw new WrongLengthOfStringException(min, max, count);
		}
	}

	/**
	 * Checks if the string contains valid date string as specified in SMPP spec.
	 *
	 * @param dateStr the date to check
	 * @throws WrongDateFormatException throwsn if the string doesn't
	 *         contain date with valid format
	 */
	protected static void checkDate(String dateStr) throws WrongDateFormatException {
		int count = dateStr == null ? 1 : (dateStr.length() + 1); // 1 is for terminating zero
		if ((count != 1) && (count != Data.SM_DATE_LEN)) {
			throw new WrongDateFormatException(dateStr);
		}
		if ((count == 1) || (!libraryCheckDateFormat)) {
			// i.e. no date provided or don't check the format
			return;
		}
		char locTime = dateStr.charAt(dateStr.length() - 1);
		if ("+-R".lastIndexOf(locTime) == -1) {
			// i.e. the locTime isn't one of the possible values
			throw new WrongDateFormatException(
				dateStr,
				"time difference relation indicator incorrect; " + "should be +, - or R and is " + locTime);
		}
		int formatLen = SMPP_TIME_DATE_FORMAT.length();
		String dateJavaStr = dateStr.substring(0, formatLen);
		synchronized (dateFormatter) {
			try {
				if (locTime == 'R') {
					// check relative date
					// won't check date validity just if it's all number it
					Long.parseLong(dateJavaStr);
				} else {
					// check absolute dates
					dateFormatter.parse(dateJavaStr);
				}
			} catch (ParseException e) {
				debug.write("Exception parsing absolute date " + dateStr + " " + e);
				throw new WrongDateFormatException(dateStr, "format of absolute date-time incorrect");
			} catch (NumberFormatException e) {
				debug.write("Exception parsing relative date " + dateStr + " " + e);
				throw new WrongDateFormatException(dateStr, "format of relative date-time incorrect");
			}
		}
		String tenthsOfSecStr = dateStr.substring(formatLen, formatLen + 1);
		try {
			Integer.parseInt(tenthsOfSecStr);
		} catch (NumberFormatException e) {
			throw new WrongDateFormatException(dateStr, "non-numeric tenths of seconds " + tenthsOfSecStr);
		}
		String timeDiffStr = dateStr.substring(formatLen + 1, formatLen + 3);
		int timeDiff = 0;
		try {
			timeDiff = Integer.parseInt(timeDiffStr);
		} catch (NumberFormatException e) {
			throw new WrongDateFormatException(dateStr, "non-numeric time difference " + timeDiffStr);
		}
		if ((timeDiff < 0) || (timeDiff > 48)) {
			// defined in SMPP v3.4 sect. 7.1.1
			throw new WrongDateFormatException(
				dateStr,
				"time difference is incorrect; " + "should be between 00-48 and is " + timeDiffStr);
		}
	}

	/**
	 * Checks if the integer value is within provided valid range of values.
	 *
	 * @param min minimal possible value
	 * @param val the value to check
	 * @param max maximal possible value
	 * @throws IntegerOutOfRangeException thrown if the value is out of bounds
	 */
	protected static void checkRange(int min, int val, int max) throws IntegerOutOfRangeException {
		if ((val < min) || (val > max)) {
			throw new IntegerOutOfRangeException(min, max, val);
		}
	}

	/**
	 * Allow a variable of type byte to carry lengths or sizes up to 255.
	 * The integral types are signed in Java, so if there is necessary to store
	 * an unsigned type into signed of the same size, the value can be stored
	 * as negative number even if it would be positive in unsigned case.
	 * For example message length can be 0 to 254 and is carried by 1 octet
	 * i.e. unsigned 8 bits. We use a byte variable to read the value from octet stream.
	 * If the length is >127, it is interpreted as negative byte using negative
	 * complement notation.
	 * So length 150 would be interpreted as Java byte -106. If we want to know
	 * the actual value (*length) we need to make a correction to a bigger integral type,
	 * in case of byte it's short. The correction from (negative) byte to short is
* (short)(256+(short)length)
* This converts the negative byte value representing positive length into positive * short value. * @see #encodeUnsigned(short) */ protected static short decodeUnsigned(byte signed) { if (signed >= 0) { return signed; } else { return (short) (256 + (short) signed); } } /** * Provides correction of positive unsigned 2 byte carried * by (signed) short into positive signed int. * See explanation in decodeUnsigned(byte). * @see #decodeUnsigned(byte) * @see #encodeUnsigned(int) */ protected static int decodeUnsigned(short signed) { if (signed >= 0) { return signed; } else { return (int) (65536 + (int) signed); } } /** * Complementary operation to decodeUnsigned. * @see #decodeUnsigned(byte) */ protected static byte encodeUnsigned(short positive) { if (positive < 128) { return (byte) positive; } else { return (byte) (- (256 - positive)); } } /** * Complementary operation to decodeUnsigned. * @see #decodeUnsigned(byte) * @see #decodeUnsigned(short) */ protected static short encodeUnsigned(int positive) { if (positive < 32768) { // [email protected] 2005-09-22: no, this isn't right! Casting the // short to a byte here overflows the byte, converts it back to a // short, and produces a bogus result. This was the cause of a bug // whereby invalid TLVs were produced: try creating a TLV longer than // 127 octets and see what happens... //return (byte)positive; return (short)positive; } else { return (short) (- (65536 - positive)); } } /** * Returns human readable version of the data carried by the object. * Derived classes should override this method with possible inclusion * of result of super.debugString(). * * @return the textual form of the content of the object */ public String debugString() { return new String(""); } } /* * $Log: not supported by cvs2svn $ * Revision 1.2 2005/09/25 09:33:45 paoloc * Fixed bug in encodeUnsigned(int): if one created a TLV longer than 127 octets, the resul was invalid (invalid L) * * Revision 1.1 2003/07/23 00:28:39 sverkera * Imported * * * Old changelog: * 13-07-01 [email protected] indentation fixed, tabs aren't used anymore * 03-10-01 [email protected] string passed as a parameter to the string length * checking routines is now checked first if it's not null * 03-10-01 [email protected] the datetime string format is fully checked * in the function checkDate according to the date format * spec in smpp * 31-10-01 [email protected] added methods for correction from 'smaller' int negative * to 'bigger' int positive (for variables carrying lengths) * (several times reported this, thanks!) * 15-11-01 [email protected] added support for checking length of data produced * from string with multibyte encoding * 16-11-01 [email protected] added method for checking if length provided as int * is within provided bounds * 20-11-01 [email protected] fixed date checking where relative dates were * rejected as incorrect; now relative dates are checked * only partially */




© 2015 - 2024 Weber Informatics LLC | Privacy Policy