Utils.java [src/csip] Revision: 445c5e807c8bf0fabd9f52f0e394eced6b4cc91e  Date: Wed Apr 26 16:46:23 MDT 2017
/*
 * $Id$
 *
 * This file is part of the Cloud Services Integration Platform (CSIP),
 * a Model-as-a-Service framework, API and application suite.
 *
 * 2012-2017, Olaf David and others, OMSLab, Colorado Stage University.
 *
 * OMSLab licenses this file to you under the MIT license.
 * See the LICENSE file in the project root for more information.
 */
package csip;

import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.net.UnknownHostException;
import java.util.HashSet;
import java.util.Properties;
import java.util.Set;
import java.util.logging.Level;
import javax.servlet.http.HttpServletRequest;
import javax.ws.rs.Path;
import javax.ws.rs.WebApplicationException;
import javax.ws.rs.core.Response;
import oms3.annotations.Description;
import oms3.annotations.Name;
import org.apache.commons.net.util.SubnetUtils;
import csip.annotations.Stage;

/**
 * CSIP core package Utilities.
 *
 * @author od
 */
public class Utils {

    static void checkRemoteAccessACL(HttpServletRequest req) {
        String reqIp = req.getHeader("X-Forwarded-For");
        if (reqIp == null) {
            reqIp = req.getRemoteAddr();
        }
        if (!checkRemoteAccessACL(reqIp)) {
            Config.LOG.log(Level.WARNING, req.getMethod() + " " + req.getRequestURI() + ", denied for " + reqIp);
            throw new WebApplicationException(Response.Status.UNAUTHORIZED);
        }
        Config.LOG.log(Level.INFO, req.getMethod() + " " + req.getRequestURI() + ", OK for " + reqIp);
    }


    static boolean checkRemoteAccessACL(String ip) {
        // default is "localhost" only.
        String acls = Config.getString(Config.CSIP_REMOTE_ACL);
        String[] acl = acls.split("\\s+");
        for (String sn : acl) {
            if (sn.indexOf('/') == -1) {
                if (sn.equals(ip)) {
                    return true;
                }
            } else {
                if (isInSubnet(ip, sn)) {
                    return true;
                }
            }
        }
        return false;
    }


    static boolean isInSubnet(String ip, String subnet) {
        try {
            SubnetUtils utils = new SubnetUtils(subnet);
            utils.setInclusiveHostCount(true);
            return utils.getInfo().isInRange(ip);
        } catch (Exception E) {
            Config.LOG.log(Level.WARNING, "Invalid Subnet: " + subnet, E);
            return false;
        }
    }


    /**
     * Resolve a string with system and CSIP properties.
     *
     * @param str the string to resolve
     * @return the resolved string.
     */
    public static String resolve(String str) {
        if (str == null) {
            return null;
        }
        if (!str.contains("${")) {
            return str;
        }
        String res = resolve0(str, Config.getMergedProperties(), new HashSet<>());
        if (res.contains("${")) {
            Config.LOG.warning("Resolving one or more varariables failed in: " + res);
        }
        return res;
    }


    /**
     * property substitution in a string.
     *
     * @param str
     * @return
     */
    private static String resolve0(String str, Properties prop, Set<String> keys) {
        int idx = 0;
        while (idx < str.length()) {
            int start = str.indexOf("${", idx);
            int end = str.indexOf("}", idx);
            if (start == -1 || end == -1 || end < start) {
                break;
            }
            String key = str.substring(start + 2, end);
            if (keys.contains(key)) {
                System.err.println("Circular property reference: " + key);
                break;
            }
            String val = prop.getProperty(key);
            if (val != null) {
                keys.add(key);
                val = resolve0(val, prop, keys);
                keys.remove(key);
                str = str.replace("${" + key + "}", val);
                idx = start + val.length();
            } else {
                idx = start + key.length() + 3;
            }
        }
        return str;
    }


    static void callStaticMethodIfExist(Class<?> c, String method) {
        try {
            Method m = c.getMethod(method);
            m.invoke(null);
            Config.LOG.info("Found and Invoked '" + method + "' in: " + c);
        } catch (NoSuchMethodException ex) {
            return; // no problem
        } catch (SecurityException | IllegalAccessException | IllegalArgumentException | InvocationTargetException ex) {
            Config.LOG.log(Level.SEVERE, null, ex);
        }
    }


    static String humanReadableByteCount(long bytes, boolean si) {
        int unit = si ? 1000 : 1024;
        if (bytes < unit) {
            return bytes + " B";
        }
        int exp = (int) (Math.log(bytes) / Math.log(unit));
        String pre = (si ? "kMGTPE" : "KMGTPE").charAt(exp - 1) + (si ? "" : "i");
        return String.format("%.1f %sB", bytes / Math.pow(unit, exp), pre);
    }


    static String getServiceDescription(Class<?> c) {
        Description p = c.getAnnotation(Description.class);
        return (p != null) ? p.value() : null;
    }


    static String getServicePath(Class<?> c) {
        Path p = c.getAnnotation(Path.class);
        return (p != null) ? p.value() : null;
    }


    static String getServiceName(Class<?> c) {
        Name p = c.getAnnotation(Name.class);
        return (p != null) ? p.value() : null;
    }


    static String getServiceStage(Class<?> c) {
        Deprecated d = c.getAnnotation(Deprecated.class);
        if (d != null) {
            return Stage.DEPRECATED;
        }
        Stage p = c.getAnnotation(Stage.class);
        if (p != null) {
            return p.value();
        }
        return null;
    }


    public static void main(String[] args) throws UnknownHostException {
        System.out.println(Utils.isInSubnet("101.2.228.68", "101.2.228.0/8"));
    }

}