Package org.springframework.data.hadoop.mapreduce

Source Code of org.springframework.data.hadoop.mapreduce.HadoopCodeExecutor

/*
* Copyright 2011-2013 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 org.springframework.data.hadoop.mapreduce;

import java.security.PrivilegedExceptionAction;
import java.util.Arrays;
import java.util.Properties;

import org.apache.hadoop.conf.Configuration;
import org.apache.hadoop.security.UserGroupInformation;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.BeanClassLoaderAware;
import org.springframework.beans.factory.InitializingBean;
import org.springframework.core.io.Resource;
import org.springframework.data.hadoop.configuration.JobConfUtils;
import org.springframework.data.hadoop.mapreduce.ExecutionUtils.ExitTrapped;
import org.springframework.util.Assert;
import org.springframework.util.ClassUtils;
import org.springframework.util.StringUtils;

/**
* Base configuration class for executing custom Hadoop code (such as Tool or Jar).
*
* @author Costin Leau
*/
abstract class HadoopCodeExecutor<T> extends JobGenericOptions implements InitializingBean, BeanClassLoaderAware {

  String[] arguments;
  Configuration configuration;
  T target;
  String targetClassName;
  Properties properties;
  Resource jar;
  private ClassLoader beanClassLoader;
  private boolean closeFs = true;

  // do the JRE leak prevention, once per class-loader
  static {
    ExecutionUtils.preventJreTcclLeaks();
  }

  @Override
  public void afterPropertiesSet() throws Exception {
    Assert.isTrue(target != null || StringUtils.hasText(targetClassName) || (jar != null && jar.exists()),
        "a target instance, class name or a Jar (with Main-Class) is required");
  }


  protected int runCode() throws Exception {
    // merge configuration options
    final Configuration cfg = resolveConfiguration();

    // resolve target object
    final Class<T> type = resolveTargetClass(cfg);
    final T target = resolveTargetObject(type);

    // setup the invocation context
    Thread th = Thread.currentThread();
    ClassLoader oldTccl = th.getContextClassLoader();

    log.info("Invoking [" + (target != null ? target : type) + "] "
        + (jar != null ? "from jar [" + jar.getURI() + "]" : "") + " with args [" + Arrays.toString(arguments)
        + "]");

    ClassLoader newCL = cfg.getClassLoader();
    boolean isJarCL = newCL instanceof ParentLastURLClassLoader;
    try {
      ExecutionUtils.disableSystemExitCall();
      if (isJarCL) {
        ExecutionUtils.preventHadoopLeaks(beanClassLoader);
      }

      //ExecutionUtils.earlyLeaseDaemonInit(cfg);

      th.setContextClassLoader(newCL);

      if (StringUtils.hasText(user)) {
        UserGroupInformation ugi = UserGroupInformation.createProxyUser(user,
            UserGroupInformation.getLoginUser());

        return ugi.doAs(new PrivilegedExceptionAction<Integer>() {
          @Override
          public Integer run() throws Exception {
            return invokeTarget(cfg, target, type, arguments);
          }
        });
      }
      else {
        return invokeTarget(cfg, target, type, arguments);
      }
    } finally {
      ExecutionUtils.enableSystemExitCall();
      th.setContextClassLoader(oldTccl);

      if (isJarCL) {
        if (closeFs) {
          ExecutionUtils.shutdownFileSystem(cfg);
        }
        ExecutionUtils.patchLeakedClassLoader(newCL, oldTccl);
      }
    }
  }


  protected Configuration resolveConfiguration() throws Exception {
    Configuration cfg = JobConfUtils.createFrom(configuration, properties);
    // add the jar if present
    if (jar != null) {
      String jarUrl = jar.getURL().toString();
      if (log.isTraceEnabled()) {
        log.trace("Setting Configuration Jar URL to [" +jarUrl+"]");
      }

      cfg.set("mapred.jar", jarUrl);
    }

    buildGenericOptions(cfg);
    return cfg;
  }

