PageRenderTime 17ms CodeModel.GetById 1ms app.highlight 11ms RepoModel.GetById 1ms app.codeStats 0ms

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