/protocols/smpp/src/main/java/org/mobicents/protocols/smpp/util/PacketFactory.java

http://mobicents.googlecode.com/ · Java · 290 lines · 161 code · 16 blank · 113 comment · 14 complexity · b5d69170f9cd9760dd94e4a7678292cd 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.util;
  23. import java.lang.reflect.Constructor;
  24. import java.util.HashMap;
  25. import java.util.Map;
  26. import org.slf4j.Logger;
  27. import org.slf4j.LoggerFactory;
  28. import org.mobicents.protocols.smpp.BadCommandIDException;
  29. import org.mobicents.protocols.smpp.SMPPRuntimeException;
  30. import org.mobicents.protocols.smpp.message.AlertNotification;
  31. import org.mobicents.protocols.smpp.message.BindReceiver;
  32. import org.mobicents.protocols.smpp.message.BindReceiverResp;
  33. import org.mobicents.protocols.smpp.message.BindTransceiver;
  34. import org.mobicents.protocols.smpp.message.BindTransceiverResp;
  35. import org.mobicents.protocols.smpp.message.BindTransmitter;
  36. import org.mobicents.protocols.smpp.message.BindTransmitterResp;
  37. import org.mobicents.protocols.smpp.message.BroadcastSM;
  38. import org.mobicents.protocols.smpp.message.BroadcastSMResp;
  39. import org.mobicents.protocols.smpp.message.CancelBroadcastSM;
  40. import org.mobicents.protocols.smpp.message.CancelBroadcastSMResp;
  41. import org.mobicents.protocols.smpp.message.CancelSM;
  42. import org.mobicents.protocols.smpp.message.CancelSMResp;
  43. import org.mobicents.protocols.smpp.message.DataSM;
  44. import org.mobicents.protocols.smpp.message.DataSMResp;
  45. import org.mobicents.protocols.smpp.message.DeliverSM;
  46. import org.mobicents.protocols.smpp.message.DeliverSMResp;
  47. import org.mobicents.protocols.smpp.message.EnquireLink;
  48. import org.mobicents.protocols.smpp.message.EnquireLinkResp;
  49. import org.mobicents.protocols.smpp.message.GenericNack;
  50. import org.mobicents.protocols.smpp.message.Outbind;
  51. import org.mobicents.protocols.smpp.message.ParamRetrieve;
  52. import org.mobicents.protocols.smpp.message.ParamRetrieveResp;
  53. import org.mobicents.protocols.smpp.message.QueryBroadcastSM;
  54. import org.mobicents.protocols.smpp.message.QueryBroadcastSMResp;
  55. import org.mobicents.protocols.smpp.message.QueryLastMsgs;
  56. import org.mobicents.protocols.smpp.message.QueryLastMsgsResp;
  57. import org.mobicents.protocols.smpp.message.QueryMsgDetails;
  58. import org.mobicents.protocols.smpp.message.QueryMsgDetailsResp;
  59. import org.mobicents.protocols.smpp.message.QuerySM;
  60. import org.mobicents.protocols.smpp.message.QuerySMResp;
  61. import org.mobicents.protocols.smpp.message.ReplaceSM;
  62. import org.mobicents.protocols.smpp.message.ReplaceSMResp;
  63. import org.mobicents.protocols.smpp.message.SMPPPacket;
  64. import org.mobicents.protocols.smpp.message.SubmitMulti;
  65. import org.mobicents.protocols.smpp.message.SubmitMultiResp;
  66. import org.mobicents.protocols.smpp.message.SubmitSM;
  67. import org.mobicents.protocols.smpp.message.SubmitSMResp;
  68. import org.mobicents.protocols.smpp.message.Unbind;
  69. import org.mobicents.protocols.smpp.message.UnbindResp;
  70. /**
  71. * Factory class for SMPP packets.
  72. * @version $Id: PacketFactory.java 457 2009-01-15 17:37:42Z orank $
  73. */
  74. public final class PacketFactory {
  75. private static final Logger LOG = LoggerFactory.getLogger(PacketFactory.class);
  76. private final Map<Integer, Class<? extends SMPPPacket>> commands =
  77. new HashMap<Integer, Class<? extends SMPPPacket>>();
  78. private final Map<Integer, Class<? extends SMPPPacket>> userCommands =
  79. new HashMap<Integer, Class<? extends SMPPPacket>>();
  80. public PacketFactory() {
  81. add(new AlertNotification());
  82. add(new BindReceiver(), new BindReceiverResp());
  83. add(new BindTransceiver(), new BindTransceiverResp());
  84. add(new BindTransmitter(), new BindTransmitterResp());
  85. add(new BroadcastSM(), new BroadcastSMResp());
  86. add(new CancelBroadcastSM(), new CancelBroadcastSMResp());
  87. add(new CancelSM(), new CancelSMResp());
  88. add(new DataSM(), new DataSMResp());
  89. add(new DeliverSM(), new DeliverSMResp());
  90. add(new EnquireLink(), new EnquireLinkResp());
  91. add(new GenericNack());
  92. add(new Outbind());
  93. add(new ParamRetrieve(), new ParamRetrieveResp());
  94. add(new QueryBroadcastSM(), new QueryBroadcastSMResp());
  95. add(new QueryLastMsgs(), new QueryLastMsgsResp());
  96. add(new QueryMsgDetails(), new QueryMsgDetailsResp());
  97. add(new QuerySM(), new QuerySMResp());
  98. add(new ReplaceSM(), new ReplaceSMResp());
  99. add(new SubmitMulti(), new SubmitMultiResp());
  100. add(new SubmitSM(), new SubmitSMResp());
  101. add(new Unbind(), new UnbindResp());
  102. }
  103. /**
  104. * Create a new instance of the appropriate sub class of SMPPPacket. Packet
  105. * fields are all left at their default initial state.
  106. *
  107. * @param id
  108. * The SMPP command ID of the packet type to return.
  109. * @return A sub-class instance of {@link org.mobicents.protocols.smpp.message.SMPPPacket}
  110. * representing SMPP command <code>id</code>.
  111. * @throws org.mobicents.protocols.smpp.BadCommandIDException
  112. * if the command ID is not recognized.
  113. */
  114. public SMPPPacket newInstance(int id) {
  115. return newInstance(id, null);
  116. }
  117. /**
  118. * Get a response packet for the specified request. The returned response
  119. * packet will have its sequence number initialised to the same value
  120. * as <code>packet</code>.
  121. * @param packet The request packet to get a response for.
  122. * @return An SMPP response packet.
  123. * @throws BadCommandIDException If there is no response packet for the
  124. * specified request (for example, an <code>AlertNotification</code>).
  125. * @throws SMPPRuntimeException If an attempt is made to create a
  126. * response to a response packet.
  127. */
  128. public SMPPPacket newResponse(SMPPPacket packet) {
  129. if (packet.isResponse()) {
  130. throw new SMPPRuntimeException(
  131. "Cannot create a response to a response!");
  132. }
  133. int id = packet.getCommandId();
  134. SMPPPacket response = newInstance(id | 0x80000000, packet);
  135. response.setSequenceNum(packet.getSequenceNum());
  136. return response;
  137. }
  138. /**
  139. * Register a vendor packet with the factory. The SMPP allows for
  140. * vendor-specific packets to be defined. In order for these to be
  141. * usable with the API, primarily so that they can be identified and
  142. * decoded when received from an SMSC, they must be registered with
  143. * the packet factory.
  144. * <p>
  145. * This implementation assumes that the ID of the response packet will
  146. * be the ID of the request packet ORed with <code>0x80000000</code>.
  147. * This implementation also accepts <code>null</code> for the
  148. * <code>responseType</code> since there is at least one incidence in
  149. * the specification of such a case (<code>AlertNotification</code> has
  150. * no response packet).
  151. * </p>
  152. * @param id The command ID of the request packet.
  153. * @param requestType The class which implements the vendor request packet.
  154. * @param responseType The class which implements the vendor response
  155. * packet.
  156. */
  157. public void registerVendorPacket(int id,
  158. Class<? extends SMPPPacket> requestType,
  159. Class<? extends SMPPPacket> responseType) {
  160. userCommands.put(Integer.valueOf(id), requestType);
  161. if (responseType != null) {
  162. userCommands.put(
  163. Integer.valueOf(id | 0x80000000), responseType);
  164. }
  165. }
  166. /**
  167. * Remove a vendor packet definition from this factory.
  168. * @param id The ID of the vendor packet to remove. This will also
  169. * unregister the response packet if it exists.
  170. */
  171. public void unregisterVendorPacket(int id) {
  172. userCommands.remove(Integer.valueOf(id));
  173. userCommands.remove(Integer.valueOf(id | 0x80000000));
  174. }
  175. /**
  176. * Add an internal API-defined packet type.
  177. * @param command The request packet to add.
  178. */
  179. private void add(SMPPPacket command) {
  180. int commandId = command.getCommandId();
  181. Class<? extends SMPPPacket> commandClass = command.getClass();
  182. commands.put(Integer.valueOf(commandId), commandClass);
  183. if (LOG.isDebugEnabled()) {
  184. LOG.debug("Mapping id 0x{} to class {}",
  185. Integer.toHexString(commandId), commandClass.getName());
  186. }
  187. }
  188. /**
  189. * Add an internal API-defined packet type.
  190. * @param requestClass The request packet to add.
  191. * @param responseClass The response packet to add.
  192. */
  193. private void add(SMPPPacket request, SMPPPacket response) {
  194. add(request);
  195. if (response != null) {
  196. add(response);
  197. }
  198. }
  199. /**
  200. * Get a new instance of an SMPP packet for the specified ID.
  201. * @param id The command ID to get the packet object for.
  202. * @param request If a response packet is being created, this parameter
  203. * may be optionally supplied and an attempt will be made to call a
  204. * constructor which accepts an SMPPPacket as its argument. All of the
  205. * response packets that are supplied as part of the API have such
  206. * a constructor.
  207. * @return A new instance of the relevant SMPPPacket implementation.
  208. * @throws BadCommandIDException If no matching class can be found for
  209. * <code>id</code>.
  210. * @throws SMPPRuntimeException If a packet&apos;s constructor throws
  211. * an exception.
  212. */
  213. private SMPPPacket newInstance(int id, SMPPPacket request) {
  214. SMPPPacket response = null;
  215. Class<? extends SMPPPacket> clazz = getClassForId(id);
  216. if (clazz == null) {
  217. throw new BadCommandIDException(
  218. "Unrecognized command id " + Integer.toHexString(id), id);
  219. }
  220. try {
  221. if (request != null) {
  222. response = constructWithPacketArg(clazz, request);
  223. }
  224. if (response == null) {
  225. response = clazz.newInstance();
  226. }
  227. } catch (Exception x) {
  228. throw new SMPPRuntimeException(
  229. "Packet constructor threw an exception.", x);
  230. }
  231. return response;
  232. }
  233. /**
  234. * Construct an SMPPPacket implementation class using a single-argument
  235. * constructor which takes an SMPPPacket object as its argument.
  236. * @param clazz The class to instantiate.
  237. * @param request The object to pass to the constructor.
  238. * @return The instantiated class, or <code>null</code> if the class does
  239. * not implement a single-argument constructor which accepts an SMPPPacket.
  240. * @throws Exception Any exception that is thrown by
  241. * {@link Constructor#newInstance(java.lang.Object[])} can be thrown
  242. * by this method.
  243. */
  244. private SMPPPacket constructWithPacketArg(
  245. Class<? extends SMPPPacket> clazz,
  246. SMPPPacket request) throws Exception {
  247. SMPPPacket packet = null;
  248. try {
  249. Constructor<? extends SMPPPacket> cons = clazz.getConstructor(
  250. new Class[] {SMPPPacket.class});
  251. packet = cons.newInstance(
  252. new Object[] {request});
  253. } catch (NoSuchMethodException x) {
  254. LOG.debug("No SMPPPacket constructor; will fall back to default.");
  255. }
  256. return packet;
  257. }
  258. /**
  259. * Get the implementation class for SMPP <code>commandId</code>.
  260. * The internally supplied SMPPPacket implementations will be queried
  261. * first, followed by all registered vendor packets.
  262. * @param commandId The command ID of the packet to get.
  263. * @return The implementing class, or <code>null</code> if there is
  264. * no class for the specified command ID.
  265. */
  266. private Class<? extends SMPPPacket> getClassForId(int commandId) {
  267. Integer id = Integer.valueOf(commandId);
  268. Class<? extends SMPPPacket> clazz = commands.get(id);
  269. if (clazz == null) {
  270. clazz = userCommands.get(id);
  271. }
  272. return clazz;
  273. }
  274. }