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.impl.DefaultProducer;
023    import org.apache.commons.logging.Log;
024    import org.apache.commons.logging.LogFactory;
025    import org.jsmpp.DefaultPDUReader;
026    import org.jsmpp.DefaultPDUSender;
027    import org.jsmpp.InvalidResponseException;
028    import org.jsmpp.PDUException;
029    import org.jsmpp.SynchronizedPDUSender;
030    import org.jsmpp.bean.Alphabet;
031    import org.jsmpp.bean.BindType;
032    import org.jsmpp.bean.ESMClass;
033    import org.jsmpp.bean.GeneralDataCoding;
034    import org.jsmpp.bean.MessageClass;
035    import org.jsmpp.bean.NumberingPlanIndicator;
036    import org.jsmpp.bean.RegisteredDelivery;
037    import org.jsmpp.bean.SubmitSm;
038    import org.jsmpp.bean.TypeOfNumber;
039    import org.jsmpp.extra.NegativeResponseException;
040    import org.jsmpp.extra.ResponseTimeoutException;
041    import org.jsmpp.session.BindParameter;
042    import org.jsmpp.session.SMPPSession;
043    import org.jsmpp.util.DefaultComposer;
044    
045    /**
046     * An implementation of @{link Producer} which use the SMPP protocol
047     * 
048     * @version $Revision: 945986 $
049     * @author muellerc
050     */
051    public class SmppProducer extends DefaultProducer {
052    
053        private static final transient Log LOG = LogFactory.getLog(SmppProducer.class);
054    
055        private SmppConfiguration configuration;
056        private SMPPSession session;
057    
058        public SmppProducer(SmppEndpoint endpoint, SmppConfiguration configuration) {
059            super(endpoint);
060            this.configuration = configuration;
061        }
062    
063        @Override
064        protected void doStart() throws Exception {
065            if (LOG.isDebugEnabled()) {
066                LOG.debug("Connecting to: " + getEndpoint().getConnectionString() + "...");
067            }
068    
069            super.doStart();
070    
071            session = createSMPPSession();
072            session.setEnquireLinkTimer(this.configuration.getEnquireLinkTimer());
073            session.setTransactionTimer(this.configuration.getTransactionTimer());
074            session.connectAndBind(
075                    this.configuration.getHost(),
076                    this.configuration.getPort(),
077                    new BindParameter(
078                            BindType.BIND_TX,
079                            this.configuration.getSystemId(),
080                            this.configuration.getPassword(), 
081                            this.configuration.getSystemType(),
082                            TypeOfNumber.valueOf(configuration.getTypeOfNumber()),
083                            NumberingPlanIndicator.valueOf(configuration.getNumberingPlanIndicator()),
084                            ""));
085    
086            LOG.info("Connected to: " + getEndpoint().getConnectionString());
087        }
088        
089        /**
090         * Factory method to easily instantiate a mock SMPPSession
091         * 
092         * @return the SMPPSession
093         */
094        SMPPSession createSMPPSession() {
095            if (configuration.getUsingSSL()) {
096                return new SMPPSession(new SynchronizedPDUSender(new DefaultPDUSender(new DefaultComposer())),
097                                       new DefaultPDUReader(), SmppSSLConnectionFactory.getInstance());
098            } else {
099                return new SMPPSession();
100            }
101        }
102    
103        public void process(Exchange exchange) throws Exception {
104            if (LOG.isDebugEnabled()) {
105                LOG.debug("Sending a short message for exchange id '"
106                        + exchange.getExchangeId() + "'...");
107            }
108    
109            SubmitSm submitSm = getEndpoint().getBinding().createSubmitSm(exchange);
110            String messageId;
111            try {
112                messageId = doProcess(submitSm);
113            } catch (Exception e) {
114                if (LOG.isDebugEnabled()) {
115                    LOG.debug("Caught exception while trying to send short message for exchange id '"
116                            + exchange.getExchangeId() + "', retrying...", e);
117                }
118                doStop();
119                doStart();
120                
121                messageId = doProcess(submitSm);
122            }
123    
124            if (LOG.isDebugEnabled()) {
125                LOG.debug("Sent a short message for exchange id '"
126                        + exchange.getExchangeId() + "' and received message id '"
127                        + messageId + "'");
128            }
129    
130            if (exchange.getPattern().isOutCapable()) {
131                if (LOG.isDebugEnabled()) {
132                    LOG.debug("Exchange is out capable, setting headers on out exchange...");
133                }
134                exchange.getOut().setHeader(SmppBinding.ID, messageId);
135            } else {
136                if (LOG.isDebugEnabled()) {
137                    LOG.debug("Exchange is not out capable, setting headers on in exchange...");
138                }
139                exchange.getIn().setHeader(SmppBinding.ID, messageId);
140            }
141        }
142    
143        private String doProcess(SubmitSm submitSm) throws PDUException,
144                ResponseTimeoutException, InvalidResponseException,
145                NegativeResponseException, IOException {
146    
147            String messageId = session.submitShortMessage(
148                    submitSm.getServiceType(), 
149                    TypeOfNumber.valueOf(submitSm.getSourceAddrTon()),
150                    NumberingPlanIndicator.valueOf(submitSm.getSourceAddrNpi()),
151                    submitSm.getSourceAddr(),
152                    TypeOfNumber.valueOf(submitSm.getDestAddrTon()),
153                    NumberingPlanIndicator.valueOf(submitSm.getDestAddrNpi()),
154                    submitSm.getDestAddress(),
155                    new ESMClass(),
156                    submitSm.getProtocolId(),
157                    submitSm.getPriorityFlag(),
158                    submitSm.getScheduleDeliveryTime(),
159                    submitSm.getValidityPeriod(),
160                    new RegisteredDelivery(submitSm.getRegisteredDelivery()),
161                    submitSm.getReplaceIfPresent(),
162                    new GeneralDataCoding(
163                            false,
164                            false,
165                            MessageClass.CLASS1,
166                            Alphabet.ALPHA_DEFAULT),
167                    (byte) 0,
168                    submitSm.getShortMessage());
169    
170            return messageId;
171        }
172    
173        @Override
174        protected void doStop() throws Exception {
175            if (LOG.isDebugEnabled()) {
176                LOG.debug("Disconnecting from: " + getEndpoint().getConnectionString() + "...");
177            }
178    
179            super.doStop();
180    
181            if (session != null) {
182                session.close();
183                session = null;
184            }
185    
186            LOG.info("Disconnected from: " + getEndpoint().getConnectionString());
187        }
188    
189        @Override
190        public SmppEndpoint getEndpoint() {
191            return (SmppEndpoint) super.getEndpoint();
192        }
193    
194        /**
195         * Returns the smppConfiguration for this producer
196         * 
197         * @return the configuration
198         */
199        public SmppConfiguration getConfiguration() {
200            return configuration;
201        }
202    
203        @Override
204        public String toString() {
205            return "SmppProducer[" + getEndpoint().getConnectionString() + "]";
206        }
207    
208    }