Skip to content

Commit

Permalink
Support scanning for expected methods and ignoring the rest (OpenHFT#654
Browse files Browse the repository at this point in the history
)

* Support scanning for expected methods and ignoring the rest

* Windows newlines

---------

Co-authored-by: Peter Lawrey <[email protected]>
  • Loading branch information
peter-lawrey and peter-lawrey authored May 5, 2023
1 parent d83fc08 commit 2bfdddb
Show file tree
Hide file tree
Showing 8 changed files with 260 additions and 66 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -36,6 +36,8 @@
* Base class for generated method readers.
*/
public abstract class AbstractGeneratedMethodReader implements MethodReader {
@Deprecated(/* to be removed in x.26 */)
private static final boolean RETRY_UNKOWN_METHOD = Jvm.getBoolean("retry.unknown.method", true);
private static final Consumer<MessageHistory> NO_OP_MH_CONSUMER = Mocker.ignored(Consumer.class);
private static final MessageHistoryThreadLocal TEMP_MESSAGE_HISTORY = new MessageHistoryThreadLocal();
protected final WireParselet debugLoggingParselet;
Expand Down Expand Up @@ -83,17 +85,30 @@ public void historyConsumer(Consumer<MessageHistory> historyConsumer) {
* @param wireIn Data input.
* @return <code>true</code> if reading is successful, <code>false</code> if reading should be delegated.
*/
protected abstract boolean readOneCall(WireIn wireIn);
protected Boolean readOneGenerated(WireIn wireIn) {
return readOneCall(wireIn);
}

@Deprecated(/* for removal in x.26*/)
protected boolean readOneCall(WireIn wireIn) {
// one of these methods must be overridden
return Boolean.TRUE.equals(readOneGenerated(wireIn));
}

protected Boolean readOneMetaGenerated(WireIn wireIn) {
return readOneCallMeta(wireIn);
}
@Deprecated(/* for removal in x.26*/)
protected boolean readOneCallMeta(WireIn wireIn) {
return false;
// one of these methods must be overridden
return Boolean.TRUE.equals(readOneMetaGenerated(wireIn));
}

/**
* @param context Reading document context.
* @return <code>true</code> if reading is successful, <code>false</code> if reading should be delegated.
*/
public boolean readOne0(DocumentContext context) {
public Boolean readOne0(DocumentContext context) {
if (context.isMetaData())
return false;

Expand Down Expand Up @@ -122,7 +137,10 @@ public boolean readOne0(DocumentContext context) {
break;
long start = bytes.readPosition();

if (readOneCall(wireIn))
Boolean read = readOneGenerated(wireIn);
if (read == null)
return decoded ? Boolean.TRUE : null;
if (read)
decoded = true;

if (restIgnored())
Expand All @@ -149,7 +167,7 @@ public boolean readOne0(DocumentContext context) {
}
}

public boolean readOneMeta(DocumentContext context) {
public Boolean readOneMeta(DocumentContext context) {
WireIn wireIn = context.wire();
if (wireIn == null)
return false;
Expand All @@ -162,7 +180,10 @@ public boolean readOneMeta(DocumentContext context) {
break;
long start = bytes.readPosition();

if (readOneCallMeta(wireIn))
Boolean read = readOneMetaGenerated(wireIn);
if (read == null)
return decoded ? Boolean.TRUE : null;
if (read)
decoded = true;

if (restIgnored())
Expand Down Expand Up @@ -220,19 +241,26 @@ private void writeUnwrittenMessageHistory(DocumentContext context) {
public boolean readOne() {
throwExceptionIfClosed();

boolean ok;
do {
try (DocumentContext context = in.readingDocument()) {
if (!context.isPresent()) {
return false;
}

try (DocumentContext context = in.readingDocument()) {
if (!context.isPresent()) {
return false;
if (context.isMetaData()) {
Boolean ok = readOneMeta(context);
if (Boolean.FALSE.equals(ok))
return false;
// retry on a metadata message even if known
} else {
Boolean ok = readOne0(context);
if (ok != null)
return ok;
// retry on a data message unless a known message is found.
}
}

ok = context.isMetaData()
? readOneMeta(context)
: readOne0(context);
}

return ok;
} while(RETRY_UNKOWN_METHOD && !isClosing());
return false;
}

public void throwExceptionIfClosed() {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -259,7 +259,7 @@ private void generateSourceCode() {
}

sourceCode.append("@Override\n" +
"protected boolean readOneCall(WireIn wireIn) {\n" +
"protected Boolean readOneGenerated(WireIn wireIn) {\n" +
"ValueIn valueIn = wireIn.getValueIn();\n" +
"String lastEventName = \"\";\n" +
"if (wireIn.bytes().peekUnsignedByte() == BinaryWireCode.FIELD_NUMBER) {\n" +
Expand Down Expand Up @@ -292,7 +292,7 @@ private void generateSourceCode() {

sourceCode.append("default:\n" +
"defaultParselet.accept(lastEventName, valueIn);\n" +
"return true;\n" +
"return null;\n" +
"}\n" +
"return true;\n" +
"} \n" +
Expand All @@ -302,7 +302,7 @@ private void generateSourceCode() {
"}\n");

sourceCode.append("@Override\n" +
"protected boolean readOneCallMeta(WireIn wireIn) {\n" +
"protected Boolean readOneMetaGenerated(WireIn wireIn) {\n" +
"ValueIn valueIn = wireIn.getValueIn();\n" +
"String lastEventName = \"\";\n" +
"if (wireIn.bytes().peekUnsignedByte() == BinaryWireCode.FIELD_NUMBER) {\n" +
Expand Down Expand Up @@ -333,7 +333,7 @@ private void generateSourceCode() {

sourceCode.append("default:\n" +
"valueIn.skipValue();\n" +
"return true;\n" +
"return null;\n" +
"}\n" +
"return true;\n" +
"} \n" +
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,7 @@
import net.openhft.chronicle.bytes.MethodReaderBuilder;
import net.openhft.chronicle.bytes.MethodReaderInterceptorReturns;
import net.openhft.chronicle.core.Jvm;
import net.openhft.chronicle.core.onoes.ExceptionHandler;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;

Expand All @@ -35,27 +36,27 @@ public class VanillaMethodReaderBuilder implements MethodReaderBuilder {
private static final Class<?> COMPILE_FAILED = ClassNotFoundException.class;

private final MarshallableIn in;
private boolean warnMissing = false;
private boolean ignoreDefaults;
private WireParselet defaultParselet;
private MethodReaderInterceptorReturns methodReaderInterceptorReturns;
private WireType wireType;
private Object[] metaDataHandler = null;
private ExceptionHandler exceptionHandlerOnUnknownMethod = Jvm.debug();

public VanillaMethodReaderBuilder(MarshallableIn in) {
this.in = in;
}

@NotNull
public static WireParselet createDefaultParselet(boolean warnMissing) {
public static WireParselet createDefaultParselet(ExceptionHandler exceptionHandlerOnUnknownMethod) {
return (s, v) -> {
MessageHistory history = MessageHistory.get();
long sourceIndex = history.lastSourceIndex();
v.skipValue();
if (s.length() == 0 || warnMissing)
Jvm.warn().on(VanillaMethodReader.class, errorMsg(s, history, sourceIndex));
else if (Jvm.isDebugEnabled(VanillaMethodReader.class))
Jvm.debug().on(VanillaMethodReader.class, errorMsg(s, history, sourceIndex));
ExceptionHandler eh = s.length() == 0
? Jvm.warn()
: exceptionHandlerOnUnknownMethod;
eh.on(VanillaMethodReader.class, errorMsg(s, history, sourceIndex));
};
}

Expand Down Expand Up @@ -97,12 +98,9 @@ public VanillaMethodReaderBuilder methodReaderInterceptorReturns(MethodReaderInt
return this;
}

public boolean warnMissing() {
return warnMissing;
}

public VanillaMethodReaderBuilder warnMissing(boolean warnMissing) {
this.warnMissing = warnMissing;
@Override
public MethodReaderBuilder exceptionHandlerOnUnknownMethod(ExceptionHandler exceptionHandler) {
this.exceptionHandlerOnUnknownMethod = exceptionHandler;
return this;
}

Expand All @@ -120,7 +118,7 @@ private MethodReader createGeneratedInstance(Object... impls) {
if (ignoreDefaults || Jvm.getBoolean(DISABLE_READER_PROXY_CODEGEN))
return null;

GenerateMethodReader generateMethodReader = new GenerateMethodReader(wireType, methodReaderInterceptorReturns, metaDataHandler, impls);
GenerateMethodReader generateMethodReader = new GenerateMethodReader(wireType, methodReaderInterceptorReturns, metaDataHandler, impls);

String fullClassName = generateMethodReader.packageName() + "." + generateMethodReader.generatedClassName();

Expand Down Expand Up @@ -165,7 +163,7 @@ public MethodReaderBuilder metaDataHandler(Object... components) {
@NotNull
public MethodReader build(Object... impls) {
if (this.defaultParselet == null)
this.defaultParselet = createDefaultParselet(warnMissing);
this.defaultParselet = createDefaultParselet(exceptionHandlerOnUnknownMethod);

final MethodReader generatedInstance = createGeneratedInstance(impls);

Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,132 @@
/*
* Copyright 2016-2022 chronicle.software
*
* https://chronicle.software
*
* 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 net.openhft.chronicle.wire;

import net.openhft.chronicle.bytes.Bytes;
import net.openhft.chronicle.bytes.MethodReader;
import net.openhft.chronicle.core.Jvm;
import net.openhft.chronicle.core.Mocker;
import net.openhft.chronicle.core.onoes.ExceptionHandler;
import net.openhft.chronicle.core.util.IgnoresEverything;
import org.jetbrains.annotations.NotNull;
import org.junit.Test;

import java.io.StringWriter;

import static org.junit.Assert.assertEquals;

public class MethodReaderBuilderExceptionHandlerTest extends WireTestCommon {
static final String input = "" +
"---\n" +
"a: a1\n" +
"...\n" +
"---\n" +
"b: b1\n" +
"...\n" +
"---\n" +
"c: c1\n" +
"...\n" +
"---\n" +
"a: a2\n" +
"...\n" +
"---\n" +
"b: b2\n" +
"...\n" +
"---\n" +
"c: c2\n" +
"...\n";

interface _A {
void a(String text);
}

interface _B {
void b(String text);
}

interface _C {
void c(String text);
}

interface _BC extends _B, _C {
}

@Test
public void testNothing() {
doTest("" +
"# false\n",
ExceptionHandler.ignoresEverything(), IgnoresEverything.class);
}

@Test
public void testA() {
doTest("" +
"a[a1]\n" +
"# true\n" +
"a[a2]\n" +
"# true\n" +
"# false\n",
ExceptionHandler.ignoresEverything(), _A.class);
}

@Test
public void testBC() {
doTest("" +
"b[b1]\n" +
"# true\n" +
"c[c1]\n" +
"# true\n" +
"b[b2]\n" +
"# true\n" +
"c[c2]\n" +
"# true\n" +
"# false\n",
ExceptionHandler.ignoresEverything(), _BC.class);
}

@Test
public void testBCWarn() {
expectException("Unknown method-name='a'");
doTest("" +
"b[b1]\n" +
"# true\n" +
"c[c1]\n" +
"# true\n" +
"b[b2]\n" +
"# true\n" +
"c[c2]\n" +
"# true\n" +
"# false\n",
Jvm.warn(), _BC.class);
}

private void doTest(String expected, ExceptionHandler eh, Class type) {
@NotNull StringWriter out = new StringWriter();
Wire wire = WireType.YAML_ONLY.apply(Bytes.from(input));
MethodReader reader = wire
.methodReaderBuilder()
.exceptionHandlerOnUnknownMethod(eh)
.build(Mocker.logging(type, "", out));
while (!wire.isEmpty()) {
boolean read = reader.readOne();
out.append("# ").append(Boolean.toString(read)).append("\n");
}
assertEquals(expected, out.toString().replace("\r", ""));
}
}
Loading

0 comments on commit 2bfdddb

Please sign in to comment.