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    }