edu.usc.pgroup.floe.client.FloeClient.java Source code

Java tutorial

Introduction

Here is the source code for edu.usc.pgroup.floe.client.FloeClient.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.client;

import edu.usc.pgroup.floe.config.ConfigProperties;
import edu.usc.pgroup.floe.config.FloeConfig;
import edu.usc.pgroup.floe.thriftgen.AppStatus;
import edu.usc.pgroup.floe.thriftgen.TCoordinator;
import edu.usc.pgroup.floe.thriftgen.TFloeApp;
import edu.usc.pgroup.floe.utils.Utils;
import org.apache.commons.io.FilenameUtils;
import org.apache.thrift.TException;
import org.apache.thrift.transport.TTransportException;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import java.io.File;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.IOException;
import java.nio.ByteBuffer;
import java.nio.channels.Channels;
import java.nio.channels.ReadableByteChannel;
import java.nio.channels.WritableByteChannel;

/**
 * Client API for FLOE.
 *
 * @author Alok Kumbhare
 */
public class FloeClient extends ThriftClient {

    /**
     * Logger.
     */
    private static final Logger LOGGER = LoggerFactory.getLogger(FloeClient.class);

    /**
     * Single floe client instance.
     */
    private static FloeClient instance;

    /**
     * the client object to communicate with the Coordinator.
     */
    private final TCoordinator.Client client;

    /**
     * default public constructor. Establishes connection with the Floe Server.
     *
     * @throws TTransportException Exception.
     */
    public FloeClient() throws TTransportException {
        super();
        if (getProtocol() != null) {
            client = new TCoordinator.Client(getProtocol());
        } else {
            throw new RuntimeException("Error occurred while establishing connection to the server.");
        }
    }

    /**
     * client entry point.
     *
     * @param args command line arguments.
     */
    public static void main(final String[] args) {
        try {

            LOGGER.info(FloeConfig.getConfig().getString(ConfigProperties.CONTAINER_HEARTBEAT_PERIOD));

            FloeClient client = new FloeClient();
            String reply = client.getClient().ping("Ping Text");
            LOGGER.info("Received reply: '" + reply + "' from the server.");

            LOGGER.info("Uploading file:" + args[0]);
            client.uploadFileSync(args[0]);
            LOGGER.info("Finished uploading file:" + args[0]);

            LOGGER.info("Downloading file:" + args[0]);
            client.downloadFileSync(args[0], "downloaded.jar");
            LOGGER.info("Finished Downloading file:" + args[0]);
        } catch (TTransportException e) {
            e.printStackTrace();
            LOGGER.error("Exception occurred while connecting");
            LOGGER.error(e.getMessage());
        } catch (TException e) {
            e.printStackTrace();
            LOGGER.error("Exception occurred while pinging");
            LOGGER.error(e.getMessage());
        }
    }

    /**
     * get the thrift client stub object.
     *
     * @return configured and connected thrift client.
     */
    public final TCoordinator.Client getClient() {
        return client;
    }

    /**
     * Uploads the file to the coordinator.
     * The file is uploaded relative to the coordinator's scratch folder.
     *
     * @param fileName name of the file to be stored on the coordinator.
     * @return the base fileName which may be used for downloading the file
     * later.
     */
    public final String uploadFileSync(final String fileName) {
        String baseFile = FilenameUtils.getName(fileName);
        try {
            int fid = getClient().beginFileUpload(baseFile);
            ReadableByteChannel inChannel = Channels.newChannel(new FileInputStream(fileName));
            ByteBuffer buffer = ByteBuffer.allocate(Utils.Constants.BUFFER_SIZE);
            while (inChannel.read(buffer) > 0) {
                buffer.flip();
                getClient().uploadChunk(fid, buffer);
                buffer.clear();
            }
            inChannel.close();
            getClient().finishUpload(fid);
        } catch (TException e) {
            LOGGER.error(e.getMessage());
            throw new RuntimeException(e);
        } catch (FileNotFoundException e) {
            LOGGER.error(e.getMessage());
            throw new RuntimeException(e);
        } catch (IOException e) {
            LOGGER.error(e.getMessage());
            throw new RuntimeException(e);
        }
        return baseFile;
    }

