Loading plugins/org.etsi.mts.tdl.execution.java.runtime/src/org/etsi/mts/tdl/execution/java/adapters/PojoReflection.java 0 → 100644 +95 −0 Original line number Diff line number Diff line package org.etsi.mts.tdl.execution.java.adapters; import java.lang.reflect.Field; import java.lang.reflect.InvocationTargetException; import java.lang.reflect.Method; import java.lang.reflect.Modifier; import java.util.ArrayList; import java.util.List; /** * Reflective access to POJO members shared by {@link PojoValidator} and * {@link PojoRenderer}: the members of an object are its non-static fields * (including superclasses), read through the JavaBeans getter if the class * provides one and directly otherwise. */ final class PojoReflection { private PojoReflection() { } /** * A readable member of a class. */ static final class Member { final Field field; final Method getter; Member(Field field, Method getter) { this.field = field; this.getter = getter; } String getName() { return field.getName(); } Object read(Object target) { try { if (getter != null) return getter.invoke(target); field.setAccessible(true); return field.get(target); } catch (IllegalAccessException | InvocationTargetException e) { throw new AssertionError("Cannot read " + field.getDeclaringClass().getName() + "." + field.getName(), e); } } } /** * The members of a class: all non-static, non-synthetic fields declared by the * class and its superclasses (excluding {@link Object}), in declaration order. */ static List<Member> members(Class<?> type) { List<Member> members = new ArrayList<>(); for (Class<?> c = type; c != null && c != Object.class; c = c.getSuperclass()) for (Field f : c.getDeclaredFields()) { if (Modifier.isStatic(f.getModifiers()) || f.isSynthetic()) continue; members.add(new Member(f, findGetter(c, f))); } return members; } private static Method findGetter(Class<?> c, Field f) { String name = f.getName(); String suffix = Character.toUpperCase(name.charAt(0)) + name.substring(1); String[] candidates = f.getType() == boolean.class || f.getType() == Boolean.class ? new String[] { "is" + suffix, "get" + suffix } : new String[] { "get" + suffix }; for (String candidate : candidates) { try { Method m = c.getMethod(candidate); if (!Modifier.isStatic(m.getModifiers()) && m.getReturnType() != void.class) return m; } catch (NoSuchMethodException e) { // try next } } return null; } /** * Whether an object is a leaf that is compared/rendered as a whole rather than * member by member: enums and JDK types (String, boxed primitives, temporal * types, BigDecimal, ...). */ static boolean isLeaf(Object o) { if (o instanceof Enum) return true; String p = o.getClass().getPackageName(); return p.startsWith("java.") || p.startsWith("javax."); } } plugins/org.etsi.mts.tdl.execution.java.runtime/src/org/etsi/mts/tdl/execution/java/adapters/PojoRenderer.java 0 → 100644 +136 −0 Original line number Diff line number Diff line package org.etsi.mts.tdl.execution.java.adapters; import java.util.Iterator; import java.util.List; import java.util.Map; import org.etsi.mts.tdl.execution.java.rt.core.TemplateImpl; import org.etsi.mts.tdl.execution.java.tri.Data; import org.etsi.mts.tdl.execution.java.tri.SpecialValue; import org.etsi.mts.tdl.execution.java.tri.Template; /** * Renders mapped data for logging, from its value and template. The notation * follows TDL: <code>?</code> for <i>AnyValue</i>, <code>*</code> for * <i>AnyValueOrOmit</i>, <code>omit</code> for <i>OmitValue</i>. The rest is * JSON-like. Members that are unassigned at TDL level are shown with the * treatment in effect for them, or left out if none is defined. */ public final class PojoRenderer { private PojoRenderer() { } /** * Render expected data. */ public static String render(Data<?, ?> data) { if (data == null) return "null"; return render(data.getValue(), data.getTemplate()); } public static String render(Object value, Template template) { StringBuilder out = new StringBuilder(); render(value, template != null ? template : TemplateImpl.NONE, out); return out.toString(); } public static String renderMember(Object value, Template container, String name) { Template t = (container != null ? container : TemplateImpl.NONE).getMember(name); if (t.getSpecialValue() == null && value == null) return symbol(container != null ? container.getUnassignedMemberTreatment() : null); return render(value, t); } private static void render(Object value, Template template, StringBuilder out) { if (template.getSpecialValue() != null) { out.append(symbol(template.getSpecialValue())); return; } if (value == null) { out.append("null"); return; } if (value instanceof CharSequence || value instanceof Character) { out.append('"').append(value).append('"'); return; } if (PojoReflection.isLeaf(value) && !(value instanceof List) && !(value instanceof Map)) { out.append(value); return; } if (value instanceof List) { out.append('['); Iterator<?> it = ((List<?>) value).iterator(); for (int i = 0; it.hasNext(); i++) { if (i > 0) out.append(", "); renderPart(it.next(), template.getItem(i), template, out); } out.append(']'); return; } out.append('{'); boolean first = true; if (value instanceof Map) { for (Map.Entry<?, ?> e : ((Map<?, ?>) value).entrySet()) first = renderNamed(String.valueOf(e.getKey()), e.getValue(), template, first, out); } else { for (PojoReflection.Member m : PojoReflection.members(value.getClass())) first = renderNamed(m.getName(), m.read(value), template, first, out); } out.append('}'); } private static boolean renderNamed(String name, Object value, Template container, boolean first, StringBuilder out) { Template t = container.getMember(name); if (t.getSpecialValue() == null && value == null) { String treatment = symbol(container.getUnassignedMemberTreatment()); if (treatment == null) // Unassigned and no treatment defined: left to the validator default return first; if (!first) out.append(", "); out.append(name).append(": ").append(treatment); return false; } if (!first) out.append(", "); out.append(name).append(": "); render(value, t, out); return false; } private static void renderPart(Object value, Template t, Template container, StringBuilder out) { if (t.getSpecialValue() == null && value == null) { String treatment = symbol(container.getUnassignedMemberTreatment()); out.append(treatment != null ? treatment : "null"); return; } render(value, t, out); } /** * The TDL notation of a special value. * * @return <code>?</code>, <code>*</code> or <code>omit</code>, or <b>null</b> * for <b>null</b>. */ public static String symbol(SpecialValue v) { if (v == null) return null; switch (v) { case AnyValue: return "?"; case AnyValueOrOmit: return "*"; case OmitValue: return "omit"; default: return v.name(); } } } plugins/org.etsi.mts.tdl.execution.java.runtime/src/org/etsi/mts/tdl/execution/java/adapters/http/HttpSystemAdapter.java +52 −28 Original line number Diff line number Diff line Loading @@ -29,6 +29,7 @@ import java.util.concurrent.ConcurrentLinkedQueue; import java.util.concurrent.LinkedBlockingQueue; import java.util.regex.Pattern; import org.etsi.mts.tdl.execution.java.adapters.PojoRenderer; import org.etsi.mts.tdl.execution.java.rt.core.PojoData; import org.etsi.mts.tdl.execution.java.tri.Argument; import org.etsi.mts.tdl.execution.java.tri.ComponentInstanceRole; Loading @@ -41,6 +42,7 @@ import org.etsi.mts.tdl.execution.java.tri.NamedElement; import org.etsi.mts.tdl.execution.java.tri.Procedure; import org.etsi.mts.tdl.execution.java.tri.Reporter; import org.etsi.mts.tdl.execution.java.tri.SystemAdapter; import org.etsi.mts.tdl.execution.java.tri.Template; import org.etsi.mts.tdl.execution.java.tri.Type; import org.etsi.mts.tdl.execution.java.tri.Validator; import org.etsi.mts.tdl.execution.java.tri.Value; Loading Loading @@ -201,6 +203,8 @@ public class HttpSystemAdapter implements SystemAdapter { if (t != null) handleError(t); else { reporter.log((target != null ? target.componentName : defaultSut), "SystemAdapter | " + "Incoming: " + response.statusCode() + " | " + toDefault(response.body(), "<empty body>")); synchronized (unhandledInputs) { unhandledInputs.add(new HttpInput(response, null, target, connection)); unhandledInputs.notifyAll(); Loading Loading @@ -306,10 +310,10 @@ public class HttpSystemAdapter implements SystemAdapter { requestBuilder.uri(uri); // TODO logging reporter.comment("SystemAdapter | " + source.getName(), "Outgoing (headers): " + httpData.method.toString() + " | " + uri); reporter.log(source.getName(), "SystemAdapter | " + "Outgoing (headers): " + httpData.method.toString() + " | " + uri); byte[] body = encodeBody(httpData.body); reporter.comment("SystemAdapter | " + source.getName(), "Outgoing (body): " + toDefault(mapper.writeValueAsString(httpData.body), "<empty body>")); reporter.log(source.getName(), "SystemAdapter | " + "Outgoing (body): " + toDefault(mapper.writeValueAsString(httpData.body), "<empty body>")); requestBuilder.method(httpData.method.toString(), HttpRequest.BodyPublishers.ofByteArray(body)); if (httpData.headers != null) Loading Loading @@ -363,8 +367,8 @@ public class HttpSystemAdapter implements SystemAdapter { int length = body.length; // TODO logging reporter.comment("SystemAdapter | " + source.getName(), "Outgoing (headers): " + httpData.status + " | length=" + length); reporter.comment("SystemAdapter | " + source.getName(), "Outgoing (body): " + toDefault(mapper.writeValueAsString(httpData.body), "<empty body>")); reporter.log(source.getName(), "SystemAdapter | " + "Outgoing (headers): " + httpData.status + " | length=" + length); reporter.log(source.getName(), "SystemAdapter | " + "Outgoing (body): " + toDefault(mapper.writeValueAsString(httpData.body), "<empty body>")); unhandledExchange.sendResponseHeaders(httpData.status, length); Loading Loading @@ -408,8 +412,6 @@ public class HttpSystemAdapter implements SystemAdapter { String body = response.body(); // TODO logging //reporter.comment(target.getName(), "Incoming: " + response.statusCode() + " | " + body); try { Loading @@ -427,16 +429,12 @@ public class HttpSystemAdapter implements SystemAdapter { Data received = new PojoData<>(receivedHttpData); if (expected != null) { String expectedBody = null; if (expectedHttpData.body != null) { if (expectedHttpData.body != null) receivedHttpData.body = decodeBody(body, expectedHttpData.body.getClass()); // For logging only expectedBody = StandardCharsets.UTF_8.decode(ByteBuffer.wrap(encodeBody(expectedHttpData.body))).toString(); } reporter.comment("SystemAdapter | " + target.getName(), "Matching: " + response.statusCode() + " | " + toDefault(body, "<empty body>")); reporter.comment("SystemAdapter | " + target.getName(), "\t vs " + toAny(expectedHttpData.status) + " | " + toAny(expectedBody)); reporter.log(target.getName(), "SystemAdapter | " + "Matching:\t " + response.statusCode() + " | " + toDefault(body, "<empty body>")); reporter.log(target.getName(), "SystemAdapter | " + "\t expected: " + describeExpected(expected, "status")); if (this.validator.matches(expected, received)) { reporter.comment("SystemAdapter | " + target.getName(), "\t MATCHED"); reporter.log(target.getName(), "SystemAdapter | " + "\t MATCHED"); unhandledInputs.remove(input); return received; } Loading Loading @@ -465,9 +463,8 @@ public class HttpSystemAdapter implements SystemAdapter { // TODO other encodings Charset cs = StandardCharsets.UTF_8; input.body = new String(is.readAllBytes(), cs); reporter.log(target.getName(), "SystemAdapter | " + "Incoming: " + exchange.getRequestMethod() + " " + exchange.getRequestURI() + " | " + toDefault(input.body, "<empty body>")); // TODO logging // reporter.comment(target.getName(), "Incoming: " + exchange.getRequestMethod() + " | " + input.body); } catch (IOException e) { handleError(e); Loading @@ -488,16 +485,12 @@ public class HttpSystemAdapter implements SystemAdapter { Data received = new PojoData<>(receivedHttpData); boolean isReceived = false; if (expected != null) { String expectedBody = null; if (expectedHttpData.body != null) { if (expectedHttpData.body != null) receivedHttpData.body = decodeBody(input.body, expectedHttpData.body.getClass()); // For logging only expectedBody = StandardCharsets.UTF_8.decode(ByteBuffer.wrap(encodeBody(expectedHttpData.body))).toString(); } reporter.comment("SystemAdapter | " + target.getName(), "Matching: " + exchange.getRequestMethod() + " | " + toDefault(input.body, "<empty body>")); reporter.comment("SystemAdapter | " + target.getName(), "\t vs " + toAny(expectedHttpData.method) + " | " + toAny(expectedBody)); reporter.log(target.getName(), "SystemAdapter | " + "Matching:\t " + exchange.getRequestMethod() + " | " + toDefault(input.body, "<empty body>")); reporter.log(target.getName(), "SystemAdapter | " + "\t expected: " + describeExpected(expected, "method")); if (this.validator.matches(expected, received)) { reporter.comment("SystemAdapter | " + target.getName(), "\t MATCHED"); reporter.log(target.getName(), "SystemAdapter | " + "\t MATCHED"); isReceived = true; } Loading Loading @@ -527,19 +520,50 @@ public class HttpSystemAdapter implements SystemAdapter { return null; } private String toAny(Object value) { return toDefault(value, "*"); } private String toDefault(Object value, String def) { return value != null && !value.equals("null") ? value.toString() : def; } /** * Renders expected request/response data as "head | body" from its value and * template, so that special values (<code>?</code>, <code>*</code>, * <code>omit</code>) and unassigned parts show as such rather than as the * placeholders the mapped object holds for them. * * @param headMember The member rendered as head: "status" for responses, * "method" for requests. */ private String describeExpected(Data expected, String headMember) { Object value = expected.getValue(); Template template = expected.getTemplate(); if (template.getSpecialValue() != null) // The whole message is a special value return PojoRenderer.render(expected); Object head = null; Object body = null; if (value instanceof HttpRequestData) { head = ((HttpRequestData) value).method; body = ((HttpRequestData) value).body; } else if (value instanceof HttpResponseData) { head = ((HttpResponseData) value).status; body = ((HttpResponseData) value).body; } else { return PojoRenderer.render(expected); } // An unassigned head/body with no treatment defined is left to the // validator default; shown as "*" to keep the log readable return toDefault(PojoRenderer.renderMember(head, template, headMember), "*") + " | " + toDefault(PojoRenderer.renderMember(body, template, "body"), "*"); } @Override public void logUnexpected(Data received, Connection connection, NamedElement target) { reporter.log(target.getName(), "SystemAdapter | " + "UNEXPECTED: " + describe(received)); } /** * Renders received request/response data as "head | body". */ private String describe(Data data) { Object value = data.getValue(); Object head; Loading Loading
plugins/org.etsi.mts.tdl.execution.java.runtime/src/org/etsi/mts/tdl/execution/java/adapters/PojoReflection.java 0 → 100644 +95 −0 Original line number Diff line number Diff line package org.etsi.mts.tdl.execution.java.adapters; import java.lang.reflect.Field; import java.lang.reflect.InvocationTargetException; import java.lang.reflect.Method; import java.lang.reflect.Modifier; import java.util.ArrayList; import java.util.List; /** * Reflective access to POJO members shared by {@link PojoValidator} and * {@link PojoRenderer}: the members of an object are its non-static fields * (including superclasses), read through the JavaBeans getter if the class * provides one and directly otherwise. */ final class PojoReflection { private PojoReflection() { } /** * A readable member of a class. */ static final class Member { final Field field; final Method getter; Member(Field field, Method getter) { this.field = field; this.getter = getter; } String getName() { return field.getName(); } Object read(Object target) { try { if (getter != null) return getter.invoke(target); field.setAccessible(true); return field.get(target); } catch (IllegalAccessException | InvocationTargetException e) { throw new AssertionError("Cannot read " + field.getDeclaringClass().getName() + "." + field.getName(), e); } } } /** * The members of a class: all non-static, non-synthetic fields declared by the * class and its superclasses (excluding {@link Object}), in declaration order. */ static List<Member> members(Class<?> type) { List<Member> members = new ArrayList<>(); for (Class<?> c = type; c != null && c != Object.class; c = c.getSuperclass()) for (Field f : c.getDeclaredFields()) { if (Modifier.isStatic(f.getModifiers()) || f.isSynthetic()) continue; members.add(new Member(f, findGetter(c, f))); } return members; } private static Method findGetter(Class<?> c, Field f) { String name = f.getName(); String suffix = Character.toUpperCase(name.charAt(0)) + name.substring(1); String[] candidates = f.getType() == boolean.class || f.getType() == Boolean.class ? new String[] { "is" + suffix, "get" + suffix } : new String[] { "get" + suffix }; for (String candidate : candidates) { try { Method m = c.getMethod(candidate); if (!Modifier.isStatic(m.getModifiers()) && m.getReturnType() != void.class) return m; } catch (NoSuchMethodException e) { // try next } } return null; } /** * Whether an object is a leaf that is compared/rendered as a whole rather than * member by member: enums and JDK types (String, boxed primitives, temporal * types, BigDecimal, ...). */ static boolean isLeaf(Object o) { if (o instanceof Enum) return true; String p = o.getClass().getPackageName(); return p.startsWith("java.") || p.startsWith("javax."); } }
plugins/org.etsi.mts.tdl.execution.java.runtime/src/org/etsi/mts/tdl/execution/java/adapters/PojoRenderer.java 0 → 100644 +136 −0 Original line number Diff line number Diff line package org.etsi.mts.tdl.execution.java.adapters; import java.util.Iterator; import java.util.List; import java.util.Map; import org.etsi.mts.tdl.execution.java.rt.core.TemplateImpl; import org.etsi.mts.tdl.execution.java.tri.Data; import org.etsi.mts.tdl.execution.java.tri.SpecialValue; import org.etsi.mts.tdl.execution.java.tri.Template; /** * Renders mapped data for logging, from its value and template. The notation * follows TDL: <code>?</code> for <i>AnyValue</i>, <code>*</code> for * <i>AnyValueOrOmit</i>, <code>omit</code> for <i>OmitValue</i>. The rest is * JSON-like. Members that are unassigned at TDL level are shown with the * treatment in effect for them, or left out if none is defined. */ public final class PojoRenderer { private PojoRenderer() { } /** * Render expected data. */ public static String render(Data<?, ?> data) { if (data == null) return "null"; return render(data.getValue(), data.getTemplate()); } public static String render(Object value, Template template) { StringBuilder out = new StringBuilder(); render(value, template != null ? template : TemplateImpl.NONE, out); return out.toString(); } public static String renderMember(Object value, Template container, String name) { Template t = (container != null ? container : TemplateImpl.NONE).getMember(name); if (t.getSpecialValue() == null && value == null) return symbol(container != null ? container.getUnassignedMemberTreatment() : null); return render(value, t); } private static void render(Object value, Template template, StringBuilder out) { if (template.getSpecialValue() != null) { out.append(symbol(template.getSpecialValue())); return; } if (value == null) { out.append("null"); return; } if (value instanceof CharSequence || value instanceof Character) { out.append('"').append(value).append('"'); return; } if (PojoReflection.isLeaf(value) && !(value instanceof List) && !(value instanceof Map)) { out.append(value); return; } if (value instanceof List) { out.append('['); Iterator<?> it = ((List<?>) value).iterator(); for (int i = 0; it.hasNext(); i++) { if (i > 0) out.append(", "); renderPart(it.next(), template.getItem(i), template, out); } out.append(']'); return; } out.append('{'); boolean first = true; if (value instanceof Map) { for (Map.Entry<?, ?> e : ((Map<?, ?>) value).entrySet()) first = renderNamed(String.valueOf(e.getKey()), e.getValue(), template, first, out); } else { for (PojoReflection.Member m : PojoReflection.members(value.getClass())) first = renderNamed(m.getName(), m.read(value), template, first, out); } out.append('}'); } private static boolean renderNamed(String name, Object value, Template container, boolean first, StringBuilder out) { Template t = container.getMember(name); if (t.getSpecialValue() == null && value == null) { String treatment = symbol(container.getUnassignedMemberTreatment()); if (treatment == null) // Unassigned and no treatment defined: left to the validator default return first; if (!first) out.append(", "); out.append(name).append(": ").append(treatment); return false; } if (!first) out.append(", "); out.append(name).append(": "); render(value, t, out); return false; } private static void renderPart(Object value, Template t, Template container, StringBuilder out) { if (t.getSpecialValue() == null && value == null) { String treatment = symbol(container.getUnassignedMemberTreatment()); out.append(treatment != null ? treatment : "null"); return; } render(value, t, out); } /** * The TDL notation of a special value. * * @return <code>?</code>, <code>*</code> or <code>omit</code>, or <b>null</b> * for <b>null</b>. */ public static String symbol(SpecialValue v) { if (v == null) return null; switch (v) { case AnyValue: return "?"; case AnyValueOrOmit: return "*"; case OmitValue: return "omit"; default: return v.name(); } } }
plugins/org.etsi.mts.tdl.execution.java.runtime/src/org/etsi/mts/tdl/execution/java/adapters/http/HttpSystemAdapter.java +52 −28 Original line number Diff line number Diff line Loading @@ -29,6 +29,7 @@ import java.util.concurrent.ConcurrentLinkedQueue; import java.util.concurrent.LinkedBlockingQueue; import java.util.regex.Pattern; import org.etsi.mts.tdl.execution.java.adapters.PojoRenderer; import org.etsi.mts.tdl.execution.java.rt.core.PojoData; import org.etsi.mts.tdl.execution.java.tri.Argument; import org.etsi.mts.tdl.execution.java.tri.ComponentInstanceRole; Loading @@ -41,6 +42,7 @@ import org.etsi.mts.tdl.execution.java.tri.NamedElement; import org.etsi.mts.tdl.execution.java.tri.Procedure; import org.etsi.mts.tdl.execution.java.tri.Reporter; import org.etsi.mts.tdl.execution.java.tri.SystemAdapter; import org.etsi.mts.tdl.execution.java.tri.Template; import org.etsi.mts.tdl.execution.java.tri.Type; import org.etsi.mts.tdl.execution.java.tri.Validator; import org.etsi.mts.tdl.execution.java.tri.Value; Loading Loading @@ -201,6 +203,8 @@ public class HttpSystemAdapter implements SystemAdapter { if (t != null) handleError(t); else { reporter.log((target != null ? target.componentName : defaultSut), "SystemAdapter | " + "Incoming: " + response.statusCode() + " | " + toDefault(response.body(), "<empty body>")); synchronized (unhandledInputs) { unhandledInputs.add(new HttpInput(response, null, target, connection)); unhandledInputs.notifyAll(); Loading Loading @@ -306,10 +310,10 @@ public class HttpSystemAdapter implements SystemAdapter { requestBuilder.uri(uri); // TODO logging reporter.comment("SystemAdapter | " + source.getName(), "Outgoing (headers): " + httpData.method.toString() + " | " + uri); reporter.log(source.getName(), "SystemAdapter | " + "Outgoing (headers): " + httpData.method.toString() + " | " + uri); byte[] body = encodeBody(httpData.body); reporter.comment("SystemAdapter | " + source.getName(), "Outgoing (body): " + toDefault(mapper.writeValueAsString(httpData.body), "<empty body>")); reporter.log(source.getName(), "SystemAdapter | " + "Outgoing (body): " + toDefault(mapper.writeValueAsString(httpData.body), "<empty body>")); requestBuilder.method(httpData.method.toString(), HttpRequest.BodyPublishers.ofByteArray(body)); if (httpData.headers != null) Loading Loading @@ -363,8 +367,8 @@ public class HttpSystemAdapter implements SystemAdapter { int length = body.length; // TODO logging reporter.comment("SystemAdapter | " + source.getName(), "Outgoing (headers): " + httpData.status + " | length=" + length); reporter.comment("SystemAdapter | " + source.getName(), "Outgoing (body): " + toDefault(mapper.writeValueAsString(httpData.body), "<empty body>")); reporter.log(source.getName(), "SystemAdapter | " + "Outgoing (headers): " + httpData.status + " | length=" + length); reporter.log(source.getName(), "SystemAdapter | " + "Outgoing (body): " + toDefault(mapper.writeValueAsString(httpData.body), "<empty body>")); unhandledExchange.sendResponseHeaders(httpData.status, length); Loading Loading @@ -408,8 +412,6 @@ public class HttpSystemAdapter implements SystemAdapter { String body = response.body(); // TODO logging //reporter.comment(target.getName(), "Incoming: " + response.statusCode() + " | " + body); try { Loading @@ -427,16 +429,12 @@ public class HttpSystemAdapter implements SystemAdapter { Data received = new PojoData<>(receivedHttpData); if (expected != null) { String expectedBody = null; if (expectedHttpData.body != null) { if (expectedHttpData.body != null) receivedHttpData.body = decodeBody(body, expectedHttpData.body.getClass()); // For logging only expectedBody = StandardCharsets.UTF_8.decode(ByteBuffer.wrap(encodeBody(expectedHttpData.body))).toString(); } reporter.comment("SystemAdapter | " + target.getName(), "Matching: " + response.statusCode() + " | " + toDefault(body, "<empty body>")); reporter.comment("SystemAdapter | " + target.getName(), "\t vs " + toAny(expectedHttpData.status) + " | " + toAny(expectedBody)); reporter.log(target.getName(), "SystemAdapter | " + "Matching:\t " + response.statusCode() + " | " + toDefault(body, "<empty body>")); reporter.log(target.getName(), "SystemAdapter | " + "\t expected: " + describeExpected(expected, "status")); if (this.validator.matches(expected, received)) { reporter.comment("SystemAdapter | " + target.getName(), "\t MATCHED"); reporter.log(target.getName(), "SystemAdapter | " + "\t MATCHED"); unhandledInputs.remove(input); return received; } Loading Loading @@ -465,9 +463,8 @@ public class HttpSystemAdapter implements SystemAdapter { // TODO other encodings Charset cs = StandardCharsets.UTF_8; input.body = new String(is.readAllBytes(), cs); reporter.log(target.getName(), "SystemAdapter | " + "Incoming: " + exchange.getRequestMethod() + " " + exchange.getRequestURI() + " | " + toDefault(input.body, "<empty body>")); // TODO logging // reporter.comment(target.getName(), "Incoming: " + exchange.getRequestMethod() + " | " + input.body); } catch (IOException e) { handleError(e); Loading @@ -488,16 +485,12 @@ public class HttpSystemAdapter implements SystemAdapter { Data received = new PojoData<>(receivedHttpData); boolean isReceived = false; if (expected != null) { String expectedBody = null; if (expectedHttpData.body != null) { if (expectedHttpData.body != null) receivedHttpData.body = decodeBody(input.body, expectedHttpData.body.getClass()); // For logging only expectedBody = StandardCharsets.UTF_8.decode(ByteBuffer.wrap(encodeBody(expectedHttpData.body))).toString(); } reporter.comment("SystemAdapter | " + target.getName(), "Matching: " + exchange.getRequestMethod() + " | " + toDefault(input.body, "<empty body>")); reporter.comment("SystemAdapter | " + target.getName(), "\t vs " + toAny(expectedHttpData.method) + " | " + toAny(expectedBody)); reporter.log(target.getName(), "SystemAdapter | " + "Matching:\t " + exchange.getRequestMethod() + " | " + toDefault(input.body, "<empty body>")); reporter.log(target.getName(), "SystemAdapter | " + "\t expected: " + describeExpected(expected, "method")); if (this.validator.matches(expected, received)) { reporter.comment("SystemAdapter | " + target.getName(), "\t MATCHED"); reporter.log(target.getName(), "SystemAdapter | " + "\t MATCHED"); isReceived = true; } Loading Loading @@ -527,19 +520,50 @@ public class HttpSystemAdapter implements SystemAdapter { return null; } private String toAny(Object value) { return toDefault(value, "*"); } private String toDefault(Object value, String def) { return value != null && !value.equals("null") ? value.toString() : def; } /** * Renders expected request/response data as "head | body" from its value and * template, so that special values (<code>?</code>, <code>*</code>, * <code>omit</code>) and unassigned parts show as such rather than as the * placeholders the mapped object holds for them. * * @param headMember The member rendered as head: "status" for responses, * "method" for requests. */ private String describeExpected(Data expected, String headMember) { Object value = expected.getValue(); Template template = expected.getTemplate(); if (template.getSpecialValue() != null) // The whole message is a special value return PojoRenderer.render(expected); Object head = null; Object body = null; if (value instanceof HttpRequestData) { head = ((HttpRequestData) value).method; body = ((HttpRequestData) value).body; } else if (value instanceof HttpResponseData) { head = ((HttpResponseData) value).status; body = ((HttpResponseData) value).body; } else { return PojoRenderer.render(expected); } // An unassigned head/body with no treatment defined is left to the // validator default; shown as "*" to keep the log readable return toDefault(PojoRenderer.renderMember(head, template, headMember), "*") + " | " + toDefault(PojoRenderer.renderMember(body, template, "body"), "*"); } @Override public void logUnexpected(Data received, Connection connection, NamedElement target) { reporter.log(target.getName(), "SystemAdapter | " + "UNEXPECTED: " + describe(received)); } /** * Renders received request/response data as "head | body". */ private String describe(Data data) { Object value = data.getValue(); Object head; Loading