Subversion Repositories HomeAutomation

Rev

Rev 1398 | Blame | Compare with Previous | Last modification | View Log | SVN | RSS feed

  1. /**
  2.  * File created by Jimmy
  3.  * at 2003-dec-28 19:56:06
  4.  */
  5. package Macbeth.Transports;
  6.  
  7. import Macbeth.Net.ServerDataHandler;
  8. import Macbeth.Net.TcpClient;
  9. import Macbeth.Net.TcpServer;
  10. import Macbeth.Utilities.MySystem;
  11. import Macbeth.System.*;
  12. import java.io.IOException;
  13. import java.net.UnknownHostException;
  14.  
  15. import org.xml.sax.SAXException;
  16.  
  17. /**
  18.  * An internet packet delivery transport for the Macbeth kernel.
  19.  * This will deliver packets to and from other remotely located
  20.  * Macbeth kernels via the internet.
  21.  * @author Jimmy
  22.  */
  23. public class MbInternetTransport extends MbPacketTransport {
  24.  
  25.     //A list of known kernels.
  26.     public MbInternetAddressList kernelList;
  27.     //The TCP port on which we're listening for internet packets.
  28.     public int ourPort;
  29.     //Indicates whether or not we're currently receaving a packet as a raw string on the internet server.
  30.     private boolean receivingPacketString;
  31.     //Indicates whether an XML declaration (eg. <?xml version="1.0" encoding="Unicode"?>) has been received
  32.     private boolean xmlDeclarationReceived;
  33.     private String receivedString;
  34.     private String clientRemoteAddress;
  35.  
  36.     //our tcp server
  37.     private TcpServer server;
  38.     //our tcp client
  39.     private TcpClient client;
  40.  
  41.     /**
  42.      * Creates a new instance of MbInternetTransport.
  43.      */
  44.     public MbInternetTransport(MbKernel parentKernel) {
  45.         super(parentKernel);
  46.         //create new kernel list
  47.         kernelList = new MbInternetAddressList();
  48.         //initial values
  49.         ourPort = 19000;
  50.         receivingPacketString = false;
  51.         xmlDeclarationReceived = false;
  52.         receivedString = "";
  53.         clientRemoteAddress = "";
  54.         server = null;
  55.         client = null;
  56.     }
  57.  
  58.     /**
  59.      * Starts up the internet delivery system.
  60.      */
  61.     public void startup() {
  62.         super.startup();
  63.         //start inet server and use our own ServerDataHandler interface to handle data
  64.         server = new TcpServer(ourPort,new MyServerDataHandler());
  65.         server.startServer();
  66.     }
  67.  
  68.     /**
  69.      * Shuts down the internet delivery system.
  70.      */
  71.     public void shutdown() {
  72.         super.shutdown();
  73.         //shut down internet server
  74.         server.stopServer();
  75.     }
  76.  
  77.     /**
  78.      * Returns the name of this transport.
  79.      * @return The name of this transport.
  80.      */
  81.     public String getName() {
  82.         return "Internet transport";
  83.     }
  84.  
  85.     /**
  86.      * Tries to deliver a packet via the internet transport.
  87.      * @param p The packet that needs to be delivered.
  88.      * @return True if the packet has been delivered successfully.
  89.      * False if this packet cannot be delivered via this transport
  90.      * (that is, if it has a destination kernel that is either unknown
  91.      * or local, "self").
  92.      * @throws Macbeth.System.MbPacketTransport.MbPacketDeliveryException if an error occured while trying
  93.      * to deliver the packet (I/O-errors or invalid addresses).
  94.      */
  95.     public boolean deliverPacket(MbPacket p) throws MbPacketTransport.MbPacketDeliveryException {
  96.         MbInternetAddress kernelAddress = kernelList.getAddress(p.getDestination().getKernel());
  97.         //if no such kernel existed in our kernel list...
  98.         if (kernelAddress==null) {
  99.             //then we cannot deliver this packet
  100.             return false;
  101.             //if we do know about the destination kernel
  102.         } else {
  103.             //lets deliver
  104.             try {
  105.                 deliverPacketViaInternet(p,kernelAddress);
  106.             } catch (Exception e) {
  107.                 throw new MbPacketTransport.MbPacketDeliveryException(e.toString());
  108.             }
  109.         }
  110.         return true;
  111.     }
  112.  
  113.     /**
  114.      * Delivers a packet via internet.
  115.      * @param p The packet that should be delivered.
  116.      * @param addr The kernel address to which the packet should be delivered.
  117.      * @throws IOException if an I/O-error occurs while trying to send the packet.
  118.      * @throws UnknownHostException if the specified address is invalid.
  119.      */
  120.     protected void deliverPacketViaInternet(MbPacket p, MbInternetAddress addr)
  121.             throws IOException, UnknownHostException
  122.     {
  123.         //connect our TCP client to the specified host and port
  124.         client = new TcpClient(addr.getPort(),addr.getHostname());
  125.         client.openConnection();
  126.         //send the packet via the client
  127.         client.sendString(p.serializeToString());
  128.         //and then disconnect
  129.         client.closeConnection();
  130.         client = null;
  131.         //we've now sent the packet successfully, so increase sent packets-counter
  132.         packetsSent++;
  133.     }
  134.  
  135.  
  136.     /**
  137.      * Will take care of incoming server data.
  138.      */
  139.     private class MyServerDataHandler implements ServerDataHandler {
  140.         /**
  141.          * Will be called when server has received a string
  142.          * that your datahandler need to take care of.
  143.          * @param data The received string.
  144.          */
  145.         public void handleServerData(String data, String address) {
  146.             //does the string contain an XML declaration line?
  147.             int xmlDeclarationStart = data.indexOf("<?xml");
  148.             if (xmlDeclarationStart!=-1) {
  149.                 //if so, start receiving the (new) XML document (discarding any previously received data)
  150.                 receivedString = data.substring(xmlDeclarationStart) + MySystem.lineBreak;
  151.                 xmlDeclarationReceived = true;
  152.             }
  153.             //does the string contain the root element of a macbeth packet?
  154.             int mbpacketStart = data.indexOf("<mbpacket");
  155.             if (mbpacketStart != -1) {
  156.                 //If so, we're about to begin receiving a packet, but first we must make sure that
  157.                 //the XML document contains an XML declaration. If this has not already been received...
  158.                 if (!xmlDeclarationReceived) {
  159.                     //begin with a standard declaration (assume ascii!)
  160.                     receivedString = "<?xml version=\"1.0\" encoding=\"ascii\"?>" + MySystem.lineBreak;
  161.                     //and add everything after the root element
  162.                     receivedString += data.substring(mbpacketStart);
  163.                 }
  164.                 //the XML declaration HAS been received
  165.                 else {
  166.                     //just append the data to the existing string
  167.                     receivedString += data;
  168.                 }
  169.                 receivingPacketString = true;
  170.                 //also put the clients remote address into this packet
  171.                 receivedString += MySystem.lineBreak + "<remoteaddress value=\"" + clientRemoteAddress + "\"/>" + MySystem.lineBreak;
  172.             }
  173.             //does this line close the root element of a macbeth packet?
  174.             int mbpacketEnd = data.indexOf("</mbpacket>");
  175.             if (mbpacketEnd != -1 && receivingPacketString) {
  176.                 receivedString += data.substring(0, mbpacketEnd + "</mbpacket>".length());
  177.                 MbPacket p = new MbPacket();
  178.                 //if so, try to create a packet from the string we've received
  179.                 try {
  180.                     p.createFromString(receivedString);
  181.                     //if successful, handle this packet now
  182.                     packetReceived(p);
  183.                 }
  184.                 catch (SAXException e) {
  185.                     //if unsuccessful, log this error
  186.                     _info.println("A string was received on the server port, but it could not " +
  187.                                   "be identified as a packet due to syntax errors (" + e + ")");
  188.                     _info.println("The received string was:" + MySystem.lineBreak + receivedString);
  189.                 }
  190.                 //clear received-string now
  191.                 receivedString = new String();
  192.                 xmlDeclarationReceived = false;
  193.             }
  194.             //all data inside the packet should just be appended
  195.             if (mbpacketStart==-1 && mbpacketEnd==-1 && xmlDeclarationStart==-1 && receivingPacketString) {
  196.                 receivedString += data;
  197.             }
  198.         }
  199.  
  200.         /**
  201.          * Notifies your datahandler about a clients remote address.
  202.          * Will be called by server when a new socket is opened.
  203.          * @param address The clients remote address (IP number)
  204.          */
  205.         public void setRemoteAddress(String address) {
  206.             //save the remote address for later use
  207.             clientRemoteAddress = address;
  208.         }
  209.  
  210.         public void clientDropped(String address) { }
  211.     }
  212. }
  213.