001/** 002 * Licensed to the Apache Software Foundation (ASF) under one 003 * or more contributor license agreements. See the NOTICE file 004 * distributed with this work for additional information 005 * regarding copyright ownership. The ASF licenses this file 006 * to you under the Apache License, Version 2.0 (the 007 * "License"); you may not use this file except in compliance 008 * with the License. You may obtain a copy of the License at 009 * 010 * http://www.apache.org/licenses/LICENSE-2.0 011 * 012 * Unless required by applicable law or agreed to in writing, 013 * software distributed under the License is distributed on an 014 * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY 015 * KIND, either express or implied. See the License for the 016 * specific language governing permissions and limitations 017 * under the License. 018 */ 019package org.apache.reef.runtime.common; 020 021import org.apache.reef.runtime.common.launch.LaunchClass; 022import org.apache.reef.runtime.common.launch.REEFErrorHandler; 023import org.apache.reef.runtime.common.launch.REEFMessageCodec; 024import org.apache.reef.runtime.common.launch.parameters.ClockConfigurationPath; 025import org.apache.reef.runtime.common.launch.parameters.ErrorHandlerRID; 026import org.apache.reef.runtime.common.launch.parameters.LaunchID; 027import org.apache.reef.tang.Configuration; 028import org.apache.reef.tang.Injector; 029import org.apache.reef.tang.JavaConfigurationBuilder; 030import org.apache.reef.tang.Tang; 031import org.apache.reef.tang.exceptions.BindException; 032import org.apache.reef.tang.exceptions.InjectionException; 033import org.apache.reef.tang.formats.CommandLine; 034import org.apache.reef.util.EnvironmentUtils; 035import org.apache.reef.util.ThreadLogger; 036import org.apache.reef.util.logging.LoggingSetup; 037import org.apache.reef.wake.remote.RemoteConfiguration; 038 039import java.io.IOException; 040import java.util.Collection; 041import java.util.logging.Level; 042import java.util.logging.Logger; 043 044/** 045 * The main entrance point into any REEF process. It is mostly instantiating LaunchClass and calling .run() on it. 046 */ 047public final class Launcher { 048 049 private final static Logger LOG = Logger.getLogger(Launcher.class.getName()); 050 051 static { 052 LoggingSetup.setupCommonsLogging(); 053 } 054 055 private Launcher() { 056 } 057 058 /** 059 * Parse command line options of the launcher. 060 * 061 * @param args Command line as passed into main(). 062 * @return TANG configuration object. 063 */ 064 private static Configuration processCommandLine( 065 final String[] args) throws BindException, IOException, InjectionException { 066 067 final JavaConfigurationBuilder commandLineBuilder = 068 Tang.Factory.getTang().newConfigurationBuilder(); 069 070 new CommandLine(commandLineBuilder) 071 .registerShortNameOfClass(ClockConfigurationPath.class) 072 .registerShortNameOfClass(ErrorHandlerRID.class) 073 .registerShortNameOfClass(LaunchID.class) 074 .processCommandLine(args); 075 076 return commandLineBuilder 077 // Bind the wake error handler 078 .bindNamedParameter(RemoteConfiguration.ErrorHandler.class, REEFErrorHandler.class) 079 .bindNamedParameter(RemoteConfiguration.ManagerName.class, "REEF_LAUNCHER") 080 // Bind the wake codec 081 .bindNamedParameter(RemoteConfiguration.MessageCodec.class, REEFMessageCodec.class) 082 .build(); 083 } 084 085 private static void fail(final String msg, final Throwable t) { 086 LOG.log(Level.SEVERE, msg, t); 087 throw new RuntimeException(msg, t); 088 } 089 090 091 /** 092 * Launches a REEF client process (Driver or Evaluator). 093 * 094 * @param args 095 * @throws Exception 096 */ 097 public static void main(final String[] args) { 098 LOG.log(Level.FINE, "Launcher started with user name [{0}]", System.getProperty("user.name")); 099 100 LOG.log(Level.FINE, "Launcher started. Assertions are {0} in this process.", 101 EnvironmentUtils.areAssertionsEnabled() ? "ENABLED" : "DISABLED"); 102 Injector injector = null; 103 try { 104 injector = Tang.Factory.getTang().newInjector(processCommandLine(args)); 105 } catch (final BindException | IOException | InjectionException e) { 106 fail("Error in parsing the command line", e); 107 } 108 109 try (final LaunchClass lc = injector.getInstance(LaunchClass.class)) { 110 LOG.log(Level.FINE, "Launcher starting"); 111 lc.run(); 112 LOG.log(Level.FINE, "Launcher exiting"); 113 } catch (final Throwable throwable) { 114 fail("Unable to run LaunchClass", throwable); 115 } 116 117 LOG.log(Level.INFO, "Exiting Launcher.main()"); 118 if (LOG.isLoggable(Level.FINEST)) { 119 LOG.log(Level.FINEST, ThreadLogger.getFormattedThreadList("Threads running after Launcher.close():")); 120 } 121 System.exit(0); 122 if (LOG.isLoggable(Level.FINEST)) { 123 LOG.log(Level.FINEST, ThreadLogger.getFormattedThreadList("Threads running after System.exit():")); 124 } 125 } 126 127 /** 128 * Pass values of the properties specified in the propNames array as <code>-D...</code> 129 * command line parameters. Currently used only to pass logging configuration to child JVMs processes. 130 * 131 * @param vargs List of command line parameters to append to. 132 * @param copyNull create an empty parameter if the property is missing in current process. 133 * @param propNames property names. 134 */ 135 public static void propagateProperties( 136 final Collection<String> vargs, final boolean copyNull, final String... propNames) { 137 for (final String propName : propNames) { 138 final String propValue = System.getProperty(propName); 139 if (propValue == null || propValue.isEmpty()) { 140 if (copyNull) { 141 vargs.add("-D" + propName); 142 } 143 } else { 144 vargs.add(String.format("-D%s=%s", propName, propValue)); 145 } 146 } 147 } 148 149 /** 150 * Same as above, but with copyNull == false by default. 151 */ 152 public static void propagateProperties( 153 final Collection<String> vargs, final String... propNames) { 154 propagateProperties(vargs, false, propNames); 155 } 156}