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

📄 tlvtable.java

📁 SMPP(点到点短消息协议)的java实现
💻 JAVA
字号:
package ie.omk.smpp.message.tlv;import ie.omk.smpp.util.SMPPIO;import java.io.IOException;import java.io.OutputStream;import java.util.HashMap;import java.util.Iterator;import java.util.Map;/** * Table of optional parameters (TLVs). * <p> * TLV stands for Tag/Length/Value and was a capability added to SMPP version * 3.4. It is an extensible means of adding new parameter types to SMPP packets. * Each optional parameter has a 2-byte tag, which is a unique identifier of * that parameter, a 2-byte length, which is an integer value representing the * length of the value of the parameter and a value. The value may be of various * types including integers, C Strings, octet strings, bit masks etc. The tag * defines the type of the value. * </p> * <p> * This class holds a mapping of tags to values. Each SMPP packet holds a TLV * table which holds that packet's set of current optional parameters. Upon * serializing the packet to an output stream or byte array, the format of the * serialized packet is: * </p> *  * <pre> *  *    +-------------------------+ *    | SMPP Packet             | *    | +----------------------+| *    | | SMPP Header          || *    | +----------------------+| *    | |                      || *    | |                      || *    | | Mandatory parameters || *    | |                      || *    | |                      || *    | +----------------------+| *    | | Optional parameters  || *    | | +------------------+ || *    | | | Tag/Length/Value | || *    | | +------------------+ || *    | | |     ...          | || *    | | +------------------+ || *    | +----------------------+| *    +-------------------------+ *   * </pre> *  * @author Oran Kelly * @version $Id: TLVTable.java 267 2006-03-09 16:37:31Z orank $ */public class TLVTable implements java.io.Serializable {    static final long serialVersionUID = -4113000096792513355L;    /**     * Map of tag to values.     */    private Map map = new HashMap();    /**     * Undecoded options. TLVTable is lazy about decoding optional parameters.     * It will decode a TLV param only when it is requested using the     * <code>get</code> method. Certain method calls, however, will force     * TLVTable to parse the entire set of options (using     * <code>parseAllOpts</code>). When that happens, this array is released     * for garbage collection.     */    private byte[] opts;    /**     * Create a new, empty, TLVTable.     */    public TLVTable() {    }    /**     * Decode a full set of optional parameters from a byte array.     *      * @param b     *            The byte array to decode from.     * @param offset     *            The first byte of the tag of the first optional parameter.     * @param len     *            The length in the byte array of all the optional parameters.     */    public void readFrom(byte[] b, int offset, int len) {        synchronized (map) {            opts = new byte[len];            System.arraycopy(b, offset, opts, 0, len);        }    }    /**     * Encode all the optional parameters in this table to an output stream.     *      * @param out     *            The output stream to encode the parameters to.     * @throws java.io.IOException     *             If an error occurs writing to the output stream.     */    public void writeTo(OutputStream out) throws IOException {        synchronized (map) {            byte[] buffer = new byte[1024];            Iterator i = map.keySet().iterator();            while (i.hasNext()) {                Tag t = (Tag) i.next();                Encoder enc = t.getEncoder();                Object v = map.get(t);                int l = enc.getValueLength(t, v);                if (buffer.length < (l + 4)) {                    buffer = new byte[l + 4];                }                SMPPIO.intToBytes(t.intValue(), 2, buffer, 0);                SMPPIO.intToBytes(l, 2, buffer, 2);                enc.writeTo(t, v, buffer, 4);                // write the buffer out.                out.write(buffer, 0, l + 4);            }        }    }    /**     * Get the value for a tag. Note that this method can return null in two     * cases: if the parameter is not set or if the value is null, which can     * occur if the particular tag type has no value. To check if a parameter     * which has no value is set, use {@link #isSet}.     *      * @param tag     *            The tag to get the value for.     * @return The currently set value for <code>tag</code>, or null if it is     *         not set.     */    public Object get(Tag tag) {        Object v = map.get(tag);        if (v == null) {            v = getValueFromBytes(tag);        }        return v;    }    /**     * Get the value for a tag.     *      * @see #get(ie.omk.smpp.message.tlv.Tag)     */    public Object get(int tag) {        Tag tagObj = Tag.getTag(tag);        Object v = map.get(tagObj);        if (v == null) {            v = getValueFromBytes(tagObj);        }        return v;    }    /**     * Check if an optional parameter currently has a value set.     *      * @param tag     *            The tag of the parameter to check is set.     * @return true if the parameter is set, false if not.     */    public boolean isSet(Tag tag) {        return map.containsKey(tag);    }    /**     * Set a value for an optional parameter.     *      * @param tag     *            The tag of the parameter to set.     * @param value     *            The value of the parameter to set.     * @return The previous value for the parameter, or null if there was none.     * @throws ie.omk.smpp.message.tlv.BadValueTypeException     *             if an attempt is made to set a value using a Java type that     *             is not allowed for that parameter type.     * @throws ie.omk.smpp.message.tlv.InvalidSizeForValueException     *             if the value's encoded length is outside the bounds allowed     *             for that parameter.     */    public Object set(Tag tag, Object value) throws BadValueTypeException,            InvalidSizeForValueException {        synchronized (map) {            if (opts != null) {                parseAllOpts();            }            if (tag.getType() == null) {                if (value != null) {                    throw new BadValueTypeException("Tag "                            + Integer.toHexString(tag.intValue())                            + " does not accept a value.");                }            } else if (!tag.getType().isAssignableFrom(value.getClass())) {                throw new BadValueTypeException("Tag "                        + Integer.toHexString(tag.intValue())                        + " expects a value of type " + tag.getType());            }            // Enforce the length restrictions on the Value specified by the            // Tag.            int min = tag.getMinLength();            int max = tag.getMaxLength();            int actual = tag.getEncoder().getValueLength(tag, value);            boolean illegal = min > -1 && actual < min;            if (!illegal) {                illegal = max > -1 && actual > max;            }            if (illegal) {                throw new InvalidSizeForValueException("Tag "                        + Integer.toHexString(tag.intValue())                        + " must have a length in the range " + min                        + " <= len <= " + max);            }            return map.put(tag, value);        }    }    /**     * Clear all optional parameters out of this table.     */    public void clear() {        synchronized (map) {            map.clear();        }    }    /**     * Force the TLVTable to parse all the optional parameters from the internal     * byte array and place them in the map. Normally, TLVTable is lazy about     * parsing parameters. It will only decode them and place them in the     * internal map when they are requested using {@link #get}. Calling this     * method causes all the parameters to be parsed and placed in the internal     * map and the byte array containing the parameter's bytes to be released     * for garbage collection.     * <p>     * It is not normally needed for an application to call this method.     * <code>TLVTable</code> uses it internally when necessary to ensure there     * is no loss of synchronization between the internal map and the byte     * array.     */    public final void parseAllOpts() {        synchronized (map) {            int p = 0;            while (p < opts.length) {                Object val = null;                Tag t = Tag.getTag(SMPPIO.bytesToInt(opts, p, 2));                Encoder enc = t.getEncoder();                int l = SMPPIO.bytesToInt(opts, p + 2, 2);                val = enc.readFrom(t, opts, p + 4, l);                map.put(t, val);                p += 4 + l;            }            opts = null;        }    }    /**     * Get the value of an option from the <code>opts</code> byte array.     *      * @param tag     *            The tag to get the value for.     * @return The value object for tag <code>tag</code>.<code>null</code>     *         if it is not set.     */    private Object getValueFromBytes(Tag tag) {        if (opts == null || opts.length < 4) {            return null;        }        Encoder enc = tag.getEncoder();        Object val = null;        int p = 0;        while (true) {            int t = SMPPIO.bytesToInt(opts, p, 2);            int l = SMPPIO.bytesToInt(opts, p + 2, 2);            if (tag.equals(t)) {                val = enc.readFrom(tag, opts, p + 4, l);                synchronized (map) {                    map.put(tag, val);                    break;               }            }            p += 4 + l;            if (p >= opts.length) {                break;            }        }        return val;    }    /**     * Get the length the parameters in the table would encode as. The length of     * an SMPP packet is determined by: <br>     * <code>sizeof (smpp_header) + sizeof (mandatory_parameters)     * + sizeof (optional_parameters).</code>     * <br>     * The value returned for this method is the last clause in this equation.     *      * @return The full length that the optional parameters would encode as.     */    public int getLength() {        if (opts != null) {            parseAllOpts();        }        // Length is going to be (number of options) * (2 bytes for tag) * (2        // bytes for length) + (size of all encoded values)        int length = map.size() * 4;        Tag tag;        Encoder enc;        Iterator i = map.keySet().iterator();        while (i.hasNext()) {            tag = (Tag) i.next();            enc = tag.getEncoder();            length += enc.getValueLength(tag, map.get(tag));        }        return length;    }    /**     * Get the set of tags in this TLVTable.     *      * @return A java.util.Set containing all the Tags in this TLVTable.     */    public java.util.Set tagSet() {        if (opts != null) {            parseAllOpts();        }        return map.keySet();    }    /**     * Get a Collection view of the set of values in this TLVTable.     *      * @return A java.util.Collection view of all the values in this TLVTable.     */    public java.util.Collection values() {        if (opts != null) {            parseAllOpts();        }        return map.values();    }}

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -