/* ***** BEGIN LICENSE BLOCK ***** * Version: MPL 1.1 * * The contents of this file are subject to the Mozilla Public License Version * 1.1 (the "License"); you may not use this file except in compliance with * the License. You may obtain a copy of the License at * http://www.mozilla.org/MPL/ * * Software distributed under the License is distributed on an "AS IS" basis, * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License * for the specific language governing rights and limitations under the * License. * * The Original Code is OpenEMRConnect. * * The Initial Developer of the Original Code is International Training & * Education Center for Health (I-TECH) <http://www.go2itech.org/> * * Portions created by the Initial Developer are Copyright (C) 2011 * the Initial Developer. All Rights Reserved. * * Contributor(s): * * ***** END LICENSE BLOCK ***** */ package ke.go.moh.oec.lib; import java.net.InetAddress; import java.net.UnknownHostException; import java.util.Enumeration; import java.util.HashMap; import java.util.Map; import java.util.Properties; import java.util.logging.Level; import java.util.logging.Logger; /** * Information about the next hop to which we will send a message. * Information includes the IP Address and port of the next hop, * the maximum packet size allowed (if any maximum), and * whether or not to zip compress the packet before transmission. * * @author Jim Grace */ public class NextHop { private String ipAddressPort; private int maxSize = Integer.MAX_VALUE; // Default maxSize setting; private boolean zip = false; private boolean md5Required = false; private boolean lengthRequired = false; static private Map<String, NextHop> nextHopByAddress = new HashMap<String, NextHop>(); static private Map<String, NextHop> nextHopByIpPort = new HashMap<String, NextHop>(); public String getIpAddressPort() { return ipAddressPort; } public void setIpAddressPort(String ipAddressPort) { this.ipAddressPort = ipAddressPort; } public boolean isLengthRequired() { return lengthRequired; } public void setLengthRequired(boolean lengthRequired) { this.lengthRequired = lengthRequired; } public int getMaxSize() { return maxSize; } public void setMaxSize(int maxSize) { this.maxSize = maxSize; } public boolean isMd5Required() { return md5Required; } public void setMd5Required(boolean md5Required) { this.md5Required = md5Required; } public boolean isZip() { return zip; } public void setZip(boolean zip) { this.zip = zip; } private static NextHop parseHopString(String hopString) { NextHop hop = new NextHop(); int slash = hopString.indexOf("/"); if (slash > 0) { String options = hopString.substring(slash + 1); hopString = hopString.substring(0, slash); for (String opt : options.split("/")) { if (opt.equalsIgnoreCase("zip")) { hop.zip = true; } else if (opt.equalsIgnoreCase("length")) { hop.lengthRequired = true; } else if (opt.equalsIgnoreCase("md5")) { hop.md5Required = true; } String[] pair = opt.split("="); if (pair[0].equalsIgnoreCase("maxSize")) { hop.maxSize = Integer.parseInt(pair[1]); } } } hop.ipAddressPort = hopString; return hop; } /** * Gets next hop information for a destination address * <p> * The next hop information corresponding to a destination address is found * in properties for this application starting with "IPAddressPort." * If the full address is not found, then we look for successively * higher levels in the address name, where levels are separated by * dots. Finally we look for the catch-all entry "IPAddressPort.*" * to which we forward any otherwise-unresolved address. * <p> * For example, if the address to find is "aa.bb.cc", we will look * for the following properties in this order until we find a value: * <p> * IpAddressPort.aa.bb.cc <br> * IpAddressPort.aa.bb <br> * IpAddressPort.aa <br> * IpAddressPort.* <br> * * @param destination where the message is to be sent * @return IP address:port to which to forward the message. * Returns <code>null</code> if the destination is ourselves, * or the destination address cannot be translated to IP + port. */ public static synchronized NextHop getNextHopByAddress(String destination) { // // If the destination is us, return null. This means that // we don't have to go to the network to find the address; // the address is our own. // if (destination.equalsIgnoreCase(Mediator.getProperty("Instance.Address"))) { return null; } // // If we have the next hop already in our cache, return it. // NextHop hop = nextHopByAddress.get(destination); // // If it wasn't in our cache, parse it from the properties. // (Note that it may have been in our cache with a value of null. Check for that.) // if (hop == null && !nextHopByAddress.containsKey(destination)) { final String propertyPrefix = "IPAddressPort."; // // Check for an explicit entry for this destination address. // String hopString = Mediator.getProperty(propertyPrefix + destination); // // If there was no entry for the whole address, try successively // shorter strings by chopping off the end from the last '.' character. // String d = destination; while (hopString == null) { int i = d.lastIndexOf('.'); // // If there are no more segments to chop, try for // the catch-all wildcard entry. // if (i < 0) { hopString = Mediator.getProperty(propertyPrefix + "*"); break; } // // Chop the string and look for the next higher level. // d = d.substring(0, i); hopString = Mediator.getProperty(propertyPrefix + d); } if (hopString != null) { hop = parseHopString(hopString); } // Put it in our cache (whether result was null or not) for the next time. nextHopByAddress.put(destination, hop); } return hop; } /** * Resolves an IP address by translating any symbolic host name * to numerical form, if necessary. * * @param address IP address (and port) to translate * @return IP address translated to numerical form (and port, if present). */ private static String numericIpAddress(String address) { String returnValue = address; String ip = address; int i = address.indexOf(":"); if (i >= 0) { ip = address.substring(0, i); } InetAddress ia = null; try { ia = InetAddress.getByName(ip); } catch (UnknownHostException ex) { Logger.getLogger(NextHop.class.getName()).log(Level.SEVERE, "Can't translate IP address '" + address + "'", ex); } if (ia != null) { returnValue = ia.getHostAddress(); if (i >= 0) { returnValue += address.substring(i); } } return returnValue; } /** * Gets next hop information for a numeric IP address and (if we have it) port number. * * @param address numeric IP address and (if we have it) port number. * @return next hop information. */ public static synchronized NextHop getNextHopByIpPort(String address) { // // If we have the next hop already in our cache, return it. // NextHop hop = nextHopByIpPort.get(address); // // If it wasn't in our cache, parse it from the properties. // (Note that it may have been in our cache with a value of null. Check for that.) // if (hop == null && !nextHopByIpPort.containsKey(address)) { int portSeparator = address.indexOf(":"); Properties props = Mediator.getProperties(); for (Enumeration e = props.propertyNames(); e.hasMoreElements();) { String propName = (String) e.nextElement(); if (propName.startsWith("IPAddressPort")) { String hopString = props.getProperty(propName); hop = parseHopString(hopString); String numericIp = numericIpAddress(hop.ipAddressPort); // // If we only came here with an IP address (no port), // then strip the port number off the properties entry for comparision. if (portSeparator < 0) { int i = numericIp.indexOf(":"); if (i >= 0) { numericIp = numericIp.substring(0, i); } } if (address.equals(numericIp)) { break; // NextHop is found } } } // Put it in our cache (whether result was null or not) for the next time. nextHopByIpPort.put(address, hop); } return hop; } }