#9747 Fix Java Execution compilation breaking for datasets with more than 255 parents

Fixes #9755
This commit is contained in:
Armin 2018-06-18 17:16:57 +02:00 committed by Armin Braun
parent c56d62f4ae
commit 99b5f87f86
3 changed files with 67 additions and 27 deletions

View file

@ -8,9 +8,7 @@ import java.nio.charset.StandardCharsets;
import java.nio.file.Files;
import java.nio.file.Path;
import java.nio.file.Paths;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collection;
import java.util.HashMap;
import java.util.Map;
import java.util.regex.Pattern;
@ -26,6 +24,9 @@ import org.codehaus.janino.SimpleCompiler;
*/
public final class ComputeStepSyntaxElement<T extends Dataset> {
public static final VariableDefinition CTOR_ARGUMENT =
new VariableDefinition(Map.class, "arguments");
private static final Path SOURCE_DIR = debugDir();
private static final ISimpleCompiler COMPILER = new SimpleCompiler();
@ -82,7 +83,7 @@ public final class ComputeStepSyntaxElement<T extends Dataset> {
);
CLASS_CACHE.put(this, clazz);
}
return (T) clazz.<T>getConstructor(ctorTypes()).newInstance(ctorArguments());
return (T) clazz.<T>getConstructor(Map.class).newInstance(ctorArguments());
} catch (final CompileException | ClassNotFoundException | IOException
| NoSuchMethodException | InvocationTargetException | InstantiationException
| IllegalAccessException ex) {
@ -141,22 +142,16 @@ public final class ComputeStepSyntaxElement<T extends Dataset> {
return sourceDir;
}
/**
* @return Array of constructor argument types with the same ordering that is used by
* {@link #ctorArguments()}.
*/
private Class<?>[] ctorTypes() {
return fields.ctorAssigned().getFields().stream()
.map(FieldDefinition::asVariable)
.map(typedVar -> typedVar.type).toArray(Class<?>[]::new);
}
/**
* @return Array of constructor arguments
*/
private Object[] ctorArguments() {
return fields.ctorAssigned().getFields().stream()
.map(FieldDefinition::getCtorArgument).toArray();
private Map<String, Object> ctorArguments() {
final Map<String, Object> result = new HashMap<>();
fields.ctorAssigned().getFields().forEach(
fieldDefinition ->
result.put(fieldDefinition.getName(), fieldDefinition.getCtorArgument())
);
return result;
}
/**
@ -176,20 +171,30 @@ public final class ComputeStepSyntaxElement<T extends Dataset> {
private String fieldsAndCtor(final String name) {
final Closure constructor = new Closure();
final FieldDeclarationGroup ctorFields = fields.ctorAssigned();
final Collection<VariableDefinition> ctor = new ArrayList<>();
for (final FieldDefinition field : ctorFields.getFields()) {
if (field.getCtorArgument() != null) {
final String fieldName = field.getName();
final VariableDefinition fieldVar = field.asVariable();
final VariableDefinition argVar =
fieldVar.rename(SyntaxFactory.join(fieldName, "argument"));
constructor.add(SyntaxFactory.assignment(fieldVar.access(), argVar.access()));
ctor.add(argVar);
constructor.add(
SyntaxFactory.assignment(
fieldVar.access(),
SyntaxFactory.cast(
fieldVar.type,
CTOR_ARGUMENT.access().call(
"get",
SyntaxFactory.value(
SyntaxFactory.join("\"", field.getName(), "\"")
)
)
)
)
);
}
}
return combine(
ctorFields,
MethodSyntaxElement.constructor(name, constructor.add(fields.afterInit()), ctor)
MethodSyntaxElement.constructor(
name, constructor.add(fields.afterInit())
)
);
}

View file

@ -2,6 +2,7 @@ package org.logstash.config.ir.compiler;
import java.util.Arrays;
import java.util.Collection;
import java.util.Collections;
import java.util.stream.Collectors;
import java.util.stream.StreamSupport;
import org.jruby.RubyArray;
@ -15,12 +16,13 @@ interface MethodSyntaxElement extends SyntaxElement {
* Builds a constructor from the given method body and arguments.
* @param classname Name of the Class
* @param body Constructor Method Body
* @param arguments Method Argument Definitions
* @return Method Syntax
*/
static MethodSyntaxElement constructor(final String classname, final Closure body,
final Iterable<VariableDefinition> arguments) {
return new MethodSyntaxElement.MethodSyntaxElementImpl(classname, "", body, arguments);
static MethodSyntaxElement constructor(final String classname, final Closure body) {
return new MethodSyntaxElement.MethodSyntaxElementImpl(
classname, "", body,
Collections.singletonList(ComputeStepSyntaxElement.CTOR_ARGUMENT)
);
}
/**

View file

@ -1,5 +1,6 @@
package org.logstash.config.ir;
import com.google.common.base.Strings;
import java.util.Collection;
import java.util.Collections;
import java.util.HashMap;
@ -179,6 +180,38 @@ public final class CompiledPipelineTest extends RubyEnvTestCase {
MatcherAssert.assertThat(testEvent.getEvent().getField("foo"), CoreMatchers.nullValue());
}
@Test
public void moreThan255Parents() throws Exception {
final PipelineIR pipelineIR = ConfigCompiler.configToPipelineIR(
"input {mockinput{}} filter { " +
"if [foo] != \"bar\" { " +
"mockfilter {} " +
"mockaddfilter {} " +
"if [foo] != \"bar\" { " +
"mockfilter {} " +
Strings.repeat("} else if [foo] != \"bar\" {" +
"mockfilter {} ", 300) + " } } " +
"} output {mockoutput{} }",
false
);
final JrubyEventExtLibrary.RubyEvent testEvent =
JrubyEventExtLibrary.RubyEvent.newRubyEvent(RubyUtil.RUBY, new Event());
final Map<String, Supplier<IRubyObject>> filters = new HashMap<>();
filters.put("mockfilter", () -> IDENTITY_FILTER);
filters.put("mockaddfilter", () -> ADD_FIELD_FILTER);
new CompiledPipeline(
pipelineIR,
new CompiledPipelineTest.MockPluginFactory(
Collections.singletonMap("mockinput", () -> null),
filters,
Collections.singletonMap("mockoutput", mockOutputSupplier())
)
).buildExecution().compute(RubyUtil.RUBY.newArray(testEvent), false, false);
final Collection<JrubyEventExtLibrary.RubyEvent> outputEvents = EVENT_SINKS.get(runId);
MatcherAssert.assertThat(outputEvents.size(), CoreMatchers.is(1));
MatcherAssert.assertThat(outputEvents.contains(testEvent), CoreMatchers.is(true));
}
private Supplier<Consumer<Collection<JrubyEventExtLibrary.RubyEvent>>> mockOutputSupplier() {
return () -> events -> events.forEach(
event -> EVENT_SINKS.get(runId).add((JrubyEventExtLibrary.RubyEvent) event)