  @SuppressWarnings("unchecked")
  protected Class<T> resolveTargetClass(Configuration cfg) throws Exception {
    ClassLoader cl = beanClassLoader;
    // no target set - we might need to load one from the custom jar
    if (target == null) {
      cl = createClassLoaderForJar(jar, cl, cfg);

      // make sure to pass this to the Configuration
      cfg.setClassLoader(cl);

      if (jar != null) {
        if (log.isTraceEnabled()) {
          log.trace("Creating custom classloader " + cl);
        }

        // fall-back to main
        if (!StringUtils.hasText(targetClassName)) {
          String mainClass = ExecutionUtils.mainClass(jar);
          Assert.notNull(mainClass, "no target class specified and no Main-Class available");
          targetClassName = mainClass;

          if (log.isDebugEnabled()) {
            log.debug("Discovered Main-Class [" + mainClass + "]");
          }
        }
      }
      else {
        Assert.hasText(targetClassName, "No target object, class or jar specified - execution aborted");
      }
      return loadClass(targetClassName, cl);
    }

    return (Class<T>) target.getClass();
  }

  protected T resolveTargetObject(Class<T> type) {
    return (target != null ? target : BeanUtils.instantiateClass(type));
  }

  protected ClassLoader createClassLoaderForJar(Resource jar, ClassLoader parentCL, Configuration cfg) {
    return ExecutionUtils.createParentLastClassLoader(jar, parentCL, cfg);
  }

  @SuppressWarnings("unchecked")
  protected Class<T> loadClass(String className, ClassLoader cl) {
    return (Class<T>) ClassUtils.resolveClassName(className, cl);
  }

  private Integer invokeTarget(Configuration cfg, T target, Class<T> targetClass, String[] args) throws Exception {
    preExecution(cfg);
    try {
      Object result = invokeTargetObject(cfg, target, targetClass, args);
      if (result instanceof Integer) {
        return (Integer) result;
      }

      return Integer.valueOf(0);
    } catch (ExitTrapped trap) {
      log.debug("Code exited");
      return trap.getExitCode();
    } finally {
      postExecution(cfg);
    }
  }

  protected void preExecution(Configuration cfg) {
    // no-op
  }

  protected void postExecution(Configuration cfg) {
    // no-op
  }

  protected abstract Object invokeTargetObject(Configuration cfg, T target, Class<T> targetClass, String[] args)
      throws Exception;


  /**
   * Sets the target code jar.
   *
   * @param jar target jar
   */
  public void setJar(Resource jar) {
    this.jar = jar;
  }

  /**
   * Sets the arguments.
   *
   * @param arguments The arguments to set.
   */
  public void setArguments(String... arguments) {
    this.arguments = arguments;
  }

  /**
   * Sets the configuration.
   *
   * @param configuration The configuration to set.
   */
  public void setConfiguration(Configuration configuration) {
    this.configuration = configuration;
  }

  /**
   * Sets the properties.
   *
   * @param properties The properties to set.
   */
  public void setProperties(Properties properties) {
    this.properties = properties;
  }

  @Override
  public void setBeanClassLoader(ClassLoader classLoader) {
    this.beanClassLoader = classLoader;
  }

  /**
   * Indicates whether or not to close the Hadoop file-systems
   * resulting from the custom code execution.
   * Default is true. Turn this to false if the code reuses the same
   * file-system used by the rest of the application.
   *
   * @param closeFs the new close fs
   */
  public void setCloseFs(boolean closeFs) {
    this.closeFs = closeFs;
  }

  /**
   * Sets the target class.
   *
   * @param target The target class to set.
   */
  void setTargetObject(T target) {
    Assert.isNull(targetClassName, "a target class already set");
    this.target = target;
  }

  /**
   * Sets the target class name.
   *
   * @param targetClassName the target class name.
   */
  void setTargetClassName(String targetClassName) {
    this.targetClassName = targetClassName;
  }
}
TOP

Related Classes of org.springframework.data.hadoop.mapreduce.HadoopCodeExecutor

TOP
Copyright © 2018 www.massapi.com. All rights reserved.
All source code are property of their respective owners. Java is a trademark of Sun Microsystems, Inc and owned by ORACLE Inc. Contact coftware#gmail.com.