package org.kannel.protocol.kbinds; import java.io.File; import java.io.FileInputStream; import java.io.IOException; import java.io.InputStream; import java.io.OutputStream; import java.io.BufferedOutputStream; import java.net.InetAddress; import java.net.UnknownHostException; import java.util.Properties; import org.kannel.protocol.exceptions.NotEnoughPropertiesException; import org.kannel.protocol.exceptions.PacketParseException; import org.kannel.protocol.exceptions.WrongPropertieException; import org.kannel.protocol.packets.AckMessage; import org.kannel.protocol.packets.BasicKannelProtocolMessage; import org.kannel.protocol.packets.BasicPacket; import org.kannel.protocol.packets.KInteger; import org.kannel.protocol.packets.SMSPacketMessage; import org.kannel.protocol.tools.DataTypesTools; /** * This class is used to maintain a link with a bearerbox, its purpuse is to * allow simple writing, reading and automated heart beating using a specified * rate. * * @author Oscar Medina Duarte * @author Garth Patil <garthpatil@gmail.com> */ public class KannelBinding { protected static final String prop_heartbeat_rate = "KannelBinding.heartbeating_rate"; protected static final String prop_initialConnectedState = "KannelBinding.initialConnectedState"; protected static final String prop_bearerbox_host = "KannelBinding.bearerbox_host"; protected static final String prop_bearerbox_port = "KannelBinding.bearerbox_port"; protected static final String prop_boxc_id = "KannelBinding.boxc_id"; protected long heartBeatRate = 60 * 1000; protected boolean connectedAtStart = false; protected InetAddress bearerBox = null; protected int port = 0; protected String boxc_id = null; protected Thread heartBeaterThread = null; protected HeartBeating heartBeater = null; protected KSocket kannelSocket = null; protected Properties conf = null; protected InputStream inBoundStream = null; protected OutputStream outBoundStream = null; /** * No-op constructor for the KannelBinding object. Used with IOC container config. */ public KannelBinding() {} /** * Constructor for the KannelBinding object * * @param conf Parameters to configure this * class's behaviour. * @exception NotEnoughPropertiesException Exception thrown when an important * property config is missing * @exception WrongPropertieException Exception thrown when a value for a * property is inapropriate * @exception IOException Exception thrown when connection to * the bearer box fails */ public KannelBinding(Properties conf) throws NotEnoughPropertiesException, WrongPropertieException, IOException { init(conf); if (this.connectedAtStart) { connect(); } } /** * This method starts a conenction with a bearerbox, as specified in the * properties file. * * @exception IOException Exception thrown when a connection error occurs */ public void connect() throws IOException { this.kannelSocket = new KSocket(this.bearerBox, this.port, this.boxc_id); this.inBoundStream = this.kannelSocket.getInputStream(); this.outBoundStream = this.kannelSocket.getOutputStream(); startHeartBeating(); } /** * Stops a bearerbox connection. * * @exception IOException Exception thrown when an error occurs */ public void disconnect() throws IOException { if (this.kannelSocket != null) { synchronized (this.kannelSocket) { this.kannelSocket.close(); } } stopHeartBeating(); } /** * Starts the heart beating thread class that sends Heat Beats to the bearer * in fixed slices of time as defined in the properties */ public void startHeartBeating() { if (this.heartBeater == null) { this.heartBeater = new HeartBeating(this, this.getHeartBeatRate()); } if (this.heartBeaterThread == null) { this.heartBeaterThread = new Thread(this.heartBeater); } if (!this.heartBeaterThread.isAlive()) { this.heartBeaterThread.start(); } } /** * Stops the heart beating Thread */ public void stopHeartBeating() { this.heartBeater.stop(); } /** * Sets the heartBeatRate attribute of the KannelBinding object * * @param heartBeatRate The new heartBeatRate value */ public void setHeartBeatRate(long heartBeatRate) { this.heartBeatRate = heartBeatRate; } /** * Gets the heartBeatRate attribute of the KannelBinding object * * @return The heartBeatRate value */ public long getHeartBeatRate() { return this.heartBeatRate; } /** * Sets the connectedAtStart attribute of the KannelBinding object * * @param connectedAtStart The new connectedAtStart value */ public void setConnectedAtStart(boolean connectedAtStart) { this.connectedAtStart = connectedAtStart; } /** * Gets the connectedAtStart attribute of the KannelBinding object * * @return The connectedAtStart value */ public boolean getConnectedAtStart() { return this.connectedAtStart; } /** * Sets the bearerBox attribute of the KannelBinding object * * @param bearerBox The new bearerBox value */ public void setBearerBox(InetAddress bearerBox) { this.bearerBox = bearerBox; } /** * Gets the bearerBox attribute of the KannelBinding object * * @return The bearerBox value */ public InetAddress getBearerBox() { return this.bearerBox; } /** * Sets the port attribute of the KannelBinding object * * @param port The new port value */ public void setPort(int port) { this.port = port; } /** * Gets the port attribute of the KannelBinding object * * @return The port value */ public int getPort() { return this.port; } /** * Sets the boxc_id attribute of the KannelBinding object * * @param boxc_id The new boxc_id value */ public void setBoxc_Id(String boxc_id) { this.boxc_id = boxc_id; } /** * Gets the boxc_id attribute of the KannelBinding object * * @return The boxc_id value */ public String getBoxc_Id() { return this.boxc_id; } /** * Gets the connected attribute of the KannelBinding object * * @return True if the link is up, false otherwise */ public boolean isConnected() { return this.kannelSocket.isConnected(); } /** * Sets up the properties variables from a properties file * * @param conf Description of the Parameter * @exception NotEnoughPropertiesException Exception thrown when * @exception WrongPropertieException Exception thrown when */ protected void init(Properties conf) throws NotEnoughPropertiesException, WrongPropertieException { // This sets up the configurations String swap = conf.getProperty(this.prop_heartbeat_rate); try { this.heartBeatRate = Integer.parseInt(swap); } catch (NumberFormatException e) { throw new WrongPropertieException(this.prop_heartbeat_rate + " = " + swap); } swap = conf.getProperty(this.prop_initialConnectedState); this.connectedAtStart = swap.equalsIgnoreCase("connected"); swap = conf.getProperty(this.prop_bearerbox_host); try { this.bearerBox = InetAddress.getByName(swap); } catch (UnknownHostException e) { throw new WrongPropertieException(this.prop_bearerbox_host + " = " + swap); } swap = conf.getProperty(this.prop_bearerbox_port); try { this.port = Integer.parseInt(swap); } catch (NumberFormatException e) { throw new WrongPropertieException(this.prop_bearerbox_port + " = " + swap); } this.boxc_id = conf.getProperty(this.prop_boxc_id); } public BasicPacket read() throws Exception { return readNext(); } /** * Reads next packet from link * * @return BasicPacket object * @exception IOException Exception thrown when reading fails or * there is not enough data to fill a field * @exception PacketParseException Exception thrown when parsing of a Packet * fails */ protected BasicPacket readNext() throws IOException, PacketParseException { BasicPacket bPckt = null; KInteger kLen = null; int len = 0; KInteger kType = null; int type = -1; byte[] bInt = new byte[4]; byte[] swap = null; int read = 0; // leemos 4 bytes para la long KInteger //System.out.println("---"); read = this.inBoundStream.read(bInt); //System.out.println("+++"); if (read < bInt.length) { throw new IOException("Not enough data to be read to fill a KInteger!"); } else { kLen = new KInteger(bInt); len = kLen.getIntValue(); // System.out.println("len: " + len); if (len < 4) { return null; } } //System.out.println("i"); read = 0; bInt[0] = bInt[1] = bInt[2] = bInt[3] = 0; // leemos 4 bytes para el tipo KInteger read = this.inBoundStream.read(bInt); if (read < bInt.length) { throw new IOException("Not enough data to be read to fill a KInteger!"); } else { kType = new KInteger(bInt); type = kType.getIntValue(); } read = 0; bInt = null; //System.out.println("f"); // leemos len numerio de bytes a un byte array bInt = new byte[len + 4]; swap = kLen.getBytes(); for (int i = 0; i < 4; i++) { bInt[read] = swap[i]; read++; } swap = kType.getBytes(); for (int i = 0; i < 4; i++) { bInt[read] = swap[i]; read++; } swap = null; read = this.inBoundStream.read(bInt, 8, len - 8 ); this.inBoundStream.read(); this.inBoundStream.read(); this.inBoundStream.read(); this.inBoundStream.read(); System.out.println("in:\n" + DataTypesTools.hexDump(bInt)); // Parseamos segun sea el Type // System.out.println("Leyendo... type: " + type); switch (type) { case 2: { bPckt = new SMSPacketMessage(bInt); //System.out.println("++ " + bPckt); break; }case 3: { bPckt = new AckMessage(bInt); break; } default: { } } return bPckt; } public void write(BasicKannelProtocolMessage bkpMessage) throws Exception { writeNext(bkpMessage); } /** * Writes a packet to the link * * @param bkpMessage Packet to be sent * @exception IOException Exception thrown when writing fails */ protected void writeNext(BasicKannelProtocolMessage bkpMessage) throws IOException { //synchronized (this.outBoundStream) { System.out.println("out:\n" + DataTypesTools.hexDump(bkpMessage.getMessage())); //System.out.print("."); this.outBoundStream.write(bkpMessage.getMessage()); //this.outBoundStream.write((char) 10); this.outBoundStream.flush(); /*BufferedOutputStream bos = new BufferedOutputStream(this.outBoundStream); byte[] out = bkpMessage.getMessage(); bos.write(out, 0, out.length ); bos.flush();*/ //} } public void rawWrite(byte[] pktMessage) throws IOException { //synchronized (this.outBoundStream) { // System.out.println("out:\n" + DataTypesTools.hexDump(bkpMessage.getMessage())); this.outBoundStream.write(pktMessage); //this.outBoundStream.write((char) 10); this.outBoundStream.flush(); //} } /** * Testing method * * @param args Description of the Parameter * @exception Exception Exception thrown when */ public static void main(String args[]) throws Exception { Properties props = new Properties(); props.load(new FileInputStream(new File(args[0]))); KannelBinding kbndg = new KannelBinding(props); int i = 0; BasicPacket bPckt; SMSPacketMessage sms = new SMSPacketMessage("12345", "6505551212", "", "test message"); kbndg.writeNext(sms); while (i < 2) { bPckt = kbndg.readNext(); if (bPckt != null) { System.out.println(bPckt); i++; Thread.sleep(1000); kbndg.writeNext(new AckMessage(0, (SMSPacketMessage) bPckt)); } } } }