    /**
     * Download the file from the Coordinator's scratch folder.
     * Note: Filename should not be an absolute path or contain ".."
     *
     * @param fileName    name of the file to be downloaded from coordinator's
     *                    scratch.
     * @param outFileName (local) output file name.
     */
    public final void downloadFileSync(final String fileName, final String outFileName) {
        if (!Utils.checkValidFileName(fileName)) {
            throw new IllegalArgumentException(
                    "Filename is valid. Should not" + " contain .. and should not be an absolute path.");
        }

        int rfid = 0;
        WritableByteChannel outChannel = null;
        try {
            rfid = getClient().beginFileDownload(fileName);
            File outFile = new File(outFileName);
            File parent = outFile.getParentFile();
            if (!parent.exists()) {
                parent.mkdirs();
            }
            outChannel = Channels.newChannel(new FileOutputStream(outFileName));
        } catch (TException e) {
            LOGGER.error(e.getMessage());
            throw new RuntimeException(e);
        } catch (FileNotFoundException e) {
            LOGGER.error(e.getMessage());
            throw new RuntimeException(e);
        }

        int written;
        try {
            do {
                ByteBuffer buffer = null;

                buffer = getClient().downloadChunk(rfid);

                written = outChannel.write(buffer);
                LOGGER.info(String.valueOf(written));
            } while (written != 0);
        } catch (TException e) {
            LOGGER.error(e.getMessage());
            throw new RuntimeException(e);
        } catch (IOException e) {
            LOGGER.error(e.getMessage());
            throw new RuntimeException(e);
        } finally {
            if (outChannel != null) {
                try {
                    outChannel.close();
                } catch (IOException e) {
                    LOGGER.error(e.getMessage());
                    throw new RuntimeException(e);
                }
            }
        }
    }

    /**
     * Download the file from the Coordinator's scratch folder.
     * Note: Filename should not be an absolute path or contain ".."
     *
     * @param fileName name of the file to be downloaded from the coordinator.
     */
    public final void downloadFileSync(final String fileName) {
        downloadFileSync(fileName, fileName);
    }

    /**
     * @return singleton FloeClient instance.
     * @throws TTransportException thrift exception.
     */
    public static synchronized FloeClient getInstance() throws TTransportException {
        if (instance == null) {
            instance = new FloeClient();
        }
        return instance;
    }

    /**
     * Submit the floe app to the coordinator.
     * @param appName name of the app.
     * @throws TException thrift exception.
     */
    public final void killApp(final String appName) throws TException {
        LOGGER.info("Submitting kill request.");
        getClient().killApp(appName);
        LOGGER.info("Request submitted.");

        //Now wait for app's status to be Running.
        boolean again = true;
        AppStatus prevStatus = null;
        LOGGER.info("Waiting for application to terminate.");

        int failedAttempts = 0;
        final int maxFailedAttempts = 5;
        final int sleepTime = 50;
        String dots = ".";
        while (again && failedAttempts < maxFailedAttempts) {
            AppStatus status = null;
            try {
                status = getClient().getAppStatus(appName);
            } catch (TException ex) {
                LOGGER.warn("Application not found. Application terminated or" + " does not exist.");
                again = false;
                break;
            }
            if (status == AppStatus.TERMINATED) {
                again = false;
            }

            if (prevStatus == status) {
                dots += ".";
            } else {
                dots = ".";
            }

            LOGGER.info(status.toString() + " " + dots);

            prevStatus = status;

            try {
                Thread.sleep(sleepTime);
            } catch (InterruptedException e) {
                e.printStackTrace();
                LOGGER.warn("Thread interrupted while waiting for app status");
            }
        }
    }

    /**
     * Submit the floe app to the coordinator.
     * @param appName name of the app.
     * @param app the FloeApp topology.
     * @throws TException thrift exception.
     */
    public final void submitApp(final String appName, final TFloeApp app) throws TException {

        LOGGER.info("Submitting app to the coordinator.");
        getClient().submitApp(appName, app);
        LOGGER.info("Request submitted.");

        //Now wait for app's status to be Running.
        boolean again = true;
        AppStatus prevStatus = null;
        LOGGER.info("Waiting for application to start.");

        int failedAttempts = 0;
        final int maxFailedAttempts = 5;
        final int sleepTime = 50;
        String dots = ".";
        while (again && failedAttempts < maxFailedAttempts) {
            AppStatus status = null;
            try {
                status = getClient().getAppStatus(appName);
            } catch (TException ex) {
                LOGGER.warn("Application not found. Yet to be deployed. " + "Trying again.");
                failedAttempts++;
                continue;
            }
            if (status == AppStatus.RUNNING) {
                again = false;
            }

            if (prevStatus == status) {
                dots += ".";
            } else {
                dots = ".";
            }

            LOGGER.info(status.toString() + " " + dots);

            prevStatus = status;

            try {
                Thread.sleep(sleepTime);
            } catch (InterruptedException e) {
                e.printStackTrace();
                LOGGER.warn("Thread interrupted while waiting for app status");
            }
        }
    }

}