/protocols/smpp/src/main/java/org/mobicents/protocols/smpp/message/tlv/TLVTableImpl.java
Java | 258 lines | 128 code | 22 blank | 108 comment | 21 complexity | 09950570ff79f759f1498d16db13428a MD5 | raw file
1/* 2 * JBoss, Home of Professional Open Source 3 * Copyright 2011, Red Hat, Inc. and individual contributors 4 * by the @authors tag. See the copyright.txt in the distribution for a 5 * full listing of individual contributors. 6 * 7 * This is free software; you can redistribute it and/or modify it 8 * under the terms of the GNU Lesser General Public License as 9 * published by the Free Software Foundation; either version 2.1 of 10 * the License, or (at your option) any later version. 11 * 12 * This software is distributed in the hope that it will be useful, 13 * but WITHOUT ANY WARRANTY; without even the implied warranty of 14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 15 * Lesser General Public License for more details. 16 * 17 * You should have received a copy of the GNU Lesser General Public 18 * License along with this software; if not, write to the Free 19 * Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 20 * 02110-1301 USA, or see the FSF site: http://www.fsf.org. 21 */ 22 23package org.mobicents.protocols.smpp.message.tlv; 24 25import java.io.IOException; 26import java.text.MessageFormat; 27import java.util.BitSet; 28import java.util.LinkedHashMap; 29import java.util.Map; 30 31import org.mobicents.protocols.smpp.message.param.ParamDescriptor; 32import org.mobicents.protocols.smpp.util.PacketDecoder; 33import org.mobicents.protocols.smpp.util.PacketEncoder; 34 35/** 36 * Implementation of the TLVTable interface. 37 * This implementation will maintain the ordering of added parameters. 38 * @version $Id: TLVTableImpl.java 457 2009-01-15 17:37:42Z orank $ 39 */ 40public class TLVTableImpl extends LinkedHashMap<Tag, Object> implements TLVTable { 41 private static final long serialVersionUID = 2L; 42 43 public TLVTableImpl() { 44 } 45 46 /** 47 * Decode a full set of optional parameters from a byte array. 48 */ 49 public void readFrom(PacketDecoder decoder, int length) { 50 int endIndex = (decoder.getParsePosition() + length) - 1; 51 while (decoder.getParsePosition() < endIndex) { 52 Object val = null; 53 Tag tag = Tag.getTag(decoder.readUInt2()); 54 int valueLen = decoder.readUInt2(); 55 ParamDescriptor descriptor = tag.getParamDescriptor(); 56 val = descriptor.readObject(decoder, valueLen); 57 put(tag, val); 58 } 59 } 60 61 /** 62 * Encode all the optional parameters in this table to an output stream. 63 * 64 * @param out 65 * The output stream to encode the parameters to. 66 * @throws java.io.IOException 67 * If an error occurs writing to the output stream. 68 */ 69 public void writeTo(PacketEncoder encoder) throws IOException { 70 for (Map.Entry<Tag, Object> entry : entrySet()) { 71 Tag tag = entry.getKey(); 72 Object value = entry.getValue(); 73 ParamDescriptor descriptor = tag.getParamDescriptor(); 74 int valueLen = descriptor.sizeOf(value); 75 encoder.writeUInt2(tag.intValue()); 76 encoder.writeUInt2(valueLen); 77 descriptor.writeObject(value, encoder); 78 } 79 } 80 81 /** 82 * Get the value for a tag. This is a convenience method to convert 83 * the tag integer to its appropriate Tag object and then look that 84 * tag up in the map. 85 * @param tag The tag's integer value. 86 */ 87 public Object get(int tag) { 88 Tag tagObj = Tag.getTag(tag); 89 return get(tagObj); 90 } 91 92 /** 93 * Get the tag's value as a string. 94 * @param tag The tag to retrieve the value for. 95 * @return The value as a string, or <code>null</code> if the specified 96 * tag is not set in this table. 97 */ 98 public String getString(Tag tag) { 99 Object obj = get(tag); 100 return obj != null ? obj.toString() : null; 101 } 102 103 /** 104 * Get the tag's value as an int. 105 * @param tag The tag to retrieve the value for. 106 * @return The value as an integer, or <code>-1</code> if the specified 107 * tag is not set in this table. 108 * @throws ClassCastException If the value for the specified tag is not 109 * a number (castable as a <code>java.lang.Number</code>). 110 */ 111 public int getInt(Tag tag) { 112 Object obj = get(tag); 113 if (obj != null) { 114 return ((Number) obj).intValue(); 115 } else { 116 return -1; 117 } 118 } 119 120 /** 121 * Get the tag's value as a long. 122 * @param tag The tag to retrieve the value for. 123 * @return The value as a long, or <code>-1</code> if the specified 124 * tag is not set in this table. 125 * @throws ClassCastException If the value for the specified tag is not 126 * a number (castable as a <code>java.lang.Number</code>). 127 */ 128 public long getLong(Tag tag) { 129 Object obj = get(tag); 130 if (obj != null) { 131 return ((Number) obj).intValue(); 132 } else { 133 return -1; 134 } 135 } 136 137 /** 138 * Get the tag's value as a bit set. 139 * @param tag The tag to retrieve the value for. 140 * @return The value, cast as a <code>java.util.BitSet</code>, or 141 * <code>null</code> if the specified tag is not set in this table. 142 * @throws ClassCastException If the value for the specified tag is not 143 * a bit mask. 144 */ 145 public BitSet getBitmask(Tag tag) { 146 return ((BitSet) get(tag)); 147 } 148 149 /** 150 * Get the tag's value as a byte array. 151 * @param tag The tag to retrieve the value for. 152 * @return The value, cast as a <code>byte[]</code>, or <code>null</code> 153 * if the specified tag is not set in this table. 154 * @throws ClassCastException If the value for the specified tag is not 155 * a byte array. 156 */ 157 public byte[] getBytes(Tag tag) { 158 return ((byte[]) get(tag)); 159 } 160 161 /** 162 * Set the value of a TLV. 163 * @param tag The tag of the parameter to set. 164 * @param value The tag's value. 165 * @throws BadValueTypeException If <code>tag</code> does not accept 166 * the type that <code>value</code> is. 167 * @throws InvalidSizeForValueException If <code>value</code> 168 * exceeds either the minimum or maximum size allowed by <code>tag</code>. 169 */ 170 @Override 171 public Object put(Tag tag, Object value) 172 throws BadValueTypeException, InvalidSizeForValueException { 173 ParamDescriptor descriptor = tag.getParamDescriptor(); 174 if (descriptor.equals(BasicDescriptors.NULL) && value != null) { 175 String error = MessageFormat.format( 176 "Tag {0} does not accept any value.", 177 new Object[] {tag}); 178 throw new BadValueTypeException(error); 179 } else if (value == null) { 180 String error = MessageFormat.format( 181 "Tag {0} does not accept a null value.", 182 new Object[] {tag}); 183 throw new BadValueTypeException(error); 184 } 185 186 // Enforce the length restrictions on the Value specified by the 187 // Tag. 188 int min = tag.getMinLength(); 189 int max = tag.getMaxLength(); 190 int actual = descriptor.sizeOf(value); 191 if ((min > -1 && actual < min) || (max > -1 && actual > max)) { 192 throw new InvalidSizeForValueException("Tag " 193 + tag.toHexString() 194 + " must have a length in the range " + min 195 + " <= len <= " + max); 196 } 197 return super.put(tag, value); 198 } 199 200 public Object put(Tag tag, char value) { 201 return put(tag, Character.valueOf(value)); 202 } 203 204 public Object put(Tag tag, short value) { 205 return put(tag, Short.valueOf(value)); 206 } 207 208 public Object put(Tag tag, int value) { 209 return put(tag, Integer.valueOf(value)); 210 } 211 212 public Object put(Tag tag, long value) { 213 return put(tag, Long.valueOf(value)); 214 } 215 216 /** 217 * Remove (or un-set) a tag/value from this table. 218 * @param tag The tag to remove from the table. 219 */ 220 public void remove(int tag) { 221 super.remove(Tag.getTag(tag)); 222 } 223 224 @Override 225 public String toString() { 226 StringBuffer buffer = new StringBuffer(); 227 for (Map.Entry<Tag, Object> entry : entrySet()) { 228 ParamDescriptor descriptor = entry.getKey().getParamDescriptor(); 229 Object value = entry.getValue(); 230 buffer.append('{') 231 .append(entry.getKey().toHexString()) 232 .append(',').append(descriptor.sizeOf(value)) 233 .append(',').append(value); 234 } 235 return buffer.toString(); 236 } 237 238 /** 239 * Get the length the parameters in the table would encode as. The length of 240 * an SMPP packet is determined by: <br> 241 * <code>sizeof (smpp_header) + sizeof (mandatory_parameters) 242 * + sizeof (optional_parameters).</code> 243 * <br> 244 * The value returned for this method is the last clause in this equation. 245 * 246 * @return The full length that the optional parameters would encode as. 247 */ 248 public int getLength() { 249 // Length is going to be (number of options) * (2 bytes for tag) * (2 250 // bytes for length) + (size of all encoded values) 251 int length = size() * 4; 252 for (Map.Entry<Tag, Object> entry : entrySet()) { 253 Tag tag = entry.getKey(); 254 length += tag.getParamDescriptor().sizeOf(entry.getValue()); 255 } 256 return length; 257 } 258}