/** * Copyright 2011-2017 Asakusa Framework Team. * * 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 com.asakusafw.testdriver.windgate.emulation; import java.io.File; import java.io.IOException; import java.net.URI; import java.net.URL; import java.text.MessageFormat; import java.util.ArrayList; import java.util.Arrays; import java.util.Collections; import java.util.HashMap; import java.util.List; import java.util.Map; import java.util.Optional; import java.util.Properties; import org.apache.hadoop.conf.Configuration; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import org.slf4j.MDC; import com.asakusafw.runtime.stage.launcher.ApplicationLauncher; import com.asakusafw.testdriver.TestDriverContext; import com.asakusafw.testdriver.TestExecutionPlan; import com.asakusafw.testdriver.hadoop.ConfigurationFactory; import com.asakusafw.testdriver.inprocess.CommandEmulator; import com.asakusafw.testdriver.inprocess.EmulatorUtils; import com.asakusafw.testdriver.windgate.PluginClassLoader; import com.asakusafw.testdriver.windgate.WindGateTestHelper; import com.asakusafw.vocabulary.windgate.Constants; import com.asakusafw.windgate.bootstrap.CommandLineUtil; import com.asakusafw.windgate.core.GateProfile; import com.asakusafw.windgate.core.ParameterList; import com.asakusafw.windgate.core.ProfileContext; /** * An abstract implementation of WindGate command emulators. * @since 0.6.0 */ public abstract class AbstractWindGateCommandEmulator extends CommandEmulator { private static final Logger LOG = LoggerFactory.getLogger(AbstractWindGateCommandEmulator.class); static final String MODULE_NAME_PREFIX = Constants.MODULE_NAME + '.'; static final String PATH_WINDGATE = "windgate"; //$NON-NLS-1$ private static final String PATH_CONF = PATH_WINDGATE + "/conf"; //$NON-NLS-1$ private static final String PATH_PLUGIN = WindGateTestHelper.PRODUCTION_PLUGIN_DIRECTORY; private static final String PATTERN_PROFILE = WindGateTestHelper.PRODUCTION_PROFILE_PATH; static final int ARG_PROFILE = 1; @Override public final void execute( TestDriverContext context, ConfigurationFactory configurations, TestExecutionPlan.Command command) throws IOException, InterruptedException { configureLogs(context); try (PluginClassLoader classLoader = createClassLoader(context, configurations)) { ClassLoader contextClassLoader = ApplicationLauncher.switchContextClassLoader(classLoader); try { GateProfile profile = loadProfile( context, configurations, classLoader, command.getCommandTokens().get(ARG_PROFILE)); execute0(context, classLoader, profile, command); } finally { ApplicationLauncher.switchContextClassLoader(contextClassLoader); WindGateTestHelper.disposePluginClassLoader(classLoader); } } } /** * Executes WindGate tasks internally. * @param context the current test context * @param classLoader the class loader for this execution * @param profile the target WindGate profile * @param command the command information * @throws IOException if failed to execute the command * @throws InterruptedException if interrupted while processing the command */ protected abstract void execute0( TestDriverContext context, ClassLoader classLoader, GateProfile profile, TestExecutionPlan.Command command) throws IOException, InterruptedException; private static void configureLogs(TestDriverContext context) { MDC.put("batchId", context.getCurrentBatchId()); //$NON-NLS-1$ MDC.put("flowId", context.getCurrentBatchId()); //$NON-NLS-1$ MDC.put("executionId", context.getCurrentBatchId()); //$NON-NLS-1$ } private static PluginClassLoader createClassLoader( TestDriverContext context, ConfigurationFactory configurations) throws IOException { ClassLoader parent = configurations.newInstance().getClassLoader(); List<URL> libraries = new ArrayList<>(); libraries.add(new File(context.getFrameworkHomePath(), PATH_CONF).toURI().toURL()); libraries.add(EmulatorUtils.getJobflowLibraryPath(context).toURI().toURL()); for (File file : EmulatorUtils.getBatchLibraryPaths(context)) { libraries.add(file.toURI().toURL()); } File plugins = new File(context.getFrameworkHomePath(), PATH_PLUGIN); if (plugins.isDirectory()) { for (File file : list(plugins)) { if (file.isFile()) { libraries.add(file.toURI().toURL()); } } } return PluginClassLoader.newInstance(parent, libraries); } private static List<File> list(File file) { return Optional.ofNullable(file.listFiles()) .map(Arrays::asList) .orElse(Collections.emptyList()); } private static GateProfile loadProfile( TestDriverContext context, ConfigurationFactory configurations, ClassLoader classLoader, String profile) { LOG.debug("Loading profile: {}", profile); //$NON-NLS-1$ try { File profilePath = new File( context.getFrameworkHomePath(), MessageFormat.format(PATTERN_PROFILE, profile)).getAbsoluteFile(); Map<String, String> variables = new HashMap<>(context.getEnvironmentVariables()); variables.put("WINDGATE_PROFILE", profile); //$NON-NLS-1$ ParameterList contextParameters = new ParameterList(variables); ProfileContext profileContext = new ProfileContext(classLoader, contextParameters) .withResource(Configuration.class, configurations.newInstance()); URI uri = profilePath.toURI(); Properties properties = CommandLineUtil.loadProperties(uri, classLoader); return GateProfile.loadFrom(CommandLineUtil.toName(uri), properties, profileContext); } catch (Exception e) { throw new IllegalArgumentException(MessageFormat.format( Messages.getString("AbstractWindGateCommandEmulator.errorInvalidProfile"), //$NON-NLS-1$ profile), e); } } }