/protocol/src/main/java/org/kannel/protocol/kbinds/KannelBinding.java

https://github.com/sdqali/kannel-java · Java · 431 lines · 231 code · 52 blank · 148 comment · 19 complexity · 040b0d3470234310d900f6a330d02cc6 MD5 · raw file

  1. package org.kannel.protocol.kbinds;
  2. import java.io.File;
  3. import java.io.FileInputStream;
  4. import java.io.IOException;
  5. import java.io.InputStream;
  6. import java.io.OutputStream;
  7. import java.io.BufferedOutputStream;
  8. import java.net.InetAddress;
  9. import java.net.UnknownHostException;
  10. import java.util.Properties;
  11. import org.kannel.protocol.exceptions.NotEnoughPropertiesException;
  12. import org.kannel.protocol.exceptions.PacketParseException;
  13. import org.kannel.protocol.exceptions.WrongPropertieException;
  14. import org.kannel.protocol.packets.AckMessage;
  15. import org.kannel.protocol.packets.BasicKannelProtocolMessage;
  16. import org.kannel.protocol.packets.BasicPacket;
  17. import org.kannel.protocol.packets.KInteger;
  18. import org.kannel.protocol.packets.SMSPacketMessage;
  19. import org.kannel.protocol.tools.DataTypesTools;
  20. /**
  21. * This class is used to maintain a link with a bearerbox, its purpuse is to
  22. * allow simple writing, reading and automated heart beating using a specified
  23. * rate.
  24. *
  25. * @author Oscar Medina Duarte
  26. * @author Garth Patil <garthpatil@gmail.com>
  27. */
  28. public class KannelBinding
  29. {
  30. protected static final String prop_heartbeat_rate = "KannelBinding.heartbeating_rate";
  31. protected static final String prop_initialConnectedState = "KannelBinding.initialConnectedState";
  32. protected static final String prop_bearerbox_host = "KannelBinding.bearerbox_host";
  33. protected static final String prop_bearerbox_port = "KannelBinding.bearerbox_port";
  34. protected static final String prop_boxc_id = "KannelBinding.boxc_id";
  35. protected long heartBeatRate = 60 * 1000;
  36. protected boolean connectedAtStart = false;
  37. protected InetAddress bearerBox = null;
  38. protected int port = 0;
  39. protected String boxc_id = null;
  40. protected Thread heartBeaterThread = null;
  41. protected HeartBeating heartBeater = null;
  42. protected KSocket kannelSocket = null;
  43. protected Properties conf = null;
  44. protected InputStream inBoundStream = null;
  45. protected OutputStream outBoundStream = null;
  46. /**
  47. * No-op constructor for the KannelBinding object. Used with IOC container config.
  48. */
  49. public KannelBinding() {}
  50. /**
  51. * Constructor for the KannelBinding object
  52. *
  53. * @param conf Parameters to configure this
  54. * class's behaviour.
  55. * @exception NotEnoughPropertiesException Exception thrown when an important
  56. * property config is missing
  57. * @exception WrongPropertieException Exception thrown when a value for a
  58. * property is inapropriate
  59. * @exception IOException Exception thrown when connection to
  60. * the bearer box fails
  61. */
  62. public KannelBinding(Properties conf) throws NotEnoughPropertiesException, WrongPropertieException, IOException {
  63. init(conf);
  64. if (this.connectedAtStart) {
  65. connect();
  66. }
  67. }
  68. /**
  69. * This method starts a conenction with a bearerbox, as specified in the
  70. * properties file.
  71. *
  72. * @exception IOException Exception thrown when a connection error occurs
  73. */
  74. public void connect() throws IOException {
  75. this.kannelSocket = new KSocket(this.bearerBox,
  76. this.port,
  77. this.boxc_id);
  78. this.inBoundStream = this.kannelSocket.getInputStream();
  79. this.outBoundStream = this.kannelSocket.getOutputStream();
  80. startHeartBeating();
  81. }
  82. /**
  83. * Stops a bearerbox connection.
  84. *
  85. * @exception IOException Exception thrown when an error occurs
  86. */
  87. public void disconnect() throws IOException {
  88. if (this.kannelSocket != null) {
  89. synchronized (this.kannelSocket) {
  90. this.kannelSocket.close();
  91. }
  92. }
  93. stopHeartBeating();
  94. }
  95. /**
  96. * Starts the heart beating thread class that sends Heat Beats to the bearer
  97. * in fixed slices of time as defined in the properties
  98. */
  99. public void startHeartBeating() {
  100. if (this.heartBeater == null) {
  101. this.heartBeater = new HeartBeating(this, this.getHeartBeatRate());
  102. }
  103. if (this.heartBeaterThread == null) {
  104. this.heartBeaterThread = new Thread(this.heartBeater);
  105. }
  106. if (!this.heartBeaterThread.isAlive()) {
  107. this.heartBeaterThread.start();
  108. }
  109. }
  110. /**
  111. * Stops the heart beating Thread
  112. */
  113. public void stopHeartBeating() {
  114. this.heartBeater.stop();
  115. }
  116. /**
  117. * Sets the heartBeatRate attribute of the KannelBinding object
  118. *
  119. * @param heartBeatRate The new heartBeatRate value
  120. */
  121. public void setHeartBeatRate(long heartBeatRate) {
  122. this.heartBeatRate = heartBeatRate;
  123. }
  124. /**
  125. * Gets the heartBeatRate attribute of the KannelBinding object
  126. *
  127. * @return The heartBeatRate value
  128. */
  129. public long getHeartBeatRate() {
  130. return this.heartBeatRate;
  131. }
  132. /**
  133. * Sets the connectedAtStart attribute of the KannelBinding object
  134. *
  135. * @param connectedAtStart The new connectedAtStart value
  136. */
  137. public void setConnectedAtStart(boolean connectedAtStart) {
  138. this.connectedAtStart = connectedAtStart;
  139. }
  140. /**
  141. * Gets the connectedAtStart attribute of the KannelBinding object
  142. *
  143. * @return The connectedAtStart value
  144. */
  145. public boolean getConnectedAtStart() {
  146. return this.connectedAtStart;
  147. }
  148. /**
  149. * Sets the bearerBox attribute of the KannelBinding object
  150. *
  151. * @param bearerBox The new bearerBox value
  152. */
  153. public void setBearerBox(InetAddress bearerBox) {
  154. this.bearerBox = bearerBox;
  155. }
  156. /**
  157. * Gets the bearerBox attribute of the KannelBinding object
  158. *
  159. * @return The bearerBox value
  160. */
  161. public InetAddress getBearerBox() {
  162. return this.bearerBox;
  163. }
  164. /**
  165. * Sets the port attribute of the KannelBinding object
  166. *
  167. * @param port The new port value
  168. */
  169. public void setPort(int port) {
  170. this.port = port;
  171. }
  172. /**
  173. * Gets the port attribute of the KannelBinding object
  174. *
  175. * @return The port value
  176. */
  177. public int getPort() {
  178. return this.port;
  179. }
  180. /**
  181. * Sets the boxc_id attribute of the KannelBinding object
  182. *
  183. * @param boxc_id The new boxc_id value
  184. */
  185. public void setBoxc_Id(String boxc_id) {
  186. this.boxc_id = boxc_id;
  187. }
  188. /**
  189. * Gets the boxc_id attribute of the KannelBinding object
  190. *
  191. * @return The boxc_id value
  192. */
  193. public String getBoxc_Id() {
  194. return this.boxc_id;
  195. }
  196. /**
  197. * Gets the connected attribute of the KannelBinding object
  198. *
  199. * @return True if the link is up, false otherwise
  200. */
  201. public boolean isConnected() {
  202. return this.kannelSocket.isConnected();
  203. }
  204. /**
  205. * Sets up the properties variables from a properties file
  206. *
  207. * @param conf Description of the Parameter
  208. * @exception NotEnoughPropertiesException Exception thrown when
  209. * @exception WrongPropertieException Exception thrown when
  210. */
  211. protected void init(Properties conf) throws NotEnoughPropertiesException, WrongPropertieException {
  212. // This sets up the configurations
  213. String swap = conf.getProperty(this.prop_heartbeat_rate);
  214. try {
  215. this.heartBeatRate = Integer.parseInt(swap);
  216. } catch (NumberFormatException e) {
  217. throw new WrongPropertieException(this.prop_heartbeat_rate + " = " + swap);
  218. }
  219. swap = conf.getProperty(this.prop_initialConnectedState);
  220. this.connectedAtStart = swap.equalsIgnoreCase("connected");
  221. swap = conf.getProperty(this.prop_bearerbox_host);
  222. try {
  223. this.bearerBox = InetAddress.getByName(swap);
  224. } catch (UnknownHostException e) {
  225. throw new WrongPropertieException(this.prop_bearerbox_host + " = " + swap);
  226. }
  227. swap = conf.getProperty(this.prop_bearerbox_port);
  228. try {
  229. this.port = Integer.parseInt(swap);
  230. } catch (NumberFormatException e) {
  231. throw new WrongPropertieException(this.prop_bearerbox_port + " = " + swap);
  232. }
  233. this.boxc_id = conf.getProperty(this.prop_boxc_id);
  234. }
  235. public BasicPacket read() throws Exception
  236. {
  237. return readNext();
  238. }
  239. /**
  240. * Reads next packet from link
  241. *
  242. * @return BasicPacket object
  243. * @exception IOException Exception thrown when reading fails or
  244. * there is not enough data to fill a field
  245. * @exception PacketParseException Exception thrown when parsing of a Packet
  246. * fails
  247. */
  248. protected BasicPacket readNext() throws IOException, PacketParseException
  249. {
  250. BasicPacket bPckt = null;
  251. KInteger kLen = null;
  252. int len = 0;
  253. KInteger kType = null;
  254. int type = -1;
  255. byte[] bInt = new byte[4];
  256. byte[] swap = null;
  257. int read = 0;
  258. // leemos 4 bytes para la long KInteger
  259. //System.out.println("---");
  260. read = this.inBoundStream.read(bInt);
  261. //System.out.println("+++");
  262. if (read < bInt.length) {
  263. throw new IOException("Not enough data to be read to fill a KInteger!");
  264. } else {
  265. kLen = new KInteger(bInt);
  266. len = kLen.getIntValue();
  267. // System.out.println("len: " + len);
  268. if (len < 4) {
  269. return null;
  270. }
  271. }
  272. //System.out.println("i");
  273. read = 0;
  274. bInt[0] = bInt[1] = bInt[2] = bInt[3] = 0;
  275. // leemos 4 bytes para el tipo KInteger
  276. read = this.inBoundStream.read(bInt);
  277. if (read < bInt.length) {
  278. throw new IOException("Not enough data to be read to fill a KInteger!");
  279. } else {
  280. kType = new KInteger(bInt);
  281. type = kType.getIntValue();
  282. }
  283. read = 0;
  284. bInt = null;
  285. //System.out.println("f");
  286. // leemos len numerio de bytes a un byte array
  287. bInt = new byte[len + 4];
  288. swap = kLen.getBytes();
  289. for (int i = 0; i < 4; i++) {
  290. bInt[read] = swap[i];
  291. read++;
  292. }
  293. swap = kType.getBytes();
  294. for (int i = 0; i < 4; i++) {
  295. bInt[read] = swap[i];
  296. read++;
  297. }
  298. swap = null;
  299. read = this.inBoundStream.read(bInt, 8, len - 8 );
  300. this.inBoundStream.read();
  301. this.inBoundStream.read();
  302. this.inBoundStream.read();
  303. this.inBoundStream.read();
  304. System.out.println("in:\n" + DataTypesTools.hexDump(bInt));
  305. // Parseamos segun sea el Type
  306. // System.out.println("Leyendo... type: " + type);
  307. switch (type) {
  308. case 2:
  309. {
  310. bPckt = new SMSPacketMessage(bInt);
  311. //System.out.println("++ " + bPckt);
  312. break;
  313. }case 3:
  314. {
  315. bPckt = new AckMessage(bInt);
  316. break;
  317. }
  318. default:
  319. {
  320. }
  321. }
  322. return bPckt;
  323. }
  324. public void write(BasicKannelProtocolMessage bkpMessage) throws Exception
  325. {
  326. writeNext(bkpMessage);
  327. }
  328. /**
  329. * Writes a packet to the link
  330. *
  331. * @param bkpMessage Packet to be sent
  332. * @exception IOException Exception thrown when writing fails
  333. */
  334. protected void writeNext(BasicKannelProtocolMessage bkpMessage) throws IOException {
  335. //synchronized (this.outBoundStream) {
  336. System.out.println("out:\n" + DataTypesTools.hexDump(bkpMessage.getMessage()));
  337. //System.out.print(".");
  338. this.outBoundStream.write(bkpMessage.getMessage());
  339. //this.outBoundStream.write((char) 10);
  340. this.outBoundStream.flush();
  341. /*BufferedOutputStream bos = new BufferedOutputStream(this.outBoundStream);
  342. byte[] out = bkpMessage.getMessage();
  343. bos.write(out, 0, out.length );
  344. bos.flush();*/
  345. //}
  346. }
  347. public void rawWrite(byte[] pktMessage) throws IOException {
  348. //synchronized (this.outBoundStream) {
  349. // System.out.println("out:\n" + DataTypesTools.hexDump(bkpMessage.getMessage()));
  350. this.outBoundStream.write(pktMessage);
  351. //this.outBoundStream.write((char) 10);
  352. this.outBoundStream.flush();
  353. //}
  354. }
  355. /**
  356. * Testing method
  357. *
  358. * @param args Description of the Parameter
  359. * @exception Exception Exception thrown when
  360. */
  361. public static void main(String args[]) throws Exception {
  362. Properties props = new Properties();
  363. props.load(new FileInputStream(new File(args[0])));
  364. KannelBinding kbndg = new KannelBinding(props);
  365. int i = 0;
  366. BasicPacket bPckt;
  367. SMSPacketMessage sms = new SMSPacketMessage("12345", "6505551212", "", "test message");
  368. kbndg.writeNext(sms);
  369. while (i < 2) {
  370. bPckt = kbndg.readNext();
  371. if (bPckt != null) {
  372. System.out.println(bPckt);
  373. i++;
  374. Thread.sleep(1000);
  375. kbndg.writeNext(new AckMessage(0, (SMSPacketMessage) bPckt));
  376. }
  377. }
  378. }
  379. }