/protocols/smpp/src/main/java/org/mobicents/protocols/smpp/gsm/UserDataImpl.java

http://mobicents.googlecode.com/ · Java · 185 lines · 121 code · 14 blank · 50 comment · 26 complexity · 357b94e4cdbe44ef42794c223ebca1fb 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. package org.mobicents.protocols.smpp.gsm;
  23. import java.nio.ByteBuffer;
  24. import java.util.ArrayList;
  25. import java.util.Collections;
  26. import java.util.LinkedList;
  27. import java.util.List;
  28. /**
  29. * Implementation of {@link UserData}.
  30. *
  31. * <p>This implementation automatically handles the inclusion of the
  32. * concatenated SMS {@link HeaderElement}. Calling code should <strong>not
  33. * </strong> attempt to add a {@link ConcatenatedSms} header element
  34. * via {@link #addHeaderElement(HeaderElement)}.</p>
  35. * @version $Id: UserDataImpl.java 486 2010-02-15 10:48:15Z orank $
  36. */
  37. public class UserDataImpl implements UserData {
  38. private LinkedList<HeaderElement> headerElements = new LinkedList<HeaderElement>();
  39. private byte[] data;
  40. private boolean useConcat16;
  41. /**
  42. * Create a new <tt>UserDataImpl</tt> that uses 8-bit reference numbers,
  43. * if concatenated SMS is required.
  44. */
  45. public UserDataImpl() {
  46. }
  47. /**
  48. * Create a new <tt>UserDataImpl</tt>.
  49. * @param useConcat16 If concatenated SMS is required, pass <tt>true</tt>
  50. * for this value to use 16-bit segment reference numbers or <tt>false</tt>
  51. * to use 8-bit segment reference numbers.
  52. */
  53. public UserDataImpl(boolean useConcat16) {
  54. this.useConcat16 = useConcat16;
  55. }
  56. /**
  57. * {@inheritDoc}
  58. * @throws IllegalArgumentException If <tt>element</tt> is an instance of
  59. * {@link ConcatenatedSms}.
  60. */
  61. public void addHeaderElement(HeaderElement element) {
  62. if (element instanceof ConcatenatedSms) {
  63. throw new IllegalArgumentException(
  64. "Concatenated SMS is handled automatically.");
  65. }
  66. headerElements.add(element);
  67. Collections.sort(headerElements, new HeaderElementComparator());
  68. }
  69. public byte[] toSingleSms() {
  70. byte[][] segments = toSegments();
  71. if (segments.length > 1) {
  72. throw new IllegalStateException(
  73. "There is more than one message segment");
  74. }
  75. return segments[0];
  76. }
  77. public byte[][] toSegments() {
  78. List<ByteBuffer> segments = new ArrayList<ByteBuffer>();
  79. List<HeaderElement> elements;
  80. if (calcSize(headerElements, data) > 140) {
  81. // Concatenation is required.
  82. elements = dupElements();
  83. HeaderElement concat = new ConcatenatedSms(useConcat16);
  84. elements.add(0, concat);
  85. } else {
  86. elements = headerElements;
  87. }
  88. ByteBuffer dataBuffer;
  89. if (data != null) {
  90. dataBuffer = ByteBuffer.wrap(data);
  91. } else {
  92. dataBuffer = ByteBuffer.wrap(new byte[0]);
  93. }
  94. boolean needMoreSegments = true;
  95. boolean needUdhl = elements.size() > 0;
  96. int segmentNum = 0;
  97. while (needMoreSegments) {
  98. segmentNum++;
  99. ByteBuffer segment = ByteBuffer.allocate(140);
  100. if (needUdhl) {
  101. segment.put((byte) 0);
  102. }
  103. boolean allComplete = true;
  104. for (HeaderElement element : elements) {
  105. if (element.isRecurring() || !element.isComplete()) {
  106. element.write(segmentNum, segment);
  107. }
  108. allComplete &= element.isComplete();
  109. if (segment.remaining() < 2) {
  110. break;
  111. }
  112. }
  113. int headerSize = (segment.capacity() - segment.remaining()) - 1;
  114. segment.put(0, (byte) headerSize);
  115. if (segment.remaining() > 0) {
  116. int numBytes =
  117. Math.min(segment.remaining(), dataBuffer.remaining());
  118. dataBuffer.get(segment.array(), segment.position(), numBytes);
  119. segment.position(segment.position() + numBytes);
  120. }
  121. segments.add(segment);
  122. if (allComplete && dataBuffer.remaining() == 0) {
  123. needMoreSegments = false;
  124. }
  125. }
  126. for (HeaderElement element : elements) {
  127. element.postProcess(segments);
  128. }
  129. byte[][] result = new byte[segments.size()][];
  130. for (int i = 0; i < segments.size(); i++) {
  131. ByteBuffer segment = segments.get(i);
  132. // If the segment was completely filled, just use the ByteBuffer's
  133. // backing array. If it wasn't filled, copy out the exact
  134. // number of bytes that were filled into the array.
  135. if (segment.remaining() == 0) {
  136. result[i] = segment.array();
  137. } else {
  138. segment.flip();
  139. result[i] = new byte[segment.remaining()];
  140. segment.get(result[i], 0, result[i].length);
  141. }
  142. }
  143. return result;
  144. }
  145. public boolean isMultiMessage() {
  146. return calcSize(headerElements, data) > 140;
  147. }
  148. public byte[] getData() {
  149. return data;
  150. }
  151. public void setData(byte[] data) {
  152. this.data = data;
  153. }
  154. private int calcSize(List<HeaderElement> elements, byte[] data) {
  155. int size = 0;
  156. if (elements.size() > 0) {
  157. // 1 octet for specifying the length of the UDH.
  158. size += 1;
  159. }
  160. if (data != null) {
  161. size += data.length;
  162. }
  163. for (HeaderElement element : elements) {
  164. size += element.getLength() + 2;
  165. }
  166. return size;
  167. }
  168. private List<HeaderElement> dupElements() {
  169. return new LinkedList<HeaderElement>(headerElements);
  170. }
  171. }