Skip to content

Commit 016aeec

Browse files
authored
Merge pull request #102 from Systems-Modeling/feature/ST5AS-233
feat: ST5AS-233 constrain Query by properties typed by Data
2 parents 36c6340 + bee21d4 commit 016aeec

8 files changed

Lines changed: 216 additions & 22 deletions

File tree

app/dao/impl/jpa/JpaDataDao.java

Lines changed: 39 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
/*
22
* SysML v2 REST/HTTP Pilot Implementation
3-
* Copyright (C) 2021-2022 Twingineer LLC
3+
* Copyright (C) 2021-2023 Twingineer LLC
44
*
55
* This program is free software: you can redistribute it and/or modify
66
* it under the terms of the GNU Lesser General Public License as published by
@@ -20,6 +20,7 @@
2020

2121
package dao.impl.jpa;
2222

23+
import com.fasterxml.jackson.databind.JsonNode;
2324
import com.google.common.collect.Streams;
2425
import config.MetamodelProvider;
2526
import dao.DataDao;
@@ -40,6 +41,7 @@
4041
import org.omg.sysml.lifecycle.impl.*;
4142
import org.omg.sysml.query.*;
4243
import org.omg.sysml.query.impl.QueryImpl;
44+
import play.libs.Json;
4345

4446
import javax.inject.Inject;
4547
import javax.persistence.EntityManager;
@@ -48,6 +50,7 @@
4850
import javax.persistence.TypedQuery;
4951
import javax.persistence.criteria.*;
5052
import java.beans.PropertyDescriptor;
53+
import java.io.IOException;
5154
import java.util.*;
5255
import java.util.concurrent.ConcurrentHashMap;
5356
import java.util.function.Function;
@@ -232,10 +235,23 @@ else if (constraint instanceof PrimitiveConstraint) {
232235
return data -> {
233236
Object actualValue;
234237
Object constrainedValue;
238+
239+
JsonNode constrainedValueJson;
240+
try {
241+
constrainedValueJson = primitiveConstraint.getValue() != null ?
242+
Json.mapper().readTree(primitiveConstraint.getValue()) :
243+
null;
244+
} catch (IOException e) {
245+
throw new IllegalArgumentException(e);
246+
}
247+
235248
switch (primitiveConstraint.getProperty()) {
236249
case "@id":
237250
actualValue = data.getId();
238-
constrainedValue = JavaBeanHelper.convert(primitiveConstraint.getValue(), UUID.class);
251+
constrainedValue = JavaBeanHelper.convert(
252+
constrainedValueJson != null ? constrainedValueJson.asText() : null,
253+
UUID.class
254+
);
239255
break;
240256
case "@type":
241257
try {
@@ -246,19 +262,36 @@ else if (constraint instanceof PrimitiveConstraint) {
246262
} catch (ClassNotFoundException e) {
247263
throw new IllegalStateException(e);
248264
}
249-
constrainedValue = primitiveConstraint.getValue();
265+
constrainedValue = constrainedValueJson != null ? constrainedValueJson.asText() : null;
250266
break;
251267
default:
252268
PropertyDescriptor property = JavaBeanHelper.getBeanProperties(data).get(primitiveConstraint.getProperty());
253269
if (property == null) {
254270
return false;
255271
}
256272
if (SUPPORTED_PRIMITIVE_CONSTRAINT_CLASSES.stream()
257-
.noneMatch(supported -> supported.isAssignableFrom(property.getPropertyType()))) {
273+
.anyMatch(supported -> supported.isAssignableFrom(property.getPropertyType()))) {
274+
actualValue = JavaBeanHelper.getBeanPropertyValue(data, property);
275+
constrainedValue = JavaBeanHelper.convert(
276+
constrainedValueJson != null ? constrainedValueJson.asText() : null,
277+
property.getPropertyType()
278+
);
279+
} else if (Data.class.isAssignableFrom(property.getPropertyType())) {
280+
Object _actualValue = JavaBeanHelper.getBeanPropertyValue(data, property);
281+
actualValue = _actualValue != null ? ((Data) _actualValue).getId() : null;
282+
constrainedValue = constrainedValueJson != null ?
283+
JavaBeanHelper.convert(
284+
// intentionally `textValue` instead of `asText` to get a null value for
285+
// improved error reporting
286+
constrainedValueJson.path("@id").textValue(),
287+
UUID.class
288+
) : null;
289+
if (constrainedValue == null) {
290+
throw new IllegalArgumentException();
291+
}
292+
} else {
258293
return false;
259294
}
260-
actualValue = JavaBeanHelper.getBeanPropertyValue(data, property);
261-
constrainedValue = JavaBeanHelper.convert(primitiveConstraint.getValue(), property.getPropertyType());
262295
break;
263296
}
264297
if (actualValue == null || constrainedValue == null) {

app/javabean/UuidPropertyEditor.java

Lines changed: 21 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,23 @@
1+
/*
2+
* SysML v2 REST/HTTP Pilot Implementation
3+
* Copyright (C) 2022-2023 Twingineer LLC
4+
*
5+
* This program is free software: you can redistribute it and/or modify
6+
* it under the terms of the GNU Lesser General Public License as published by
7+
* the Free Software Foundation, either version 3 of the License, or
8+
* (at your option) any later version.
9+
*
10+
* This program is distributed in the hope that it will be useful,
11+
* but WITHOUT ANY WARRANTY; without even the implied warranty of
12+
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13+
* GNU Lesser General Public License for more details.
14+
*
15+
* You should have received a copy of the GNU Lesser General Public License
16+
* along with this program. If not, see <https://www.gnu.org/licenses/>.
17+
*
18+
* @license LGPL-3.0-or-later <http://spdx.org/licenses/LGPL-3.0-or-later>
19+
*/
20+
121
package javabean;
222

323
import java.beans.PropertyEditorSupport;
@@ -7,6 +27,6 @@ public class UuidPropertyEditor extends PropertyEditorSupport {
727

828
@Override
929
public void setAsText(String text) throws IllegalArgumentException {
10-
setValue(UUID.fromString(text));
30+
setValue(text != null ? UUID.fromString(text) : null);
1131
}
1232
}

app/org/omg/sysml/query/PrimitiveConstraint.java

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@
22
* SysML v2 REST/HTTP Pilot Implementation
33
* Copyright (C) 2020 InterCAX LLC
44
* Copyright (C) 2020 California Institute of Technology ("Caltech")
5+
* Copyright (C) 2023 Twingineer LLC
56
*
67
* This program is free software: you can redistribute it and/or modify
78
* it under the terms of the GNU Lesser General Public License as published by
@@ -32,7 +33,7 @@ public interface PrimitiveConstraint extends Constraint {
3233

3334
String getValue();
3435

35-
void setValue(String value);
36+
// void setValue(String value);
3637

3738
PrimitiveOperator getOperator();
3839

app/org/omg/sysml/query/impl/PrimitiveConstraintImpl.java

Lines changed: 18 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@
22
* SysML v2 REST/HTTP Pilot Implementation
33
* Copyright (C) 2020 InterCAX LLC
44
* Copyright (C) 2020 California Institute of Technology ("Caltech")
5+
* Copyright (C) 2023 Twingineer LLC
56
*
67
* This program is free software: you can redistribute it and/or modify
78
* it under the terms of the GNU Lesser General Public License as published by
@@ -21,13 +22,17 @@
2122

2223
package org.omg.sysml.query.impl;
2324

25+
import com.fasterxml.jackson.annotation.JsonRawValue;
2426
import com.fasterxml.jackson.annotation.JsonTypeName;
27+
import com.fasterxml.jackson.core.JsonProcessingException;
28+
import com.fasterxml.jackson.databind.JsonNode;
29+
import com.fasterxml.jackson.databind.annotation.JsonDeserialize;
30+
import com.fasterxml.jackson.databind.deser.std.JsonNodeDeserializer;
2531
import org.omg.sysml.query.PrimitiveConstraint;
2632
import org.omg.sysml.query.PrimitiveOperator;
33+
import play.libs.Json;
2734

2835
import javax.persistence.*;
29-
import java.util.ArrayList;
30-
import java.util.Collection;
3136

3237
// @Embeddable // Can't embed and have polymorphism between Constraints, which is necessary for CompositeConstraint.constraint
3338
@Entity(name = "PrimitiveConstraint")
@@ -66,13 +71,14 @@ public void setProperty(String property) {
6671

6772
@Override
6873
@Column
74+
@JsonRawValue
6975
public String getValue() {
70-
return value;
76+
return value != null ? value : "null";
7177
}
7278

73-
@Override
74-
public void setValue(String value) {
75-
this.value = value;
79+
@JsonDeserialize(using = OpenJsonNodeDeserializer.class)
80+
public void setValue(JsonNode value) throws JsonProcessingException {
81+
this.value = value != null ? Json.mapper().writeValueAsString(value) : "null";
7682
}
7783

7884
@Override
@@ -88,4 +94,10 @@ public PrimitiveOperator getOperator() {
8894
public void setOperator(PrimitiveOperator operator) {
8995
this.operator = operator;
9096
}
97+
98+
public static final class OpenJsonNodeDeserializer extends JsonNodeDeserializer {
99+
public OpenJsonNodeDeserializer() {
100+
super();
101+
}
102+
}
91103
}

conf/json/schema/api/schemas-sans-metamodel-requests.json

Lines changed: 34 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -868,7 +868,23 @@
868868
"type": "string"
869869
},
870870
"value": {
871-
"type": "string"
871+
"oneOf": [
872+
{
873+
"type": "boolean"
874+
},
875+
{
876+
"type": "number"
877+
},
878+
{
879+
"type": "string"
880+
},
881+
{
882+
"$ref": "https://www.omg.org/spec/SysML/20230201/Identified"
883+
},
884+
{
885+
"type": "null"
886+
}
887+
]
872888
}
873889
},
874890
"required": [
@@ -904,7 +920,23 @@
904920
"type": "string"
905921
},
906922
"value": {
907-
"type": "string"
923+
"oneOf": [
924+
{
925+
"type": "boolean"
926+
},
927+
{
928+
"type": "number"
929+
},
930+
{
931+
"type": "string"
932+
},
933+
{
934+
"$ref": "https://www.omg.org/spec/SysML/20230201/Identified"
935+
},
936+
{
937+
"type": "null"
938+
}
939+
]
908940
}
909941
},
910942
"required": [

conf/json/schema/api/schemas.json

Lines changed: 34 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -867,7 +867,23 @@
867867
"type": "string"
868868
},
869869
"value": {
870-
"type": "string"
870+
"oneOf": [
871+
{
872+
"type": "boolean"
873+
},
874+
{
875+
"type": "number"
876+
},
877+
{
878+
"type": "string"
879+
},
880+
{
881+
"$ref": "https://www.omg.org/spec/SysML/20230201/Identified"
882+
},
883+
{
884+
"type": "null"
885+
}
886+
]
871887
}
872888
},
873889
"required": [
@@ -903,7 +919,23 @@
903919
"type": "string"
904920
},
905921
"value": {
906-
"type": "string"
922+
"oneOf": [
923+
{
924+
"type": "boolean"
925+
},
926+
{
927+
"type": "number"
928+
},
929+
{
930+
"type": "string"
931+
},
932+
{
933+
"$ref": "https://www.omg.org/spec/SysML/20230201/Identified"
934+
},
935+
{
936+
"type": "null"
937+
}
938+
]
907939
}
908940
},
909941
"required": [

public/docs/openapi-x.json

Lines changed: 34 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -3044,7 +3044,23 @@
30443044
"type": "string"
30453045
},
30463046
"value": {
3047-
"type": "string"
3047+
"oneOf": [
3048+
{
3049+
"type": "boolean"
3050+
},
3051+
{
3052+
"type": "number"
3053+
},
3054+
{
3055+
"type": "string"
3056+
},
3057+
{
3058+
"$ref": "#/components/schemas/Identified"
3059+
},
3060+
{
3061+
"type": "null"
3062+
}
3063+
]
30483064
}
30493065
},
30503066
"required": [
@@ -3080,7 +3096,23 @@
30803096
"type": "string"
30813097
},
30823098
"value": {
3083-
"type": "string"
3099+
"oneOf": [
3100+
{
3101+
"type": "boolean"
3102+
},
3103+
{
3104+
"type": "number"
3105+
},
3106+
{
3107+
"type": "string"
3108+
},
3109+
{
3110+
"$ref": "#/components/schemas/Identified"
3111+
},
3112+
{
3113+
"type": "null"
3114+
}
3115+
]
30843116
}
30853117
},
30863118
"required": [

0 commit comments

Comments
 (0)