PageRenderTime 24ms CodeModel.GetById 21ms RepoModel.GetById 0ms app.codeStats 0ms

/etlunit-execute/src/main/java/org/bitbucket/bradleysmithllc/etlunit/feature/execute/JavaExecutor.java

https://bitbucket.org/bradleysmithllc/etl-unit
Java | 221 lines | 154 code | 42 blank | 25 comment | 23 complexity | bcc0ba67d904bd5d44b4c6bdb1db7dee MD5 | raw file
  1. package org.bitbucket.bradleysmithllc.etlunit.feature.execute;
  2. /*
  3. * #%L
  4. * etlunit-execute
  5. * %%
  6. * Copyright (C) 2010 - 2014 bradleysmithllc
  7. * %%
  8. * Licensed under the Apache License, Version 2.0 (the "License");
  9. * you may not use this file except in compliance with the License.
  10. * You may obtain a copy of the License at
  11. *
  12. * http://www.apache.org/licenses/LICENSE-2.0
  13. *
  14. * Unless required by applicable law or agreed to in writing, software
  15. * distributed under the License is distributed on an "AS IS" BASIS,
  16. * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  17. * See the License for the specific language governing permissions and
  18. * limitations under the License.
  19. * #L%
  20. */
  21. import org.bitbucket.bradleysmithllc.etlunit.*;
  22. import org.bitbucket.bradleysmithllc.etlunit.context.VariableContext;
  23. import org.bitbucket.bradleysmithllc.etlunit.feature.execute.json.java_executor.execute.ExecuteHandler;
  24. import org.bitbucket.bradleysmithllc.etlunit.feature.execute.json.java_executor.execute.ExecuteRequest;
  25. import org.bitbucket.bradleysmithllc.etlunit.feature.execute.json.java_executor.execute.SystemProperties;
  26. import org.bitbucket.bradleysmithllc.etlunit.feature.logging.LogFileManager;
  27. import org.bitbucket.bradleysmithllc.etlunit.io.JavaForker;
  28. import org.bitbucket.bradleysmithllc.etlunit.listener.NullClassListener;
  29. import org.bitbucket.bradleysmithllc.etlunit.metadata.MetaDataArtifact;
  30. import org.bitbucket.bradleysmithllc.etlunit.metadata.MetaDataContext;
  31. import org.bitbucket.bradleysmithllc.etlunit.metadata.MetaDataManager;
  32. import org.bitbucket.bradleysmithllc.etlunit.metadata.MetaDataPackageContext;
  33. import org.bitbucket.bradleysmithllc.etlunit.parser.ETLTestMethod;
  34. import org.bitbucket.bradleysmithllc.etlunit.parser.ETLTestOperation;
  35. import org.bitbucket.bradleysmithllc.etlunit.parser.ETLTestValueObject;
  36. import org.codehaus.plexus.util.FileUtils;
  37. import org.codehaus.plexus.util.io.InputStreamFacade;
  38. import javax.inject.Inject;
  39. import java.io.File;
  40. import java.io.IOException;
  41. import java.io.InputStream;
  42. import java.lang.reflect.Method;
  43. import java.lang.reflect.Modifier;
  44. import java.util.List;
  45. import java.util.Map;
  46. import java.util.regex.Pattern;
  47. public class JavaExecutor extends NullClassListener implements ExecuteHandler {
  48. private RuntimeSupport runtimeSupport;
  49. private LogFileManager logFileManager;
  50. private MetaDataManager metaDataManager;
  51. private MetaDataContext javaMetaContext;
  52. @Inject
  53. public void receiveRuntimeSupport(RuntimeSupport support) {
  54. runtimeSupport = support;
  55. }
  56. @Inject
  57. public void receiveLogFileManager(LogFileManager manager) {
  58. logFileManager = manager;
  59. }
  60. @Inject
  61. public void receiveMetaDataManager(MetaDataManager manager)
  62. {
  63. metaDataManager = manager;
  64. javaMetaContext = metaDataManager.getMetaData().getOrCreateContext("java");
  65. }
  66. @Override
  67. public action_code execute(ExecuteRequest request, ETLTestMethod mt, ETLTestOperation testOperation, ETLTestValueObject valueObject, VariableContext variableContext, ExecutionContext executionContext)
  68. throws TestAssertionFailure, TestExecutionError, TestWarning {
  69. String className = request.getJavaClass();
  70. try {
  71. Class cl = Thread.currentThread().getContextClassLoader().loadClass(className);
  72. MetaDataPackageContext pc = javaMetaContext.createPackageContextForCurrentTest(MetaDataPackageContext.path_type.external_source);
  73. MetaDataArtifact art = pc.createArtifact("java-classpath", runtimeSupport.getTempDirectory());
  74. art.createContent(className).referencedByCurrentTest("java-main-class");
  75. Method mth = cl.getDeclaredMethod("main", new Class[]{String[].class});
  76. int mods = mth.getModifiers();
  77. if (!Modifier.isPublic(mods)) {
  78. throw new TestExecutionError("Java class has main method, but it isn't public: " + mth, ExecuteConstants.ERR_JAVA_MAIN_NOT_PUBLIC);
  79. }
  80. if (!Modifier.isStatic(mods)) {
  81. throw new TestExecutionError("Java class has public main method, but it isn't static: " + mth, ExecuteConstants.ERR_JAVA_MAIN_NOT_STATIC);
  82. }
  83. List<String> requestArguments = request.getArguments();
  84. String[] args;
  85. JavaForker javaForker = new JavaForker(runtimeSupport);
  86. // use the temp folder as the working dir
  87. javaForker.setWorkingDirectory(runtimeSupport.getTempDirectory());
  88. javaForker.setMainClassName(className);
  89. // set a debug token in the system properties to identify this test
  90. javaForker.addSystemProperty("etlunit.active", "true");
  91. javaForker.addSystemProperty("etlunit.test.class", testOperation.getTestClass().getQualifiedName());
  92. javaForker.addSystemProperty("etlunit.test.method", testOperation.getTestMethod().getName());
  93. javaForker.addSystemProperty("etlunit.test.method.qualified", testOperation.getTestMethod().getQualifiedName());
  94. javaForker.addSystemProperty("etlunit.test.operation", testOperation.getOperationName());
  95. javaForker.addSystemProperty("etlunit.test.operation.ordinal", String.valueOf(testOperation.getOrdinal()));
  96. javaForker.addSystemProperty("etlunit.test.operation.qualified", testOperation.getQualifiedName());
  97. // adjust the classpath if running in maven
  98. String property = System.getProperty("etlunit.maven.plugin.classpath");
  99. if (property != null) {
  100. String[] pathElements = property.split(Pattern.quote(File.pathSeparator));
  101. for (String pathElement : pathElements) {
  102. javaForker.addClasspathEntry(new File(pathElement));
  103. }
  104. }
  105. if (requestArguments != null && requestArguments.size() != 0) {
  106. args = new String[requestArguments.size()];
  107. for (int i = 0; i < args.length; i++) {
  108. String argument = requestArguments.get(i);
  109. // wrap with velocity
  110. javaForker.addArgument(variableContext.contextualize(argument));
  111. args[i] = argument;
  112. }
  113. }
  114. SystemProperties properties = request.getSystemProperties();
  115. if (properties != null) {
  116. Map<String, String> additionalProperties = properties.getAdditionalProperties();
  117. if (additionalProperties != null) {
  118. for (Map.Entry<String, String> addProperty : additionalProperties.entrySet()) {
  119. javaForker.addSystemProperty(
  120. addProperty.getKey(),
  121. variableContext.contextualize(addProperty.getValue())
  122. );
  123. }
  124. }
  125. }
  126. String runId = className + "_" + testOperation.getQualifiedName();
  127. if (request.getRunId() != null) {
  128. runId = request.getRunId();
  129. }
  130. final ProcessFacade proc = javaForker.startProcess();
  131. proc.waitForCompletion();
  132. // make sure the stream threads get caught up
  133. proc.waitForOutputStreamsToComplete();
  134. File out = runtimeSupport.createGeneratedSourceFile("java-executor", runId + ".out");
  135. // stream the standard out and standard err into the logs
  136. FileUtils.copyStreamToFile(new InputStreamFacade() {
  137. @Override
  138. public InputStream getInputStream() throws IOException {
  139. return proc.getInputStream();
  140. }
  141. }, out);
  142. File err = runtimeSupport.createGeneratedSourceFile("java-executor", runId + ".err");
  143. FileUtils.copyStreamToFile(new InputStreamFacade() {
  144. @Override
  145. public InputStream getInputStream() throws IOException {
  146. return proc.getErrorStream();
  147. }
  148. }, err);
  149. if (mt != null)
  150. {
  151. logFileManager.addLogFile(mt, testOperation, out, "standard-out");
  152. logFileManager.addLogFile(mt, testOperation, err, "standard-err");
  153. }
  154. else
  155. {
  156. logFileManager.addLogFile(testOperation, out, "standard-out");
  157. logFileManager.addLogFile(testOperation, err, "standard-err");
  158. }
  159. if (request.getExitCode() != null) {
  160. int ret = proc.getCompletionCode();
  161. int exp = request.getExitCode().intValue();
  162. if (ret != exp) {
  163. throw new TestExecutionError("Unexpected process exit code. [" + exp + "] expected, [" + ret + "] observed.", ExecuteConstants.ERR_JAVA_EXECUTION_ERROR_BAD_RETURN_CODE);
  164. }
  165. }
  166. } catch (ClassNotFoundException e) {
  167. throw new TestExecutionError("Java class not found: " + className, ExecuteConstants.ERR_JAVA_CLASS_NOT_FOUND, e);
  168. } catch (NoSuchMethodException e) {
  169. throw new TestExecutionError("Java class found, but it does not have a main method: " + className, ExecuteConstants.ERR_JAVA_MAIN_METHOD_NOT_FOUND, e);
  170. } catch (IOException e) {
  171. throw new TestExecutionError("Java execution failure: " + className, ExecuteConstants.ERR_JAVA_EXECUTION_ERROR, e);
  172. } catch (TestExecutionError e) {
  173. throw e;
  174. } catch (Exception e) {
  175. throw new TestExecutionError("Java execution prepare failure: " + className, ExecuteConstants.ERR_JAVA_EXECUTION_ERROR, e);
  176. }
  177. return action_code.handled;
  178. }
  179. }