001 /**
002 * Licensed to the Apache Software Foundation (ASF) under one or more
003 * contributor license agreements. See the NOTICE file distributed with
004 * this work for additional information regarding copyright ownership.
005 * The ASF licenses this file to You under the Apache License, Version 2.0
006 * (the "License"); you may not use this file except in compliance with
007 * the License. You may obtain a copy of the License at
008 *
009 * http://www.apache.org/licenses/LICENSE-2.0
010 *
011 * Unless required by applicable law or agreed to in writing, software
012 * distributed under the License is distributed on an "AS IS" BASIS,
013 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
014 * See the License for the specific language governing permissions and
015 * limitations under the License.
016 */
017 package org.apache.camel.component.smpp;
018
019 import java.io.IOException;
020
021 import org.apache.camel.Exchange;
022 import org.apache.camel.Processor;
023 import org.apache.camel.impl.DefaultConsumer;
024 import org.apache.commons.logging.Log;
025 import org.apache.commons.logging.LogFactory;
026 import org.jsmpp.DefaultPDUReader;
027 import org.jsmpp.DefaultPDUSender;
028 import org.jsmpp.SynchronizedPDUSender;
029 import org.jsmpp.bean.AlertNotification;
030 import org.jsmpp.bean.BindType;
031 import org.jsmpp.bean.DataSm;
032 import org.jsmpp.bean.DeliverSm;
033 import org.jsmpp.bean.NumberingPlanIndicator;
034 import org.jsmpp.bean.TypeOfNumber;
035 import org.jsmpp.extra.ProcessRequestException;
036 import org.jsmpp.extra.SessionState;
037 import org.jsmpp.session.BindParameter;
038 import org.jsmpp.session.DataSmResult;
039 import org.jsmpp.session.MessageReceiverListener;
040 import org.jsmpp.session.SMPPSession;
041 import org.jsmpp.session.Session;
042 import org.jsmpp.session.SessionStateListener;
043 import org.jsmpp.util.DefaultComposer;
044 import org.jsmpp.util.MessageIDGenerator;
045 import org.jsmpp.util.MessageId;
046 import org.jsmpp.util.RandomMessageIDGenerator;
047
048 /**
049 * An implementation of @{link Consumer} which use the SMPP protocol
050 *
051 * @version $Revision: 954316 $
052 * @author muellerc
053 */
054 public class SmppConsumer extends DefaultConsumer {
055
056 private static final transient Log LOG = LogFactory.getLog(SmppConsumer.class);
057
058 private SmppConfiguration configuration;
059 private SMPPSession session;
060 private MessageReceiverListener messageReceiverListener;
061 private SessionStateListener sessionStateListener;
062
063 /**
064 * The constructor which gets a smpp endpoint, a smpp configuration and a
065 * processor
066 */
067 public SmppConsumer(SmppEndpoint endpoint, SmppConfiguration config, Processor processor) {
068 super(endpoint, processor);
069
070 this.configuration = config;
071 this.sessionStateListener = new SessionStateListener() {
072 public void onStateChange(SessionState newState, SessionState oldState, Object source) {
073 if (newState.equals(SessionState.CLOSED)) {
074 LOG.warn("Loost connection to: " + getEndpoint().getConnectionString()
075 + " - trying to reconnect...");
076 closeSession(session);
077 reconnect(configuration.getInitialReconnectDelay());
078 }
079 }
080 };
081 this.messageReceiverListener = new MessageReceiverListener() {
082 private final MessageIDGenerator messageIDGenerator = new RandomMessageIDGenerator();
083
084 public void onAcceptAlertNotification(AlertNotification alertNotification) {
085 if (LOG.isDebugEnabled()) {
086 LOG.debug("Received an alertNotification " + alertNotification);
087 }
088
089 try {
090 Exchange exchange = getEndpoint().createOnAcceptAlertNotificationExchange(
091 alertNotification);
092
093 LOG.trace("Processing the new smpp exchange...");
094 getProcessor().process(exchange);
095 LOG.trace("Processed the new smpp exchange");
096 } catch (Exception e) {
097 getExceptionHandler().handleException(e);
098 }
099 }
100
101 public void onAcceptDeliverSm(DeliverSm deliverSm) {
102 if (LOG.isDebugEnabled()) {
103 LOG.debug("Received a deliverSm " + deliverSm);
104 }
105
106 try {
107 Exchange exchange = getEndpoint().createOnAcceptDeliverSmExchange(deliverSm);
108
109 LOG.trace("processing the new smpp exchange...");
110 getProcessor().process(exchange);
111 LOG.trace("processed the new smpp exchange");
112 } catch (Exception e) {
113 getExceptionHandler().handleException(e);
114 }
115 }
116
117 public DataSmResult onAcceptDataSm(DataSm dataSm, Session session)
118 throws ProcessRequestException {
119 if (LOG.isDebugEnabled()) {
120 LOG.debug("Received a dataSm " + dataSm);
121 }
122
123 MessageId newMessageId = messageIDGenerator.newMessageId();
124
125 try {
126 Exchange exchange = getEndpoint().createOnAcceptDataSm(dataSm,
127 newMessageId.getValue());
128
129 LOG.trace("processing the new smpp exchange...");
130 getProcessor().process(exchange);
131 LOG.trace("processed the new smpp exchange");
132 } catch (Exception e) {
133 getExceptionHandler().handleException(e);
134 throw new ProcessRequestException(e.getMessage(), 255, e);
135 }
136
137 return new DataSmResult(newMessageId, dataSm.getOptionalParametes());
138 }
139 };
140 }
141
142 @Override
143 protected void doStart() throws Exception {
144 LOG.debug("Connecting to: " + getEndpoint().getConnectionString() + "...");
145
146 super.doStart();
147 session = createSession();
148
149 LOG.info("Connected to: " + getEndpoint().getConnectionString());
150 }
151
152 private SMPPSession createSession() throws IOException {
153 SMPPSession session = createSMPPSession();
154 session = createSMPPSession();
155 session.setEnquireLinkTimer(configuration.getEnquireLinkTimer());
156 session.setTransactionTimer(configuration.getTransactionTimer());
157 session.addSessionStateListener(sessionStateListener);
158 session.setMessageReceiverListener(messageReceiverListener);
159 session.connectAndBind(this.configuration.getHost(), this.configuration.getPort(),
160 new BindParameter(BindType.BIND_RX, this.configuration.getSystemId(),
161 this.configuration.getPassword(), this.configuration.getSystemType(),
162 TypeOfNumber.UNKNOWN, NumberingPlanIndicator.UNKNOWN, ""));
163
164 return session;
165 }
166
167 /**
168 * Factory method to easily instantiate a mock SMPPSession
169 *
170 * @return the SMPPSession
171 */
172 SMPPSession createSMPPSession() {
173 if (configuration.getUsingSSL()) {
174 return new SMPPSession(new SynchronizedPDUSender(new DefaultPDUSender(
175 new DefaultComposer())), new DefaultPDUReader(), SmppSSLConnectionFactory
176 .getInstance());
177 } else {
178 return new SMPPSession();
179 }
180 }
181
182 @Override
183 protected void doStop() throws Exception {
184 LOG.debug("Disconnecting from: " + getEndpoint().getConnectionString() + "...");
185
186 super.doStop();
187 closeSession(session);
188
189 LOG.info("Disconnected from: " + getEndpoint().getConnectionString());
190 }
191
192 private void closeSession(SMPPSession session) {
193 if (session != null) {
194 session.removeSessionStateListener(this.sessionStateListener);
195 session.close();
196 session = null;
197 }
198 }
199
200 private void reconnect(final long initialReconnectDelay) {
201 new Thread() {
202 @Override
203 public void run() {
204 LOG.info("Schedule reconnect after " + initialReconnectDelay + " millis");
205 try {
206 Thread.sleep(initialReconnectDelay);
207 } catch (InterruptedException e) {
208 }
209
210 int attempt = 0;
211 while (!(isStopping() || isStopped()) && (session == null || session.getSessionState().equals(SessionState.CLOSED))) {
212 try {
213 LOG.info("Trying to reconnect to " + getEndpoint().getConnectionString() + " - attempt #" + (++attempt) + "...");
214 session = createSession();
215 } catch (IOException e) {
216 LOG.info("Failed to reconnect to " + getEndpoint().getConnectionString());
217 closeSession(session);
218 try {
219 Thread.sleep(configuration.getReconnectDelay());
220 } catch (InterruptedException ee) {
221 }
222 }
223 }
224 LOG.info("Reconnected to " + getEndpoint().getConnectionString());
225 }
226 }.start();
227 }
228
229 @Override
230 public String toString() {
231 return "SmppConsumer[" + getEndpoint().getConnectionString() + "]";
232 }
233
234 @Override
235 public SmppEndpoint getEndpoint() {
236 return (SmppEndpoint) super.getEndpoint();
237 }
238
239 /**
240 * Returns the smpp configuration
241 *
242 * @return the configuration
243 */
244 public SmppConfiguration getConfiguration() {
245 return configuration;
246 }
247 }