📄 connection.java
字号:
package ie.omk.smpp;import ie.omk.smpp.event.ConnectionObserver;import ie.omk.smpp.event.EventDispatcher;import ie.omk.smpp.event.ReceiverExceptionEvent;import ie.omk.smpp.event.ReceiverExitEvent;import ie.omk.smpp.event.ReceiverStartEvent;import ie.omk.smpp.event.SMPPEvent;import ie.omk.smpp.event.SimpleEventDispatcher;import ie.omk.smpp.message.Bind;import ie.omk.smpp.message.BindResp;import ie.omk.smpp.message.DeliverSM;import ie.omk.smpp.message.DeliverSMResp;import ie.omk.smpp.message.EnquireLink;import ie.omk.smpp.message.EnquireLinkResp;import ie.omk.smpp.message.InvalidParameterValueException;import ie.omk.smpp.message.SMPPPacket;import ie.omk.smpp.message.SMPPProtocolException;import ie.omk.smpp.message.SMPPRequest;import ie.omk.smpp.message.SMPPResponse;import ie.omk.smpp.message.Unbind;import ie.omk.smpp.message.UnbindResp;import ie.omk.smpp.message.tlv.Tag;import ie.omk.smpp.net.SmscLink;import ie.omk.smpp.net.TcpLink;import ie.omk.smpp.util.APIConfig;import ie.omk.smpp.util.AlphabetEncoding;import ie.omk.smpp.util.DefaultSequenceScheme;import ie.omk.smpp.util.PacketFactory;import ie.omk.smpp.util.PropertyNotFoundException;import ie.omk.smpp.util.SMPPIO;import ie.omk.smpp.util.SequenceNumberScheme;import ie.omk.smpp.version.SMPPVersion;import ie.omk.smpp.version.VersionException;import java.io.IOException;import java.lang.reflect.Constructor;import java.lang.reflect.InvocationTargetException;import java.net.SocketTimeoutException;import java.util.ArrayList;import java.util.Iterator;import java.util.List;import org.apache.commons.logging.Log;import org.apache.commons.logging.LogFactory;/** * SMPP client connection (ESME). An SMPP Connection represents any kind of * connection to the SMSC, be it a transmitter, receiver or transceiver. It also * supports both synchronous and asynchronous modes of communication. * Synchronous mode is only useful for very simple applications that use * single-threading. Asynchronous mode is recommended for more complex * applications, especially those that will be running many threads. * <p> * <b>Important Note </b>: if you wish to use synchronous mode in a * multi-threaded environment, it is the <u>application's </u> responsiblity to * ensure there is only one thread executing a call to either or both of the * <code>sendRequest</code> and <code>readNextPacket</code> methods. If * there are concurrent calls to these methods executing, there is a strong * possibility of the incorrect packet being returned in a particular thread and * both the API and the application getting confused. These are the only methods * that contain such a race condition. * </p> * * @author Oran Kelly * @version $Id: Connection.java 302 2006-08-10 20:36:40Z orank $ */public class Connection implements java.lang.Runnable { /** SMPP Transmitter connection type. */ public static final int TRANSMITTER = 1; /** SMPP Receiver connection type. */ public static final int RECEIVER = 2; /** SMPP Transciever connection type. */ public static final int TRANSCEIVER = 3; /** Connection state: not bound to the SMSC. */ public static final int UNBOUND = 0; /** * Connection state: waiting for successful acknowledgement to bind request. */ public static final int BINDING = 1; /** Connection state: bound to the SMSC. */ public static final int BOUND = 2; /** * Connection state: waiting for successful acknowledgement to unbind * request or waiting for application to respond to unbind request. */ public static final int UNBINDING = 3; private static final Log LOGGER = LogFactory.getLog(Connection.class); /** Type of this SMPP connection. */ private int connectionType; /** Packet listener thread for Asyncronous comms. */ private Thread rcvThread; /** * Queue of incoming packets to deliver to application before reading from * the network. The queue is used only in syncrhonized mode. In the case * where an application has sent a request to the SMSC and is blocked * waiting a response and the SMSC initiates a request of it's own (an * unbind request or an enquire_link), the API will cache the request packet * and wait for the response to it's packet. Any other type of packet will * be added to the packetQueue and subsequent calls to * <code>readNextPacket</code> will clear this queue. */ private List packetQueue; /** * Object used to notify observers of SMPP events. */ private EventDispatcher eventDispatcher; /** Byte buffer used in readNextPacketInternal. */ private byte[] buf = new byte[300]; /** Sequence numbering scheme to use for this connection. */ private SequenceNumberScheme seqNumScheme = new DefaultSequenceScheme(); /** The network link (virtual circuit) to the SMSC */ private SmscLink link; /** * SMPP protocol version number. */ protected SMPPVersion interfaceVersion = SMPPVersion.getDefaultVersion(); /** * Does the remote end support optional parameters? According to the * SMPPv3.4 specification, if the SMSC does not return the * sc_interface_version optional parameter in its bind response packet, then * we must assume it does not support optional parameters. */ protected boolean supportOptionalParams = true; /** * Current state of the SMPP connection. Possible states are UNBOUND, * BINDING, BOUND and UNBINDING. */ private transient int state = UNBOUND; /** * Specify whether the listener thread will automatically ack enquire_link * primitives received from the Smsc */ protected boolean ackQryLinks = true; /** * Automatically acknowledge incoming deliver_sm messages. Only valid for * the Receiver */ protected boolean ackDeliverSm; /** Is the user using synchronous are async communication?. */ protected boolean asyncComms; /** * The default alphabet to use for this connection. */ protected AlphabetEncoding defaultAlphabet; /** * Initialise a new SMPP connection object. This is a convenience * constructor that will create a new {@link ie.omk.smpp.net.TcpLink}object * using the host name and port provided. The connection created will use * synchronous communications. * * @param host * the hostname of the SMSC. * @param port * the port to connect to. If 0, use the default SMPP port * number. */ public Connection(String host, int port) throws java.net.UnknownHostException { this(new TcpLink(host, port), false); } /** * Initialise a new SMPP connection object. This is a convenience * constructor that will create a new {@link ie.omk.smpp.net.TcpLink}object * using the host name and port provided. * * @param host * the hostname of the SMSC. * @param port * the port to connect to. If 0, use the default SMPP port * number. * @param async * true for asyncronous communication, false for synchronous. */ public Connection(String host, int port, boolean async) throws java.net.UnknownHostException { this(new TcpLink(host, port), async); } /** * Initialise a new SMPP connection object. The connection will use * synchronous communications. * * @param link * The network link object to the Smsc (cannot be null) */ public Connection(SmscLink link) { this(link, false); } /** * Initialise a new SMPP connection object, specifying the type of * communication desired. See the {@link Connection}class description for * some required knowledge on using the Connection in syncrhonous mode. * * @param link * The network link object to the Smsc (cannot be null) * @param async * true for asyncronous communication, false for synchronous. */ public Connection(SmscLink link, boolean async) { this.link = link; this.asyncComms = async; if (asyncComms) { initAsyncComms(); } else { initSyncComms(); } } private void initAsyncComms() { String className = ""; try { className = APIConfig.getInstance().getProperty( APIConfig.EVENT_DISPATCHER_CLASS); if (className != null && !"".equals(className)) { Class cl = Class.forName(className); Constructor ctr = cl.getConstructor(new Class[0]); eventDispatcher = (EventDispatcher) ctr.newInstance(new Object[0]); } else { LOGGER.info("EventDispatcher property value is empty."); } } catch (PropertyNotFoundException x) { LOGGER.debug("No event dispatcher specified in properties. Using default."); } catch (ClassNotFoundException x) { LOGGER.error("Cannot locate event dispatcher class " + className, x); } catch (ClassCastException x) { LOGGER.error(className + " does not implement the EventDispatcher interface.", x); } catch (NoSuchMethodException x) { LOGGER.error(className + " does not have a no-argument constructor."); } catch (IllegalAccessException x) { LOGGER.error(className + " constructor is not visible.", x); } catch (IllegalArgumentException x) { LOGGER.error("Internal error in the SMPPAPI. Please inform the maintainer.", x); } catch (InstantiationException x) { LOGGER.error("Could not instantiate an instance of " + className, x); } catch (InvocationTargetException x) { LOGGER.error(className + " constructor threw an exception.", x); } finally { if (eventDispatcher == null) { eventDispatcher = new SimpleEventDispatcher(); } } LOGGER.info("Using event dispatcher " + eventDispatcher.getClass().getName()); // Initialise the event dispatcher eventDispatcher.init(); // Create the receiver daemon thread. createRecvThread(); } private void initSyncComms() { packetQueue = new ArrayList(); } /** * Create the receiver thread if asynchronous communications is on, does * nothing otherwise. */ private void createRecvThread() { LOGGER.info("Creating receiver thread"); rcvThread = new Thread(this, "ReceiverDaemon"); rcvThread.setDaemon(true); } /** * Set the default alphabet of the SMSC this <code>Connection</code> is * communicating with. Each SMSC has its own default alphabet it uses. When * messages arrive and announce themselves with a data coding value of zero, * that means the message is encoded in the SMSC's default alphabet. The * smppapi assumes the GSM default alphabet as it's default alphabet. By * setting the default alphabet on the <code>Connection</code> all packets * returned by {@link #newInstance(int)}will use the Connection's default * alphabet plus any packets read from the wire with a data coding value of * zero will have their default alphabet initialised appropriately. * * @param alphabet * the alphabet to use as the default for this connection (may be * <code>null</code> in which case the API falls back to using * its own internal default). */ public void setDefaultAlphabet(AlphabetEncoding alphabet) { this.defaultAlphabet = alphabet; } /** * Get the current alphabet this <code>Connection</code> is using as its * default. * * @return the default alphabet for this <code>Connection</code>. */ public AlphabetEncoding getDefaultAlphabet() { return defaultAlphabet; } /** * Set the state of this ESME. * * @see ie.omk.smpp.Connection#getState */ private void setState(int state) { LOGGER.info("Setting state " + state); this.state = state; } /** * Set the SMPP version this connection will use. Setting the version is * only a valid operation before the connection is bound. Any attempt to set * the version after binding to the SMSC will result in an exception being * thrown. * * @param version * the SMPP version to use. * @throws ie.omk.smpp.version.VersionException * if an attempt is made to set the version of the connection * after binding to the SMSC. * @see ie.omk.smpp.version.SMPPVersion */ public void setVersion(SMPPVersion version) throws VersionException { if (getState() != UNBOUND) { throw new VersionException("Cannot set SMPP version after binding"); } if (version == null) { this.interfaceVersion = SMPPVersion.getDefaultVersion(); } else { this.interfaceVersion = version; } } /** * Get the SMPP version in use by this connection. The version in use by the * connection <b>may </b> be different to that specified before the bind * operation as binding to the SMSC may result in an alternative SMPP * version being negotiated. For instance, if the client sends a bind packet * to the SMSC specifying that it supports SMPP version 3.4 but the SMSC * returns a bind_resp stating it supports version 3.3, the Connection * automatically sets it's internal version to use down to 3.3. */ public SMPPVersion getVersion() { return interfaceVersion; } /** * Get the current state of the ESME. One of UNBOUND, BINDING, BOUND or * UNBINDING. */ public int getState() { return state; }
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -