edu.usc.pgroup.floe.utils.Utils.java Source code

Java tutorial

Introduction

Here is the source code for edu.usc.pgroup.floe.utils.Utils.java

Source

/*
 * Copyright 2014 University of Southern California
 *
 * Licensed under the Apache License, Version 2.0 (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.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

package edu.usc.pgroup.floe.utils;

import edu.usc.pgroup.floe.config.ConfigProperties;
import edu.usc.pgroup.floe.config.FloeConfig;
import org.apache.commons.lang.StringUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.zeromq.ZMQ;

import java.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream;
import java.io.File;
import java.io.IOException;
import java.io.ObjectInputStream;
import java.io.ObjectOutputStream;
import java.lang.reflect.Constructor;
import java.net.Inet6Address;
import java.net.InetAddress;
import java.net.MalformedURLException;
import java.net.NetworkInterface;
import java.net.SocketException;
import java.net.URL;
import java.net.URLClassLoader;
import java.nio.file.FileSystems;
import java.nio.file.Path;
import java.util.Enumeration;

/**
 * Common Utility Class.
 *
 * @author Alok Kumbhare
 */
public final class Utils {

    /**
     * the global logger instance.
     */
    private static final Logger LOGGER = LoggerFactory.getLogger(Utils.class);

    /**
     * Hiding public constructor.
     */
    private Utils() {

    }

    /**
     * returns the canonical host name or reads it from the config file.
     * @return the hostname or ip read from the config file.
     */
    public static String getHostNameOrIpAddress() {
        String hostnameOrIpAddr;
        if (FloeConfig.getConfig().containsKey(ConfigProperties.HOST_NAME)) {
            hostnameOrIpAddr = FloeConfig.getConfig().getString(ConfigProperties.HOST_NAME);
        } else {
            hostnameOrIpAddr = Utils.getIpAddress();
        }
        //hostnameOrIpAddr = Utils.getIpAddress();
        return hostnameOrIpAddr;
    }

    /**
     * returns the canonical host name. This assumes a unique host name for
     * each machine in the cluster does not apply.
     * FixMe: In local cloud environment (local eucalyptus in system mode)
     * where the DNS server is not running, this might be an issue.
     *
     * @return the canonical hostname.
     *
    public static String getHostName() {
    try {
        return InetAddress.getLocalHost().getCanonicalHostName();
    } catch (UnknownHostException e) {
        LOGGER.error("Error occurred while retrieving hostname"
                + e.getMessage());
        throw new RuntimeException("Error occurred while "
                + "retrieving hostname" + e.getMessage());
    }
    }*/

    /**
     * returns the canonical host name. This assumes a unique host name for
     * each machine in the cluster does not apply.
     * FixMe: In local cloud environment (local eucalyptus in system mode)
     * where the DNS server is not running, this might be an issue.
     * @return The first IPv4 address found for any interface that is up and
     * running.
     */
    public static String getIpAddress() {
        String ip = null;
        try {
            Enumeration<NetworkInterface> interfaces = NetworkInterface.getNetworkInterfaces();
            LOGGER.error("Getting ip");

            while (interfaces.hasMoreElements()) {
                LOGGER.error("Next iface");
                NetworkInterface current = interfaces.nextElement();
                if (!current.isUp() || current.isLoopback() || current.isVirtual()) {
                    continue;
                }
                Enumeration<InetAddress> addresses = current.getInetAddresses();
                while (addresses.hasMoreElements()) {
                    InetAddress currentAddr = addresses.nextElement();
                    if (currentAddr.isLoopbackAddress() || (currentAddr instanceof Inet6Address)) {
                        continue;
                    }
                    ip = currentAddr.getHostAddress();
                }
            }
        } catch (SocketException e) {
            LOGGER.error("Error occurred while retrieving hostname" + e.getMessage());
            throw new RuntimeException("Error occurred while " + "retrieving hostname" + e.getMessage());
        }
        return ip;
    }

    /**
     * Checks if the filename (to be uploaded or downloaded) is valid.
     * It should not contain ".." and should not be an absolute path.
     *
     * @param fileName filename to be uploaded or downloaded relative to the
     *                 coordinator's scratch folder.
     * @return returns true if the filename is valid and can be used in the
     * download or upload functions.
     */
    public static boolean checkValidFileName(final String fileName) {
        if (fileName.contains("..")) {
            return false;
        }

        Path filePath = FileSystems.getDefault().getPath(fileName);
        if (filePath.isAbsolute()) {
            return true;
        }
        return true;
    }

    /**
     * Returns a complete command for launching a java child process.
     * with SAME classpath as the parent.
     * @param className Child's class name.
     * @param jvmParams Additional params to be passed to the JVM
     * @param appParams custom application params, appended into a single
     *                  string.
     * @return command string to launch the given class in a JVM
     */
    public static String getJavaProcessLaunchCommand(final String className, final String appParams,
            final String... jvmParams) {
        String javaHome = FloeConfig.getConfig().getString(ConfigProperties.SYS_JAVA_HOME);

        String classPath = FloeConfig.getConfig().getString(ConfigProperties.SYS_JAVA_CLASS_PATH);

        //TODO: Add other required parameters

        String fileSeparator = FloeConfig.getConfig().getString(ConfigProperties.SYS_FILE_SEPARATOR);
        String javaCmd = javaHome + fileSeparator + "bin" + fileSeparator + "java";

        String params = StringUtils.join(jvmParams, ' ');

        String command = StringUtils
                .join(new String[] { javaCmd, "-cp " + classPath, params, className, appParams }, ' ');

        return command;
    }

    /**
     * Use reflection to create an instance of the given class.
     * @param fqdnClassName the fully qualified class name in the default
     *                      class loader.
     * @return a new instance of the given class. NULL if there was an error
     * creating the instance.
     */
    public static Object instantiateObject(final String fqdnClassName) {
        return instantiateObject(fqdnClassName, null);
    }

    /**
     * Use reflection to create an instance of the given class.
     * @param fqdnClassName the fully qualified class name.
     * @param loader class loader to be used.
     * @return a new instance of the given class. NULL if there was an error
     * creating the instance.
     */
    public static Object instantiateObject(final String fqdnClassName, final ClassLoader loader) {
        Object instance = null;
        try {
            Class<?> klass;
            if (loader == null) {
                klass = Class.forName(fqdnClassName);
            } else {
                klass = Class.forName(fqdnClassName, true, loader);
            }
            instance = klass.newInstance();
        } catch (ClassNotFoundException e) {
            LOGGER.error("Could not create an instance of {}, Exception:{}", fqdnClassName, e);
        } catch (InstantiationException e) {
            LOGGER.error("Could not create an instance of {}, Exception:{}", fqdnClassName, e);
        } catch (IllegalAccessException e) {
            LOGGER.error("Could not create an instance of {}, Exception:{}", fqdnClassName, e);
        }
        return instance;
    }

    /**
     * Use reflection to create an instance of the given class.
     * @param fqdnClassName the fully qualified class name.
     * @param params types of parameters to query for the constructor.
     * @return a new instance of the given class. NULL if there was an error
     * creating the instance.
     */
    public static Constructor<?> getConstructor(final String fqdnClassName, final Class<?>... params) {
        try {
            Class<?> klass = Class.forName(fqdnClassName);

            return klass.getConstructor(params);

        } catch (ClassNotFoundException e) {
            LOGGER.error("Could not create an instance of {}, Exception:{}", fqdnClassName, e);
        } catch (NoSuchMethodException e) {
            LOGGER.error("No such constructor found, Exception:{}", fqdnClassName, e);
        }
        return null;
    }

    /**
     * Serializer used for storing data into zookeeper. We use the default
     * java serializer (since the amount of data to be serialized is usually
     * very small).
     * NOTE: THIS IS DIFFERENT FROM THE SERIALIZER USED DURING COMMUNICATION
     * BETWEEN DIFFERENT FLAKES. THAT ONE IS PLUGABBLE, THIS IS NOT.
     *
     * @param obj Object to be serialized
     * @return serialized byte array.
     */
    public static byte[] serialize(final Object obj) {
        try {
            ByteArrayOutputStream bos = new ByteArrayOutputStream();
            ObjectOutputStream oos = new ObjectOutputStream(bos);
            oos.writeObject(obj);
            oos.close();
            return bos.toByteArray();
        } catch (IOException ioe) {
            throw new RuntimeException(ioe);
        }
    }

    /**
     * Deserializer for Zookeeper data. See comments for serialize function.
     *
     * @param serialized serialized byte array (default java serialized)
     *                   obtained from the serialize function.
     * @return the constructed java object. Needs to be typecasted to
     * appropriate object before using. No checks are actionCompleted here.
     */
    public static Object deserialize(final byte[] serialized) {
        try {
            ByteArrayInputStream bis = new ByteArrayInputStream(serialized);
            ObjectInputStream ois = new ObjectInputStream(bis);
            Object ret = ois.readObject();
            ois.close();
            return ret;
        } catch (IOException ioe) {
            throw new RuntimeException(ioe);
        } catch (ClassNotFoundException e) {
            throw new RuntimeException(e);
        }
    }

    /**
     * Deserializer for Zookeeper data. See comments for serialize function.
     *
     * @param serialized serialized byte array (default java serialized)
     *                   obtained from the serialize function.
     * @param classLoader Custom Class loader to used to deserialize the
     *                    object.
     * @return the constructed java object. Needs to be typecasted to
     * appropriate object before using. No checks are actionCompleted here.
     */
    public static Object deserialize(final byte[] serialized, final ClassLoader classLoader) {
        try {
            ByteArrayInputStream bis = new ByteArrayInputStream(serialized);
            //ObjectInputStream ois = new ObjectInputStream(bis);
            ClassLoaderObjectInputStream ois = new ClassLoaderObjectInputStream(classLoader, bis);
            Object ret = ois.readObject();
            ois.close();
            return ret;
        } catch (IOException ioe) {
            throw new RuntimeException(ioe);
        } catch (ClassNotFoundException e) {
            throw new RuntimeException(e);
        }
    }

    /**
     * returns the pull local path of the application jar.
     * @param appName name of the application.
     * @param jarName jar name.
     * @return the path to the application jar.
     */
    public static String getContainerJarDownloadPath(final String appName, final String jarName) {
        String downloadLocation = FloeConfig.getConfig().getString(ConfigProperties.FLOE_EXEC_SCRATCH_FOLDER)
                + Utils.Constants.FILE_PATH_SEPARATOR
                + FloeConfig.getConfig().getString(ConfigProperties.CONTAINER_LOCAL_FOLDER)
                + Utils.Constants.FILE_PATH_SEPARATOR + Utils.Constants.CONTAINER_APP_FOLDER
                + Utils.Constants.FILE_PATH_SEPARATOR + appName + Utils.Constants.FILE_PATH_SEPARATOR + jarName;

        return downloadLocation;
    }

    /**
     * Generates a unique flake id given cid and fid.
     * @param cid container's id on which this flake resides.
     * @param fid flake's id.
     * @return globally unique flake id.
     */
    public static String generateFlakeId(final String cid, final String fid) {
        return cid + "-" + fid;
    }

    /**
     * Once the poller.poll returns, use this function as a component in the
     * proxy to forward messages from one socket to another.
     * @param from socket to read from.
     * @param to socket to send messages to
     */
    public static void forwardCompleteMessage(final ZMQ.Socket from, final ZMQ.Socket to) {
        byte[] message;
        boolean more = false;
        while (true) {
            // receive message
            message = from.recv(0);
            more = from.hasReceiveMore();
            // Broker it
            int flags = 0;
            if (more) {
                flags = ZMQ.SNDMORE;
            }
            to.send(message, flags);
            if (!more) {
                break;
            }
        }
    }

    /**
     * receives a complete message from the socket and ignores.
     * @param from the socket to read from.
     */
    public static void recvAndignore(final ZMQ.Socket from) {
        byte[] message;
        boolean more = false;
        while (true) {
            // receive message
            message = from.recv(0);
            more = from.hasReceiveMore();
            // Broker it
            int flags = 0;
            if (more) {
                flags = ZMQ.SNDMORE;
            }
            if (!more) {
                break;
            }
        }
    }

    /**
     * Creates and returns a class loader with the given jar file.
     * @param path path to the jar file.
     * @param parent parent class loader.
     * @return a new child class loader
     */
    public static ClassLoader getClassLoader(final String path, final ClassLoader parent) {
        ClassLoader loader = null;
        try {
            File relativeJarLoc = new File(path);

            URL jarLoc = new URL("file://" + relativeJarLoc.getAbsolutePath());

            LOGGER.info("Loading jar: {} into class loader.", jarLoc);
            loader = URLClassLoader.newInstance(new URL[] { jarLoc }, parent);
        } catch (MalformedURLException e) {
            e.printStackTrace();
            LOGGER.error("Invalid Jar URL Exception: {}", e);
        }
        return loader;
    }

    /**
     * Various Constants used across the project.
     * Note: The string constants for configuration file,
     * and for the zookeeper paths are in config/ConfigProperties and
     * zookeeper/ZKConstants respectively. This file contains other generic
     * constants.
     */
    public static final class Constants {
        /**
         * The system file separator.
         */
        public static final String FILE_PATH_SEPARATOR = FloeConfig.getConfig()
                .getString(ConfigProperties.SYS_FILE_SEPARATOR);

        /**
         * The local execution mode for FLOE.
         */
        public static final String LOCAL = "local";

        /**
         * The distributed execution mode for FLOE.
         */
        public static final String DISTRIBUTED = "distributed";

        /**
         * Milli multiplier.
         */
        public static final int MILLI = 1000;

        /**
         * Chunk size to read from file and send to the coordinator.
         */
        public static final int BUFFER_SIZE = 1024 * 4;

        //public static final String FlakeReceiverFrontEndPrefix = ""

        /**
         * Flake receiver frontend prefix (this is suffixed by host and port).
         * Used for connecting to the predecessor flake.
         */
        public static final String FLAKE_RECEIVER_FRONTEND_CONNECT_SOCK_PREFIX = "tcp://";

        /**
         * Flake sender middle-end prefix (this is suffixed by a listening
         * port).
         * Receives data messages from the middle end. and uses PUSH to
         * send it to all flakes containing the pellet instances for the
         * succeeding pellet.
         */
        public static final String FLAKE_SENDER_BACKEND_SOCK_PREFIX = "tcp://*:";

        /**
         * Flake receiver backend prefix (this is suffixed by flake id).
         * Used for a PUSH socket to receive data from RECEIVER frontend and
         * send it to the pellets evenly.
         */
        public static final String FLAKE_RECEIVER_BACKEND_SOCK_PREFIX = "inproc://receiver-backend-";

        /**
         * Flake receiver backed for signals. This is suffixed by flake id.
         * Used to publish the signal to all pellet instances. Hence uses the
         * PUB/SUB model.
         */
        public static final String FLAKE_RECEIVER_SIGNAL_BACKEND_SOCK_PREFIX = "inproc://receiver-signal-backend-";
        /**
         * Flake receiver Control socket prefix (this is suffixed by flake id).
         * Used for receiving control signals from the container.
         */
        public static final String FLAKE_CONTROL_SOCK_PREFIX = "ipc://flake-control-";

        /**
         * Flake receiver Control socket prefix (this is suffixed by flake id).
         * Used for receiving control signals from the container.
         */
        public static final String FLAKE_RECEIVER_MIDDLE_PREFIX = "inproc://flake-recv-middle-";

