message: [RM] Feature Implement embedded message option in Xml and JsonYaml DictionaryStructureWriters

diff:
******************************************************************************/
package com.exactpro.sf.testwebgui.structures;
-import com.exactpro.sf.common.impl.messages.json.JsonYamlDictionaryWriter;
-import com.exactpro.sf.common.impl.messages.json.configuration.JsonAttribute;
-import com.exactpro.sf.common.impl.messages.json.configuration.JsonField;
-import com.exactpro.sf.common.impl.messages.json.configuration.JsonMessage;
-import com.exactpro.sf.common.impl.messages.json.configuration.JsonYamlDictionary;
-import com.exactpro.sf.common.messages.structures.IAttributeStructure;
-import com.exactpro.sf.common.util.EPSCommonException;
-
import java.io.File;
import java.io.FileNotFoundException;
import java.io.FileOutputStream;
@@ -34,6 +26,14 @@ import java.util.LinkedHashMap;
import java.util.List;
import java.util.Map;
+import com.exactpro.sf.common.impl.messages.json.JsonYamlDictionaryWriter;
+import com.exactpro.sf.common.impl.messages.json.configuration.JsonAttribute;
+import com.exactpro.sf.common.impl.messages.json.configuration.JsonField;
+import com.exactpro.sf.common.impl.messages.json.configuration.JsonMessage;
+import com.exactpro.sf.common.impl.messages.json.configuration.JsonYamlDictionary;
+import com.exactpro.sf.common.messages.structures.IAttributeStructure;
+import com.exactpro.sf.common.util.EPSCommonException;
+
public class JsonYamlDictionaryStructureWriter {
public static void write(ModifiableDictionaryStructure dictionaryStructure, OutputStream output, boolean asYaml) {
@@ -97,12 +97,7 @@ public class JsonYamlDictionaryStructureWriter {
for (ModifiableMessageStructure messageStructure : dictionaryStructure.getImplMessageStructures()) {
- JsonMessage jsonMessage = new JsonMessage();
-
- jsonMessage.setName(messageStructure.getName());
- jsonMessage.setDescription(messageStructure.getDescription());
-
- addAttributes(messageStructure, jsonMessage);
+ JsonMessage jsonMessage = createMessageFromStructure(messageStructure, structureMessageMap, structureFieldMap, referenceMap);
if (messageStructure.getReference() != null) {
messageReferenceMap.put(jsonMessage, (ModifiableMessageStructure)messageStructure.getReference());
@@ -110,25 +105,6 @@ public class JsonYamlDictionaryStructureWriter {
structureMessageMap.put(messageStructure, jsonMessage);
- for (ModifiableFieldStructure fieldStructure : messageStructure.getImplFields().values()) {
-
- JsonField jsonField = createFieldFromStructure(fieldStructure);
-
- addAttributes(fieldStructure, jsonField);
-
- if (fieldStructure.getReference() != null) {
-
- if (fieldStructure.getImplReference().isImplSimple() || fieldStructure.getImplReference().isImplEnum()) {
- jsonField.setReference(structureFieldMap.get(fieldStructure.getImplReference()));
- jsonField.setReferenceName(jsonField.getReference().getName());
- } else {
- referenceMap.put(jsonField, fieldStructure.getImplReference());
- }
- }
-
- jsonMessage.getFields().add(jsonField);
- }
-
messages.add(jsonMessage);
}
@@ -204,4 +180,45 @@ public class JsonYamlDictionaryStructureWriter {
return attribute;
}
+
+ private static JsonMessage createMessageFromStructure(ModifiableMessageStructure messageStructure,
+ Map<ModifiableMessageStructure, JsonMessage> structureMessageMap, Map<ModifiableFieldStructure, JsonField> structureFieldMap,
+ Map<JsonField, ModifiableFieldStructure> referenceMap) {
+
+ JsonMessage jsonMessage = new JsonMessage();
+
+ jsonMessage.setName(messageStructure.getName());
+ jsonMessage.setDescription(messageStructure.getDescription());
+
+ addAttributes(messageStructure, jsonMessage);
+
+ structureMessageMap.put(messageStructure, jsonMessage);
+
+ for (ModifiableFieldStructure fieldStructure : messageStructure.getImplFields().values()) {
+
+ if (fieldStructure.isMessage()) {
+ JsonMessage embeddedMessage = createMessageFromStructure((ModifiableMessageStructure)fieldStructure,
+ structureMessageMap, structureFieldMap, referenceMap);
+ jsonMessage.getFields().add(embeddedMessage);
+ } else {
+
+ JsonField jsonField = createFieldFromStructure(fieldStructure);
+
+ addAttributes(fieldStructure, jsonField);
+
+ if (fieldStructure.getReference() != null) {
+
+ if (fieldStructure.getImplReference().isImplSimple() || fieldStructure.getImplReference().isImplEnum()) {
+ jsonField.setReference(structureFieldMap.get(fieldStructure.getImplReference()));
+ jsonField.setReferenceName(jsonField.getReference().getName());
+ } else {
+ referenceMap.put(jsonField, fieldStructure.getImplReference());
+ }
+ }
+
+ jsonMessage.getFields().add(jsonField);
+ }
+ }
+ return jsonMessage;
+ }
}

diff:
@@ -103,34 +103,14 @@ public class XmlDictionaryStructureWriter {
for (ModifiableMessageStructure messageStructure : dictionaryStructure.getImplMessageStructures()) {
- Message message = new Message();
- message.setId("M_" + messageStructure.getName());
- message.setName(messageStructure.getName());
- message.setDescription(messageStructure.getDescription());
- addAttributes(messageStructure, message);
+ Message message = createMessageFromStructure(messageStructure, structureMessageMap, structureFieldMap, referenceMap);
+
if (messageStructure.getReference() != null) {
messageReferenceMap.put(message, (ModifiableMessageStructure)messageStructure.getReference());
}
structureMessageMap.put(messageStructure, message);
- for(ModifiableFieldStructure fieldStructure : messageStructure.getImplFields().values()) {
-
- Field field = createFieldFromStructure(fieldStructure, false);
- addAttributes(fieldStructure, field);
-
- if (fieldStructure.getReference() != null) {
-
- if (fieldStructure.getImplReference().isImplSimple() || fieldStructure.getImplReference().isImplEnum()) {
- field.setReference(structureFieldMap.get(fieldStructure.getImplReference()));
- } else {
- referenceMap.put(field, fieldStructure.getImplReference());
- }
- }
-
- message.getFieldsAndMessages().add(field);
- }
-
messages.getMessages().add(message);
}
@@ -204,4 +184,41 @@ public class XmlDictionaryStructureWriter {
}
+ private static Message createMessageFromStructure(ModifiableMessageStructure messageStructure,
+ Map<ModifiableMessageStructure, Message> structureMessageMap, Map<ModifiableFieldStructure, Field> structureFieldMap,
+ Map<Field, ModifiableFieldStructure> referenceMap) {
+
+ Message message = new Message();
+ message.setId("M_" + messageStructure.getName());
+ message.setName(messageStructure.getName());
+ message.setDescription(messageStructure.getDescription());
+ addAttributes(messageStructure, message);
+
+ structureMessageMap.put(messageStructure, message);
+
+ for (ModifiableFieldStructure fieldStructure : messageStructure.getImplFields().values()) {
+
+ if (fieldStructure.isMessage()) {
+ message.getFieldsAndMessages().add(createMessageFromStructure((ModifiableMessageStructure)fieldStructure,
+ structureMessageMap, structureFieldMap, referenceMap));
+ } else {
+
+ Field field = createFieldFromStructure(fieldStructure, false);
+ addAttributes(fieldStructure, field);
+
+ if (fieldStructure.getReference() != null) {
+
+ if (fieldStructure.getImplReference().isImplSimple() || fieldStructure.getImplReference().isImplEnum()) {
+ field.setReference(structureFieldMap.get(fieldStructure.getImplReference()));
+ } else {
+ referenceMap.put(field, fieldStructure.getImplReference());
+ }
+ }
+
+ message.getFieldsAndMessages().add(field);
+ }
+ }
+ return message;
+ }
+
}
\ No newline at end of file

diff:
+/*******************************************************************************
+ * Copyright 2009-2020 Exactpro (Exactpro Systems Limited)
+ *
+ * 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.exactpro.sf.testwebgui.structures;
+
+import java.util.ArrayList;
+import java.util.List;
+
+import com.exactpro.sf.common.messages.structures.DictionaryComparator.DictionaryPath;
+import com.exactpro.sf.common.messages.structures.DictionaryComparator.DistinctionType;
+import com.exactpro.sf.common.messages.structures.DictionaryComparator.IDiffListener;
+
+public class DifferenceListener implements IDiffListener {
+
+ List<String> differences = new ArrayList<>();
+
+ @Override
+ public void differnce(DistinctionType distinctionType, Object first, Object second,
+ DictionaryPath dictionaryPath) {
+
+ StringBuilder differenceStorage = new StringBuilder();
+
+ differenceStorage.append('[');
+ if (first != null) {
+ differenceStorage.append(first.getClass().getSimpleName()).append(" : ");
+ }
+ differenceStorage.append(first).append(']')
+ .append(' ')
+ .append('[');
+ if (second != null) {
+ differenceStorage.append(second.getClass().getSimpleName()).append(" : ");
+ }
+ differenceStorage.append(second).append(']');
+ if (distinctionType != null) {
+ differenceStorage.append(" - ").append(distinctionType);
+ }
+
+ differences.add(differenceStorage.toString());
+ }
+
+ List<String> getDifferences() {
+ return differences;
+ }
+}
+
+

diff:
@@ -21,8 +21,6 @@ import java.io.IOException;
import java.io.InputStream;
import java.nio.file.Path;
import java.nio.file.Paths;
-import java.util.ArrayList;
-import java.util.List;
import org.junit.Assert;
import org.junit.Rule;
@@ -30,18 +28,15 @@ import org.junit.Test;
import org.junit.rules.TemporaryFolder;
import com.exactpro.sf.common.messages.structures.DictionaryComparator;
-import com.exactpro.sf.common.messages.structures.DictionaryComparator.DictionaryPath;
-import com.exactpro.sf.common.messages.structures.DictionaryComparator.DistinctionType;
-import com.exactpro.sf.common.messages.structures.DictionaryComparator.IDiffListener;
-import com.exactpro.sf.common.messages.structures.IDictionaryStructure;
-import com.exactpro.sf.common.messages.structures.loaders.JsonYamlDictionaryStructureLoader;
public class TestJsonYamlDictionaryStructureWriter {
private static final Path BASE_DIR = Paths.get((System.getProperty("basedir") == null) ? "." : System.getProperty("basedir")).toAbsolutePath().normalize();
+ private static final String TEST_FILES_DIRECTORY_PATH = BASE_DIR + File.separator + "src" + File.separator + "test" + File.separator + "resources";
- private static final String MESSAGE_INHERITANCE_FILE_PATH = BASE_DIR + File.separator + "src" + File.separator + "test" + File.separator + "resources" + File.separator + "message-inheritance.json";
- private static final String WRITER_TEST_DICTIONARY_FILE_PATH = BASE_DIR + File.separator + "src" + File.separator + "test" + File.separator + "resources" + File.separator + "writer-test-dictionary.json";
+ private static final File MESSAGE_INHERITANCE_FILE = new File(TEST_FILES_DIRECTORY_PATH, "message-inheritance.json");
+ private static final File WRITER_TEST_DICTIONARY_FILE = new File(TEST_FILES_DIRECTORY_PATH, "writer-test-dictionary.json");
+ private static final File MESSAGE_EMBEDDED_FILE = new File(TEST_FILES_DIRECTORY_PATH, "message-embedded.json");
@Rule
public TemporaryFolder folder = new TemporaryFolder();
@@ -49,59 +44,38 @@ public class TestJsonYamlDictionaryStructureWriter {
@Test
public void testWriterWithoutDifference() throws IOException {
- ModifiableDictionaryStructure modifiableDictionaryStructure;
-
- try (FileInputStream inputStream = new FileInputStream(MESSAGE_INHERITANCE_FILE_PATH)) {
-
- modifiableDictionaryStructure = new ModifiableJsonYamlDictionaryStructureLoader()
- .load(inputStream);
- }
+ ModifiableDictionaryStructure modifiableDictionaryStructure = getDictionaryStructure(MESSAGE_INHERITANCE_FILE);
File tempFile = folder.newFile("jsonDictionary.json");
JsonYamlDictionaryStructureWriter.write(modifiableDictionaryStructure, tempFile, false);
- IDictionaryStructure dictionaryStructureFromJson;
- try (InputStream inputStream = new FileInputStream(tempFile)) {
-
- JsonYamlDictionaryStructureLoader loader = new JsonYamlDictionaryStructureLoader();
- dictionaryStructureFromJson = loader.load(inputStream);
- }
+ ModifiableDictionaryStructure dictionaryStructureFromJson = getDictionaryStructure(tempFile);
- Listener listener = new Listener();
+ DifferenceListener listener = new DifferenceListener();
DictionaryComparator comparator = new DictionaryComparator();
comparator.compare(listener,
modifiableDictionaryStructure, dictionaryStructureFromJson, true, false, true);
- Assert.assertEquals(listener.getDifferences().isEmpty(), true);
+ Assert.assertTrue(listener.getDifferences().isEmpty());
}
@Test
public void testWriterWithDifference() throws IOException {
- ModifiableDictionaryStructure modifiableDictionaryStructure;
-
- try (FileInputStream inputStream = new FileInputStream(WRITER_TEST_DICTIONARY_FILE_PATH)) {
- modifiableDictionaryStructure = new ModifiableJsonYamlDictionaryStructureLoader()
- .load(inputStream);
- }
+ ModifiableDictionaryStructure modifiableDictionaryStructure = getDictionaryStructure(WRITER_TEST_DICTIONARY_FILE);
File tempFile = folder.newFile("jsonDictionary.json");
JsonYamlDictionaryStructureWriter.write(modifiableDictionaryStructure, tempFile, false);
- IDictionaryStructure dictionaryStructureFromJson;
- try (InputStream inputStream = new FileInputStream(tempFile)) {
-
- JsonYamlDictionaryStructureLoader loader = new JsonYamlDictionaryStructureLoader();
- dictionaryStructureFromJson = loader.load(inputStream);
- }
+ ModifiableDictionaryStructure dictionaryStructureFromJson = getDictionaryStructure(tempFile);
modifiableDictionaryStructure.setNamespace("SetDifferentNamespace");
modifiableDictionaryStructure.setDescription("SetDifferentDescription");
- Listener listener = new Listener();
+ DifferenceListener listener = new DifferenceListener();
DictionaryComparator comparator = new DictionaryComparator();
comparator.compare(listener,
@@ -113,37 +87,30 @@ public class TestJsonYamlDictionaryStructureWriter {
}
- private class Listener implements IDiffListener {
+ @Test
+ public void testEmbeddedMessage() throws IOException {
- List<String> differences = new ArrayList<>();
+ ModifiableDictionaryStructure dictionaryStructureBeforeWriting = getDictionaryStructure(MESSAGE_EMBEDDED_FILE);
- @Override
- public void differnce(DistinctionType distinctionType, Object first, Object second,
- DictionaryPath dictionaryPath) {
+ File tempFile = folder.newFile("jsonDictionary.json");
- StringBuilder differenceStorage = new StringBuilder();
+ JsonYamlDictionaryStructureWriter.write(dictionaryStructureBeforeWriting, tempFile, false);
- differenceStorage.append('[');
- if (first != null) {
- differenceStorage.append(first.getClass().getSimpleName()).append(" : ");
- }
- differenceStorage.append(first).append(']')
- .append(' ')
- .append('[');
- if (second != null) {
- differenceStorage.append(second.getClass().getSimpleName()).append(" : ");
- }
- differenceStorage.append(second).append(']');
- if (distinctionType != null) {
- differenceStorage.append(" - ").append(distinctionType);
- }
+ ModifiableDictionaryStructure dictionaryStructureAfterWriting = getDictionaryStructure(tempFile);
- differences.add(differenceStorage.toString());
+ DifferenceListener listener = new DifferenceListener();
+ DictionaryComparator comparator = new DictionaryComparator();
+
+ comparator.compare(listener,
+ dictionaryStructureBeforeWriting, dictionaryStructureAfterWriting, true, false, true);
+
+ Assert.assertTrue(listener.getDifferences().isEmpty());
}
- List<String> getDifferences() {
- return differences;
+ private ModifiableDictionaryStructure getDictionaryStructure(File dictionary) throws IOException {
+ try (InputStream inputStream = new FileInputStream(dictionary)) {
+ ModifiableJsonYamlDictionaryStructureLoader loader = new ModifiableJsonYamlDictionaryStructureLoader();
+ return loader.load(inputStream);
}
}
-
}
\ No newline at end of file

diff:
******************************************************************************/
package com.exactpro.sf.testwebgui.structures;
-import com.exactpro.sf.common.impl.messages.xml.configuration.JavaType;
-import com.exactpro.sf.common.messages.structures.IAttributeStructure;
-import org.junit.Assert;
-import org.junit.Test;
+import static com.google.common.collect.Sets.newHashSet;
import java.io.File;
import java.io.FileInputStream;
@@ -28,39 +25,41 @@ import java.nio.file.Path;
import java.nio.file.Paths;
import java.util.Map;
-import static com.google.common.collect.Sets.newHashSet;
+import org.junit.Assert;
+import org.junit.Rule;
+import org.junit.Test;
+import org.junit.rules.TemporaryFolder;
+
+import com.exactpro.sf.common.impl.messages.xml.configuration.JavaType;
+import com.exactpro.sf.common.messages.structures.DictionaryComparator;
+import com.exactpro.sf.common.messages.structures.IAttributeStructure;
public class XmlDictionaryStructureWriterTest {
private static final Path BASE_DIR = Paths.get((System.getProperty("basedir") == null) ? "." : System.getProperty("basedir")).toAbsolutePath().normalize();
- private static final String FILE_PATH = BASE_DIR + File.separator + "src" + File.separator + "test" + File.separator + "resources" + File.separator + "dictionary_attributes.xml";
+ private static final String TEST_FILES_DIRECTORY_PATH = BASE_DIR + File.separator + "src" + File.separator + "test" + File.separator + "resources";
+
+ private static final File DICTIONARY_ATTRIBUTE_FILE = new File(TEST_FILES_DIRECTORY_PATH, "dictionary_attributes.xml");
+ private static final File MESSAGE_EMBEDDED_FILE = new File(TEST_FILES_DIRECTORY_PATH, "message-embedded.xml");
private static final String FIRST_ATTRIBUTE_NAME = "String";
private static final String SECOND_ATTRIBUTE_NAME = "Integer";
private static final String THIRD_ATTRIBUTE_NAME = "Boolean";
+ @Rule
+ public TemporaryFolder folder = new TemporaryFolder();
+
@Test
public void testDictionaryAttributesWriting() throws IOException {
- File dictionary = new File(FILE_PATH);
-
- ModifiableDictionaryStructure dictionaryStructure = getDictionaryStructure(dictionary);
+ ModifiableDictionaryStructure dictionaryStructure = getDictionaryStructure(DICTIONARY_ATTRIBUTE_FILE);
- ModifiableDictionaryStructure dictionaryStructureAfterWriting;
- File tempFile = null;
- try {
-
- tempFile = File.createTempFile("dictionary", ".xml");
+ File tempFile = folder.newFile("xmlDictionary.xml");
XmlDictionaryStructureWriter.write(dictionaryStructure, tempFile);
- dictionaryStructureAfterWriting = getDictionaryStructure(tempFile);
- } finally {
+ ModifiableDictionaryStructure dictionaryStructureAfterWriting = getDictionaryStructure(tempFile);
- if (tempFile != null) {
- tempFile.delete();
- }
- }
Map<String, IAttributeStructure> attributes = dictionaryStructureAfterWriting.getAttributes();
Assert.assertEquals(newHashSet(FIRST_ATTRIBUTE_NAME, SECOND_ATTRIBUTE_NAME, THIRD_ATTRIBUTE_NAME), attributes.keySet());
@@ -72,14 +71,34 @@ public class XmlDictionaryStructureWriterTest {
Assert.assertEquals(Integer.valueOf(attributes.get(SECOND_ATTRIBUTE_NAME).getValue()), Integer.valueOf(5112020));
Assert.assertEquals(attributes.get(THIRD_ATTRIBUTE_NAME).getType(), JavaType.JAVA_LANG_BOOLEAN);
- Assert.assertEquals(Boolean.valueOf(attributes.get(THIRD_ATTRIBUTE_NAME).getValue()), true);
+ Assert.assertTrue(Boolean.parseBoolean(attributes.get(THIRD_ATTRIBUTE_NAME).getValue()));
+ }
+
+ @Test
+ public void testMessageEmbedded() throws IOException {
+
+ File tempFile = folder.newFile("dictionary.xml");
+
+ ModifiableDictionaryStructure dictionaryStructureBeforeWriting = getDictionaryStructure(MESSAGE_EMBEDDED_FILE);
+
+ XmlDictionaryStructureWriter.write(dictionaryStructureBeforeWriting, tempFile);
+
+ ModifiableDictionaryStructure dictionaryStructureAfterWriting = getDictionaryStructure(tempFile);
+
+ DifferenceListener listener = new DifferenceListener();
+ DictionaryComparator comparator = new DictionaryComparator();
+
+ comparator.compare(listener,
+ dictionaryStructureBeforeWriting, dictionaryStructureAfterWriting, true, false, true);
+
+ Assert.assertTrue(listener.getDifferences().isEmpty());
+
}
private ModifiableDictionaryStructure getDictionaryStructure(File dictionary) throws IOException {
- ModifiableXmlDictionaryStructureLoader loader = new ModifiableXmlDictionaryStructureLoader();
try (InputStream inputStream = new FileInputStream(dictionary)) {
+ ModifiableXmlDictionaryStructureLoader loader = new ModifiableXmlDictionaryStructureLoader();
return loader.load(inputStream);
}
}
-
}
\ No newline at end of file

diff:
+{
+ "name" : "MessageEmbedded",
+ "fields" : {
+ "Integer" : {
+ "type" : "java.lang.Integer"
+ },
+ "String" : {
+ "type" : "java.lang.String"
+ }
+ },
+ "messages" : {
+ "Parent" : {
+ "attributes" : {
+ "AttributeA" : {
+ "type" : "java.lang.String",
+ "value" : "ValueA"
+ }
+ },
+ "fields" : {
+ "FieldA" : {
+ "reference" : "String"
+ },
+ "MessageEmbedded" : {
+ "attributes" : {
+ "AttributeE" : {
+ "type" : "java.lang.String",
+ "value" : "ValueE"
+ }
+ },
+ "fields" : {
+ "EmbeddedField" : {
+ "reference" : "String"
+ },
+ "SecondLevelEmbedded" : {
+ "fields" : {
+ "ThirdLevelEmbedded" : {
+ "fields" : {
+ "EmbeddedFieldFromThirdLevel" : {
+ "reference" : "Integer"
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+}
\ No newline at end of file

diff:
+<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
+<!--~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+ ~ Copyright 2009-2020 Exactpro (Exactpro Systems Limited)
+ ~
+ ~ 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.
+ ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~-->
+<dictionary name="MessageEmbedded" xmlns="http://exactprosystems.com/dictionary">
+ <fields>
+ <field name="String" id="String" type="java.lang.String"/>
+ <field name="Integer" id="Integer" type="java.lang.Integer"/>
+ </fields>
+ <messages>
+ <message name="Root" id="RootId">
+ <attribute name="AttributeA" type="java.lang.String">ValueA</attribute>
+ <message name="FirstLevelEmbedded1" id="FirstLevelEmbedded1Id">
+ <field name="FirstLevelEmbeddedField1" reference="String"/>
+ <message name="SecondLevelEmbedded1" id="SecondLevelEmbedded1Id">
+ <field name="SecondLevelEmbeddedField1" reference="String"/>
+ </message>
+ <field name="EmbeddedField" reference="String"/>
+ </message>
+ <field name="FieldA" reference="String"/>
+ <message name="FirstLevelEmbedded2" id="FirstLevelEmbedded2Id">
+ <field name="FirstdLevelEmbeddedField2" reference="String"/>
+ <message name="SecondLevelEmbedded2" id="SecondLevelEmbedded2Id">
+ <field name="SecondLevelEmbeddedField2" reference="String"/>
+ </message>
+ <field name="EmbeddedField" reference="String"/>
+ </message>
+ </message>
+ </messages>
+</dictionary>
\ No newline at end of file

original_message:
[RM] Feature #72143. Implement embedded message option in Xml and JsonYaml DictionaryStructureWriters

Change-Id: I9ee32296aadfa3b3af9c0fb86a6c1779a3deefa7


message: TH2 Create new AbstractTh2ExternalMinaCodecFactory with MessageHelper

change_type: MODIFY

diff:
@@ -42,6 +42,7 @@ import com.exactpro.sf.externalapi.codec.ResourcePath
import com.exactpro.sf.scriptrunner.utilitymanager.UtilityInfo
import com.exactpro.sf.services.IServiceContext
import com.exactpro.sf.services.ITaskExecutor
+import com.exactpro.sf.services.MessageHelper
import com.exactpro.sf.storage.IMessageStorage
import com.google.common.collect.ImmutableTable
import com.google.common.collect.Table
@@ -58,6 +59,8 @@ import java.util.EnumMap
abstract class AbstractExternalMinaCodecFactory : AbstractExternalCodecFactory() {
protected abstract val codecClass: Class<out AbstractCodec>
+ protected open val messageHelperClass: Class<out MessageHelper>? = null
+ protected open val messageHelperParams: Map<String, String> = emptyMap()
override fun createCodec(settings: IExternalCodecSettings): IExternalCodec = settings.run {
val dictionary = checkNotNull(this[MAIN]) { "Main dictionary is not set" }
@@ -75,7 +78,9 @@ abstract class AbstractExternalMinaCodecFactory : AbstractExternalCodecFactory()
),
getSettings(),
messageFactory,
- dictionary
+ dictionary,
+ messageHelperClass,
+ messageHelperParams
)
}

diff:
@@ -25,6 +25,7 @@ import com.exactpro.sf.externalapi.codec.IExternalCodec
import com.exactpro.sf.externalapi.codec.IExternalCodecContext
import com.exactpro.sf.externalapi.codec.IExternalCodecContext.Role
import com.exactpro.sf.services.IServiceContext
+import com.exactpro.sf.services.MessageHelper
import com.exactpro.sf.services.MockProtocolDecoderOutput
import com.exactpro.sf.services.MockProtocolEncoderOutput
import org.apache.mina.core.buffer.IoBuffer
@@ -36,12 +37,18 @@ class ExternalMinaCodec(
serviceContext: IServiceContext,
settings: ICommonSettings,
messageFactory: IMessageFactory,
- dictionary: IDictionaryStructure
+ dictionary: IDictionaryStructure,
+ messageHelperClass: Class<out MessageHelper>?,
+ private val messageHelperParams: Map<String, String> = emptyMap()
) : IExternalCodec {
private val codec: AbstractCodec = codecClass.newInstance().apply {
init(serviceContext, settings, messageFactory, dictionary)
}
+ private val messageHelper: MessageHelper? = messageHelperClass?.newInstance()?.apply {
+ init(messageFactory, dictionary)
+ }
+
private val encodeSession = DummySession()
private val decodeSession = DummySession()
@@ -52,7 +59,7 @@ class ExternalMinaCodec(
override fun encode(message: IMessage, context: IExternalCodecContext): ByteArray = encodeOutput.runCatching {
encodeSession.setContext(context)
- codec.encode(encodeSession, message, this)
+ codec.encode(encodeSession, messageHelper?.prepareMessageToEncode(message, messageHelperParams) ?: message, this)
check(messageQueue.size == 1) { "Expected 1 result, but got: ${messageQueue.size}" }
(messageQueue.poll() as IoBuffer).run { ByteArray(remaining()).apply { get(this) } }
}.getOrElse {

diff:
@@ -19,11 +19,15 @@ import com.exactpro.sf.common.codecs.AbstractCodec
import com.exactpro.sf.common.messages.IMessageFactory
import com.exactpro.sf.common.util.ICommonSettings
import com.exactpro.sf.configuration.factory.FASTMessageFactory
+import com.exactpro.sf.services.MessageHelper
import com.exactpro.sf.services.fast.FASTCodec
import com.exactpro.sf.services.fast.FASTCodecSettings
+import com.exactpro.sf.services.fast.FASTMessageHelper
class ExternalFastCodecFactory : AbstractExternalMinaCodecFactory() {
override val codecClass: Class<out AbstractCodec> = FASTCodec::class.java
override val settingsClass: Class<out ICommonSettings> = FASTCodecSettings::class.java
override val messageFactoryClass: Class<out IMessageFactory> = FASTMessageFactory::class.java
+ override val messageHelperClass: Class<out MessageHelper> = FASTMessageHelper::class.java
+ override val messageHelperParams: Map<String, String> = emptyMap()
}
\ No newline at end of file

diff:
@@ -19,11 +19,15 @@ import com.exactpro.sf.common.codecs.AbstractCodec
import com.exactpro.sf.common.messages.IMessageFactory
import com.exactpro.sf.common.util.ICommonSettings
import com.exactpro.sf.configuration.factory.FixMessageFactory
+import com.exactpro.sf.services.MessageHelper
import com.exactpro.sf.services.fix.FIXCodec
+import com.exactpro.sf.services.fix.FixMessageHelper
import com.exactpro.sf.services.tcpip.TCPIPSettings
class ExternalFixCodecFactory : AbstractExternalMinaCodecFactory() {
override val codecClass: Class<out AbstractCodec> = FIXCodec::class.java
override val settingsClass: Class<out ICommonSettings> = TCPIPSettings::class.java
override val messageFactoryClass: Class<out IMessageFactory> = FixMessageFactory::class.java
+ override val messageHelperClass: Class<out MessageHelper> = FixMessageHelper::class.java
+ override val messageHelperParams: Map<String, String> = emptyMap()
}
\ No newline at end of file

diff:
@@ -19,11 +19,19 @@ import com.exactpro.sf.common.codecs.AbstractCodec
import com.exactpro.sf.common.messages.IMessageFactory
import com.exactpro.sf.common.util.ICommonSettings
import com.exactpro.sf.configuration.factory.ITCHMessageFactory
+import com.exactpro.sf.services.MessageHelper
import com.exactpro.sf.services.itch.ITCHCodec
import com.exactpro.sf.services.itch.ITCHCodecSettings
+import com.exactpro.sf.services.itch.ITCHMessageHelper
class ExternalItchCodecFactory : AbstractExternalMinaCodecFactory() {
override val codecClass: Class<out AbstractCodec> = ITCHCodec::class.java
override val messageFactoryClass: Class<out IMessageFactory> = ITCHMessageFactory::class.java
override val settingsClass: Class<out ICommonSettings> = ITCHCodecSettings::class.java
+ override val messageHelperClass: Class<out MessageHelper> = ITCHMessageHelper::class.java
+ override val messageHelperParams: Map<String, String> = mapOf(ITCHMessageHelper.FIELD_MARKET_DATA_GROUP_NAME to "0",
+ ITCHMessageHelper.FIELD_SEQUENCE_NUMBER_NAME to "0",
+ ITCHMessageHelper.FIELD_MESSAGE_COUNT_NAME to "1",
+ ITCHMessageHelper.FIELD_LENGTH_NAME to "0"
+ )
}
\ No newline at end of file

diff:
@@ -19,10 +19,14 @@ import com.exactpro.sf.common.codecs.AbstractCodec
import com.exactpro.sf.common.messages.IMessageFactory
import com.exactpro.sf.common.util.ICommonSettings
import com.exactpro.sf.configuration.factory.NTGMessageFactory
+import com.exactpro.sf.services.MessageHelper
import com.exactpro.sf.services.ntg.NTGCodec
+import com.exactpro.sf.services.ntg.NTGMessageHelper
class ExternalNtgCodecFactory : AbstractExternalMinaCodecFactory() {
override val codecClass: Class<out AbstractCodec> = NTGCodec::class.java
override val settingsClass: Class<out ICommonSettings> = DummyCodecSettings::class.java
override val messageFactoryClass: Class<out IMessageFactory> = NTGMessageFactory::class.java
+ override val messageHelperClass: Class<out MessageHelper> = NTGMessageHelper::class.java
+ override val messageHelperParams: Map<String, String> = emptyMap()
}
\ No newline at end of file

license: Apache License 2.0

repo: exactpro/sailfish-core

original_message:
TH2 #1450. Create new AbstractTh2ExternalMinaCodecFactory with MessageHelper

Change-Id: Ie719e3b612a4d350c738d262192c4f4d66746dc7


message: [RM] Feature Support for loading IScriptReport from extensions and plugins.

diff:
@@ -41,6 +41,7 @@ import com.exactpro.sf.embedded.updater.UpdateService;
import com.exactpro.sf.matrixhandlers.MatrixProviderHolder;
import com.exactpro.sf.scriptrunner.AbstractScriptRunner;
import com.exactpro.sf.scriptrunner.IConnectionManager;
+import com.exactpro.sf.scriptrunner.IScriptReportLoader;
import com.exactpro.sf.scriptrunner.actionmanager.IActionManager;
import com.exactpro.sf.scriptrunner.languagemanager.LanguageManager;
import com.exactpro.sf.scriptrunner.services.IStaticServiceManager;
@@ -121,4 +122,5 @@ public interface ISFContext {
SfInstanceInfo getSfInstanceInfo();
ServiceMarshalManager getServiceMarshalManager();
+ IScriptReportLoader getScriptReportLoader();
}

diff:
@@ -109,6 +109,8 @@ public class PluginLoader {
private final List<IVersion> pluginVersions;
+ private final ILoadableManager scriptReportLoader;
+
public PluginLoader(
IWorkspaceDispatcher wd,
ILoadableManager staticServiceManager,
@@ -124,7 +126,8 @@ public class PluginLoader {
ILoadableManager statisticsReportsLoader,
PluginServiceLoader pluginServiceLoader,
IVersion coreVersion,
- ILoadableManager messageStorageLoader) {
+ ILoadableManager messageStorageLoader,
+ ILoadableManager scriptReportLoader) {
if (wd == null) {
throw new NullPointerException("IWorkspaceDispatcher can't be null");
}
@@ -144,6 +147,7 @@ public class PluginLoader {
this.pluginServiceLoader = pluginServiceLoader;
this.coreVersion = coreVersion;
this.messageStorageLoader = messageStorageLoader;
+ this.scriptReportLoader = scriptReportLoader;
this.pluginVersions = new ArrayList<>();
}
@@ -517,6 +521,19 @@ public class PluginLoader {
logger.info("Ignore message storages [No MessageStorageLoader]. Plugin: {}", pluginPath);
}
+ //
+ // Load IScriptReport in plugins
+ //
+ if (scriptReportLoader != null) {
+ try {
+ scriptReportLoader.load(loadableContext);
+ } catch (Exception e) {
+ throw new EPSCommonException(e);
+ }
+ } else {
+ logger.info("Ignore scripts reports [No ScriptReportLoader]. Plugin: {}", pluginPath);
+ }
+
// Collect service description files
if(pluginServiceLoader != null) {
try {

diff:
@@ -22,8 +22,6 @@ import java.util.List;
import java.util.Map;
import java.util.Queue;
-import com.exactpro.sf.configuration.CleanupConfiguration;
-import com.exactpro.sf.configuration.CleanupService;
import org.hibernate.Session;
import org.hibernate.SessionFactory;
import org.hibernate.cfg.Configuration;
@@ -44,6 +42,7 @@ import com.exactpro.sf.center.SFException;
import com.exactpro.sf.common.adapting.IAdapterManager;
import com.exactpro.sf.common.util.EPSCommonException;
import com.exactpro.sf.configuration.CleanupConfiguration;
+import com.exactpro.sf.configuration.CleanupService;
import com.exactpro.sf.configuration.DataManager;
import com.exactpro.sf.configuration.DefaultAdapterManager;
import com.exactpro.sf.configuration.DictionaryManager;
@@ -68,7 +67,9 @@ import com.exactpro.sf.scriptrunner.AsyncScriptRunner;
import com.exactpro.sf.scriptrunner.EnvironmentSettings;
import com.exactpro.sf.scriptrunner.EnvironmentSettings.StorageType;
import com.exactpro.sf.scriptrunner.IConnectionManager;
+import com.exactpro.sf.scriptrunner.IScriptReportLoader;
import com.exactpro.sf.scriptrunner.PreprocessorLoader;
+import com.exactpro.sf.scriptrunner.ScriptReportLoader;
import com.exactpro.sf.scriptrunner.ScriptRunnerSettings;
import com.exactpro.sf.scriptrunner.SyncScriptRunner;
import com.exactpro.sf.scriptrunner.ValidatorLoader;
@@ -192,6 +193,7 @@ public class SFLocalContext implements ISFContext {
private final IServiceStorage serviceStorage;
private final ServiceMarshalManager serviceMarshalManager;
+ private final IScriptReportLoader scriptReportLoader;
/**
@@ -311,6 +313,7 @@ public class SFLocalContext implements ISFContext {
PluginServiceLoader pluginServiceLoader = new PluginServiceLoader();
MessageStorageLoader messageStorageLoader = new MessageStorageLoader();
+ scriptReportLoader = new ScriptReportLoader();
// 5) Load core & plugins
PluginLoader pluginLoader = new PluginLoader(
@@ -328,7 +331,8 @@ public class SFLocalContext implements ISFContext {
statisticsService,
pluginServiceLoader,
version,
- messageStorageLoader);
+ messageStorageLoader,
+ scriptReportLoader);
LoadInfo loadInfo = pluginLoader.load();
loadInfo.appendClassPath(compilerClassPath);
@@ -728,4 +732,9 @@ public class SFLocalContext implements ISFContext {
public ServiceMarshalManager getServiceMarshalManager() {
return serviceMarshalManager;
}
+
+ @Override
+ public IScriptReportLoader getScriptReportLoader() {
+ return scriptReportLoader;
+ }
}

diff:
@@ -200,7 +200,7 @@ public class ServiceFactory implements IServiceFactory {
IVersion coreVersion = new CoreVersion();
PluginLoader pluginLoader = new PluginLoader(wd, staticServiceManager, null,
dictionaryManager, null, null, null, dataManager, null, null, null, null,
- null, coreVersion, null);
+ null, coreVersion, null, null);
pluginLoader.load();
this.marshalManager = new ServiceMarshalManager(staticServiceManager, dictionaryManager);

diff:
@@ -306,7 +306,7 @@ public class HelpBuilder {
}
PluginLoader pluginLoader = new PluginLoader(wd, staticServiceManager, actionManager, dictionaryManager, preprocessorLoader, validatorLoader,
- adapterManager, dataManager, languageManager, matrixProviderHolder, matrixConverterManager, statisticsReportLoader, null, version, null);
+ adapterManager, dataManager, languageManager, matrixProviderHolder, matrixConverterManager, statisticsReportLoader, null, version, null, null);
pluginLoader.load();

diff:
@@ -280,6 +280,8 @@ public abstract class AbstractScriptRunner implements IDisposable {
reportListeners.addAll(userListeners);
}
+ reportListeners.addAll(sfContext.getScriptReportLoader().createScriptReports(reportFolder, workspaceDispatcher, dictionaryManager, scriptDescription.getId()));
+
// NOTE: ZipReport must be latest
reportListeners.add(new ZipReport(reportFolder, workspaceDispatcher, scriptDescription, ReportOutputFormat.ZIP));

change_type: ADD

diff:
+/*******************************************************************************
+ * Copyright 2009-2020 Exactpro (Exactpro Systems Limited)
+ *
+ * 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.exactpro.sf.scriptrunner;
+
+import com.exactpro.sf.configuration.IDictionaryManager;
+import com.exactpro.sf.configuration.workspace.IWorkspaceDispatcher;
+
+public interface IScriptReportFactory {
+
+ IScriptReport createScriptReport(String reportFolder, IWorkspaceDispatcher workspaceDispatcher, IDictionaryManager dictionaryManager) throws Exception;
+
+}

diff:
+/*******************************************************************************
+ * Copyright 2009-2020 Exactpro (Exactpro Systems Limited)
+ *
+ * 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.exactpro.sf.scriptrunner;
+
+import java.util.Set;
+
+import com.exactpro.sf.configuration.IDictionaryManager;
+import com.exactpro.sf.configuration.ILoadableManager;
+import com.exactpro.sf.configuration.workspace.IWorkspaceDispatcher;
+
+public interface IScriptReportLoader extends ILoadableManager {
+ Set<IScriptReport> createScriptReports(String reportFolder, IWorkspaceDispatcher workspaceDispatcher, IDictionaryManager dictionaryManager, long scriptId);
+}

diff:
+/*******************************************************************************
+ * Copyright 2009-2020 Exactpro (Exactpro Systems Limited)
+ *
+ * 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.exactpro.sf.scriptrunner;
+
+import java.util.Objects;
+import java.util.ServiceLoader;
+import java.util.Set;
+import java.util.stream.Collectors;
+
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+import com.exactpro.sf.configuration.IDictionaryManager;
+import com.exactpro.sf.configuration.ILoadableManagerContext;
+import com.exactpro.sf.configuration.ILoggingConfigurator;
+import com.exactpro.sf.configuration.workspace.IWorkspaceDispatcher;
+import com.google.common.collect.HashMultimap;
+import com.google.common.collect.SetMultimap;
+
+public class ScriptReportLoader implements IScriptReportLoader {
+
+ private final Logger logger = LoggerFactory.getLogger(ILoggingConfigurator.getLoggerName(this));
+
+ private final SetMultimap<String, IScriptReportFactory> factories = HashMultimap.create();
+
+ @Override
+ public void load(ILoadableManagerContext context) throws Exception {
+ for (IScriptReportFactory factory : ServiceLoader.load(IScriptReportFactory.class, context.getClassLoaders()[0])) {
+ factories.put(context.getVersion().getAlias(), factory);
+ }
+ }
+
+ @Override
+ public Set<IScriptReport> createScriptReports(String reportFolder, IWorkspaceDispatcher workspaceDispatcher, IDictionaryManager dictionaryManager, long scriptId) {
+ return factories.entries().stream().map(entry ->
+ createScriptReport(entry.getValue(),
+ reportFolder,
+ workspaceDispatcher,
+ dictionaryManager,
+ entry.getKey(),
+ scriptId)
+ ).filter(Objects::nonNull).collect(Collectors.toSet());
+ }
+
+ private IScriptReport createScriptReport(IScriptReportFactory factory, String reportFolder, IWorkspaceDispatcher workspaceDispatcher, IDictionaryManager dictionaryManager, String pluginName, long scriptID) {
+ try {
+ return factory.createScriptReport(reportFolder, workspaceDispatcher, dictionaryManager);
+ } catch (Exception e) {
+ if (logger.isWarnEnabled()) {
+ logger.warn("Can not create script report from class '{}' from plugin '{}' for script with id '{}'", factory.getClass().getName(), pluginName, scriptID, e);
+ }
+ }
+ return null;
+ }
+
+ @Override
+ public void finalize(ILoadableManagerContext context) throws Exception {}
+}

original_message:
[RM] Feature #62422. Support for loading IScriptReport from extensions and plugins.

Change-Id: Ie3f438a43d1751560c096797ea26585546171c07


message: [RM] Feature Th2-related changes for report

diff:
@@ -280,7 +280,7 @@ public abstract class AbstractScriptRunner implements IDisposable {
reportListeners.addAll(userListeners);
}
- reportListeners.addAll(sfContext.getScriptReportLoader().createScriptReports(reportFolder, workspaceDispatcher, dictionaryManager, scriptDescription.getId()));
+ reportListeners.addAll(sfContext.getScriptReportLoader().createScriptReports(reportFolder, workspaceDispatcher, dictionaryManager, scriptDescription));
// NOTE: ZipReport must be latest
reportListeners.add(new ZipReport(reportFolder, workspaceDispatcher, scriptDescription, ReportOutputFormat.ZIP));

diff:
@@ -21,6 +21,6 @@ import com.exactpro.sf.configuration.workspace.IWorkspaceDispatcher;
public interface IScriptReportFactory {
- IScriptReport createScriptReport(String reportFolder, IWorkspaceDispatcher workspaceDispatcher, IDictionaryManager dictionaryManager) throws Exception;
+ IScriptReport createScriptReport(String reportFolder, IWorkspaceDispatcher workspaceDispatcher, IDictionaryManager dictionaryManager, TestScriptDescription testScriptDescription) throws Exception;
}

diff:
package com.exactpro.sf.scriptrunner;
-import java.util.Set;
+import java.util.Collection;
import com.exactpro.sf.configuration.IDictionaryManager;
import com.exactpro.sf.configuration.ILoadableManager;
import com.exactpro.sf.configuration.workspace.IWorkspaceDispatcher;
public interface IScriptReportLoader extends ILoadableManager {
- Set<IScriptReport> createScriptReports(String reportFolder, IWorkspaceDispatcher workspaceDispatcher, IDictionaryManager dictionaryManager, long scriptId);
+ Collection<IScriptReport> createScriptReports(String reportFolder, IWorkspaceDispatcher workspaceDispatcher, IDictionaryManager dictionaryManager, TestScriptDescription testScriptDescription);
}

diff:
package com.exactpro.sf.scriptrunner;
+import java.util.ArrayList;
+import java.util.Collection;
+import java.util.List;
import java.util.Objects;
import java.util.ServiceLoader;
import java.util.Set;
@@ -45,23 +48,23 @@ public class ScriptReportLoader implements IScriptReportLoader {
}
@Override
- public Set<IScriptReport> createScriptReports(String reportFolder, IWorkspaceDispatcher workspaceDispatcher, IDictionaryManager dictionaryManager, long scriptId) {
+ public Collection<IScriptReport> createScriptReports(String reportFolder, IWorkspaceDispatcher workspaceDispatcher, IDictionaryManager dictionaryManager, TestScriptDescription testScriptDescription) {
return factories.entries().stream().map(entry ->
createScriptReport(entry.getValue(),
reportFolder,
workspaceDispatcher,
dictionaryManager,
entry.getKey(),
- scriptId)
- ).filter(Objects::nonNull).collect(Collectors.toSet());
+ testScriptDescription)
+ ).filter(Objects::nonNull).collect(Collectors.toCollection(ArrayList::new));
}
- private IScriptReport createScriptReport(IScriptReportFactory factory, String reportFolder, IWorkspaceDispatcher workspaceDispatcher, IDictionaryManager dictionaryManager, String pluginName, long scriptID) {
+ private IScriptReport createScriptReport(IScriptReportFactory factory, String reportFolder, IWorkspaceDispatcher workspaceDispatcher, IDictionaryManager dictionaryManager, String pluginName, TestScriptDescription testScriptDescription) {
try {
- return factory.createScriptReport(reportFolder, workspaceDispatcher, dictionaryManager);
+ return factory.createScriptReport(reportFolder, workspaceDispatcher, dictionaryManager, testScriptDescription);
} catch (Exception e) {
if (logger.isWarnEnabled()) {
- logger.warn("Can not create script report from class '{}' from plugin '{}' for script with id '{}'", factory.getClass().getName(), pluginName, scriptID, e);
+ logger.warn("Can not create script report from class '{}' from plugin '{}' for script with id '{}'", factory.getClass().getName(), pluginName, testScriptDescription.getId(), e);
}
}
return null;

original_message:
[RM] Feature #69888. Th2-related changes for report

Change-Id: Ic6c499a0cb02200971587202557a3f79ef4be80d


message: TH2 Added sendRaw implementation in FixServerSessionsContainer

diff:
package com.exactpro.sf.services.fix;
+import com.exactpro.sf.common.messages.IMessage;
+import com.exactpro.sf.common.util.SendMessageFailedException;
+import com.exactpro.sf.services.ISession;
+import org.apache.commons.lang3.StringUtils;
+import org.quickfixj.CharsetSupport;
+
+import java.nio.ByteBuffer;
import java.util.Collection;
import java.util.HashMap;
import java.util.Map;
import java.util.Map.Entry;
-
-import org.apache.commons.lang3.StringUtils;
-
-import com.exactpro.sf.common.messages.IMessage;
-import com.exactpro.sf.common.util.SendMessageFailedException;
-import com.exactpro.sf.services.ISession;
+import java.util.function.Supplier;
public class FixServerSessionsContainer implements ISession {
@@ -42,32 +44,8 @@ public class FixServerSessionsContainer implements ISession {
@Override
public IMessage send(Object message) throws InterruptedException {
- Map<ISession, Exception> sentErrors = new HashMap<>();
- Collection<ISession> connectedSessions = application.getSessions();
- if (connectedSessions.isEmpty()) {
- throw new SendMessageFailedException("No sessions to send message: " + message);
- }
-
- for (ISession session : connectedSessions) {
- try {
- session.send(message);
- } catch (Exception e) {
- sentErrors.put(session, e);
- }
- }
-
- if (!sentErrors.isEmpty()) {
- StringBuilder errorBuilder = new StringBuilder("Not all message successfully sent: ");
- for (Entry<ISession, Exception> error : sentErrors.entrySet()) {
- Exception ex = error.getValue();
- String errorMsg = ex.getCause() == null ? ex.getMessage() : String.format("%s; cause: %s", ex.getMessage(), ex.getCause());
- errorBuilder.append(StringUtils.LF).append(String.format("%s : [%s]", error.getKey(), errorMsg));
- }
- SendMessageFailedException exception = new SendMessageFailedException(errorBuilder.toString());
- sentErrors.values().forEach(exception::addSuppressed);
- throw exception;
- }
-
+ tryActionToSessions(() -> "No sessions to send message: " + message,
+ session -> session.send(message));
return message instanceof IMessage ? (IMessage)message : null;
}
@@ -79,6 +57,12 @@ public class FixServerSessionsContainer implements ISession {
return message instanceof IMessage ? (IMessage)message : null;
}
+ @Override
+ public void sendRaw(byte[] rawData) throws InterruptedException {
+ tryActionToSessions(() -> "No sessions to send raw message: " + CharsetSupport.getCharsetInstance().decode(ByteBuffer.wrap(rawData)),
+ session -> session.sendRaw(rawData));
+ }
+
@Override
public void close() {
for(ISession session : application.getSessions()) {
@@ -106,4 +90,37 @@ public class FixServerSessionsContainer implements ISession {
((FIXSession)session).addExpectedSenderNum(seq);
}
}
+
+ private void tryActionToSessions(Supplier<String> onEmptyMessage, SessionAction actionForSession) {
+ Collection<ISession> connectedSessions = application.getSessions();
+
+ if (connectedSessions.isEmpty()) {
+ throw new SendMessageFailedException(onEmptyMessage.get());
+ }
+
+ Map<ISession, Exception> sentErrors = new HashMap<>();
+ for (ISession session : connectedSessions) {
+ try {
+ actionForSession.accept(session);
+ } catch (Exception e) {
+ sentErrors.put(session, e);
+ }
+ }
+
+ if (!sentErrors.isEmpty()) {
+ StringBuilder errorBuilder = new StringBuilder("Not all message successfully sent: ");
+ for (Entry<ISession, Exception> error : sentErrors.entrySet()) {
+ Exception ex = error.getValue();
+ String errorMsg = ex.getCause() == null ? ex.getMessage() : String.format("%s; cause: %s", ex.getMessage(), ex.getCause());
+ errorBuilder.append(StringUtils.LF).append(String.format("%s : [%s]", error.getKey(), errorMsg));
+ }
+ SendMessageFailedException exception = new SendMessageFailedException(errorBuilder.toString());
+ sentErrors.values().forEach(exception::addSuppressed);
+ throw exception;
+ }
+ }
+
+ private interface SessionAction {
+ void accept(ISession session) throws Exception;
+ }
}

original_message:
TH2 #1449. Added sendRaw implementation in FixServerSessionsContainer

Change-Id: I1eea3a450feb8728a150bcd456b4250485a99727


message: [RM]Bug Add the required protocols to tls

diff:
@@ -39,7 +39,7 @@ rem set "CATALINA_OPTS=%CATALINA_OPTS% -XX:+UnlockCommercialFeatures -XX:+Flight
set "CATALINA_OPTS=%CATALINA_OPTS% -Djava.net.preferIPv4Stack=true" rem IPv4 addresses preferred over IPv6 addresses
set "CATALINA_OPTS=%CATALINA_OPTS% -XX:+ExitOnOutOfMemoryError" rem Option tells what JVM should terminate process if OutOfMemoryError had been thrown
set "CATALINA_OPTS=%CATALINA_OPTS% -Duser.dir=%CATALINA_BASE%\temp" rem Uses to specify directory for relative paths
-set "CATALINA_OPTS=%CATALINA_OPTS% -Djdk.tls.client.protocols=TLSv1.2" rem Use TLSv1.2 protocol by default
+set "CATALINA_OPTS=%CATALINA_OPTS% -Djdk.tls.client.protocols=TLSv1,TLSv1.1,TLSv1.2" rem Use TLSv1.2 protocol by default
rem Deployer Jvm arguments:
set "DEPLOYER_JAVA_OPTS="

diff:
@@ -38,7 +38,7 @@ export CATALINA_OPTS="$CATALINA_OPTS -XX:+HeapDumpOnOutOfMemoryError" #Option te
export CATALINA_OPTS="$CATALINA_OPTS -Djava.net.preferIPv4Stack=true" #IPv4 addresses preferred over IPv6 addresses
export CATALINA_OPTS="$CATALINA_OPTS -XX:+ExitOnOutOfMemoryError" # Option tells that JVM should terminate process if OutOfMemoryError had been thrown
export CATALINA_OPTS="$CATALINA_OPTS -Duser.dir=$CATALINA_BASE/temp" # Uses to specify directory for relative paths
-export CATALINA_OPTS="$CATALINA_OPTS -Djdk.tls.client.protocols=TLSv1.2" # rem Use TLSv1.2 protocol by default
+export CATALINA_OPTS="$CATALINA_OPTS -Djdk.tls.client.protocols=TLSv1,TLSv1.1,TLSv1.2" # rem Use TLSv1.2 protocol by default
#Deployer Jvm arguments:
export DEPLOYER_JAVA_OPTS=""

original_message:
[RM]Bug #75184. Add the required protocols to tls

Change-Id: I35687eceeb83b26383537cd337dfe82da05349b3


message: [RM] Feature Implement the ability to define a message structure with cyclic references

diff:
/*******************************************************************************
- * Copyright 2009-2019 Exactpro (Exactpro Systems Limited)
+ * Copyright 2009-2021 Exactpro (Exactpro Systems Limited)
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@@ -17,19 +17,19 @@ package com.exactpro.sf.common.messages.structures.impl;
import java.util.Collections;
import java.util.Map;
+import java.util.function.Supplier;
import com.exactpro.sf.common.impl.messages.xml.configuration.JavaType;
import com.exactpro.sf.common.messages.structures.IAttributeStructure;
import com.exactpro.sf.common.messages.structures.IFieldStructure;
import com.exactpro.sf.common.messages.structures.IMessageStructure;
import com.exactpro.sf.common.messages.structures.StructureType;
-import com.exactpro.sf.common.util.EPSCommonException;
/**
* This structure should be immutable
*/
public class MessageStructure extends FieldStructure implements IMessageStructure {
- private final Map<String, IFieldStructure> fields;
+ private final Supplier<Map<String, IFieldStructure>> fieldsSupplier;
private final IMessageStructure reference;
public MessageStructure(String name, String namespace, boolean isCollection, IMessageStructure reference) {
@@ -51,11 +51,12 @@ public class MessageStructure extends FieldStructure implements IMessageStructur
super(name, namespace, description, reference != null ? reference.getName() : null, attributes,
null, null, isRequired, isCollection, false, null, StructureType.COMPLEX);
if (fields != null) {
- this.fields = Collections.unmodifiableMap(fields); // no reference, message-to-message reference
+ Map<String, IFieldStructure> map = Collections.unmodifiableMap(fields); // no reference, message-to-message reference
+ fieldsSupplier = () -> map;
} else if (reference != null) {
- this.fields = reference.getFields(); // field-to-message reference
+ fieldsSupplier = reference::getFields; // field-to-message reference
} else {
- this.fields = Collections.emptyMap(); // probably should not happen :(
+ fieldsSupplier = Collections::emptyMap; // probably should not happen :(
}
this.reference = reference;
@@ -64,7 +65,7 @@ public class MessageStructure extends FieldStructure implements IMessageStructur
@Override
public Map<String, IFieldStructure> getFields() {
- return fields;
+ return fieldsSupplier.get();
}
@Override

diff:
+/*
+ * Copyright 2009-2021 Exactpro (Exactpro Systems Limited)
+ *
+ * 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.exactpro.sf.common.messages.structures.impl;
+
+import static com.exactpro.sf.common.messages.structures.StructureType.COMPLEX;
+
+import java.util.Map;
+import java.util.Objects;
+import java.util.concurrent.atomic.AtomicReference;
+
+import org.jetbrains.annotations.NotNull;
+
+import com.exactpro.sf.common.impl.messages.xml.configuration.JavaType;
+import com.exactpro.sf.common.messages.structures.IAttributeStructure;
+import com.exactpro.sf.common.messages.structures.IFieldStructure;
+import com.exactpro.sf.common.messages.structures.IMessageStructure;
+import com.exactpro.sf.common.messages.structures.StructureType;
+
+public class MessageStructurePromise implements IMessageStructure {
+ private final AtomicReference<IMessageStructure> origin = new AtomicReference<>();
+ private final String name;
+
+ public MessageStructurePromise(@NotNull String name) {
+ this.name = Objects.requireNonNull(name, "Name can't be null");
+ }
+
+ public void setOrigin(@NotNull IMessageStructure messageStructure) {
+ if (!name.equals(messageStructure.getName())) {
+ throw new IllegalArgumentException("Origin message structure has incorrect name, expected '" + name + "', actual '" + messageStructure.getName() + '\'');
+ }
+ if (!origin.compareAndSet(null, Objects.requireNonNull(messageStructure, "Origin message strucure can not be null"))) {
+ throw new IllegalStateException("Origin message for promise '" + getName() + "' already set");
+ }
+ }
+
+ private IMessageStructure getOrigin() {
+ IMessageStructure msgStrucuture = origin.get();
+ if (msgStrucuture == null) {
+ throw new IllegalStateException("Origin message for promise '" + getName() + "' isn't set yet");
+ }
+ return msgStrucuture;
+ }
+
+ @Override
+ public boolean isComplex() {
+ return true;
+ }
+
+ @Override
+ public boolean isEnum() {
+ return false;
+ }
+
+ @Override
+ public boolean isSimple() {
+ return false;
+ }
+
+ @Override
+ public String getName() {
+ return name;
+ }
+
+ @Override
+ public String getDescription() {
+ return getOrigin().getDescription();
+ }
+
+ @Override
+ public Map<String, IFieldStructure> getFields() {
+ return getOrigin().getFields();
+ }
+
+ @Override
+ public Map<String, IAttributeStructure> getAttributes() {
+ return getOrigin().getAttributes();
+ }
+
+ @Override
+ public Map<String, IAttributeStructure> getValues() {
+ throw new UnsupportedOperationException("Messages don't have values. Message: " + getName());
+ }
+
+ @Override
+ public StructureType getStructureType() {
+ return COMPLEX;
+ }
+
+ @Override
+ public JavaType getJavaType() {
+ throw new UnsupportedOperationException("Messages don't have a java type. Message: " + getName());
+ }
+
+ @Override
+ public boolean isRequired() {
+ return getOrigin().isRequired();
+ }
+
+ @Override
+ public boolean isCollection() {
+ return getOrigin().isCollection();
+ }
+
+ @Override
+ public boolean isServiceName() {
+ throw new UnsupportedOperationException("Messages don't have a 'serviceName' parameter. Message: " + getName());
+ }
+
+ @Override
+ public <T> T getDefaultValue() {
+ throw new UnsupportedOperationException("Messages don't have a default value. Message: " + getName());
+ }
+
+ @Override
+ public String getNamespace() {
+ return getOrigin().getNamespace();
+ }
+
+ @Override
+ public String getReferenceName() {
+ return getOrigin().getReferenceName();
+ }
+}

diff:
/*******************************************************************************
- * Copyright 2009-2019 Exactpro (Exactpro Systems Limited)
+ * Copyright 2009-2021 Exactpro (Exactpro Systems Limited)
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@@ -47,6 +47,7 @@ import com.exactpro.sf.common.messages.structures.impl.AttributeStructure;
import com.exactpro.sf.common.messages.structures.impl.DictionaryStructure;
import com.exactpro.sf.common.messages.structures.impl.FieldStructure;
import com.exactpro.sf.common.messages.structures.impl.MessageStructure;
+import com.exactpro.sf.common.messages.structures.impl.MessageStructurePromise;
import com.exactpro.sf.common.util.EPSCommonException;
import com.sun.istack.NotNull;
@@ -57,9 +58,16 @@ public abstract class AbstractDictionaryStructureLoader implements IDictionarySt
protected final boolean aggregate;
protected final Set<String> pendingMessages = new HashSet<>();
+ protected final Map<String, MessageStructurePromise> promiseMap = new HashMap<>();
protected final Logger logger;
+ private boolean isRecursion;
+ private IField lastMessage;
+ private IFieldStructure messageFinalRecursionField;
+ private String startRecursionMessageName;
+ private boolean isCircledAttribute;
+
public AbstractDictionaryStructureLoader(boolean aggregate) {
this.aggregate = aggregate;
logger = LoggerFactory.getLogger(this.getClass());
@@ -180,7 +188,9 @@ public abstract class AbstractDictionaryStructureLoader implements IDictionarySt
convertMessage(dictionary.getName(), builder, msg);
}
+ startRecursionMessageName = null;
pendingMessages.clear();
+ promiseMap.clear();
}
Map<String, IAttributeStructure> dictAttributes = getDictionaryAttributes(dictionary);
@@ -189,11 +199,14 @@ public abstract class AbstractDictionaryStructureLoader implements IDictionarySt
builder.getMsgStructureMap(), builder.getFieldStructureMap());
}
- private void convertMessage(String namespace, StructureBuilder builder, IMessage message) {
-
+ private IMessageStructure convertMessage(String namespace, StructureBuilder builder, IMessage message) {
if (!pendingMessages.add(message.getId())) {
+ if (message.getReference() instanceof IMessage
+ && message.getReference().getReference() instanceof IMessage) {
throw new EPSCommonException(String.format("Recursion at message id: '%s' has been detected!", message.getId()));
}
+ return promiseMap.computeIfAbsent(message.getId(), (key) -> new MessageStructurePromise(message.getName()));
+ }
IField reference = message.getReference();
@@ -207,8 +220,14 @@ public abstract class AbstractDictionaryStructureLoader implements IDictionarySt
try {
IMessageStructure messageStructure = convertMessageInternal(namespace, builder, message, reference);
-
builder.addMessageStructure(messageStructure);
+
+ MessageStructurePromise promise = promiseMap.get(message.getId());
+ if (promise != null) {
+ promise.setOrigin(messageStructure);
+ }
+
+ return messageStructure;
} catch (RuntimeException e) {
throw new EPSCommonException("Message '" + message.getName() + "', problem with content", e);
}
@@ -322,8 +341,7 @@ public abstract class AbstractDictionaryStructureLoader implements IDictionarySt
struct = builder.getMessageStructure(field.getReference().getName());
if (struct == null) {
- convertMessage(namespace, builder, (IMessage)field.getReference());
- struct = builder.getMessageStructure(field.getReference().getName());
+ struct = convertMessage(namespace, builder, (IMessage)field.getReference());
}
}
@@ -456,6 +474,14 @@ public abstract class AbstractDictionaryStructureLoader implements IDictionarySt
if (aggregate) {
IField reference = field.getReference();
if (reference != null) {
+ if (isRecursion && reference.getName().equals(startRecursionMessageName)) {
+ if (isCircledAttribute) {
+ return;
+ } else {
+ collectFieldAttributesOrValues(reference, target, isValue);
+ }
+ isCircledAttribute = !isCircledAttribute;
+ }
collectFieldAttributesOrValues(reference, target, isValue);
}
}

diff:
/*******************************************************************************
- * Copyright 2009-2019 Exactpro (Exactpro Systems Limited)
+ * Copyright 2009-2021 Exactpro (Exactpro Systems Limited)
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@@ -22,7 +22,6 @@ import static java.util.Collections.singleton;
import java.io.File;
import java.io.FileInputStream;
-import java.io.FileNotFoundException;
import java.io.IOException;
import java.io.InputStream;
import java.nio.file.Paths;
@@ -115,7 +114,7 @@ public class TestDictionaryStructureLoader extends EPSTestCase {
Assert.assertEquals(JavaType.JAVA_LANG_INTEGER, dictionary.getMessages().get("MessageHeader").getFields().get("enum").getJavaType());
Assert.assertEquals(JavaType.JAVA_LANG_INTEGER, dictionary.getMessages().get("MessageHeader").getFields().get("MessageLength").getJavaType());
Assert.assertEquals(JavaType.JAVA_LANG_INTEGER, dictionary.getFields().get("enum").getJavaType());
- Assert.assertEquals(true, dictionary.getFields().get("enum").isEnum());
+ Assert.assertTrue(dictionary.getFields().get("enum").isEnum());
Assert.assertEquals(2, dictionary.getFields().get("enum").getValues().size());
}
@@ -175,23 +174,13 @@ public class TestDictionaryStructureLoader extends EPSTestCase {
@Test
public void testMessageCircularReferenceInInheritance() throws Exception {
exception.expect(EPSCommonException.class);
- exception.expectMessage("Recursion at message id: 'Message1Id' has been detected");
+ exception.expectMessage("Recursion at message id: 'Message1Id' has been detected!");
try (InputStream stream = new FileInputStream(path + "message-circular-reference-in-inheritance.xml")) {
new XmlDictionaryStructureLoader().load(stream);
}
}
- @Test
- public void testMessageCircularReferenceThroughInheritance() throws Exception {
- exception.expect(EPSCommonException.class);
- exception.expectMessage("Message 'Message2', problem with content");
-
- try (InputStream stream = new FileInputStream(path + "message-circular-reference-through-inheritance.xml")) {
- new XmlDictionaryStructureLoader().load(stream);
- }
- }
-
@Test
public void testMessageInheritance() throws Exception {
try (InputStream stream = new FileInputStream(path + "message-inheritance.xml")) {
@@ -295,4 +284,21 @@ public class TestDictionaryStructureLoader extends EPSTestCase {
);
}
+
+ @Test
+ public void testMessageCyclicReferences() throws Exception {
+ IDictionaryStructureLoader loader = new XmlDictionaryStructureLoader();
+ IDictionaryStructure dictionaryStructure;
+ try (InputStream inputStream = new FileInputStream(Paths.get(path,"messageCyclicReferences.xml").toFile())) {
+ dictionaryStructure = loader.load(inputStream);
+ }
+ Map<String, IMessageStructure> messages = dictionaryStructure.getMessages();
+ IFieldStructure selfMessage = messages.get("A").getFields().get("self");
+ Assert.assertTrue(selfMessage instanceof IMessageStructure);
+ IFieldStructure fieldFromReference = messages.get("mes2").getFields().get("field2").getFields().get("field3");
+ IFieldStructure fieldStructure = messages.get("mes3").getFields().get("field3");
+ Assert.assertEquals(fieldFromReference, fieldStructure);
+
+
+ }
}
\ No newline at end of file

diff:
/*******************************************************************************
- * Copyright 2009-2019 Exactpro (Exactpro Systems Limited)
+ * Copyright 2009-2021 Exactpro (Exactpro Systems Limited)
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@@ -187,11 +187,10 @@ public class TestJsonYamlDictionaryStructureLoader extends EPSTestCase {
@Test
public void testRecursion() throws Exception {
- exception.expect(EPSCommonException.class);
- exception.expectMessage("Message 'self', problem with content");
- exception.expectCause(new CauseMatcher(EPSCommonException.class, "Recursion at message id: 'self' has been detected!"));
- loadDictionaryFrom("recursion.json");
+ IDictionaryStructure dictionaryStructure = loadDictionaryFrom("recursion.json");
+ IFieldStructure selfMessage = dictionaryStructure.getMessages().get("self").getFields().get("s_name");
+ Assert.assertTrue(selfMessage instanceof IMessageStructure);
}
@Test
@@ -249,10 +248,8 @@ public class TestJsonYamlDictionaryStructureLoader extends EPSTestCase {
@Test
public void testMessageCircularReferenceThroughInheritance() throws Exception {
- exception.expect(EPSCommonException.class);
- exception.expectMessage("Message 'Message2', problem with content");
-
- loadDictionaryFrom("message-circular-reference-through-inheritance.json");
+ IDictionaryStructure dictionaryStructure = loadDictionaryFrom("message-circular-reference-through-inheritance.json");
+ Assert.assertTrue(dictionaryStructure.getMessages().get("Message2").getFields().get("Field1") instanceof IMessageStructure);
}
@Test
@@ -375,4 +372,11 @@ public class TestJsonYamlDictionaryStructureLoader extends EPSTestCase {
loadDictionaryFrom("messageInFields.json");
}
+
+ @Test
+ public void testMessageCiclicReferences() throws Exception {
+ IDictionaryStructure dictionary = loadDictionaryFrom("cyclicReferences.json");
+ Assert.assertTrue(dictionary.getMessages().get("A").getFields().get("self") instanceof IMessageStructure);
+ Assert.assertTrue(dictionary.getMessages().get("InnerMessage").getFields().get("circlied") instanceof IMessageStructure);
+ }
}

diff:
@@ -218,15 +218,9 @@ public class ReadConfigTest extends EPSTestCase {
File xmlFile = new File(PATH_PREFIX, "recursion.xml");
try (InputStream in = new FileInputStream(xmlFile)) {
- try {
- loader.load(in);
- } catch (EPSCommonException e) {
- Assert.assertEquals("Message 'message_name', problem with content", e.getMessage());
- Assert.assertEquals("Recursion at message id: 'self' has been detected!", e.getCause().getMessage());
- return;
- }
+ IDictionaryStructure dictionaryStructure = loader.load(in);
+ Assert.assertTrue(dictionaryStructure.getMessages().get("message_name").getFields().get("self") instanceof IMessageStructure);
}
- Assert.fail("Incorrect structure has been sucess loaded.");
}
@Test

diff:
+{
+ "name": "CyclicReferences",
+ "messages": {
+ "A": {
+ "fields": {
+ "self": {
+ "reference": "A"
+ }
+ }
+ },
+ "B": {
+ "fields": {
+ "inner": {
+ "reference": "InnerMessage"
+ }
+ }
+ },
+ "InnerMessage": {
+ "fields": {
+ "circlied": {
+ "reference": "B"
+ }
+ }
+ }
+ }
+}

diff:
+<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
+<!--
+ ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+ ~ Copyright 2009-2021 Exactpro (Exactpro Systems Limited)
+ ~
+ ~ 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.
+ ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+-->
+<dictionary name="messageCyclicReferences"
+ xmlns="http://exactprosystems.com/dictionary">
+ <messages>
+ <message id="M_T" name="T">
+ <field name="F" type="java.lang.String"/>
+ </message>
+ <message id="M_A" name="A">
+ <field name="self" reference="M_A"/>
+ </message>
+ <message id="M_mes1" name="mes1">
+ <field name="field1" reference="M_mes2"/>
+ </message>
+ <message id="M_mes2" name="mes2">
+ <field name="field2" reference="M_mes3"/>
+ </message>
+ <message id="M_mes3" name="mes3">
+ <field name="field3" reference="M_mes2"/>
+ </message>
+ </messages>
+</dictionary>

original_message:
[RM] Feature #74734. Implement the ability to define a message structure with cyclic references

Change-Id: Ie58a5189fc27cfc2245e5c573d320f0ace1c66a8


message: [RM]Feature Add th2Report to ScriptReportWithLogs

diff:
@@ -271,7 +271,9 @@ public abstract class AbstractScriptRunner implements IDisposable {
aggregateReportListeners.add(new ReportDictionaries(reportFolder));
//services report
aggregateReportListeners.add(new ReportServices(reportFolder));
-
+ //th2 report
+ aggregateReportListeners.addAll(sfContext.getScriptReportLoader().createScriptReports(
+ reportFolder, workspaceDispatcher, dictionaryManager, scriptDescription));
BroadcastScriptReport aggregateReport = new BroadcastScriptReport(aggregateReportListeners);
reportListeners.add(new ScriptReportWithLogs(aggregateReport, settings.getExcludedMessages()));
@@ -280,8 +282,6 @@ public abstract class AbstractScriptRunner implements IDisposable {
reportListeners.addAll(userListeners);
}
- reportListeners.addAll(sfContext.getScriptReportLoader().createScriptReports(reportFolder, workspaceDispatcher, dictionaryManager, scriptDescription));
-
// NOTE: ZipReport must be latest
reportListeners.add(new ZipReport(reportFolder, workspaceDispatcher, scriptDescription, ReportOutputFormat.ZIP));

original_message:
[RM]Feature #75746. Add th2Report to ScriptReportWithLogs

Change-Id: I56fdf3b62490fb5ab67792f1a4b0337ae793e9f2


diff:
/******************************************************************************
- * Copyright 2009-2018 Exactpro (Exactpro Systems Limited)
+ * Copyright 2009-2021 Exactpro (Exactpro Systems Limited)
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@@ -112,6 +112,8 @@ public class PluginLoader {
private final ILoadableManager scriptReportLoader;
+ private final ILoadableManager serviceStorageLoader;
+
public PluginLoader(
IWorkspaceDispatcher wd,
ILoadableManager staticServiceManager,
@@ -128,7 +130,8 @@ public class PluginLoader {
PluginServiceLoader pluginServiceLoader,
IVersion coreVersion,
ILoadableManager messageStorageLoader,
- ILoadableManager scriptReportLoader) {
+ ILoadableManager scriptReportLoader,
+ ILoadableManager serviceStorageLoader) {
if (wd == null) {
throw new NullPointerException("IWorkspaceDispatcher can't be null");
}
@@ -149,6 +152,7 @@ public class PluginLoader {
this.coreVersion = coreVersion;
this.messageStorageLoader = messageStorageLoader;
this.scriptReportLoader = scriptReportLoader;
+ this.serviceStorageLoader = serviceStorageLoader;
this.pluginVersions = new ArrayList<>();
}
@@ -156,7 +160,7 @@ public class PluginLoader {
/**
* @deprecated please use {@link #PluginLoader(IWorkspaceDispatcher, ILoadableManager, ILoadableManager, ILoadableManager,
* PreprocessorLoader, ValidatorLoader, ILoadableManager, ILoadableManager, ILoadableManager, MatrixProviderHolder,
- * ILoadableManager, ILoadableManager, PluginServiceLoader, IVersion, ILoadableManager, ILoadableManager)}
+ * ILoadableManager, ILoadableManager, PluginServiceLoader, IVersion, ILoadableManager, ILoadableManager, ILoadableManager)}
*/
@Deprecated
public PluginLoader(
@@ -177,7 +181,7 @@ public class PluginLoader {
ILoadableManager messageStorageLoader) {
this(wd, staticServiceManager, actionManager,
dictionaryManager, preprocessorLoader, validatorLoader, adapterManager, dataManager, languageManager, matrixProviderHolder,
- matrixConverterManager, statisticsReportsLoader, pluginServiceLoader, coreVersion, messageStorageLoader, null);
+ matrixConverterManager, statisticsReportsLoader, pluginServiceLoader, coreVersion, messageStorageLoader, null, null);
}
public LoadInfo load() throws FileNotFoundException, WorkspaceSecurityException, SailfishURIException {
@@ -562,6 +566,19 @@ public class PluginLoader {
logger.info("Ignore scripts reports [No ScriptReportLoader]. Plugin: {}", pluginPath);
}
+ //
+ // Load Th2ServiceStorage
+ //
+ if (serviceStorageLoader != null) {
+ try {
+ serviceStorageLoader.load(loadableContext);
+ } catch (Exception e) {
+ throw new EPSCommonException(e);
+ }
+ } else {
+ logger.info("Ignore service storage [No ServiceStorageLoader]. Plugin: {}", pluginPath);
+ }
+
// Collect service description files
if(pluginServiceLoader != null) {
try {

diff:
/******************************************************************************
- * Copyright 2009-2018 Exactpro (Exactpro Systems Limited)
+ * Copyright 2009-2021 Exactpro (Exactpro Systems Limited)
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@@ -99,8 +99,10 @@ import com.exactpro.sf.storage.IStorage;
import com.exactpro.sf.storage.ITestScriptStorage;
import com.exactpro.sf.storage.IVariableSetStorage;
import com.exactpro.sf.storage.MessageStorageLoader;
+import com.exactpro.sf.storage.ServiceStorageLoader;
import com.exactpro.sf.storage.impl.AbstractMessageStorage;
import com.exactpro.sf.storage.impl.BroadcastMessageStorage;
+import com.exactpro.sf.storage.impl.BroadcastServiceStorage;
import com.exactpro.sf.storage.impl.DatabaseAuthStorage;
import com.exactpro.sf.storage.impl.DatabaseEnvironmentStorage;
import com.exactpro.sf.storage.impl.DatabaseMatrixStorage;
@@ -313,6 +315,8 @@ public class SFLocalContext implements ISFContext {
PluginServiceLoader pluginServiceLoader = new PluginServiceLoader();
MessageStorageLoader messageStorageLoader = new MessageStorageLoader();
+ ServiceStorageLoader serviceStorageLoader = new ServiceStorageLoader();
+
scriptReportLoader = new ScriptReportLoader();
// 5) Load core & plugins
@@ -332,7 +336,8 @@ public class SFLocalContext implements ISFContext {
pluginServiceLoader,
version,
messageStorageLoader,
- scriptReportLoader);
+ scriptReportLoader,
+ serviceStorageLoader);
LoadInfo loadInfo = pluginLoader.load();
loadInfo.appendClassPath(compilerClassPath);
@@ -341,7 +346,7 @@ public class SFLocalContext implements ISFContext {
messageStorage = createMessageStorage(envSettings, sessionFactory, dictionaryManager, messageStorageLoader.getSecondaryMessageStorages(workspaceDispatcher, envSettings, dictionaryManager));
disposables.add(messageStorage);
- serviceStorage = createServiceStorage(envSettings, sessionFactory, workspaceDispatcher, staticServiceManager, dictionaryManager, messageStorage);
+ serviceStorage = createServiceStorage(envSettings, sessionFactory, workspaceDispatcher, staticServiceManager, dictionaryManager, messageStorage, serviceStorageLoader.getSecondaryServiceStorages(workspaceDispatcher, envSettings, dictionaryManager));
disposables.add(serviceStorage);
this.serviceContext = new DefaultServiceContext(dictionaryManager, messageStorage, serviceStorage, loggingConfigurator, taskExecutor, dataManager, wd);
@@ -439,17 +444,22 @@ public class SFLocalContext implements ISFContext {
}
private IServiceStorage createServiceStorage(EnvironmentSettings envSettings, SessionFactory sessionFactory, IWorkspaceDispatcher workspaceDispatcher, IStaticServiceManager staticServiceManager, IDictionaryManager dictionaryManager,
- IMessageStorage messageStorage) {
+ IMessageStorage messageStorage, List<IServiceStorage> secondaryStorages) {
+ IServiceStorage primaryStorage;
switch(envSettings.getStorageType()) {
case DB:
- return new DatabaseServiceStorage(sessionFactory, staticServiceManager, dictionaryManager, messageStorage);
+ primaryStorage = new DatabaseServiceStorage(sessionFactory, staticServiceManager, dictionaryManager, messageStorage);
+ break;
case FILE:
- return new FileServiceStorage(envSettings.getFileStoragePath(), workspaceDispatcher, staticServiceManager, messageStorage);
+ primaryStorage = new FileServiceStorage(envSettings.getFileStoragePath(), workspaceDispatcher, staticServiceManager, messageStorage);
+ break;
case MEMORY:
- return new MemoryServiceStorage();
+ primaryStorage = new MemoryServiceStorage();
+ break;
default:
throw new EPSCommonException("Unsupported service storage type. Check your descriptor.xml file.");
}
+ return new BroadcastServiceStorage(primaryStorage, secondaryStorages);
}
private IEnvironmentStorage createEnvironmentStorage(EnvironmentSettings envSettings, IStorage storage, IWorkspaceDispatcher workspaceDispatcher) {

diff:
@@ -211,7 +211,7 @@ public class ServiceFactory implements IServiceFactory {
IVersion coreVersion = new CoreVersion();
PluginLoader pluginLoader = new PluginLoader(wd, staticServiceManager, null,
dictionaryManager, null, null, null, dataManager, null, null, null, null,
- null, coreVersion, null, null);
+ null, coreVersion, null, null, null);
pluginLoader.load();
this.marshalManager = new ServiceMarshalManager(staticServiceManager, dictionaryManager);

diff:
@@ -306,7 +306,7 @@ public class HelpBuilder {
}
PluginLoader pluginLoader = new PluginLoader(wd, staticServiceManager, actionManager, dictionaryManager, preprocessorLoader, validatorLoader,
- adapterManager, dataManager, languageManager, matrixProviderHolder, matrixConverterManager, statisticsReportLoader, null, version, null, null);
+ adapterManager, dataManager, languageManager, matrixProviderHolder, matrixConverterManager, statisticsReportLoader, null, version, null, null, null);
pluginLoader.load();

diff:
+/*******************************************************************************
+ * Copyright 2009-2021 Exactpro (Exactpro Systems Limited)
+ *
+ * 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.exactpro.sf.storage;
+
+import com.exactpro.sf.configuration.IDictionaryManager;
+import com.exactpro.sf.configuration.workspace.IWorkspaceDispatcher;
+import com.exactpro.sf.scriptrunner.EnvironmentSettings;
+import com.exactpro.sf.storage.impl.AbstractMessageStorage;
+
+public interface IAbstractServiceStorageFactory {
+
+ /**
+ * Create secondary service storage
+ * @param environmentSettings Global settings of Sailfish
+ */
+ IServiceStorage createServiceStorage(IWorkspaceDispatcher dispatcher, EnvironmentSettings environmentSettings, IDictionaryManager dictionaryManager);
+
+}

diff:
+/*******************************************************************************
+ * Copyright 2009-2021 Exactpro (Exactpro Systems Limited)
+ *
+ * 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.exactpro.sf.storage;
+
+import java.util.LinkedList;
+import java.util.List;
+import java.util.Objects;
+import java.util.ServiceLoader;
+import java.util.stream.Collectors;
+
+import com.exactpro.sf.configuration.IDictionaryManager;
+import com.exactpro.sf.configuration.ILoadableManager;
+import com.exactpro.sf.configuration.ILoadableManagerContext;
+import com.exactpro.sf.configuration.workspace.IWorkspaceDispatcher;
+import com.exactpro.sf.scriptrunner.EnvironmentSettings;
+
+public class ServiceStorageLoader implements ILoadableManager {
+
+ private final List<IAbstractServiceStorageFactory> secondaryServiceStorageFactory;
+
+ public ServiceStorageLoader() {
+ this.secondaryServiceStorageFactory = new LinkedList<>();
+ }
+
+ @Override
+ public void load(ILoadableManagerContext context) throws Exception {
+ for (IAbstractServiceStorageFactory factory : ServiceLoader.load(IAbstractServiceStorageFactory.class, context.getClassLoaders()[0])) {
+ secondaryServiceStorageFactory.add(factory);
+ }
+ }
+
+ public List<IServiceStorage> getSecondaryServiceStorages(IWorkspaceDispatcher dispatcher, EnvironmentSettings environmentSettings, IDictionaryManager dictionaryManager){
+ return secondaryServiceStorageFactory
+ .stream()
+ .map(factory -> factory.createServiceStorage(dispatcher, environmentSettings, dictionaryManager))
+ .filter(Objects::nonNull)
+ .collect(Collectors.toList());
+ }
+
+ @Override
+ public void finalize(ILoadableManagerContext context) throws Exception {}
+}

diff:
/*******************************************************************************
- * Copyright 2009-2020 Exactpro (Exactpro Systems Limited)
+ * Copyright 2009-2021 Exactpro (Exactpro Systems Limited)
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@@ -19,11 +19,10 @@ package com.exactpro.sf.storage.impl;
import java.time.Instant;
import java.util.ArrayList;
import java.util.Arrays;
-import java.util.LinkedList;
+import java.util.Collections;
import java.util.List;
import java.util.Objects;
import java.util.function.Consumer;
-import java.util.function.Supplier;
import com.exactpro.sf.common.messages.IHumanMessage;
import com.exactpro.sf.common.messages.IMessage;
@@ -50,7 +49,7 @@ public class BroadcastMessageStorage extends AbstractMessageStorage {
}
public BroadcastMessageStorage(AbstractMessageStorage primaryStorage, AbstractMessageStorage... secondaryStorages) {
- this(primaryStorage, secondaryStorages.length > 0 ? Arrays.asList(secondaryStorages) : null);
+ this(primaryStorage, secondaryStorages.length > 0 ? Arrays.asList(secondaryStorages) : Collections.emptyList());
}
@Override

diff:
+/******************************************************************************
+ * Copyright 2009-2021 Exactpro (Exactpro Systems Limited)
+ *
+ * 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.exactpro.sf.storage.impl;
+
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.Collections;
+import java.util.Iterator;
+import java.util.List;
+import java.util.Objects;
+import java.util.function.Consumer;
+
+import org.jetbrains.annotations.NotNull;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+import com.exactpro.sf.center.IDisposable;
+import com.exactpro.sf.common.services.ServiceInfo;
+import com.exactpro.sf.common.services.ServiceName;
+import com.exactpro.sf.common.util.EPSCommonException;
+import com.exactpro.sf.services.ServiceDescription;
+import com.exactpro.sf.services.ServiceEvent;
+import com.exactpro.sf.storage.IServiceStorage;
+import com.exactpro.sf.storage.SortCriterion;
+import com.exactpro.sf.storage.StorageFilter;
+import com.exactpro.sf.storage.StorageResult;
+
+public class BroadcastServiceStorage implements IServiceStorage {
+
+ private static final Logger logger = LoggerFactory.getLogger(BroadcastServiceStorage.class);
+
+ private static final String ERROR_MESSAGE_ON_ADD_DESCRIPTION = "Can`t add service description to all storages";
+ private static final String ERROR_MESSAGE_ON_REMOVE_DESCRIPTION = "Can`t remove service description from all storages";
+ private static final String ERROR_MESSAGE_ON_UPDATE_DESCRIPTION = "Can`t update service description for all storages";
+ private static final String ERROR_MESSAGE_ON_ADD_EVENT = "Can`t add service event to all storages";
+ private static final String ERROR_MESSAGE_ON_REMOVE_EVENT = "Can`t remove service events from all storages";
+ private static final String ERROR_MESSAGE_ON_CLEAR_EVENT = "Can`t clear service events in all storages";
+ private static final String ERROR_MESSAGE_ON_DISPOSE = "Can`t dispose in all storages";
+
+ private final IServiceStorage primaryStorage;
+ private final List<IServiceStorage> writableStorages;
+
+ public BroadcastServiceStorage(IServiceStorage primaryStorage, List<IServiceStorage> secondaryStorages) {
+ this.primaryStorage = Objects.requireNonNull(primaryStorage, "Primary storage can`t be null");
+ List<ServiceDescription> serviceDescriptions = primaryStorage.getServiceDescriptions();
+ secondaryStorages.forEach(storage -> serviceDescriptions.forEach(storage::addServiceDescription));
+ writableStorages = new ArrayList<>();
+ writableStorages.add(this.primaryStorage);
+ writableStorages.addAll(Objects.requireNonNull(secondaryStorages, "Secondary storages can`t be null"));
+ }
+ public BroadcastServiceStorage(IServiceStorage primaryStorage, IServiceStorage... secondaryStorages) {
+ this(primaryStorage, secondaryStorages.length > 0 ? Arrays.asList(secondaryStorages) : Collections.emptyList());
+ }
+
+
+ @NotNull
+ @Override
+ public ServiceInfo lookupService(ServiceName serviceName) {
+ return primaryStorage.lookupService(serviceName);
+ }
+
+ @Override
+ public void addServiceDescription(ServiceDescription description) {
+ execute(serviceStorage -> serviceStorage.addServiceDescription(description), ERROR_MESSAGE_ON_ADD_DESCRIPTION);
+ }
+
+ @Override
+ public void removeServiceDescription(ServiceDescription description) {
+ execute(serviceStorage -> serviceStorage.removeServiceDescription(description), ERROR_MESSAGE_ON_REMOVE_DESCRIPTION);
+ }
+
+ @Override
+ public void removeServiceDescriptions(Iterator<ServiceDescription> iterator) {
+ execute(serviceStorage -> serviceStorage.removeServiceDescriptions(iterator), ERROR_MESSAGE_ON_REMOVE_DESCRIPTION);
+ }
+
+ @Override
+ public void updateServiceDescription(ServiceDescription description) {
+ execute(serviceStorage -> serviceStorage.updateServiceDescription(description), ERROR_MESSAGE_ON_UPDATE_DESCRIPTION);
+ }
+
+ @Override
+ public List<ServiceDescription> getServiceDescriptions() {
+ return primaryStorage.getServiceDescriptions();
+ }
+
+ @Override
+ public void addServiceEvent(ServiceDescription description, ServiceEvent event) {
+ execute(serviceStorage -> serviceStorage.addServiceEvent(description, event), ERROR_MESSAGE_ON_ADD_EVENT);
+ }
+
+ @Override
+ public long getEventsCount(ServiceDescription description, StorageFilter filter) {
+ return primaryStorage.getEventsCount(description, filter);
+ }
+
+ @Override
+ public StorageResult<ServiceEvent> getServiceEvents(ServiceDescription description, StorageFilter filter, int firstRecord, int size, List<SortCriterion> sorting) {
+ return primaryStorage.getServiceEvents(description, filter, firstRecord, size, sorting);
+ }
+
+ @Override
+ public void removeServiceEvents(ServiceDescription description) {
+ execute(serviceStorage -> serviceStorage.removeServiceEvents(description), ERROR_MESSAGE_ON_REMOVE_EVENT);
+ }
+
+ @Override
+ public void clearServiceEvents() {
+ execute(IServiceStorage::clearServiceEvents, ERROR_MESSAGE_ON_CLEAR_EVENT);
+ }
+
+ @Override
+ public void dispose() {
+ execute(IDisposable::dispose, ERROR_MESSAGE_ON_DISPOSE);
+ }
+
+ private void execute(Consumer<IServiceStorage> action, String errorMessage) {
+ EPSCommonException exception = null;
+ for (IServiceStorage storage : writableStorages) {
+ try {
+ action.accept(storage);
+ } catch (Exception e) {
+ logger.error(e.getMessage(), e);
+ if (exception == null) {
+ exception = new EPSCommonException(errorMessage);
+ }
+ exception.addSuppressed(e);
+ }
+ }
+
+ if (exception != null && exception.getSuppressed().length > 0) {
+ throw exception;
+ }
+ }
+}

original_message:
[RM]Feature#75745. Add th2serviceStorage

Change-Id: I0ee821538b499bc994e0095a2ed0b1bd692200e1