oz.hadoop.yarn.api.core.ApplicationContainer.java Source code

Java tutorial

Introduction

Here is the source code for oz.hadoop.yarn.api.core.ApplicationContainer.java

Source

/*
 * Copyright 2014 the original author or authors.
 *
 * 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 oz.hadoop.yarn.api.core;

import java.io.PrintWriter;
import java.io.StringWriter;
import java.lang.reflect.Constructor;
import java.net.InetSocketAddress;
import java.nio.ByteBuffer;
import java.util.Random;

import org.springframework.util.Assert;
import org.springframework.util.StringUtils;

import oz.hadoop.yarn.api.ApplicationContainerProcessor;
import oz.hadoop.yarn.api.YayaConstants;
import oz.hadoop.yarn.api.net.ApplicationContainerClient;
import oz.hadoop.yarn.api.net.ApplicationContainerMessageHandler;
import oz.hadoop.yarn.api.utils.ByteBufferUtils;
import oz.hadoop.yarn.api.utils.PrimitiveImmutableTypeMap;
import oz.hadoop.yarn.api.utils.ReflectionUtils;

/**
 * INTERNAL API
 * 
 * @author Oleg Zhurakousky
 *
 */
class ApplicationContainer extends AbstractContainer {

    private volatile ApplicationContainerClient client;

    private volatile InetSocketAddress listeningAddress;

    private volatile String successReplyMessage;

    private volatile String failureReplyMessage;

    /**
     * 
     * @param containerArguments
     */
    ApplicationContainer(PrimitiveImmutableTypeMap containerArguments) {
        super(containerArguments);
    }

    /**
     * 
     */
    @Override
    void launch() {

        logger.info("###### Starting APPLICATION CONTAINER ######");
        try {
            this.preLaunch();
            this.doLaunch();
        } catch (Exception e) {
            logger.error("Failed to launch an Application Container.", e);
            throw new IllegalStateException("Failed to launch an Application Container.", e);
        } finally {
            logger.info("###### Stopped APPLICATION CONTAINER ######");
        }
    }

    /**
     * 
     */
    private void doLaunch() {
        ApplicationContainerProcessor applicationContainer = null;

        String command = this.containerSpec.getString(YayaConstants.COMMAND);
        if (StringUtils.hasText(command)) {
            applicationContainer = new ProcessLaunchingApplicationContainer(new CommandProcessLauncher(command));
        } else {
            String appContainerImplClass = this.containerSpec.getString(YayaConstants.CONTAINER_IMPL);
            Assert.hasText(appContainerImplClass,
                    "Invalid condition: 'appContainerImplClass' must not be null or empty. "
                            + "Since this is coming from internal API it must be a bug. Please REPORT.");
            applicationContainer = (ApplicationContainerProcessor) ReflectionUtils
                    .newDefaultInstance(appContainerImplClass);
            String containerArguments = this.containerSpec.getString(YayaConstants.CONTAINER_ARG);
            if (StringUtils.hasText(containerArguments)) {
                applicationContainer = new ProcessLaunchingApplicationContainer(
                        new JavaProcessLauncher<ByteBuffer>(applicationContainer, containerArguments));
            }
        }
        applicationContainer = new ExceptionHandlingApplicationContainer(applicationContainer);
        this.connectWithApplicationMaster(applicationContainer);

        logger.info("Awaiting Application Container's process to finish or termination signal from the client");
        /*
         * Upon receiving a reply Server will check if application if finite and if so
         * it will close the connection which will force client to exit
         */
        this.client.awaitShutdown();

        logger.info("ApplicationContainerClient has been stopped");
    }