        /**
         * Flake receiver Control socket prefix (this is suffixed by flake id).
         * Used for receiving control signals from the container.
         */
        public static final String FLAKE_RECEIVER_CONTROL_FWD_PREFIX = "inproc://flake-control-fwd-";

        /**
         * Flake sender front-end prefix (this is suffixed by flake id).
         * Used for receiving data messages from all pellet instances.
         */
        public static final String FLAKE_SENDER_FRONTEND_SOCK_PREFIX = "inproc://sender-frontend-";

        /**
         * Flake sender middle-end prefix (this is suffixed by flake id).
         * Receives data messages from the front end. and uses PUB to
         * send it all outgoing channels based on dispersion
         * strategy (currently only duplicate it to all outgoing channels).
         */
        public static final String FLAKE_SENDER_MIDDLEEND_SOCK_PREFIX = "inproc://sender-middleend-";

        /**
         * Flake backchannel sender prefix.
         */
        public static final String FLAKE_BACKCHANNEL_SENDER_PREFIX = "inproc://flake-backchannel-sender-";

        /**
         * Flake backchannel sender control prefix. Used to trigger the send.
         */
        public static final String FLAKE_BACKCHANNEL_CONTROL_PREFIX = "inproc://flake-backchannel-control-";

        /**
         * the endpoint to be used by flakes to send their heartbeat to the
         * container.
         */
        public static final String FLAKE_HEARBEAT_SOCK_PREFIX = "ipc://flake-heartbeat-";

        /**
         * Flake Component uses this to listen for start/stop notification
         * signals.
         */
        public static final String FLAKE_COMPONENT_NOTIFY_PREFIX = "inproc://flake-comp-notify-";

        /**
         * Flake Component uses this to send kill signal to the component
         * implementation.
         */
        public static final String FLAKE_COMPONENT_KILL_PREFIX = "inproc://flake-comp-kill-";

        /**
         * the endpoint to be used by flakes to send their state checkpoints.
         */
        public static final String FLAKE_STATE_PUB_SOCK = "tcp://*:";

        /**
         * the endpoint to be used by flakes to send their state checkpoints.
         */
        public static final String FLAKE_MSG_BACKUP_PREFIX = "inproc://flake-msg-backup-";

        /**
         * the endpoint to be used by backup component to start/stop recovery
         * process (like a control channel).
         */
        public static final String FLAKE_MSG_BACKUP_CONTROL_PREFIX = "inproc://flake-msg-backup-control-";

        /**
         * the endpoint to be used during recovery. Backup component binds to
         * it, flake receiver connects to it.
         */
        public static final String FLAKE_MSG_RECOVERY_PREFIX = "inproc://flake-msg-backup-recovery-";

        /**
         * the endpoint to be used by flakes to send their state checkpoints.
         */
        public static final String FLAKE_STATE_BACKUP_PREFIX = "inproc://flake-state-backup-";

        /**
         * the endpoint to be used by flakes to send their state checkpoints.
         */
        public static final String FLAKE_STATE_SUB_SOCK_PREFIX = "tcp://";

        /**
         * Number of i/o threads to be used by ZMQ for a single flake.
         */
        public static final int FLAKE_NUM_IO_THREADS = 4;

        /**
         * Apps folder name relative to container local folder.
         */
        public static final String CONTAINER_APP_FOLDER = "apps";

        /**
         * Name of the default alternate.
         */
        public static final String DEFAULT_ALTERNATE_NAME = "default_alternate";

        /**
         * Name of the default publisher key to send messages to all
         * subscribers.
         */
        public static final String PUB_ALL = "all";

        /**
         * Name of the default output stream.
         */
        public static final String DEFAULT_STREAM_NAME = "default_stream";

        /**
         * The field name associated with the system timestamp of the tuple.
         */
        public static final String SYSTEM_TS_FIELD_NAME = "SYSTEM_TS";
        /**
         * The field name associated with the SRC pellet of the tuple.
         */
        public static final String SYSTEM_SRC_PELLET_NAME = "SYSTEM_SRC_PELLET";
    }
}