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.SynchronizedPDUSender; 028 import org.jsmpp.bean.Alphabet; 029 import org.jsmpp.bean.BindType; 030 import org.jsmpp.bean.ESMClass; 031 import org.jsmpp.bean.GeneralDataCoding; 032 import org.jsmpp.bean.MessageClass; 033 import org.jsmpp.bean.NumberingPlanIndicator; 034 import org.jsmpp.bean.RegisteredDelivery; 035 import org.jsmpp.bean.SubmitSm; 036 import org.jsmpp.bean.TypeOfNumber; 037 import org.jsmpp.extra.SessionState; 038 import org.jsmpp.session.BindParameter; 039 import org.jsmpp.session.SMPPSession; 040 import org.jsmpp.session.SessionStateListener; 041 import org.jsmpp.util.DefaultComposer; 042 043 /** 044 * An implementation of @{link Producer} which use the SMPP protocol 045 * 046 * @version $Revision: 991338 $ 047 * @author muellerc 048 */ 049 public class SmppProducer extends DefaultProducer { 050 051 private static final transient Log LOG = LogFactory.getLog(SmppProducer.class); 052 053 private SmppConfiguration configuration; 054 private SMPPSession session; 055 private SessionStateListener sessionStateListener; 056 057 public SmppProducer(SmppEndpoint endpoint, SmppConfiguration config) { 058 super(endpoint); 059 this.configuration = config; 060 this.sessionStateListener = new SessionStateListener() { 061 public void onStateChange(SessionState newState, SessionState oldState, Object source) { 062 if (newState.equals(SessionState.CLOSED)) { 063 LOG.warn("Loosing connection to: " + getEndpoint().getConnectionString() + " - trying to reconnect..."); 064 closeSession(session); 065 reconnect(configuration.getInitialReconnectDelay()); 066 } 067 } 068 }; 069 } 070 071 @Override 072 protected void doStart() throws Exception { 073 LOG.debug("Connecting to: " + getEndpoint().getConnectionString() + "..."); 074 075 super.doStart(); 076 session = createSession(); 077 078 LOG.info("Connected to: " + getEndpoint().getConnectionString()); 079 } 080 081 private SMPPSession createSession() throws IOException { 082 SMPPSession session = createSMPPSession(); 083 session.setEnquireLinkTimer(this.configuration.getEnquireLinkTimer()); 084 session.setTransactionTimer(this.configuration.getTransactionTimer()); 085 session.addSessionStateListener(sessionStateListener); 086 session.connectAndBind( 087 this.configuration.getHost(), 088 this.configuration.getPort(), 089 new BindParameter( 090 BindType.BIND_TX, 091 this.configuration.getSystemId(), 092 this.configuration.getPassword(), 093 this.configuration.getSystemType(), 094 TypeOfNumber.valueOf(configuration.getTypeOfNumber()), 095 NumberingPlanIndicator.valueOf(configuration.getNumberingPlanIndicator()), 096 "")); 097 098 return session; 099 } 100 101 /** 102 * Factory method to easily instantiate a mock SMPPSession 103 * 104 * @return the SMPPSession 105 */ 106 SMPPSession createSMPPSession() { 107 if (configuration.getUsingSSL()) { 108 return new SMPPSession(new SynchronizedPDUSender(new DefaultPDUSender(new DefaultComposer())), 109 new DefaultPDUReader(), SmppSSLConnectionFactory.getInstance()); 110 } else { 111 return new SMPPSession(); 112 } 113 } 114 115 public void process(Exchange exchange) throws Exception { 116 if (LOG.isDebugEnabled()) { 117 LOG.debug("Sending a short message for exchange id '" 118 + exchange.getExchangeId() + "'..."); 119 } 120 121 // only possible by trying to reconnect 122 if (this.session == null) { 123 throw new IOException("Lost connection to " + getEndpoint().getConnectionString() + " and yet not reconnected"); 124 } 125 126 SubmitSm submitSm = getEndpoint().getBinding().createSubmitSm(exchange); 127 String messageId = session.submitShortMessage( 128 submitSm.getServiceType(), 129 TypeOfNumber.valueOf(submitSm.getSourceAddrTon()), 130 NumberingPlanIndicator.valueOf(submitSm.getSourceAddrNpi()), 131 submitSm.getSourceAddr(), 132 TypeOfNumber.valueOf(submitSm.getDestAddrTon()), 133 NumberingPlanIndicator.valueOf(submitSm.getDestAddrNpi()), 134 submitSm.getDestAddress(), 135 new ESMClass(), 136 submitSm.getProtocolId(), 137 submitSm.getPriorityFlag(), 138 submitSm.getScheduleDeliveryTime(), 139 submitSm.getValidityPeriod(), 140 new RegisteredDelivery(submitSm.getRegisteredDelivery()), 141 submitSm.getReplaceIfPresent(), 142 new GeneralDataCoding( 143 false, 144 false, 145 MessageClass.CLASS1, 146 Alphabet.valueOf(submitSm.getDataCoding())), 147 (byte) 0, 148 submitSm.getShortMessage()); 149 150 if (LOG.isDebugEnabled()) { 151 LOG.debug("Sent a short message for exchange id '" 152 + exchange.getExchangeId() + "' and received message id '" 153 + messageId + "'"); 154 } 155 156 if (exchange.getPattern().isOutCapable()) { 157 if (LOG.isDebugEnabled()) { 158 LOG.debug("Exchange is out capable, setting headers on out exchange..."); 159 } 160 exchange.getOut().setHeader(SmppBinding.ID, messageId); 161 } else { 162 if (LOG.isDebugEnabled()) { 163 LOG.debug("Exchange is not out capable, setting headers on in exchange..."); 164 } 165 exchange.getIn().setHeader(SmppBinding.ID, messageId); 166 } 167 } 168 169 @Override 170 protected void doStop() throws Exception { 171 LOG.debug("Disconnecting from: " + getEndpoint().getConnectionString() + "..."); 172 173 super.doStop(); 174 closeSession(session); 175 176 LOG.info("Disconnected from: " + getEndpoint().getConnectionString()); 177 } 178 179 private void closeSession(SMPPSession session) { 180 if (session != null) { 181 session.removeSessionStateListener(this.sessionStateListener); 182 session.close(); 183 session = null; 184 } 185 } 186 187 private void reconnect(final long initialReconnectDelay) { 188 new Thread() { 189 @Override 190 public void run() { 191 LOG.info("Schedule reconnect after " + initialReconnectDelay + " millis"); 192 try { 193 Thread.sleep(initialReconnectDelay); 194 } catch (InterruptedException e) { 195 } 196 197 int attempt = 0; 198 while (!(isStopping() || isStopped()) && (session == null || session.getSessionState().equals(SessionState.CLOSED))) { 199 try { 200 LOG.info("Trying to reconnect to " + getEndpoint().getConnectionString() + " - attempt #" + (++attempt) + "..."); 201 session = createSession(); 202 } catch (IOException e) { 203 LOG.info("Failed to reconnect to " + getEndpoint().getConnectionString()); 204 closeSession(session); 205 try { 206 Thread.sleep(configuration.getReconnectDelay()); 207 } catch (InterruptedException ee) { 208 } 209 } 210 } 211 LOG.info("Reconnected to " + getEndpoint().getConnectionString()); 212 } 213 }.start(); 214 } 215 216 @Override 217 public SmppEndpoint getEndpoint() { 218 return (SmppEndpoint) super.getEndpoint(); 219 } 220 221 /** 222 * Returns the smppConfiguration for this producer 223 * 224 * @return the configuration 225 */ 226 public SmppConfiguration getConfiguration() { 227 return configuration; 228 } 229 230 @Override 231 public String toString() { 232 return "SmppProducer[" + getEndpoint().getConnectionString() + "]"; 233 } 234 }