    /**
     * 
     * @param applicationContainer
     * @return
     */
    private void connectWithApplicationMaster(ApplicationContainerProcessor applicationContainer) {
        MessageDispatchingHandler messageHandler = new MessageDispatchingHandler(applicationContainer);

        InetSocketAddress address = new InetSocketAddress(
                this.applicationSpecification.getString(YayaConstants.CLIENT_HOST),
                this.applicationSpecification.getInt(YayaConstants.CLIENT_PORT));
        this.client = this.buildApplicationContainerClient(address, messageHandler);
        this.listeningAddress = this.client.start();
        this.successReplyMessage = "OK:" + listeningAddress.getAddress().getHostAddress() + ":"
                + listeningAddress.getPort() + ":";
        this.failureReplyMessage = "FAILED:" + listeningAddress.getAddress().getHostAddress() + ":"
                + listeningAddress.getPort();
        if (logger.isInfoEnabled()) {
            logger.info("Started ApplicationContainerClient on " + listeningAddress);
        }
    }

    /**
     * 
     */
    private ApplicationContainerClient buildApplicationContainerClient(InetSocketAddress address,
            ApplicationContainerMessageHandler messageHandler) {
        try {
            Constructor<ApplicationContainerClient> acCtr = ReflectionUtils.getInvocableConstructor(
                    ApplicationContainerClient.class.getPackage().getName() + ".ApplicationContainerClientImpl",
                    InetSocketAddress.class, ApplicationContainerMessageHandler.class, Runnable.class);
            ApplicationContainerClient ac = acCtr.newInstance(address, messageHandler, new Runnable() {
                @Override
                public void run() {
                    // noop
                }
            });
            return ac;
        } catch (Exception e) {
            throw new IllegalStateException("Failed to create ApplicationContainerClient instance", e);
        }
    }

    /**
     * 
     */
    private void preLaunch() {
        if (this.applicationSpecification.getBoolean("FORCE_CONTAINER_ERROR")) { // strictly for testing
            if (new Random().nextInt(2) == 1) {
                throw new RuntimeException(
                        "INTENTIONALLY FORCING CONTAINER STARTUP FAILURE DUE TO 'FORCE_CONTAINER_ERROR' PROPERTY SET TO TRUE");
            }
        }
    }

    /**
     * 
     */
    private class ProcessLaunchingApplicationContainer implements ApplicationContainerProcessor {
        private final ProcessLauncher<?> processLauncher;

        ProcessLaunchingApplicationContainer(ProcessLauncher<?> processLauncher) {
            this.processLauncher = processLauncher;
        }

        @Override
        public ByteBuffer process(ByteBuffer input) {
            return (ByteBuffer) this.processLauncher.launch();
        }
    }

    /**
     * 
     */
    private class ExceptionHandlingApplicationContainer implements ApplicationContainerProcessor {
        private final ApplicationContainerProcessor targetApplicationContainer;

        ExceptionHandlingApplicationContainer(ApplicationContainerProcessor targetApplicationContainer) {
            this.targetApplicationContainer = targetApplicationContainer;
        }

        @Override
        public ByteBuffer process(ByteBuffer input) {
            try {
                ByteBuffer reply = this.targetApplicationContainer.process(input);
                if (reply == null) {
                    reply = ByteBuffer.wrap(successReplyMessage.getBytes());
                } else {
                    ByteBuffer source = ByteBuffer.wrap(successReplyMessage.getBytes());
                    source.position(source.limit());
                    reply = ByteBufferUtils.merge(source, reply);
                }
                reply.rewind();
                return reply;
            } catch (Exception e) {
                logger.error("Process failed in " + listeningAddress.getAddress().getHostAddress() + ":"
                        + listeningAddress.getPort(), e);
                StringBuffer replyMessageBuffer = new StringBuffer();
                replyMessageBuffer.append(failureReplyMessage);
                replyMessageBuffer.append(":{\n");

                StringWriter sw = new StringWriter();
                PrintWriter pw = new PrintWriter(sw);
                e.printStackTrace(pw);

                replyMessageBuffer.append(sw.toString());
                replyMessageBuffer.append("\n}");

                return ByteBuffer.wrap(replyMessageBuffer.toString().getBytes());
            }
        }
    }
}