Passed
Push — master ( ada9ea...725c83 )
by Filip
02:42 queued 15s
created

isRequired(JsonSchema)   A

Complexity

Conditions 1

Size

Total Lines 2
Code Lines 2

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
cc 1
eloc 2
dl 0
loc 2
rs 10
c 0
b 0
f 0
1
package com.hltech.vaunt.validator;
2
3
import com.fasterxml.jackson.module.jsonSchema.JsonSchema;
4
import com.fasterxml.jackson.module.jsonSchema.types.ObjectSchema;
5
import com.fasterxml.jackson.module.jsonSchema.types.SimpleTypeSchema;
6
import com.fasterxml.jackson.module.jsonSchema.types.StringSchema;
7
import com.hltech.vaunt.core.domain.model.Contract;
8
import com.hltech.vaunt.core.domain.model.DestinationType;
9
import com.hltech.vaunt.core.domain.model.Service;
10
11
import java.util.List;
12
import java.util.Map;
13
import java.util.stream.Collectors;
14
15
public class VauntValidator {
16
17
    public List<ValidationResult> validate(Service consumer, Service provider) {
18
        return consumer.getExpectations().getProviderNameToContracts().get(provider.getName()).stream()
19
                .map(consumerContract -> validateWithMatchingProviderContract(
20
                        consumerContract, provider.getCapabilities().getContracts()))
21
                .collect(Collectors.toList());
22
    }
23
24
    public List<ValidationResult> validate(List<Contract> expectations, List<Contract> capabilities) {
25
        return expectations.stream()
26
                .map(consumerContract -> validateWithMatchingProviderContract(consumerContract, capabilities))
27
                .collect(Collectors.toList());
28
    }
29
30
    private ValidationResult validateWithMatchingProviderContract(Contract consumerContract,
31
                                                                  List<Contract> providerContracts) {
32
        List<Contract> endpointMatchingContracts = providerContracts.stream()
33
                .filter(providerContract -> isEndpointMatching(consumerContract, providerContract))
34
                .collect(Collectors.toList());
35
36
        if (endpointMatchingContracts.isEmpty()) {
37
            return ValidationResult.failure(consumerContract, ValidationError.MISSING_ENDPOINT);
38
        }
39
40
        List<Contract> idMatchingContracts = endpointMatchingContracts.stream()
41
                .filter(providerContract -> isIdMatching(consumerContract.getBody(), providerContract.getBody()))
42
                .collect(Collectors.toList());
43
44
        if (idMatchingContracts.isEmpty()) {
45
            return ValidationResult.failure(consumerContract, ValidationError.MISSING_MESSAGE_WITH_NAME);
46
        }
47
48
        if (idMatchingContracts.size() > 1) {
49
            return ValidationResult.failure(consumerContract, ValidationError.DUPLICATE_MATCH);
50
        }
51
52
        return isContentMatching(consumerContract.getDestinationType(),
53
                consumerContract.getBody(),
54
                idMatchingContracts.get(0).getBody()) ? ValidationResult.success(consumerContract)
55
                : ValidationResult.failure(consumerContract, idMatchingContracts.get(0), ValidationError.WRONG_SCHEMA);
56
    }
57
58
    private boolean isEndpointMatching(Contract firstContract, Contract secondContract) {
59
        return isTmpQueueMatching(firstContract, secondContract)
60
                || (isDstTypeMatching(firstContract, secondContract)
61
                && isDstNameMatching(firstContract, secondContract));
62
    }
63
64
    private boolean isTmpQueueMatching(Contract firstContract, Contract secondContract) {
65
        return firstContract.getDestinationType() == DestinationType.TEMPORARY_QUEUE
66
                && isDstTypeMatching(firstContract, secondContract);
67
    }
68
69
    private boolean isDstTypeMatching(Contract firstContract, Contract secondContract) {
70
        return firstContract.getDestinationType() == secondContract.getDestinationType();
71
    }
72
73
    private boolean isDstNameMatching(Contract firstContract, Contract secondContract) {
74
        return firstContract.getDestinationName().equals(secondContract.getDestinationName());
75
    }
76
77
    private boolean isIdMatching(JsonSchema consumerBody, JsonSchema providerBody) {
78
        return consumerBody.getId().equals(providerBody.getId());
79
    }
80
81
    private boolean isContentMatching(DestinationType dstType, JsonSchema consumerBody, JsonSchema providerBody) {
82
        if (isStringSchema(consumerBody) && isStringSchema(providerBody)) {
83
            return compareEnumSchema(dstType, consumerBody, providerBody);
84
        }
85
86
        if (isObjectSchema(consumerBody) && isObjectSchema(providerBody)) {
87
            return compareObjectSchema(dstType, consumerBody.asObjectSchema(), providerBody.asObjectSchema());
88
        }
89
90
        return consumerBody.equals(providerBody);
91
    }
92
93
    private boolean isRequired(JsonSchema schema) {
94
        return schema.getRequired() != null && schema.getRequired();
95
    }
96
97
    private boolean isObjectSchema(JsonSchema schema) {
98
        return schema.asObjectSchema() != null;
99
    }
100
101
    private boolean isStringSchema(JsonSchema schema) {
102
        return schema.asStringSchema() != null;
103
    }
104
105
    private boolean compareEnumSchema(DestinationType dstType, JsonSchema consumerBody, JsonSchema providerBody) {
106
        return compareStringSchemaPart(dstType, consumerBody.asStringSchema(), providerBody.asStringSchema())
107
                && compareSimpleTypeSchemaPart(consumerBody.asSimpleTypeSchema(), providerBody.asSimpleTypeSchema())
108
                && compareJsonSchemaPart(consumerBody, providerBody);
109
    }
110
111
    private boolean compareStringSchemaPart(DestinationType dstType,
112
                                            StringSchema consumerBody,
113
                                            StringSchema providerBody) {
114
        return equals(consumerBody.getMaxLength(), providerBody.getMaxLength())
115
                && equals(consumerBody.getMinLength(), providerBody.getMinLength())
116
                && equals(consumerBody.getPattern(), providerBody.getPattern())
117
                && equals(consumerBody.getFormat(), providerBody.getFormat())
118
                && compareEnum(dstType, consumerBody, providerBody);
119
    }
120
121
    private boolean compareSimpleTypeSchemaPart(SimpleTypeSchema consumerBody, SimpleTypeSchema providerBody) {
122
        return equals(consumerBody.getDefault(), providerBody.getDefault())
123
                && equals(consumerBody.getTitle(), providerBody.getTitle())
124
                && equals(consumerBody.getPathStart(), providerBody.getPathStart())
125
                && equals(consumerBody.getLinks(), providerBody.getLinks());
126
    }
127
128
    private boolean compareJsonSchemaPart(JsonSchema consumerBody, JsonSchema providerBody) {
129
        return equals(consumerBody.getId(), providerBody.getId())
130
                && !isRequired(consumerBody) || isRequired(providerBody)
131
                && equals(consumerBody.getReadonly(), providerBody.getReadonly())
132
                && equals(consumerBody.get$ref(), providerBody.get$ref())
133
                && equals(consumerBody.get$schema(), providerBody.get$schema())
134
                && equals(consumerBody.getDisallow(), providerBody.getDisallow())
135
                && equals(consumerBody.getExtends(), providerBody.getExtends());
136
    }
137
138
    private boolean compareEnum(DestinationType dstType, StringSchema consumerBody, StringSchema providerBody) {
139
        switch (dstType) {
140
            case QUEUE:
141
            case TEMPORARY_QUEUE:
142
                if (representsString(consumerBody) && representsEnum(providerBody)) {
143
                    return false;
144
                }
145
146
                if (representsEnum(consumerBody) && representsEnum(providerBody)) {
147
                    return providerBody.getEnums().containsAll(consumerBody.getEnums());
148
                }
149
150
                return true;
151
            case TOPIC:
152
                if (representsString(providerBody) && representsEnum(consumerBody)) {
153
                    return false;
154
                }
155
156
                if (representsEnum(providerBody) && representsEnum(consumerBody)) {
157
                    return consumerBody.getEnums().containsAll(providerBody.getEnums());
158
                }
159
160
                return true;
161
            default:
162
                throw new RuntimeException("Unknown JMS destination type"); // TODO: handle
163
        }
164
    }
165
166
    private boolean representsEnum(StringSchema body) {
167
        return body.getEnums().size() > 0;
168
    }
169
170
    private boolean representsString(StringSchema body) {
171
        return body.getEnums().size() == 0;
172
    }
173
174
    private boolean compareObjectSchema(DestinationType dstType, ObjectSchema consumerBody, ObjectSchema providerBody) {
175
        return equals(consumerBody.getAdditionalProperties(), providerBody.getAdditionalProperties())
176
                && equals(consumerBody.getDependencies(), providerBody.getDependencies())
177
                && equals(consumerBody.getPatternProperties(), providerBody.getPatternProperties())
178
                && compareSimpleTypeSchemaPart(consumerBody.asSimpleTypeSchema(), providerBody.asSimpleTypeSchema())
179
                && compareJsonSchemaPart(consumerBody, providerBody)
180
                && compareObjectProperties(dstType, consumerBody.getProperties(), providerBody.getProperties());
181
    }
182
183
    private boolean compareObjectProperties(DestinationType dstType,
184
                                            Map<String, JsonSchema> consumerProperties,
185
                                            Map<String, JsonSchema> providerProperties) {
186
187
        return providerProperties.keySet().containsAll(consumerProperties.keySet())
188
                && consumerProperties.keySet().stream()
189
                .allMatch(key -> isContentMatching(dstType, consumerProperties.get(key), providerProperties.get(key)));
190
    }
191
192
    private boolean equals(Object object1, Object object2) {
193
        if (object1 == null) {
194
            return object2 == null;
195
        } else {
196
            return object1.equals(object2);
197
        }
198
    }
199
}
200