From 4fdfb66b84f419050e067c25af758a96a14b73e0 Mon Sep 17 00:00:00 2001 From: Filip Karnis Date: Wed, 15 Feb 2023 21:34:52 +0100 Subject: [PATCH 01/20] [controller] tag can now hold additional data --- .../perl/Shongo/ClientCli/ResourceService.pm | 32 +++++++++++-- shongo-common/pom.xml | 7 +++ .../cesnet/shongo/hibernate/package-info.java | 4 +- .../cz/cesnet/shongo/controller/api/Tag.java | 36 +++++++++++++-- .../cesnet/shongo/controller/api/TagType.java | 23 ++++++++++ .../controller/booking/resource/Tag.java | 45 +++++++++++++++++-- .../controller/AbstractDatabaseTest.java | 2 +- .../controller/booking/resource/TagTest.java | 41 +++++++++++++++++ .../migrations/2023-02-15/migration.sql | 10 +++++ 9 files changed, 188 insertions(+), 12 deletions(-) create mode 100644 shongo-controller-api/src/main/java/cz/cesnet/shongo/controller/api/TagType.java create mode 100644 shongo-deployment/migrations/2023-02-15/migration.sql diff --git a/shongo-client-cli/src/main/perl/Shongo/ClientCli/ResourceService.pm b/shongo-client-cli/src/main/perl/Shongo/ClientCli/ResourceService.pm index 65f2efd25..5e8029439 100644 --- a/shongo-client-cli/src/main/perl/Shongo/ClientCli/ResourceService.pm +++ b/shongo-client-cli/src/main/perl/Shongo/ClientCli/ResourceService.pm @@ -15,6 +15,15 @@ use Shongo::ClientCli::API::Resource; use Shongo::ClientCli::API::DeviceResource; use Shongo::ClientCli::API::Alias; +# +# Tag types +# +our $TagType = ordered_hash( + 'DEFAULT' => 'Default', + 'NOTIFY_EMAIL' => 'Notify Email', + 'RESERVATION_DATA' => 'Reservation Data', +); + # # Populate shell by options for management of resources. # @@ -477,6 +486,19 @@ sub create_tag() 'title' => 'Tag name', } ); + $tag->add_attribute( + 'type', { + 'required' => 1, + 'title' => 'Tag type', + 'type' => 'enum', + 'enum' => $Shongo::ClientCli::ResourceService::TagType, + } + ); + $tag->add_attribute( + 'data', { + 'title' => 'Tag data', + } + ); my $id = $tag->create($attributes, $options); if ( defined($id) ) { @@ -514,13 +536,17 @@ sub list_tags() 'columns' => [ {'field' => 'id', 'title' => 'Identifier'}, {'field' => 'name', 'title' => 'Name'}, + {'field' => 'type', 'title' => 'Type'}, + {'field' => 'data', 'title' => 'Data'}, ], 'data' => [] }; - foreach my $resource (@{$response}) { + foreach my $tag (@{$response}) { push(@{$table->{'data'}}, { - 'id' => $resource->{'id'}, - 'name' => $resource->{'name'}, + 'id' => $tag->{'id'}, + 'name' => $tag->{'name'}, + 'type' => $tag->{'type'}, + 'data' => $tag->{'data'}, }); } console_print_table($table); diff --git a/shongo-common/pom.xml b/shongo-common/pom.xml index 8f5d00137..60713a072 100644 --- a/shongo-common/pom.xml +++ b/shongo-common/pom.xml @@ -53,6 +53,13 @@ + + + + io.hypersistence + hypersistence-utils-hibernate-52 + 3.2.0 + diff --git a/shongo-common/src/main/java/cz/cesnet/shongo/hibernate/package-info.java b/shongo-common/src/main/java/cz/cesnet/shongo/hibernate/package-info.java index 645097e3b..67d3ab6bd 100644 --- a/shongo-common/src/main/java/cz/cesnet/shongo/hibernate/package-info.java +++ b/shongo-common/src/main/java/cz/cesnet/shongo/hibernate/package-info.java @@ -11,9 +11,11 @@ @TypeDef(name = PersistentLocalDate.NAME, typeClass = PersistentLocalDate.class), @TypeDef(name = PersistentPeriod.NAME, typeClass = PersistentPeriod.class), @TypeDef(name = PersistentInterval.NAME, typeClass = PersistentInterval.class), - @TypeDef(name = PersistentReadablePartial.NAME, typeClass = PersistentReadablePartial.class) + @TypeDef(name = PersistentReadablePartial.NAME, typeClass = PersistentReadablePartial.class), + @TypeDef(name = "jsonb", typeClass = JsonBinaryType.class), }) package cz.cesnet.shongo.hibernate; +import io.hypersistence.utils.hibernate.type.json.JsonBinaryType; import org.hibernate.annotations.TypeDef; import org.hibernate.annotations.TypeDefs; diff --git a/shongo-controller-api/src/main/java/cz/cesnet/shongo/controller/api/Tag.java b/shongo-controller-api/src/main/java/cz/cesnet/shongo/controller/api/Tag.java index d7284b6cd..364116229 100644 --- a/shongo-controller-api/src/main/java/cz/cesnet/shongo/controller/api/Tag.java +++ b/shongo-controller-api/src/main/java/cz/cesnet/shongo/controller/api/Tag.java @@ -3,6 +3,8 @@ import cz.cesnet.shongo.api.DataMap; import cz.cesnet.shongo.api.IdentifiedComplexType; +import java.util.Objects; + /** * * @author Ondřej Pavelka @@ -10,6 +12,8 @@ public class Tag extends IdentifiedComplexType { String name; + TagType type = TagType.DEFAULT; + String data; public String getName() { return name; @@ -19,13 +23,37 @@ public void setName(String name) { this.name = name; } + public TagType getType() + { + return type; + } + + public void setType(TagType type) + { + this.type = type; + } + + public String getData() + { + return data; + } + + public void setData(String data) + { + this.data = data; + } + private static final String NAME = "name"; + private static final String TYPE = "type"; + private static final String DATA = "data"; @Override public DataMap toData() { DataMap dataMap = super.toData(); dataMap.set(NAME,name); + dataMap.set(TYPE, type); + dataMap.set(DATA, data); return dataMap; } @@ -34,6 +62,8 @@ public void fromData(DataMap dataMap) { super.fromData(dataMap); name = dataMap.getString(NAME); + type = dataMap.getEnumRequired(TYPE, TagType.class); + data = dataMap.getString(DATA); } @Override @@ -43,14 +73,12 @@ public boolean equals(Object o) if (o == null || getClass() != o.getClass()) return false; Tag tag = (Tag) o; - - return name.equals(tag.name); - + return Objects.equals(name, tag.name) && type == tag.type && Objects.equals(data, tag.data); } @Override public int hashCode() { - return name.hashCode(); + return Objects.hash(name, type, data); } } diff --git a/shongo-controller-api/src/main/java/cz/cesnet/shongo/controller/api/TagType.java b/shongo-controller-api/src/main/java/cz/cesnet/shongo/controller/api/TagType.java new file mode 100644 index 000000000..03664d500 --- /dev/null +++ b/shongo-controller-api/src/main/java/cz/cesnet/shongo/controller/api/TagType.java @@ -0,0 +1,23 @@ +package cz.cesnet.shongo.controller.api; + +/** + * Type of {@link cz.cesnet.shongo.controller.booking.resource.Tag}. + */ +public enum TagType +{ + /** + * Simple tag. Does not do anything special. + */ + DEFAULT, + + /** + * Sends notifications to the email addresses specified in this {@link cz.cesnet.shongo.controller.booking.resource.Tag}. + */ + NOTIFY_EMAIL, + + /** + * Adds additional information specified in {@link cz.cesnet.shongo.controller.booking.resource.Tag} + * to {@link cz.cesnet.shongo.controller.booking.reservation.Reservation}. + */ + RESERVATION_DATA, +} diff --git a/shongo-controller/src/main/java/cz/cesnet/shongo/controller/booking/resource/Tag.java b/shongo-controller/src/main/java/cz/cesnet/shongo/controller/booking/resource/Tag.java index f3243b416..ebc9b8a6e 100644 --- a/shongo-controller/src/main/java/cz/cesnet/shongo/controller/booking/resource/Tag.java +++ b/shongo-controller/src/main/java/cz/cesnet/shongo/controller/booking/resource/Tag.java @@ -2,27 +2,63 @@ import cz.cesnet.shongo.SimplePersistentObject; import cz.cesnet.shongo.api.AbstractComplexType; +import cz.cesnet.shongo.controller.api.TagType; import cz.cesnet.shongo.controller.booking.ObjectIdentifier; +import org.hibernate.annotations.Type; import javax.persistence.Column; import javax.persistence.Entity; +import javax.persistence.EnumType; +import javax.persistence.Enumerated; /** * @author: Ondřej Pavelka */ @Entity public class Tag extends SimplePersistentObject { + private String name; + private TagType type; + + private String data; + @Column(length = AbstractComplexType.DEFAULT_COLUMN_LENGTH, unique = true) - public String getName() { + public String getName() + { return name; } - public void setName(String name) { + public void setName(String name) + { this.name = name; } + @Column(nullable = false, length = AbstractComplexType.ENUM_COLUMN_LENGTH) + @Enumerated(EnumType.STRING) + public TagType getType() + { + return type; + } + + public void setType(TagType type) + { + this.type = type; + } + + // @Type and @Column both needed, because HSQLDB does not support JSONB type + @Type(type = "jsonb") + @Column(columnDefinition = "text") + public String getData() + { + return data; + } + + public void setData(String data) + { + this.data = data; + } + /** * @return tag converted capability to API */ @@ -37,6 +73,8 @@ public void toApi(cz.cesnet.shongo.controller.api.Tag tagApi) { tagApi.setId(ObjectIdentifier.formatId(this)); tagApi.setName(name); + tagApi.setType(type); + tagApi.setData(data); } /** @@ -53,6 +91,7 @@ public static Tag createFromApi(cz.cesnet.shongo.controller.api.Tag tagApi) public void fromApi(cz.cesnet.shongo.controller.api.Tag tagApi) { this.setName(tagApi.getName()); + this.setType(tagApi.getType()); + this.setData(tagApi.getData()); } - } diff --git a/shongo-controller/src/test/java/cz/cesnet/shongo/controller/AbstractDatabaseTest.java b/shongo-controller/src/test/java/cz/cesnet/shongo/controller/AbstractDatabaseTest.java index d9dde912d..56470c926 100644 --- a/shongo-controller/src/test/java/cz/cesnet/shongo/controller/AbstractDatabaseTest.java +++ b/shongo-controller/src/test/java/cz/cesnet/shongo/controller/AbstractDatabaseTest.java @@ -24,7 +24,7 @@ public abstract class AbstractDatabaseTest * Connection. */ protected static String connectionDriver = "org.hsqldb.jdbcDriver"; - protected static String connectionUrl = "jdbc:hsqldb:mem:test; shutdown=true;"; + protected static String connectionUrl = "jdbc:hsqldb:mem:test; shutdown=true; sql.syntax_pgs=true;"; /** * Enable driver for debugging SQL. diff --git a/shongo-controller/src/test/java/cz/cesnet/shongo/controller/booking/resource/TagTest.java b/shongo-controller/src/test/java/cz/cesnet/shongo/controller/booking/resource/TagTest.java index 788125d87..dc0fe8dd1 100644 --- a/shongo-controller/src/test/java/cz/cesnet/shongo/controller/booking/resource/TagTest.java +++ b/shongo-controller/src/test/java/cz/cesnet/shongo/controller/booking/resource/TagTest.java @@ -21,6 +21,47 @@ * @author: Ondřej Pavelka */ public class TagTest extends AbstractControllerTest { + + @Test + public void testCreateTag() + { + final String tagName1 = "testTag1"; + final String tagName2 = "testTag2"; + final TagType tagType2 = TagType.RESERVATION_DATA; + final String tagData2 = "[\"karnis@cesnet.cz\", \"filip.karnis@cesnet.cz\"]"; + + ResourceService resourceService = getResourceService(); + + // tag1 init + cz.cesnet.shongo.controller.api.Tag tag1 = new cz.cesnet.shongo.controller.api.Tag(); + tag1.setName(tagName1); + + // tag2 init + cz.cesnet.shongo.controller.api.Tag tag2 = new cz.cesnet.shongo.controller.api.Tag(); + tag2.setName(tagName2); + tag2.setType(tagType2); + tag2.setData(tagData2); + + String tagId1 = resourceService.createTag(SECURITY_TOKEN_ROOT, tag1); + String tagId2 = resourceService.createTag(SECURITY_TOKEN_ROOT, tag2); + + cz.cesnet.shongo.controller.api.Tag getResult1 = resourceService.getTag(SECURITY_TOKEN_ROOT, tagId1); + cz.cesnet.shongo.controller.api.Tag getResult2 = resourceService.getTag(SECURITY_TOKEN_ROOT, tagId2); + + Assert.assertNotNull(getResult1); + Assert.assertNotNull(getResult2); + + Assert.assertEquals(tagId1, getResult1.getId()); + Assert.assertEquals(tagName1, getResult1.getName()); + Assert.assertEquals(TagType.DEFAULT, getResult1.getType()); + Assert.assertNull(getResult1.getData()); + + Assert.assertEquals(tagId2, getResult2.getId()); + Assert.assertEquals(tagName2, getResult2.getName()); + Assert.assertEquals(tagType2, getResult2.getType()); + Assert.assertEquals(tagData2, getResult2.getData()); + } + @Test public void testCreateTagsAcl() throws Exception { diff --git a/shongo-deployment/migrations/2023-02-15/migration.sql b/shongo-deployment/migrations/2023-02-15/migration.sql new file mode 100644 index 000000000..40825533c --- /dev/null +++ b/shongo-deployment/migrations/2023-02-15/migration.sql @@ -0,0 +1,10 @@ +/** + * 2023-02-15: tag can now hold additional data + */ +BEGIN TRANSACTION; + +ALTER TABLE tag + ADD COLUMN type varchar(255) NOT NULL DEFAULT 'DEFAULT', + ADD COLUMN data jsonb; + +COMMIT TRANSACTION; From b7f30c4711a6ae3af41d69e3e4db87edb8c481ac Mon Sep 17 00:00:00 2001 From: Filip Karnis Date: Sat, 11 Feb 2023 16:41:04 +0100 Subject: [PATCH 02/20] [controller] add auxData to reservation request --- .../API/ReservationRequestAbstract.pm | 4 + .../Shongo/ClientCli/ReservationService.pm | 6 +- .../api/AbstractReservationRequest.java | 24 ++++++ .../request/AbstractReservationRequest.java | 29 +++++++ .../booking/request/auxdata/AuxData.java | 62 +++++++++++++++ .../ReservationRequestModificationTest.java | 75 +++++++++++++++++++ .../migrations/2023-02-24/migration.sql | 8 ++ 7 files changed, 206 insertions(+), 2 deletions(-) create mode 100644 shongo-controller/src/main/java/cz/cesnet/shongo/controller/booking/request/auxdata/AuxData.java create mode 100644 shongo-deployment/migrations/2023-02-24/migration.sql diff --git a/shongo-client-cli/src/main/perl/Shongo/ClientCli/API/ReservationRequestAbstract.pm b/shongo-client-cli/src/main/perl/Shongo/ClientCli/API/ReservationRequestAbstract.pm index 427f39823..ca4f178c9 100644 --- a/shongo-client-cli/src/main/perl/Shongo/ClientCli/API/ReservationRequestAbstract.pm +++ b/shongo-client-cli/src/main/perl/Shongo/ClientCli/API/ReservationRequestAbstract.pm @@ -89,6 +89,10 @@ sub new() 'OWNED' => 'Owned' ) }); + $self->add_attribute('auxData', { + 'title' => 'Auxiliary data', + 'optional' => 1, + }); return $self; } diff --git a/shongo-client-cli/src/main/perl/Shongo/ClientCli/ReservationService.pm b/shongo-client-cli/src/main/perl/Shongo/ClientCli/ReservationService.pm index d3e17620b..1fa47c09d 100644 --- a/shongo-client-cli/src/main/perl/Shongo/ClientCli/ReservationService.pm +++ b/shongo-client-cli/src/main/perl/Shongo/ClientCli/ReservationService.pm @@ -274,7 +274,8 @@ sub list_reservation_requests() {'field' => 'technology', 'title' => 'Technology'}, {'field' => 'allocationState', 'title' => 'Allocation'}, {'field' => 'executableState', 'title' => 'Executable'}, - {'field' => 'description', 'title' => 'Description'} + {'field' => 'description', 'title' => 'Description'}, + {'field' => 'auxData', 'title' => 'Auxiliary Data'}, ], 'data' => [] }; @@ -321,7 +322,8 @@ sub list_reservation_requests() 'technology' => $technologies, 'allocationState' => Shongo::ClientCli::API::ReservationRequest::format_state($reservation_request->{'allocationState'}), 'executableState' => Shongo::ClientCli::API::ReservationRequest::format_state($reservation_request->{'executableState'}), - 'description' => $reservation_request->{'description'} + 'description' => $reservation_request->{'description'}, + 'auxData' => $reservation_request->{'auxData'}, }); } console_print_table($table); diff --git a/shongo-controller-api/src/main/java/cz/cesnet/shongo/controller/api/AbstractReservationRequest.java b/shongo-controller-api/src/main/java/cz/cesnet/shongo/controller/api/AbstractReservationRequest.java index 3ecbde003..183c43e48 100644 --- a/shongo-controller-api/src/main/java/cz/cesnet/shongo/controller/api/AbstractReservationRequest.java +++ b/shongo-controller-api/src/main/java/cz/cesnet/shongo/controller/api/AbstractReservationRequest.java @@ -75,6 +75,11 @@ public abstract class AbstractReservationRequest extends IdentifiedComplexType */ private boolean isSchedulerDeleted = false; + /** + * Auxiliary data. This data are specified by the {@link Tag}s of {@link Resource} which is requested for reservation. + */ + private String auxData; + /** * Constructor. */ @@ -291,6 +296,22 @@ public void setIsSchedulerDeleted(boolean isSchedulerDeleted) this.isSchedulerDeleted = isSchedulerDeleted; } + /** + * @return {@link #auxData} + */ + public String getAuxData() + { + return auxData; + } + + /** + * @param auxData sets the {@link #auxData} + */ + public void setAuxData(String auxData) + { + this.auxData = auxData; + } + private static final String TYPE = "type"; private static final String DATETIME = "dateTime"; private static final String USER_ID = "userId"; @@ -303,6 +324,7 @@ public void setIsSchedulerDeleted(boolean isSchedulerDeleted) private static final String REUSED_RESERVATION_REQUEST_MANDATORY = "reusedReservationRequestMandatory"; private static final String REUSEMENT = "reusement"; private static final String IS_SCHEDULER_DELETED = "isSchedulerDeleted"; + public static final String AUX_DATA = "auxData"; @Override public DataMap toData() @@ -320,6 +342,7 @@ public DataMap toData() dataMap.set(REUSED_RESERVATION_REQUEST_MANDATORY, reusedReservationRequestMandatory); dataMap.set(REUSEMENT, reusement); dataMap.set(IS_SCHEDULER_DELETED, isSchedulerDeleted); + dataMap.set(AUX_DATA, auxData); return dataMap; } @@ -339,5 +362,6 @@ public void fromData(DataMap dataMap) reusedReservationRequestMandatory = dataMap.getBool(REUSED_RESERVATION_REQUEST_MANDATORY); reusement = dataMap.getEnum(REUSEMENT, ReservationRequestReusement.class); isSchedulerDeleted = dataMap.getBool(IS_SCHEDULER_DELETED); + auxData = dataMap.getString(AUX_DATA); } } diff --git a/shongo-controller/src/main/java/cz/cesnet/shongo/controller/booking/request/AbstractReservationRequest.java b/shongo-controller/src/main/java/cz/cesnet/shongo/controller/booking/request/AbstractReservationRequest.java index a26ff68e1..80f99a5af 100644 --- a/shongo-controller/src/main/java/cz/cesnet/shongo/controller/booking/request/AbstractReservationRequest.java +++ b/shongo-controller/src/main/java/cz/cesnet/shongo/controller/booking/request/AbstractReservationRequest.java @@ -12,6 +12,8 @@ import cz.cesnet.shongo.controller.api.Controller; import cz.cesnet.shongo.controller.booking.Allocation; import cz.cesnet.shongo.controller.booking.ObjectIdentifier; +import cz.cesnet.shongo.controller.booking.resource.Resource; +import cz.cesnet.shongo.controller.booking.resource.Tag; import cz.cesnet.shongo.controller.booking.specification.Specification; import cz.cesnet.shongo.controller.scheduler.Scheduler; import cz.cesnet.shongo.controller.api.ReservationRequestType; @@ -20,6 +22,7 @@ import cz.cesnet.shongo.report.Report; import cz.cesnet.shongo.report.ReportableSimple; import cz.cesnet.shongo.util.ObjectHelper; +import org.hibernate.annotations.Type; import org.joda.time.DateTime; import org.joda.time.Period; @@ -115,6 +118,11 @@ public abstract class AbstractReservationRequest extends PersistentObject implem */ private ReservationRequestReusement reusement; + /** + * Auxiliary data. This data are specified by the {@link Tag}s of {@link Resource} which is requested for reservation. + */ + private String auxData; + @Id @SequenceGenerator(name = "reservation_request_id", sequenceName = "reservation_request_id_seq", allocationSize = 1) @GeneratedValue(strategy = GenerationType.AUTO, generator = "reservation_request_id") @@ -385,6 +393,24 @@ public void setReusement(ReservationRequestReusement reusement) this.reusement = reusement; } + /** + * @return {@link #auxData} + */ + @Type(type = "jsonb") + @Column(name = "aux_data", columnDefinition = "text") + public String getAuxData() + { + return auxData; + } + + /** + * @param auxData sets the {@link #auxData} + */ + public void setAuxData(String auxData) + { + this.auxData = auxData; + } + /** * Validate {@link AbstractReservationRequest}. * @@ -448,6 +474,7 @@ public boolean synchronizeFrom(AbstractReservationRequest reservationRequest, En setReusedAllocation(reservationRequest.getReusedAllocation()); setReusedAllocationMandatory(reservationRequest.isReusedAllocationMandatory()); setReusement(reservationRequest.getReusement()); + setAuxData(reservationRequest.getAuxData()); Specification oldSpecification = getSpecification(); Specification newSpecification = reservationRequest.getSpecification(); @@ -550,6 +577,7 @@ protected void toApi(cz.cesnet.shongo.controller.api.AbstractReservationRequest ObjectIdentifier.formatId(reusedAllocation.getReservationRequest()), reusedAllocationMandatory); } api.setReusement(getReusement()); + api.setAuxData(getAuxData()); // Reservation request is deleted if (state.equals(State.DELETED)) { @@ -604,6 +632,7 @@ else if (getSpecification() != null && getSpecification().equalsId(specification } setReusedAllocationMandatory(api.isReusedReservationRequestMandatory()); setReusement(api.getReusement()); + setAuxData(api.getAuxData()); } /** diff --git a/shongo-controller/src/main/java/cz/cesnet/shongo/controller/booking/request/auxdata/AuxData.java b/shongo-controller/src/main/java/cz/cesnet/shongo/controller/booking/request/auxdata/AuxData.java new file mode 100644 index 000000000..5abf133e3 --- /dev/null +++ b/shongo-controller/src/main/java/cz/cesnet/shongo/controller/booking/request/auxdata/AuxData.java @@ -0,0 +1,62 @@ +package cz.cesnet.shongo.controller.booking.request.auxdata; + +import com.fasterxml.jackson.databind.JsonNode; + +public class AuxData +{ + + private String tagName; + private boolean enabled; + private JsonNode data; + + public AuxData() + { + } + + public AuxData(String tagName, boolean enabled, JsonNode data) + { + this.tagName = tagName; + this.enabled = enabled; + this.data = data; + } + + public String getTagName() + { + return tagName; + } + + public void setTagName(String tagName) + { + this.tagName = tagName; + } + + public boolean isEnabled() + { + return enabled; + } + + public void setEnabled(boolean enabled) + { + this.enabled = enabled; + } + + public JsonNode getData() + { + return data; + } + + public void setData(JsonNode data) + { + this.data = data; + } + + @Override + public String toString() + { + return "AuxData{" + + "tag='" + tagName + '\'' + + ", enabled=" + enabled + + ", data='" + data + '\'' + + '}'; + } +} diff --git a/shongo-controller/src/test/java/cz/cesnet/shongo/controller/booking/request/ReservationRequestModificationTest.java b/shongo-controller/src/test/java/cz/cesnet/shongo/controller/booking/request/ReservationRequestModificationTest.java index f58598701..ec996996e 100644 --- a/shongo-controller/src/test/java/cz/cesnet/shongo/controller/booking/request/ReservationRequestModificationTest.java +++ b/shongo-controller/src/test/java/cz/cesnet/shongo/controller/booking/request/ReservationRequestModificationTest.java @@ -1,5 +1,8 @@ package cz.cesnet.shongo.controller.booking.request; +import com.fasterxml.jackson.core.JsonProcessingException; +import com.fasterxml.jackson.databind.ObjectMapper; +import com.fasterxml.jackson.databind.node.ArrayNode; import cz.cesnet.shongo.AliasType; import cz.cesnet.shongo.Technology; import cz.cesnet.shongo.api.Alias; @@ -13,6 +16,7 @@ import cz.cesnet.shongo.controller.api.ReservationRequestSet; import cz.cesnet.shongo.controller.api.rpc.ReservationService; import cz.cesnet.shongo.controller.booking.datetime.AbsoluteDateTimeSlot; +import cz.cesnet.shongo.controller.booking.request.auxdata.AuxData; import org.joda.time.Interval; import org.junit.Assert; import org.junit.Test; @@ -27,6 +31,77 @@ */ public class ReservationRequestModificationTest extends AbstractControllerTest { + + private final ObjectMapper objectMapper = new ObjectMapper(); + + @Test + public void testModifyAttributes() throws JsonProcessingException { + Resource resource = new Resource(); + resource.setName("resource"); + resource.setAllocatable(true); + String resourceId = createResource(resource); + + ArrayNode data = objectMapper.createArrayNode(); + data.add("karnis@cesnet.cz"); + data.add("filip.karnis@cesnet.cz"); + AuxData aux = new AuxData("test", true, data); + String auxData = objectMapper.writeValueAsString(aux); + + ReservationRequest reservationRequest = new ReservationRequest(); + reservationRequest.setDescription("request"); + reservationRequest.setSlot("2012-01-01T12:00", "PT2H"); + reservationRequest.setPurpose(ReservationRequestPurpose.SCIENCE); + reservationRequest.setSpecification(new ResourceSpecification(resourceId)); + + String id1 = getReservationService().createReservationRequest(SECURITY_TOKEN, reservationRequest); + ReservationRequest reservationRequestGet = getReservationRequest(id1, ReservationRequest.class); + + Assert.assertEquals(ReservationRequestType.NEW, reservationRequestGet.getType()); + Assert.assertEquals(reservationRequest.getPurpose(), reservationRequestGet.getPurpose()); + Assert.assertEquals(reservationRequest.getDescription(), reservationRequestGet.getDescription()); + Assert.assertEquals(reservationRequest.getInterDomain(), reservationRequestGet.getInterDomain()); + Assert.assertEquals(reservationRequest.getReusedReservationRequestId(), reservationRequestGet.getReusedReservationRequestId()); + Assert.assertEquals(ReservationRequestReusement.NONE, reservationRequestGet.getReusement()); + Assert.assertEquals(reservationRequest.getAuxData(), reservationRequestGet.getAuxData()); + Assert.assertEquals(reservationRequest.getParentReservationRequestId(), reservationRequestGet.getParentReservationRequestId()); + Assert.assertEquals(reservationRequest.getSlot(), reservationRequestGet.getSlot()); + Assert.assertEquals(reservationRequest.getReservationIds(), reservationRequestGet.getReservationIds()); + + // Modify reservation request by retrieved instance of reservation request + reservationRequestGet.setPurpose(ReservationRequestPurpose.EDUCATION); + reservationRequestGet.setPriority(5); + reservationRequestGet.setDescription("requestModified"); + reservationRequestGet.setSpecification(new AliasSpecification(Technology.ADOBE_CONNECT)); + reservationRequestGet.setReusement(ReservationRequestReusement.OWNED); + reservationRequestGet.setAuxData(auxData); + reservationRequestGet.setSlot("2012-01-01T13:00", "PT1H"); + + String id2 = getReservationService().modifyReservationRequest(SECURITY_TOKEN, reservationRequestGet); + ReservationRequest reservationRequestGet2 = getReservationRequest(id2, ReservationRequest.class); + + Assert.assertEquals(ReservationRequestType.MODIFIED, reservationRequestGet2.getType()); + Assert.assertEquals(reservationRequestGet.getPurpose(), reservationRequestGet2.getPurpose()); + Assert.assertEquals(reservationRequestGet.getPriority(), reservationRequestGet2.getPriority()); + Assert.assertEquals(reservationRequestGet.getDescription(), reservationRequestGet2.getDescription()); + Assert.assertEquals(reservationRequestGet.getInterDomain(), reservationRequestGet2.getInterDomain()); + Assert.assertEquals(reservationRequestGet.getReusedReservationRequestId(), reservationRequestGet2.getReusedReservationRequestId()); + Assert.assertEquals(reservationRequestGet.getReusement(), reservationRequestGet2.getReusement()); + Assert.assertEquals(reservationRequestGet.getAuxData(), reservationRequestGet2.getAuxData()); + Assert.assertEquals(reservationRequestGet.getParentReservationRequestId(), reservationRequestGet2.getParentReservationRequestId()); + Assert.assertEquals(reservationRequestGet.getSlot(), reservationRequestGet2.getSlot()); + Assert.assertEquals(reservationRequestGet.getAllocationState(), reservationRequestGet2.getAllocationState()); + Assert.assertEquals(reservationRequestGet.getReservationIds(), reservationRequestGet2.getReservationIds()); + + // Modify again + reservationRequestGet2.setReusedReservationRequestId(id2); + + String id3 = getReservationService().modifyReservationRequest(SECURITY_TOKEN, reservationRequestGet2); + ReservationRequest reservationRequestGet3 = getReservationRequest(id3, ReservationRequest.class); + + // Check that reused reservation request points to id3 since id2 was modified to id3 + Assert.assertEquals(id3, reservationRequestGet3.getReusedReservationRequestId()); + } + @Test public void testExtension() throws Exception { diff --git a/shongo-deployment/migrations/2023-02-24/migration.sql b/shongo-deployment/migrations/2023-02-24/migration.sql new file mode 100644 index 000000000..4eca33f3e --- /dev/null +++ b/shongo-deployment/migrations/2023-02-24/migration.sql @@ -0,0 +1,8 @@ +/** + * 2023-02-24: add auxData to reservation request + */ +BEGIN TRANSACTION; + +ALTER TABLE abstract_reservation_request ADD COLUMN aux_data jsonb; + +COMMIT TRANSACTION; From 5e983cfc38d6ae11b53fd468dacfa6f85113d9fe Mon Sep 17 00:00:00 2001 From: Filip Karnis Date: Wed, 1 Mar 2023 16:31:41 +0100 Subject: [PATCH 03/20] [controller] add aux_data to reservation_request_summary --- .../api/ReservationRequestSummary.java | 24 +++++++++++++++++++ .../api/rpc/ReservationServiceImpl.java | 3 +++ .../src/main/resources/sql/hsqldb/init.sql | 1 + .../main/resources/sql/postgresql/init.sql | 1 + .../sql/reservation_request_list.sql | 3 ++- 5 files changed, 31 insertions(+), 1 deletion(-) diff --git a/shongo-controller-api/src/main/java/cz/cesnet/shongo/controller/api/ReservationRequestSummary.java b/shongo-controller-api/src/main/java/cz/cesnet/shongo/controller/api/ReservationRequestSummary.java index d72930c69..dbc4e6474 100644 --- a/shongo-controller-api/src/main/java/cz/cesnet/shongo/controller/api/ReservationRequestSummary.java +++ b/shongo-controller-api/src/main/java/cz/cesnet/shongo/controller/api/ReservationRequestSummary.java @@ -127,6 +127,11 @@ public class ReservationRequestSummary extends IdentifiedComplexType */ private boolean allowCache = true; + /** + * Auxiliary data. This data are specified by the {@link Tag}s of {@link Resource} which is requested for reservation. + */ + private String auxData; + /** * @return {@link #resourceTags} */ @@ -496,6 +501,22 @@ public void setAllowCache(boolean allowCache) this.allowCache = allowCache; } + /** + * @return {@link #auxData} + */ + public String getAuxData() + { + return auxData; + } + + /** + * @param auxData sets the {@link #auxData} + */ + public void setAuxData(String auxData) + { + this.auxData = auxData; + } + private static final String PARENT_RESERVATION_REQUEST_ID = "parentReservationRequestId"; private static final String TYPE = "type"; private static final String DATETIME = "dateTime"; @@ -518,6 +539,7 @@ public void setAllowCache(boolean allowCache) private static final String ROOM_HAS_RECORDINGS = "roomHasRecordings"; private static final String ALLOW_CACHE = "allowCache"; private static final String RESOURCE_TAGS = "resourceTags"; + private static final String AUX_DATA = "auxData"; @Override public DataMap toData() @@ -545,6 +567,7 @@ public DataMap toData() dataMap.set(ROOM_HAS_RECORDINGS, roomHasRecordings); dataMap.set(ALLOW_CACHE, allowCache); dataMap.set(RESOURCE_TAGS, resourceTags); + dataMap.set(AUX_DATA, auxData); return dataMap; } @@ -574,6 +597,7 @@ public void fromData(DataMap dataMap) roomHasRecordings = dataMap.getBool(ROOM_HAS_RECORDINGS); allowCache = dataMap.getBool(ALLOW_CACHE); resourceTags = dataMap.getString(RESOURCE_TAGS); + auxData = dataMap.getString(AUX_DATA); } /** diff --git a/shongo-controller/src/main/java/cz/cesnet/shongo/controller/api/rpc/ReservationServiceImpl.java b/shongo-controller/src/main/java/cz/cesnet/shongo/controller/api/rpc/ReservationServiceImpl.java index a0b4cd879..d621176a1 100644 --- a/shongo-controller/src/main/java/cz/cesnet/shongo/controller/api/rpc/ReservationServiceImpl.java +++ b/shongo-controller/src/main/java/cz/cesnet/shongo/controller/api/rpc/ReservationServiceImpl.java @@ -2043,6 +2043,9 @@ else if (type.equals("RESOURCE")) { if (record[26] != null) { reservationRequestSummary.setResourceTags((String) record[26]); } + if (record[27] != null) { + reservationRequestSummary.setAuxData((String) record[27]); + } return reservationRequestSummary; } diff --git a/shongo-controller/src/main/resources/sql/hsqldb/init.sql b/shongo-controller/src/main/resources/sql/hsqldb/init.sql index 861e651c5..ac21d3f0e 100644 --- a/shongo-controller/src/main/resources/sql/hsqldb/init.sql +++ b/shongo-controller/src/main/resources/sql/hsqldb/init.sql @@ -97,6 +97,7 @@ SELECT reused_allocation.abstract_reservation_request_id AS reused_reservation_request_id, abstract_reservation_request.modified_reservation_request_id AS modified_reservation_request_id, abstract_reservation_request.allocation_id AS allocation_id, + abstract_reservation_request.aux_data AS aux_data, NULL AS child_id, NULL AS future_child_count, reservation_request.slot_start AS slot_start, diff --git a/shongo-controller/src/main/resources/sql/postgresql/init.sql b/shongo-controller/src/main/resources/sql/postgresql/init.sql index b219e9a29..f3abf6593 100644 --- a/shongo-controller/src/main/resources/sql/postgresql/init.sql +++ b/shongo-controller/src/main/resources/sql/postgresql/init.sql @@ -340,6 +340,7 @@ FROM ( reused_allocation.abstract_reservation_request_id AS reused_reservation_request_id, abstract_reservation_request.modified_reservation_request_id AS modified_reservation_request_id, abstract_reservation_request.allocation_id AS allocation_id, + abstract_reservation_request.aux_data #>> '{}' AS aux_data, reservation_request_set_earliest_child.child_id AS child_id, reservation_request_set_earliest_child.future_child_count AS future_child_count, COALESCE(reservation_request.slot_start, reservation_request_set_earliest_child.slot_start) AS slot_start, diff --git a/shongo-controller/src/main/resources/sql/reservation_request_list.sql b/shongo-controller/src/main/resources/sql/reservation_request_list.sql index dcd6a76dd..398033d0d 100644 --- a/shongo-controller/src/main/resources/sql/reservation_request_list.sql +++ b/shongo-controller/src/main/resources/sql/reservation_request_list.sql @@ -37,7 +37,8 @@ SELECT foreign_resources.foreign_resource_id, domain.name as domain_name, reservation_request_summary.allowCache as allowCache, - resource_summary.tag_names as tag_names + resource_summary.tag_names as tag_names, + reservation_request_summary.aux_data as aux_data FROM reservation_request_summary LEFT JOIN reservation_request ON reservation_request.id = reservation_request_summary.id LEFT JOIN specification_summary ON specification_summary.id = reservation_request_summary.specification_id From 8e94a328488fdd1cfb6dee71a7e1aa26868c317f Mon Sep 17 00:00:00 2001 From: Filip Karnis Date: Thu, 30 Mar 2023 03:23:16 +0200 Subject: [PATCH 04/20] [controller] add new tag data to reservation request summary --- .../client/web/models/SpecificationType.java | 20 ++++++++++++------- .../api/ReservationRequestSummary.java | 15 ++++++++++---- .../api/rpc/ReservationServiceImpl.java | 14 ++++++++++++- .../src/main/resources/sql/hsqldb/init.sql | 2 +- .../main/resources/sql/postgresql/init.sql | 2 +- .../sql/reservation_request_list.sql | 2 +- 6 files changed, 40 insertions(+), 15 deletions(-) diff --git a/shongo-client-web/src/main/java/cz/cesnet/shongo/client/web/models/SpecificationType.java b/shongo-client-web/src/main/java/cz/cesnet/shongo/client/web/models/SpecificationType.java index 4683796c4..f74309bf7 100644 --- a/shongo-client-web/src/main/java/cz/cesnet/shongo/client/web/models/SpecificationType.java +++ b/shongo-client-web/src/main/java/cz/cesnet/shongo/client/web/models/SpecificationType.java @@ -4,6 +4,10 @@ import cz.cesnet.shongo.client.web.ClientWebConfiguration; import cz.cesnet.shongo.client.web.support.MessageProvider; import cz.cesnet.shongo.controller.api.ReservationRequestSummary; +import cz.cesnet.shongo.controller.api.Tag; + +import java.util.List; +import java.util.stream.Collectors; /** * Type of specification for a reservation request. @@ -102,15 +106,17 @@ public static SpecificationType fromReservationRequestSummary(ReservationRequest case USED_ROOM: return PERMANENT_ROOM_CAPACITY; case RESOURCE: - String resourceTags = reservationRequestSummary.getResourceTags(); + List resourceTags = reservationRequestSummary.getResourceTags() + .stream() + .map(Tag::getName) + .collect(Collectors.toList()); String parkTagName = ClientWebConfiguration.getInstance().getParkingPlaceTagName(); String vehicleTagName = ClientWebConfiguration.getInstance().getVehicleTagName(); - if (resourceTags != null) { - if (parkTagName != null && resourceTags.contains(parkTagName)) { - return PARKING_PLACE; - } else if (vehicleTagName != null && resourceTags.contains(vehicleTagName)) { - return VEHICLE; - } + if (parkTagName != null && resourceTags.contains(parkTagName)) { + return PARKING_PLACE; + } + else if (vehicleTagName != null && resourceTags.contains(vehicleTagName)) { + return VEHICLE; } return MEETING_ROOM; default: diff --git a/shongo-controller-api/src/main/java/cz/cesnet/shongo/controller/api/ReservationRequestSummary.java b/shongo-controller-api/src/main/java/cz/cesnet/shongo/controller/api/ReservationRequestSummary.java index dbc4e6474..dc0be659a 100644 --- a/shongo-controller-api/src/main/java/cz/cesnet/shongo/controller/api/ReservationRequestSummary.java +++ b/shongo-controller-api/src/main/java/cz/cesnet/shongo/controller/api/ReservationRequestSummary.java @@ -110,7 +110,7 @@ public class ReservationRequestSummary extends IdentifiedComplexType /** * Resource tags. */ - private String resourceTags; + private List resourceTags = new ArrayList<>(); /** * Specifies whether room has recording service. @@ -135,17 +135,24 @@ public class ReservationRequestSummary extends IdentifiedComplexType /** * @return {@link #resourceTags} */ - public String getResourceTags() { + public List getResourceTags() { return resourceTags; } /** * @param resourceTags sets the {@link #resourceTags} */ - public void setResourceTags(String resourceTags) { + public void setResourceTags(List resourceTags) { this.resourceTags = resourceTags; } + /** + * @param resourceTag adds tag to {@link #resourceTags} + */ + public void addResourceTag(Tag resourceTag) { + this.resourceTags.add(resourceTag); + } + /** * @return {@link #parentReservationRequestId} */ @@ -596,7 +603,7 @@ public void fromData(DataMap dataMap) roomHasRecordingService = dataMap.getBool(ROOM_HAS_RECORDING_SERVICE); roomHasRecordings = dataMap.getBool(ROOM_HAS_RECORDINGS); allowCache = dataMap.getBool(ALLOW_CACHE); - resourceTags = dataMap.getString(RESOURCE_TAGS); + resourceTags = dataMap.getList(RESOURCE_TAGS, Tag.class); auxData = dataMap.getString(AUX_DATA); } diff --git a/shongo-controller/src/main/java/cz/cesnet/shongo/controller/api/rpc/ReservationServiceImpl.java b/shongo-controller/src/main/java/cz/cesnet/shongo/controller/api/rpc/ReservationServiceImpl.java index d621176a1..2aa006225 100644 --- a/shongo-controller/src/main/java/cz/cesnet/shongo/controller/api/rpc/ReservationServiceImpl.java +++ b/shongo-controller/src/main/java/cz/cesnet/shongo/controller/api/rpc/ReservationServiceImpl.java @@ -8,6 +8,7 @@ import cz.cesnet.shongo.controller.api.*; import cz.cesnet.shongo.controller.api.Reservation; import cz.cesnet.shongo.controller.api.Specification; +import cz.cesnet.shongo.controller.api.Tag; import cz.cesnet.shongo.controller.api.request.*; import cz.cesnet.shongo.controller.authorization.Authorization; import cz.cesnet.shongo.controller.authorization.AuthorizationManager; @@ -2041,7 +2042,18 @@ else if (type.equals("RESOURCE")) { reservationRequestSummary.setAllowCache((Boolean) record[25]); } if (record[26] != null) { - reservationRequestSummary.setResourceTags((String) record[26]); + String resourceTags = (String) record[26]; + Arrays.stream(resourceTags.split("\\|")).map(String::trim).map(resourceTag -> { + String[] parts = resourceTag.split(","); + Tag tag = new Tag(); + tag.setId(parts[0]); + tag.setName(parts[1]); + tag.setType(TagType.valueOf(parts[2])); + if (parts.length > 3) { + tag.setData(parts[3]); + } + return tag; + }).forEach(reservationRequestSummary::addResourceTag); } if (record[27] != null) { reservationRequestSummary.setAuxData((String) record[27]); diff --git a/shongo-controller/src/main/resources/sql/hsqldb/init.sql b/shongo-controller/src/main/resources/sql/hsqldb/init.sql index ac21d3f0e..a0b50e5cf 100644 --- a/shongo-controller/src/main/resources/sql/hsqldb/init.sql +++ b/shongo-controller/src/main/resources/sql/hsqldb/init.sql @@ -30,7 +30,7 @@ SELECT WHEN (SELECT resource_id FROM capability INNER JOIN recording_capability on recording_capability.id = capability.id WHERE resource_id = resource.id) IS NOT NULL THEN 'RECORDING_SERVICE' ELSE 'RESOURCE' END AS type, - GROUP_CONCAT(tag.name SEPARATOR ',') AS tag_names + GROUP_CONCAT(CONCAT(tag.id, ',', tag.name, ',', tag.type, ',', tag.data) SEPARATOR '|') AS tags FROM resource LEFT JOIN device_resource ON device_resource.id = resource.id LEFT JOIN device_resource_technologies ON device_resource_technologies.device_resource_id = device_resource.id diff --git a/shongo-controller/src/main/resources/sql/postgresql/init.sql b/shongo-controller/src/main/resources/sql/postgresql/init.sql index f3abf6593..760fb4fca 100644 --- a/shongo-controller/src/main/resources/sql/postgresql/init.sql +++ b/shongo-controller/src/main/resources/sql/postgresql/init.sql @@ -112,7 +112,7 @@ SELECT WHEN resource.id IN (SELECT resource_id FROM capability INNER JOIN recording_capability on recording_capability.id = capability.id) THEN 'RECORDING_SERVICE' ELSE 'RESOURCE' END AS type, - string_agg(tag.name, ',') AS tag_names + string_agg(tag.id || ',' || tag.name || ',' || tag.type || ',' || COALESCE(tag.data #>> '{}', ''), '|') AS tags FROM resource LEFT JOIN device_resource ON device_resource.id = resource.id LEFT JOIN device_resource_technologies ON device_resource_technologies.device_resource_id = device_resource.id diff --git a/shongo-controller/src/main/resources/sql/reservation_request_list.sql b/shongo-controller/src/main/resources/sql/reservation_request_list.sql index 398033d0d..60ecd03c9 100644 --- a/shongo-controller/src/main/resources/sql/reservation_request_list.sql +++ b/shongo-controller/src/main/resources/sql/reservation_request_list.sql @@ -37,7 +37,7 @@ SELECT foreign_resources.foreign_resource_id, domain.name as domain_name, reservation_request_summary.allowCache as allowCache, - resource_summary.tag_names as tag_names, + resource_summary.tags as tags, reservation_request_summary.aux_data as aux_data FROM reservation_request_summary LEFT JOIN reservation_request ON reservation_request.id = reservation_request_summary.id From 91f2e4f86f52fa42ecb9ce6f8ede6e80f4f28cf4 Mon Sep 17 00:00:00 2001 From: Filip Karnis Date: Mon, 19 Jun 2023 18:42:55 +0200 Subject: [PATCH 05/20] email notifications from tags --- .../request/auxdata/AuxDataException.java | 15 ++++ .../request/auxdata/AuxDataFilter.java | 73 +++++++++++++++++ .../request/auxdata/AuxDataService.java | 82 +++++++++++++++++++ .../auxdata/tagdata/NotifyEmailAuxData.java | 46 +++++++++++ .../auxdata/tagdata/ReservationAuxData.java | 20 +++++ .../request/auxdata/tagdata/TagData.java | 78 ++++++++++++++++++ .../booking/resource/ResourceManager.java | 21 +++++ .../notification/ReservationNotification.java | 82 +++++++++++++++++++ 8 files changed, 417 insertions(+) create mode 100644 shongo-controller/src/main/java/cz/cesnet/shongo/controller/booking/request/auxdata/AuxDataException.java create mode 100644 shongo-controller/src/main/java/cz/cesnet/shongo/controller/booking/request/auxdata/AuxDataFilter.java create mode 100644 shongo-controller/src/main/java/cz/cesnet/shongo/controller/booking/request/auxdata/AuxDataService.java create mode 100644 shongo-controller/src/main/java/cz/cesnet/shongo/controller/booking/request/auxdata/tagdata/NotifyEmailAuxData.java create mode 100644 shongo-controller/src/main/java/cz/cesnet/shongo/controller/booking/request/auxdata/tagdata/ReservationAuxData.java create mode 100644 shongo-controller/src/main/java/cz/cesnet/shongo/controller/booking/request/auxdata/tagdata/TagData.java diff --git a/shongo-controller/src/main/java/cz/cesnet/shongo/controller/booking/request/auxdata/AuxDataException.java b/shongo-controller/src/main/java/cz/cesnet/shongo/controller/booking/request/auxdata/AuxDataException.java new file mode 100644 index 000000000..feb1363f1 --- /dev/null +++ b/shongo-controller/src/main/java/cz/cesnet/shongo/controller/booking/request/auxdata/AuxDataException.java @@ -0,0 +1,15 @@ +package cz.cesnet.shongo.controller.booking.request.auxdata; + +public class AuxDataException extends Exception +{ + + public AuxDataException(String message) + { + super(message); + } + + public AuxDataException(String message, Throwable cause) + { + super(message, cause); + } +} diff --git a/shongo-controller/src/main/java/cz/cesnet/shongo/controller/booking/request/auxdata/AuxDataFilter.java b/shongo-controller/src/main/java/cz/cesnet/shongo/controller/booking/request/auxdata/AuxDataFilter.java new file mode 100644 index 000000000..86ac3593d --- /dev/null +++ b/shongo-controller/src/main/java/cz/cesnet/shongo/controller/booking/request/auxdata/AuxDataFilter.java @@ -0,0 +1,73 @@ +package cz.cesnet.shongo.controller.booking.request.auxdata; + +import cz.cesnet.shongo.controller.api.TagType; + +public class AuxDataFilter +{ + + private final String tagName; + private final TagType tagType; + private final Boolean enabled; + + private AuxDataFilter(String tagName, TagType tagType, boolean enabled) + { + this.tagName = tagName; + this.tagType = tagType; + this.enabled = enabled; + } + + public static Builder builder() + { + return new Builder(); + } + + public String getTagName() + { + return tagName; + } + + public TagType getTagType() + { + return tagType; + } + + public Boolean isEnabled() + { + return enabled; + } + + public static class Builder + { + + private String tagName; + private TagType tagType; + private boolean enabled; + + private Builder() + { + } + + public Builder tagName(String tagName) + { + this.tagName = tagName; + return this; + } + + public Builder tagType(TagType tagType) + { + this.tagType = tagType; + return this; + } + + public Builder enabled(boolean enabled) + { + this.enabled = enabled; + return this; + } + + public AuxDataFilter build() + { + return new AuxDataFilter(tagName, tagType, enabled); + } + } +} diff --git a/shongo-controller/src/main/java/cz/cesnet/shongo/controller/booking/request/auxdata/AuxDataService.java b/shongo-controller/src/main/java/cz/cesnet/shongo/controller/booking/request/auxdata/AuxDataService.java new file mode 100644 index 000000000..6b8658f92 --- /dev/null +++ b/shongo-controller/src/main/java/cz/cesnet/shongo/controller/booking/request/auxdata/AuxDataService.java @@ -0,0 +1,82 @@ +package cz.cesnet.shongo.controller.booking.request.auxdata; + +import com.fasterxml.jackson.core.JsonProcessingException; +import com.fasterxml.jackson.core.type.TypeReference; +import com.fasterxml.jackson.databind.ObjectMapper; +import cz.cesnet.shongo.TodoImplementException; +import cz.cesnet.shongo.controller.booking.request.AbstractReservationRequest; +import cz.cesnet.shongo.controller.booking.request.auxdata.tagdata.TagData; +import cz.cesnet.shongo.controller.booking.resource.Resource; +import cz.cesnet.shongo.controller.booking.resource.ResourceManager; +import cz.cesnet.shongo.controller.booking.resource.ResourceSpecification; +import cz.cesnet.shongo.controller.booking.resource.Tag; +import cz.cesnet.shongo.controller.booking.room.RoomSpecification; +import cz.cesnet.shongo.controller.booking.specification.Specification; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +import javax.persistence.EntityManager; +import java.util.ArrayList; +import java.util.List; +import java.util.stream.Collectors; + +public class AuxDataService +{ + + private static final Logger logger = LoggerFactory.getLogger(AuxDataService.class); + + private static final ObjectMapper objectMapper = new ObjectMapper(); + + public static > List getTagData( + AbstractReservationRequest reservationRequest, + AuxDataFilter filter, EntityManager entityManager + ) throws AuxDataException, JsonProcessingException + { + List> tagData = getAllTagData(reservationRequest, entityManager); + + return tagData + .stream() + .filter(data -> data.filter(filter)) + .map(data -> (T) data) + .collect(Collectors.toList()); + } + + private static List> getAllTagData( + AbstractReservationRequest reservationRequest, + EntityManager entityManager + ) throws AuxDataException, JsonProcessingException + { + if (reservationRequest.getAuxData() == null) { + throw new AuxDataException("AuxData is null"); + } + + List auxData = objectMapper.readValue(reservationRequest.getAuxData(), new TypeReference<>() {}); + + Resource resource = getResource(reservationRequest); + List resourceTags = new ResourceManager(entityManager).getResourceTags(resource); + + List> tagData = new ArrayList<>(); + for (Tag tag : resourceTags) { + for (AuxData auxData1 : auxData) { + if (auxData1.getTagName().equals(tag.getName())) { + tagData.add(TagData.create(tag, auxData1)); + } + } + } + return tagData; + } + + private static Resource getResource(AbstractReservationRequest reservationRequest) + { + Specification specification = reservationRequest.getSpecification(); + if (specification instanceof ResourceSpecification) { + return ((ResourceSpecification) specification).getResource(); + } + else if (specification instanceof RoomSpecification) { + return ((RoomSpecification) specification).getDeviceResource(); + } + else { + throw new TodoImplementException(specification.getClass()); + } + } +} diff --git a/shongo-controller/src/main/java/cz/cesnet/shongo/controller/booking/request/auxdata/tagdata/NotifyEmailAuxData.java b/shongo-controller/src/main/java/cz/cesnet/shongo/controller/booking/request/auxdata/tagdata/NotifyEmailAuxData.java new file mode 100644 index 000000000..8a320fc12 --- /dev/null +++ b/shongo-controller/src/main/java/cz/cesnet/shongo/controller/booking/request/auxdata/tagdata/NotifyEmailAuxData.java @@ -0,0 +1,46 @@ +package cz.cesnet.shongo.controller.booking.request.auxdata.tagdata; + +import com.fasterxml.jackson.core.JsonProcessingException; +import com.fasterxml.jackson.core.type.TypeReference; +import cz.cesnet.shongo.controller.booking.request.auxdata.AuxData; +import cz.cesnet.shongo.controller.booking.resource.Tag; + +import java.util.ArrayList; +import java.util.List; +import java.util.stream.Collectors; +import java.util.stream.Stream; + +public class NotifyEmailAuxData extends TagData> +{ + + public NotifyEmailAuxData(Tag tag, AuxData auxData) + { + super(tag, auxData); + } + + @Override + public List getData() + { + List tagDataEmails; + List auxDataEmails; + + try { + tagDataEmails = objectMapper.readValue(tag.getData(), new TypeReference<>() { + }); + } catch (JsonProcessingException | NullPointerException e) { + logger.warn("Error while parsing tag data: {}", e.getMessage()); + tagDataEmails = new ArrayList<>(); + } + try { + auxDataEmails = objectMapper.readValue(aux.getData().toString(), new TypeReference<>() { + }); + } catch (JsonProcessingException | NullPointerException e) { + logger.warn("Error while parsing aux data: {}", e.getMessage()); + auxDataEmails = new ArrayList<>(); + } + + return Stream + .concat(tagDataEmails.stream(), auxDataEmails.stream()) + .collect(Collectors.toList()); + } +} diff --git a/shongo-controller/src/main/java/cz/cesnet/shongo/controller/booking/request/auxdata/tagdata/ReservationAuxData.java b/shongo-controller/src/main/java/cz/cesnet/shongo/controller/booking/request/auxdata/tagdata/ReservationAuxData.java new file mode 100644 index 000000000..a19d5487b --- /dev/null +++ b/shongo-controller/src/main/java/cz/cesnet/shongo/controller/booking/request/auxdata/tagdata/ReservationAuxData.java @@ -0,0 +1,20 @@ +package cz.cesnet.shongo.controller.booking.request.auxdata.tagdata; + +import cz.cesnet.shongo.TodoImplementException; +import cz.cesnet.shongo.controller.booking.request.auxdata.AuxData; +import cz.cesnet.shongo.controller.booking.resource.Tag; + +public class ReservationAuxData extends TagData +{ + + public ReservationAuxData(Tag tag, AuxData auxData) + { + super(tag, auxData); + } + + @Override + public String getData() + { + throw new TodoImplementException("Not implemented"); + } +} diff --git a/shongo-controller/src/main/java/cz/cesnet/shongo/controller/booking/request/auxdata/tagdata/TagData.java b/shongo-controller/src/main/java/cz/cesnet/shongo/controller/booking/request/auxdata/tagdata/TagData.java new file mode 100644 index 000000000..47b07586b --- /dev/null +++ b/shongo-controller/src/main/java/cz/cesnet/shongo/controller/booking/request/auxdata/tagdata/TagData.java @@ -0,0 +1,78 @@ +package cz.cesnet.shongo.controller.booking.request.auxdata.tagdata; + +import com.fasterxml.jackson.databind.ObjectMapper; +import cz.cesnet.shongo.TodoImplementException; +import cz.cesnet.shongo.controller.booking.request.auxdata.AuxData; +import cz.cesnet.shongo.controller.booking.request.auxdata.AuxDataFilter; +import cz.cesnet.shongo.controller.booking.resource.Tag; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +public abstract class TagData +{ + + protected static Logger logger = LoggerFactory.getLogger(TagData.class); + + protected final ObjectMapper objectMapper = new ObjectMapper(); + + protected final Tag tag; + protected final AuxData aux; + + public TagData(Tag tag, AuxData aux) + { + this.tag = tag; + this.aux = aux; + } + + public Tag getTag() + { + return tag; + } + + public AuxData getAuxData() + { + return aux; + } + + public abstract T getData(); + + public static TagData create(Tag tag, AuxData auxData) + { + switch (tag.getType()) { + case NOTIFY_EMAIL: + return new NotifyEmailAuxData(tag, auxData); + case RESERVATION_DATA: + return new ReservationAuxData(tag, auxData); + default: + throw new TodoImplementException("Not implemented for tag type: " + tag.getType()); + } + } + + public boolean filter(AuxDataFilter filter) + { + if (filter.getTagName() != null) { + if (!filter.getTagName().equals(tag.getName())) { + return false; + } + } + if (filter.getTagType() != null) { + if (!filter.getTagType().equals(tag.getType())) { + return false; + } + } + if (filter.isEnabled() != null) { + if (!filter.isEnabled().equals(aux.isEnabled())) { + return false; + } + } + return true; + } + + @Override + public String toString() { + return "TagData{" + + "tag=" + tag + + ", aux=" + aux + + '}'; + } +} diff --git a/shongo-controller/src/main/java/cz/cesnet/shongo/controller/booking/resource/ResourceManager.java b/shongo-controller/src/main/java/cz/cesnet/shongo/controller/booking/resource/ResourceManager.java index bcab61e34..6e3573745 100644 --- a/shongo-controller/src/main/java/cz/cesnet/shongo/controller/booking/resource/ResourceManager.java +++ b/shongo-controller/src/main/java/cz/cesnet/shongo/controller/booking/resource/ResourceManager.java @@ -27,6 +27,7 @@ import javax.persistence.TypedQuery; import javax.persistence.criteria.*; import java.util.List; +import java.util.stream.Collectors; /** * Manager for {@link Resource}. @@ -686,6 +687,26 @@ public List getForeignResourceTags(ForeignResources foreignResource return typedQuery.getResultList(); } + /** + * Returns list of {@link Tag} for given {@link Resource} + * @param resource + * @return + */ + public List getResourceTags(Resource resource) + { + CriteriaBuilder criteriaBuilder = entityManager.getCriteriaBuilder(); + + CriteriaQuery query = criteriaBuilder.createQuery(ResourceTag.class); + Root resourceTagRoot = query.from(ResourceTag.class); + javax.persistence.criteria.Predicate param1 = criteriaBuilder.equal(resourceTagRoot.get("resource"), resource.getId()); + query.select(resourceTagRoot).where(param1); + + TypedQuery typedQuery = entityManager.createQuery(query); + List resourceTags = typedQuery.getResultList(); + + return resourceTags.stream().map(ResourceTag::getTag).collect(Collectors.toList()); + } + /** * List {@link ResourceTag} by given {@link Tag} id * @param tagId diff --git a/shongo-controller/src/main/java/cz/cesnet/shongo/controller/notification/ReservationNotification.java b/shongo-controller/src/main/java/cz/cesnet/shongo/controller/notification/ReservationNotification.java index d04a9363d..92e9083ae 100644 --- a/shongo-controller/src/main/java/cz/cesnet/shongo/controller/notification/ReservationNotification.java +++ b/shongo-controller/src/main/java/cz/cesnet/shongo/controller/notification/ReservationNotification.java @@ -1,17 +1,23 @@ package cz.cesnet.shongo.controller.notification; +import com.fasterxml.jackson.core.JsonProcessingException; import cz.cesnet.shongo.AliasType; import cz.cesnet.shongo.PersonInformation; import cz.cesnet.shongo.TodoImplementException; import cz.cesnet.shongo.api.UserInformation; import cz.cesnet.shongo.controller.LocalDomain; import cz.cesnet.shongo.controller.ObjectRole; +import cz.cesnet.shongo.controller.api.TagType; import cz.cesnet.shongo.controller.authorization.AuthorizationManager; import cz.cesnet.shongo.controller.booking.Allocation; import cz.cesnet.shongo.controller.booking.ObjectIdentifier; import cz.cesnet.shongo.controller.booking.alias.Alias; import cz.cesnet.shongo.controller.booking.request.AbstractReservationRequest; +import cz.cesnet.shongo.controller.booking.request.auxdata.AuxDataException; +import cz.cesnet.shongo.controller.booking.request.auxdata.AuxDataFilter; +import cz.cesnet.shongo.controller.booking.request.auxdata.AuxDataService; +import cz.cesnet.shongo.controller.booking.request.auxdata.tagdata.NotifyEmailAuxData; import cz.cesnet.shongo.controller.booking.reservation.Reservation; import cz.cesnet.shongo.controller.booking.resource.Resource; import cz.cesnet.shongo.controller.booking.room.RoomEndpoint; @@ -22,6 +28,7 @@ import javax.persistence.EntityManager; import java.util.*; +import java.util.stream.Collectors; /** * {@link ConfigurableNotification} for a {@link Reservation}. @@ -63,6 +70,7 @@ private ReservationNotification(Reservation reservation, // Add administrators as recipients addAdministratorRecipientsForReservation(reservation.getTargetReservation(), authorizationManager); + addRecipientsFromNotificationTags(reservationRequest, entityManager); // Add child targets for (Reservation childReservation : reservation.getChildReservations()) { @@ -70,6 +78,43 @@ private ReservationNotification(Reservation reservation, } } + private void addRecipientsFromNotificationTags(AbstractReservationRequest reservationRequest, + EntityManager entityManager) + { + AuxDataFilter filter = AuxDataFilter.builder() + .tagType(TagType.NOTIFY_EMAIL) + .enabled(true) + .build(); + + List notifyEmailAuxData; + try { + notifyEmailAuxData = AuxDataService.getTagData(reservationRequest, filter, entityManager); + } catch (JsonProcessingException e) { + logger.error("Error while parsing auxData", e); + return; + } catch (AuxDataException e) { + logger.warn("Error while getting notify email aux data for reservation request {}.", reservationRequest.getId(), e); + return; + } + + List tagPersonInformationList = notifyEmailAuxData + .stream() + .map(this::notifyEmailDataToPersonInformation) + .flatMap(Collection::stream) + .collect(Collectors.toList()); + logger.debug("Adding tag recipients: {}", tagPersonInformationList); + tagPersonInformationList.forEach(personInformation -> addRecipient(personInformation, true)); + } + + private Collection notifyEmailDataToPersonInformation(NotifyEmailAuxData notifyEmailAuxData) + { + return notifyEmailAuxData + .getData() + .stream() + .map(email -> new TagPersonInformation(notifyEmailAuxData.getTag().getName(), email)) + .collect(Collectors.toList()); + } + public String getId() { return id; @@ -389,4 +434,41 @@ public String getType() return "DELETED"; } } + + private static class TagPersonInformation implements PersonInformation + { + + private final String name; + private final String email; + + public TagPersonInformation(String name, String email) + { + this.name = name; + this.email = email; + } + + @Override + public String getFullName() + { + return name; + } + + @Override + public String getRootOrganization() + { + return null; + } + + @Override + public String getPrimaryEmail() + { + return email; + } + + @Override + public String toString() + { + return "Tag[" + name + "] (" + email + ")"; + } + } } From b6755ff24bf2cc02acf89f963daae0ae01f62791 Mon Sep 17 00:00:00 2001 From: Filip Karnis Date: Tue, 11 Jul 2023 00:10:46 +0200 Subject: [PATCH 06/20] change Tag.data type to JsonNode --- .../auxdata/tagdata/NotifyEmailAuxData.java | 29 ++++------------- .../request/auxdata/tagdata/TagData.java | 3 -- .../controller/booking/resource/Tag.java | 32 ++++++++++++++++--- .../controller/booking/resource/TagTest.java | 4 +-- 4 files changed, 36 insertions(+), 32 deletions(-) diff --git a/shongo-controller/src/main/java/cz/cesnet/shongo/controller/booking/request/auxdata/tagdata/NotifyEmailAuxData.java b/shongo-controller/src/main/java/cz/cesnet/shongo/controller/booking/request/auxdata/tagdata/NotifyEmailAuxData.java index 8a320fc12..d6a0bdeed 100644 --- a/shongo-controller/src/main/java/cz/cesnet/shongo/controller/booking/request/auxdata/tagdata/NotifyEmailAuxData.java +++ b/shongo-controller/src/main/java/cz/cesnet/shongo/controller/booking/request/auxdata/tagdata/NotifyEmailAuxData.java @@ -1,14 +1,11 @@ package cz.cesnet.shongo.controller.booking.request.auxdata.tagdata; -import com.fasterxml.jackson.core.JsonProcessingException; -import com.fasterxml.jackson.core.type.TypeReference; +import com.fasterxml.jackson.databind.JsonNode; import cz.cesnet.shongo.controller.booking.request.auxdata.AuxData; import cz.cesnet.shongo.controller.booking.resource.Tag; import java.util.ArrayList; import java.util.List; -import java.util.stream.Collectors; -import java.util.stream.Stream; public class NotifyEmailAuxData extends TagData> { @@ -21,26 +18,14 @@ public NotifyEmailAuxData(Tag tag, AuxData auxData) @Override public List getData() { - List tagDataEmails; - List auxDataEmails; + List emails = new ArrayList<>(); - try { - tagDataEmails = objectMapper.readValue(tag.getData(), new TypeReference<>() { - }); - } catch (JsonProcessingException | NullPointerException e) { - logger.warn("Error while parsing tag data: {}", e.getMessage()); - tagDataEmails = new ArrayList<>(); + for (JsonNode child : tag.getData()) { + emails.add(child.asText()); } - try { - auxDataEmails = objectMapper.readValue(aux.getData().toString(), new TypeReference<>() { - }); - } catch (JsonProcessingException | NullPointerException e) { - logger.warn("Error while parsing aux data: {}", e.getMessage()); - auxDataEmails = new ArrayList<>(); + for (JsonNode child : aux.getData()) { + emails.add(child.asText()); } - - return Stream - .concat(tagDataEmails.stream(), auxDataEmails.stream()) - .collect(Collectors.toList()); + return emails; } } diff --git a/shongo-controller/src/main/java/cz/cesnet/shongo/controller/booking/request/auxdata/tagdata/TagData.java b/shongo-controller/src/main/java/cz/cesnet/shongo/controller/booking/request/auxdata/tagdata/TagData.java index 47b07586b..7abb5c8f9 100644 --- a/shongo-controller/src/main/java/cz/cesnet/shongo/controller/booking/request/auxdata/tagdata/TagData.java +++ b/shongo-controller/src/main/java/cz/cesnet/shongo/controller/booking/request/auxdata/tagdata/TagData.java @@ -1,6 +1,5 @@ package cz.cesnet.shongo.controller.booking.request.auxdata.tagdata; -import com.fasterxml.jackson.databind.ObjectMapper; import cz.cesnet.shongo.TodoImplementException; import cz.cesnet.shongo.controller.booking.request.auxdata.AuxData; import cz.cesnet.shongo.controller.booking.request.auxdata.AuxDataFilter; @@ -13,8 +12,6 @@ public abstract class TagData protected static Logger logger = LoggerFactory.getLogger(TagData.class); - protected final ObjectMapper objectMapper = new ObjectMapper(); - protected final Tag tag; protected final AuxData aux; diff --git a/shongo-controller/src/main/java/cz/cesnet/shongo/controller/booking/resource/Tag.java b/shongo-controller/src/main/java/cz/cesnet/shongo/controller/booking/resource/Tag.java index ebc9b8a6e..6df57e70d 100644 --- a/shongo-controller/src/main/java/cz/cesnet/shongo/controller/booking/resource/Tag.java +++ b/shongo-controller/src/main/java/cz/cesnet/shongo/controller/booking/resource/Tag.java @@ -1,5 +1,8 @@ package cz.cesnet.shongo.controller.booking.resource; +import com.fasterxml.jackson.core.JsonProcessingException; +import com.fasterxml.jackson.databind.JsonNode; +import com.fasterxml.jackson.databind.ObjectMapper; import cz.cesnet.shongo.SimplePersistentObject; import cz.cesnet.shongo.api.AbstractComplexType; import cz.cesnet.shongo.controller.api.TagType; @@ -10,6 +13,7 @@ import javax.persistence.Entity; import javax.persistence.EnumType; import javax.persistence.Enumerated; +import javax.persistence.Transient; /** * @author: Ondřej Pavelka @@ -17,11 +21,14 @@ @Entity public class Tag extends SimplePersistentObject { + @Transient + private final ObjectMapper objectMapper = new ObjectMapper(); + private String name; private TagType type; - private String data; + private JsonNode data; @Column(length = AbstractComplexType.DEFAULT_COLUMN_LENGTH, unique = true) public String getName() @@ -49,12 +56,12 @@ public void setType(TagType type) // @Type and @Column both needed, because HSQLDB does not support JSONB type @Type(type = "jsonb") @Column(columnDefinition = "text") - public String getData() + public JsonNode getData() { return data; } - public void setData(String data) + public void setData(JsonNode data) { this.data = data; } @@ -74,7 +81,16 @@ public void toApi(cz.cesnet.shongo.controller.api.Tag tagApi) tagApi.setId(ObjectIdentifier.formatId(this)); tagApi.setName(name); tagApi.setType(type); - tagApi.setData(data); + if (data == null) { + tagApi.setData(""); + } + else { + try { + tagApi.setData(objectMapper.writeValueAsString(data)); + } catch (JsonProcessingException e) { + throw new IllegalArgumentException("Failed to parse data", e); + } + } } /** @@ -92,6 +108,12 @@ public void fromApi(cz.cesnet.shongo.controller.api.Tag tagApi) { this.setName(tagApi.getName()); this.setType(tagApi.getType()); - this.setData(tagApi.getData()); + if (tagApi.getData() != null) { + try { + setData(objectMapper.readTree(tagApi.getData())); + } catch (JsonProcessingException e) { + throw new IllegalArgumentException("Data is not a valid JSON", e); + } + } } } diff --git a/shongo-controller/src/test/java/cz/cesnet/shongo/controller/booking/resource/TagTest.java b/shongo-controller/src/test/java/cz/cesnet/shongo/controller/booking/resource/TagTest.java index dc0fe8dd1..6bf148999 100644 --- a/shongo-controller/src/test/java/cz/cesnet/shongo/controller/booking/resource/TagTest.java +++ b/shongo-controller/src/test/java/cz/cesnet/shongo/controller/booking/resource/TagTest.java @@ -28,7 +28,7 @@ public void testCreateTag() final String tagName1 = "testTag1"; final String tagName2 = "testTag2"; final TagType tagType2 = TagType.RESERVATION_DATA; - final String tagData2 = "[\"karnis@cesnet.cz\", \"filip.karnis@cesnet.cz\"]"; + final String tagData2 = "[\"karnis@cesnet.cz\",\"filip.karnis@cesnet.cz\"]"; ResourceService resourceService = getResourceService(); @@ -54,7 +54,7 @@ public void testCreateTag() Assert.assertEquals(tagId1, getResult1.getId()); Assert.assertEquals(tagName1, getResult1.getName()); Assert.assertEquals(TagType.DEFAULT, getResult1.getType()); - Assert.assertNull(getResult1.getData()); + Assert.assertEquals("", getResult1.getData()); Assert.assertEquals(tagId2, getResult2.getId()); Assert.assertEquals(tagName2, getResult2.getName()); From aa4c0511f07254240c2c76cf76fd14fecfa2e135 Mon Sep 17 00:00:00 2001 From: Filip Karnis Date: Wed, 12 Jul 2023 17:43:40 +0200 Subject: [PATCH 07/20] auxiliary data API --- .../Shongo/ClientCli/API/AuxiliaryData.pm | 45 ++++++ .../API/ReservationRequestAbstract.pm | 8 +- .../api/AbstractReservationRequest.java | 11 +- .../shongo/controller/api/AuxiliaryData.java | 140 ++++++++++++++++++ .../request/AbstractReservationRequest.java | 43 +++++- .../booking/request/auxdata/AuxData.java | 25 +++- .../request/auxdata/AuxDataService.java | 17 +-- .../ReservationRequestModificationTest.java | 24 +-- 8 files changed, 273 insertions(+), 40 deletions(-) create mode 100644 shongo-client-cli/src/main/perl/Shongo/ClientCli/API/AuxiliaryData.pm create mode 100644 shongo-controller-api/src/main/java/cz/cesnet/shongo/controller/api/AuxiliaryData.java diff --git a/shongo-client-cli/src/main/perl/Shongo/ClientCli/API/AuxiliaryData.pm b/shongo-client-cli/src/main/perl/Shongo/ClientCli/API/AuxiliaryData.pm new file mode 100644 index 000000000..76a29a3b2 --- /dev/null +++ b/shongo-client-cli/src/main/perl/Shongo/ClientCli/API/AuxiliaryData.pm @@ -0,0 +1,45 @@ +# +# Auxiliary data for ReservationRequestAbstract +# +# @author Filip Karnis +# +package Shongo::ClientCli::API::AuxiliaryData; +use base qw(Shongo::ClientCli::API::Object); + +use strict; +use warnings; + +use Shongo::Common; +use Shongo::Console; + +# +# Create a new instance of auxiliary data +# +# @static +# +sub new() +{ + my $class = shift; + my (%attributes) = @_; + my $self = Shongo::ClientCli::API::Object->new(@_); + bless $self, $class; + + $self->set_object_class('AuxData'); + $self->set_object_name('Auxiliary Data'); + $self->add_attribute('tagName', { + 'required' => 1, + 'type' => 'string', + }); + $self->add_attribute('enabled', { + 'required' => 1, + 'type' => 'bool', + }); + $self->add_attribute('data', { + 'required' => 0, + 'type' => 'string', + }); + + return $self; +} + +1; diff --git a/shongo-client-cli/src/main/perl/Shongo/ClientCli/API/ReservationRequestAbstract.pm b/shongo-client-cli/src/main/perl/Shongo/ClientCli/API/ReservationRequestAbstract.pm index ca4f178c9..013de7872 100644 --- a/shongo-client-cli/src/main/perl/Shongo/ClientCli/API/ReservationRequestAbstract.pm +++ b/shongo-client-cli/src/main/perl/Shongo/ClientCli/API/ReservationRequestAbstract.pm @@ -13,6 +13,7 @@ use Shongo::Common; use Shongo::Console; use Shongo::ClientCli::API::ReservationRequest; use Shongo::ClientCli::API::ReservationRequestSet; +use Shongo::ClientCli::API::AuxiliaryData; # Enumeration of reservation request purpose our $Purpose = ordered_hash( @@ -90,7 +91,12 @@ sub new() ) }); $self->add_attribute('auxData', { - 'title' => 'Auxiliary data', + 'type' => 'collection', + 'item' => { + 'title' => 'Auxiliary Data', + 'class' => 'Shongo::ClientCli::API::AuxiliaryData', + 'short' => 1, + }, 'optional' => 1, }); diff --git a/shongo-controller-api/src/main/java/cz/cesnet/shongo/controller/api/AbstractReservationRequest.java b/shongo-controller-api/src/main/java/cz/cesnet/shongo/controller/api/AbstractReservationRequest.java index 183c43e48..48fe8d986 100644 --- a/shongo-controller-api/src/main/java/cz/cesnet/shongo/controller/api/AbstractReservationRequest.java +++ b/shongo-controller-api/src/main/java/cz/cesnet/shongo/controller/api/AbstractReservationRequest.java @@ -7,6 +7,9 @@ import cz.cesnet.shongo.controller.api.rpc.ReservationService; import org.joda.time.DateTime; +import java.util.ArrayList; +import java.util.List; + /** * Request for reservation of resources. * @@ -78,7 +81,7 @@ public abstract class AbstractReservationRequest extends IdentifiedComplexType /** * Auxiliary data. This data are specified by the {@link Tag}s of {@link Resource} which is requested for reservation. */ - private String auxData; + private List auxData = new ArrayList<>(); /** * Constructor. @@ -299,7 +302,7 @@ public void setIsSchedulerDeleted(boolean isSchedulerDeleted) /** * @return {@link #auxData} */ - public String getAuxData() + public List getAuxData() { return auxData; } @@ -307,7 +310,7 @@ public String getAuxData() /** * @param auxData sets the {@link #auxData} */ - public void setAuxData(String auxData) + public void setAuxData(List auxData) { this.auxData = auxData; } @@ -362,6 +365,6 @@ public void fromData(DataMap dataMap) reusedReservationRequestMandatory = dataMap.getBool(REUSED_RESERVATION_REQUEST_MANDATORY); reusement = dataMap.getEnum(REUSEMENT, ReservationRequestReusement.class); isSchedulerDeleted = dataMap.getBool(IS_SCHEDULER_DELETED); - auxData = dataMap.getString(AUX_DATA); + auxData = dataMap.getList(AUX_DATA, AuxiliaryData.class); } } diff --git a/shongo-controller-api/src/main/java/cz/cesnet/shongo/controller/api/AuxiliaryData.java b/shongo-controller-api/src/main/java/cz/cesnet/shongo/controller/api/AuxiliaryData.java new file mode 100644 index 000000000..b520cd331 --- /dev/null +++ b/shongo-controller-api/src/main/java/cz/cesnet/shongo/controller/api/AuxiliaryData.java @@ -0,0 +1,140 @@ +package cz.cesnet.shongo.controller.api; + +import com.fasterxml.jackson.annotation.JsonIgnore; +import com.fasterxml.jackson.core.JsonProcessingException; +import com.fasterxml.jackson.databind.JsonNode; +import com.fasterxml.jackson.databind.ObjectMapper; +import cz.cesnet.shongo.api.AbstractComplexType; +import cz.cesnet.shongo.api.DataMap; + +import java.util.Objects; + +public class AuxiliaryData extends AbstractComplexType +{ + + private static final ObjectMapper objectMapper = new ObjectMapper(); + + private String tagName; + private boolean enabled; + private String data = objectMapper.nullNode().toString(); + + public AuxiliaryData() + { + } + + public AuxiliaryData(String tagName, boolean enabled, String data) + { + setTagName(tagName); + setEnabled(enabled); + setData(data); + } + + public String getTagName() + { + return tagName; + } + + public void setTagName(String tagName) + { + this.tagName = tagName; + } + + public boolean isEnabled() + { + return enabled; + } + + public void setEnabled(boolean enabled) + { + this.enabled = enabled; + } + + public String getData() + { + return data; + } + + @JsonIgnore + public JsonNode getDataAsJsonNode() + { + if (data == null) { + return null; + } + + try { + return objectMapper.readTree(data); + } catch (JsonProcessingException e) { + throw new RuntimeException(e); + } + } + + public void setData(String data) + { + if (data == null) { + this.data = objectMapper.nullNode().toString(); + return; + } + + this.data = data; + } + + public void setData(JsonNode data) + { + try { + this.data = objectMapper.writeValueAsString(data); + } catch (JsonProcessingException e) { + throw new RuntimeException(e); + } + } + + @Override + @JsonIgnore + public String getClassName() { + return super.getClassName(); + } + + @Override + public DataMap toData() + { + DataMap dataMap = super.toData(); + dataMap.set("tagName", tagName); + dataMap.set("enabled", enabled); + dataMap.set("data", data); + return dataMap; + } + + @Override + public void fromData(DataMap dataMap) + { + super.fromData(dataMap); + tagName = dataMap.getString("tagName"); + enabled = dataMap.getBoolean("enabled"); + data = dataMap.getString("data"); + } + + @Override + public boolean equals(Object o) + { + if (this == o) return true; + if (o == null || getClass() != o.getClass()) return false; + AuxiliaryData auxData = (AuxiliaryData) o; + return enabled == auxData.enabled && Objects.equals(tagName, auxData.tagName) && + Objects.equals(getDataAsJsonNode(), auxData.getDataAsJsonNode()); + } + + @Override + public int hashCode() + { + return Objects.hash(tagName, enabled, data); + } + + @Override + public String toString() + { + return "AuxiliaryData{" + + "tagName='" + tagName + '\'' + + ", enabled=" + enabled + + ", data='" + data + '\'' + + '}'; + } +} diff --git a/shongo-controller/src/main/java/cz/cesnet/shongo/controller/booking/request/AbstractReservationRequest.java b/shongo-controller/src/main/java/cz/cesnet/shongo/controller/booking/request/AbstractReservationRequest.java index 80f99a5af..630f7407f 100644 --- a/shongo-controller/src/main/java/cz/cesnet/shongo/controller/booking/request/AbstractReservationRequest.java +++ b/shongo-controller/src/main/java/cz/cesnet/shongo/controller/booking/request/AbstractReservationRequest.java @@ -1,5 +1,8 @@ package cz.cesnet.shongo.controller.booking.request; +import com.fasterxml.jackson.core.JsonProcessingException; +import com.fasterxml.jackson.core.type.TypeReference; +import com.fasterxml.jackson.databind.ObjectMapper; import cz.cesnet.shongo.CommonReportSet; import cz.cesnet.shongo.PersistentObject; import cz.cesnet.shongo.TodoImplementException; @@ -9,9 +12,11 @@ import cz.cesnet.shongo.controller.ObjectType; import cz.cesnet.shongo.controller.ReservationRequestPurpose; import cz.cesnet.shongo.controller.ReservationRequestReusement; +import cz.cesnet.shongo.controller.api.AuxiliaryData; import cz.cesnet.shongo.controller.api.Controller; import cz.cesnet.shongo.controller.booking.Allocation; import cz.cesnet.shongo.controller.booking.ObjectIdentifier; +import cz.cesnet.shongo.controller.booking.request.auxdata.AuxData; import cz.cesnet.shongo.controller.booking.resource.Resource; import cz.cesnet.shongo.controller.booking.resource.Tag; import cz.cesnet.shongo.controller.booking.specification.Specification; @@ -28,7 +33,9 @@ import javax.persistence.*; import java.util.HashMap; +import java.util.List; import java.util.Map; +import java.util.stream.Collectors; /** * Represents a base class for all reservation requests which contains common attributes. @@ -40,6 +47,10 @@ @Inheritance(strategy = InheritanceType.JOINED) public abstract class AbstractReservationRequest extends PersistentObject implements ReportableSimple { + + @Transient + private final ObjectMapper objectMapper = new ObjectMapper(); + /** * Date/time when the {@link AbstractReservationRequest} was created. */ @@ -403,6 +414,18 @@ public String getAuxData() return auxData; } + /** + * @return {@link #auxData} + */ + @Transient + public List getAuxDataList() throws JsonProcessingException + { + if (auxData == null) { + return null; + } + return objectMapper.readValue(getAuxData(), new TypeReference<>(){}); + } + /** * @param auxData sets the {@link #auxData} */ @@ -411,6 +434,19 @@ public void setAuxData(String auxData) this.auxData = auxData; } + /** + * @param auxDataApi sets the {@link #auxData} + */ + public void setAuxData(List auxDataApi) + { + List auxData = auxDataApi.stream().map(AuxData::fromApi).collect(Collectors.toList()); + try { + setAuxData(objectMapper.writeValueAsString(auxData)); + } catch (JsonProcessingException e) { + throw new RuntimeException(e); + } + } + /** * Validate {@link AbstractReservationRequest}. * @@ -577,7 +613,12 @@ protected void toApi(cz.cesnet.shongo.controller.api.AbstractReservationRequest ObjectIdentifier.formatId(reusedAllocation.getReservationRequest()), reusedAllocationMandatory); } api.setReusement(getReusement()); - api.setAuxData(getAuxData()); + try { + api.setAuxData(getAuxDataList().stream().map(AuxData::toApi).collect(Collectors.toList())); + } catch (JsonProcessingException e) { + throw new RuntimeException(e); + } catch (NullPointerException ignored) { + } // Reservation request is deleted if (state.equals(State.DELETED)) { diff --git a/shongo-controller/src/main/java/cz/cesnet/shongo/controller/booking/request/auxdata/AuxData.java b/shongo-controller/src/main/java/cz/cesnet/shongo/controller/booking/request/auxdata/AuxData.java index 5abf133e3..9e594d3d3 100644 --- a/shongo-controller/src/main/java/cz/cesnet/shongo/controller/booking/request/auxdata/AuxData.java +++ b/shongo-controller/src/main/java/cz/cesnet/shongo/controller/booking/request/auxdata/AuxData.java @@ -13,13 +13,6 @@ public AuxData() { } - public AuxData(String tagName, boolean enabled, JsonNode data) - { - this.tagName = tagName; - this.enabled = enabled; - this.data = data; - } - public String getTagName() { return tagName; @@ -59,4 +52,22 @@ public String toString() ", data='" + data + '\'' + '}'; } + + public cz.cesnet.shongo.controller.api.AuxiliaryData toApi() + { + cz.cesnet.shongo.controller.api.AuxiliaryData api = new cz.cesnet.shongo.controller.api.AuxiliaryData(); + api.setTagName(getTagName()); + api.setEnabled(isEnabled()); + api.setData(getData()); + return api; + } + + public static AuxData fromApi(cz.cesnet.shongo.controller.api.AuxiliaryData api) + { + AuxData auxData = new AuxData(); + auxData.setTagName(api.getTagName()); + auxData.setEnabled(api.isEnabled()); + auxData.setData(api.getDataAsJsonNode()); + return auxData; + } } diff --git a/shongo-controller/src/main/java/cz/cesnet/shongo/controller/booking/request/auxdata/AuxDataService.java b/shongo-controller/src/main/java/cz/cesnet/shongo/controller/booking/request/auxdata/AuxDataService.java index 6b8658f92..daf88484d 100644 --- a/shongo-controller/src/main/java/cz/cesnet/shongo/controller/booking/request/auxdata/AuxDataService.java +++ b/shongo-controller/src/main/java/cz/cesnet/shongo/controller/booking/request/auxdata/AuxDataService.java @@ -1,9 +1,6 @@ package cz.cesnet.shongo.controller.booking.request.auxdata; import com.fasterxml.jackson.core.JsonProcessingException; -import com.fasterxml.jackson.core.type.TypeReference; -import com.fasterxml.jackson.databind.ObjectMapper; -import cz.cesnet.shongo.TodoImplementException; import cz.cesnet.shongo.controller.booking.request.AbstractReservationRequest; import cz.cesnet.shongo.controller.booking.request.auxdata.tagdata.TagData; import cz.cesnet.shongo.controller.booking.resource.Resource; @@ -25,8 +22,6 @@ public class AuxDataService private static final Logger logger = LoggerFactory.getLogger(AuxDataService.class); - private static final ObjectMapper objectMapper = new ObjectMapper(); - public static > List getTagData( AbstractReservationRequest reservationRequest, AuxDataFilter filter, EntityManager entityManager @@ -50,9 +45,12 @@ private static List> getAllTagData( throw new AuxDataException("AuxData is null"); } - List auxData = objectMapper.readValue(reservationRequest.getAuxData(), new TypeReference<>() {}); + List auxData = reservationRequest.getAuxDataList(); Resource resource = getResource(reservationRequest); + if (resource == null) { + throw new AuxDataException("Resource is null"); + } List resourceTags = new ResourceManager(entityManager).getResourceTags(resource); List> tagData = new ArrayList<>(); @@ -66,7 +64,7 @@ private static List> getAllTagData( return tagData; } - private static Resource getResource(AbstractReservationRequest reservationRequest) + private static Resource getResource(AbstractReservationRequest reservationRequest) throws AuxDataException { Specification specification = reservationRequest.getSpecification(); if (specification instanceof ResourceSpecification) { @@ -75,8 +73,7 @@ private static Resource getResource(AbstractReservationRequest reservationReques else if (specification instanceof RoomSpecification) { return ((RoomSpecification) specification).getDeviceResource(); } - else { - throw new TodoImplementException(specification.getClass()); - } + throw new AuxDataException(String.format("Specification: %s does not have a resource (so neither tags)", + specification.getClass())); } } diff --git a/shongo-controller/src/test/java/cz/cesnet/shongo/controller/booking/request/ReservationRequestModificationTest.java b/shongo-controller/src/test/java/cz/cesnet/shongo/controller/booking/request/ReservationRequestModificationTest.java index ec996996e..d766573e9 100644 --- a/shongo-controller/src/test/java/cz/cesnet/shongo/controller/booking/request/ReservationRequestModificationTest.java +++ b/shongo-controller/src/test/java/cz/cesnet/shongo/controller/booking/request/ReservationRequestModificationTest.java @@ -1,8 +1,5 @@ package cz.cesnet.shongo.controller.booking.request; -import com.fasterxml.jackson.core.JsonProcessingException; -import com.fasterxml.jackson.databind.ObjectMapper; -import com.fasterxml.jackson.databind.node.ArrayNode; import cz.cesnet.shongo.AliasType; import cz.cesnet.shongo.Technology; import cz.cesnet.shongo.api.Alias; @@ -11,18 +8,14 @@ import cz.cesnet.shongo.controller.ReservationRequestPurpose; import cz.cesnet.shongo.controller.ReservationRequestReusement; import cz.cesnet.shongo.controller.api.*; -import cz.cesnet.shongo.controller.api.AbstractReservationRequest; +import cz.cesnet.shongo.controller.api.AuxiliaryData; import cz.cesnet.shongo.controller.api.ReservationRequest; -import cz.cesnet.shongo.controller.api.ReservationRequestSet; import cz.cesnet.shongo.controller.api.rpc.ReservationService; -import cz.cesnet.shongo.controller.booking.datetime.AbsoluteDateTimeSlot; -import cz.cesnet.shongo.controller.booking.request.auxdata.AuxData; import org.joda.time.Interval; import org.junit.Assert; import org.junit.Test; import java.util.List; -import java.util.Locale; /** * Tests for reallocation of reservations. @@ -32,21 +25,13 @@ public class ReservationRequestModificationTest extends AbstractControllerTest { - private final ObjectMapper objectMapper = new ObjectMapper(); - @Test - public void testModifyAttributes() throws JsonProcessingException { + public void testModifyAttributes() { Resource resource = new Resource(); resource.setName("resource"); resource.setAllocatable(true); String resourceId = createResource(resource); - ArrayNode data = objectMapper.createArrayNode(); - data.add("karnis@cesnet.cz"); - data.add("filip.karnis@cesnet.cz"); - AuxData aux = new AuxData("test", true, data); - String auxData = objectMapper.writeValueAsString(aux); - ReservationRequest reservationRequest = new ReservationRequest(); reservationRequest.setDescription("request"); reservationRequest.setSlot("2012-01-01T12:00", "PT2H"); @@ -73,6 +58,11 @@ public void testModifyAttributes() throws JsonProcessingException { reservationRequestGet.setDescription("requestModified"); reservationRequestGet.setSpecification(new AliasSpecification(Technology.ADOBE_CONNECT)); reservationRequestGet.setReusement(ReservationRequestReusement.OWNED); + List auxData = List.of( + new AuxiliaryData("tag1", true, "[\"karnis@cenet.cz\", \"filip.karnis@cesnet.cz\"]"), + new AuxiliaryData("tag2", false, "[\"shouldnotbe@used\"]"), + new AuxiliaryData("tag3", true, null) + ); reservationRequestGet.setAuxData(auxData); reservationRequestGet.setSlot("2012-01-01T13:00", "PT1H"); From c5373c6b922989ec0c9c32ac4b8c4e44d5ef1ead Mon Sep 17 00:00:00 2001 From: Filip Karnis Date: Tue, 25 Jul 2023 19:27:43 +0200 Subject: [PATCH 08/20] add lombok dependency --- pom.xml | 10 ++++++++++ shongo-controller-api/pom.xml | 5 +++++ shongo-controller/pom.xml | 7 +++++++ 3 files changed, 22 insertions(+) diff --git a/pom.xml b/pom.xml index 457a53d6f..1d92be6f9 100644 --- a/pom.xml +++ b/pom.xml @@ -97,6 +97,16 @@ + + + + org.projectlombok + lombok + 1.18.22 + + + + diff --git a/shongo-controller-api/pom.xml b/shongo-controller-api/pom.xml index bce341e6b..0ebf28667 100644 --- a/shongo-controller-api/pom.xml +++ b/shongo-controller-api/pom.xml @@ -40,6 +40,11 @@ jackson-core 2.10.1 + + org.projectlombok + lombok + provided + diff --git a/shongo-controller/pom.xml b/shongo-controller/pom.xml index a3266ef6b..79cf72936 100644 --- a/shongo-controller/pom.xml +++ b/shongo-controller/pom.xml @@ -201,6 +201,13 @@ ical4j-zoneinfo-outlook 1.0.3 + + + + org.projectlombok + lombok + provided + From bf8d92436600333af2148ae179f22913026a8c4b Mon Sep 17 00:00:00 2001 From: Filip Karnis Date: Tue, 25 Jul 2023 19:42:58 +0200 Subject: [PATCH 09/20] use lombok --- .../shongo/controller/api/AuxiliaryData.java | 65 ++++--------------- .../booking/request/auxdata/AuxData.java | 46 +------------ .../request/auxdata/AuxDataFilter.java | 49 +------------- .../request/auxdata/tagdata/TagData.java | 38 +++-------- 4 files changed, 25 insertions(+), 173 deletions(-) diff --git a/shongo-controller-api/src/main/java/cz/cesnet/shongo/controller/api/AuxiliaryData.java b/shongo-controller-api/src/main/java/cz/cesnet/shongo/controller/api/AuxiliaryData.java index b520cd331..d61a59e23 100644 --- a/shongo-controller-api/src/main/java/cz/cesnet/shongo/controller/api/AuxiliaryData.java +++ b/shongo-controller-api/src/main/java/cz/cesnet/shongo/controller/api/AuxiliaryData.java @@ -6,9 +6,14 @@ import com.fasterxml.jackson.databind.ObjectMapper; import cz.cesnet.shongo.api.AbstractComplexType; import cz.cesnet.shongo.api.DataMap; - -import java.util.Objects; - +import lombok.Data; +import lombok.EqualsAndHashCode; +import lombok.NoArgsConstructor; +import lombok.ToString; + +@Data +@NoArgsConstructor +@EqualsAndHashCode(callSuper = false) public class AuxiliaryData extends AbstractComplexType { @@ -16,12 +21,10 @@ public class AuxiliaryData extends AbstractComplexType private String tagName; private boolean enabled; + @ToString.Exclude + @EqualsAndHashCode.Exclude private String data = objectMapper.nullNode().toString(); - public AuxiliaryData() - { - } - public AuxiliaryData(String tagName, boolean enabled, String data) { setTagName(tagName); @@ -29,32 +32,14 @@ public AuxiliaryData(String tagName, boolean enabled, String data) setData(data); } - public String getTagName() - { - return tagName; - } - - public void setTagName(String tagName) - { - this.tagName = tagName; - } - - public boolean isEnabled() - { - return enabled; - } - - public void setEnabled(boolean enabled) - { - this.enabled = enabled; - } - public String getData() { return data; } @JsonIgnore + @ToString.Include(name = "data") + @EqualsAndHashCode.Include public JsonNode getDataAsJsonNode() { if (data == null) { @@ -111,30 +96,4 @@ public void fromData(DataMap dataMap) enabled = dataMap.getBoolean("enabled"); data = dataMap.getString("data"); } - - @Override - public boolean equals(Object o) - { - if (this == o) return true; - if (o == null || getClass() != o.getClass()) return false; - AuxiliaryData auxData = (AuxiliaryData) o; - return enabled == auxData.enabled && Objects.equals(tagName, auxData.tagName) && - Objects.equals(getDataAsJsonNode(), auxData.getDataAsJsonNode()); - } - - @Override - public int hashCode() - { - return Objects.hash(tagName, enabled, data); - } - - @Override - public String toString() - { - return "AuxiliaryData{" + - "tagName='" + tagName + '\'' + - ", enabled=" + enabled + - ", data='" + data + '\'' + - '}'; - } } diff --git a/shongo-controller/src/main/java/cz/cesnet/shongo/controller/booking/request/auxdata/AuxData.java b/shongo-controller/src/main/java/cz/cesnet/shongo/controller/booking/request/auxdata/AuxData.java index 9e594d3d3..fcc352427 100644 --- a/shongo-controller/src/main/java/cz/cesnet/shongo/controller/booking/request/auxdata/AuxData.java +++ b/shongo-controller/src/main/java/cz/cesnet/shongo/controller/booking/request/auxdata/AuxData.java @@ -1,7 +1,9 @@ package cz.cesnet.shongo.controller.booking.request.auxdata; import com.fasterxml.jackson.databind.JsonNode; +import lombok.Data; +@Data public class AuxData { @@ -9,50 +11,6 @@ public class AuxData private boolean enabled; private JsonNode data; - public AuxData() - { - } - - public String getTagName() - { - return tagName; - } - - public void setTagName(String tagName) - { - this.tagName = tagName; - } - - public boolean isEnabled() - { - return enabled; - } - - public void setEnabled(boolean enabled) - { - this.enabled = enabled; - } - - public JsonNode getData() - { - return data; - } - - public void setData(JsonNode data) - { - this.data = data; - } - - @Override - public String toString() - { - return "AuxData{" + - "tag='" + tagName + '\'' + - ", enabled=" + enabled + - ", data='" + data + '\'' + - '}'; - } - public cz.cesnet.shongo.controller.api.AuxiliaryData toApi() { cz.cesnet.shongo.controller.api.AuxiliaryData api = new cz.cesnet.shongo.controller.api.AuxiliaryData(); diff --git a/shongo-controller/src/main/java/cz/cesnet/shongo/controller/booking/request/auxdata/AuxDataFilter.java b/shongo-controller/src/main/java/cz/cesnet/shongo/controller/booking/request/auxdata/AuxDataFilter.java index 86ac3593d..57977b045 100644 --- a/shongo-controller/src/main/java/cz/cesnet/shongo/controller/booking/request/auxdata/AuxDataFilter.java +++ b/shongo-controller/src/main/java/cz/cesnet/shongo/controller/booking/request/auxdata/AuxDataFilter.java @@ -1,7 +1,9 @@ package cz.cesnet.shongo.controller.booking.request.auxdata; import cz.cesnet.shongo.controller.api.TagType; +import lombok.Builder; +@Builder public class AuxDataFilter { @@ -9,18 +11,6 @@ public class AuxDataFilter private final TagType tagType; private final Boolean enabled; - private AuxDataFilter(String tagName, TagType tagType, boolean enabled) - { - this.tagName = tagName; - this.tagType = tagType; - this.enabled = enabled; - } - - public static Builder builder() - { - return new Builder(); - } - public String getTagName() { return tagName; @@ -35,39 +25,4 @@ public Boolean isEnabled() { return enabled; } - - public static class Builder - { - - private String tagName; - private TagType tagType; - private boolean enabled; - - private Builder() - { - } - - public Builder tagName(String tagName) - { - this.tagName = tagName; - return this; - } - - public Builder tagType(TagType tagType) - { - this.tagType = tagType; - return this; - } - - public Builder enabled(boolean enabled) - { - this.enabled = enabled; - return this; - } - - public AuxDataFilter build() - { - return new AuxDataFilter(tagName, tagType, enabled); - } - } } diff --git a/shongo-controller/src/main/java/cz/cesnet/shongo/controller/booking/request/auxdata/tagdata/TagData.java b/shongo-controller/src/main/java/cz/cesnet/shongo/controller/booking/request/auxdata/tagdata/TagData.java index 7abb5c8f9..30a3af142 100644 --- a/shongo-controller/src/main/java/cz/cesnet/shongo/controller/booking/request/auxdata/tagdata/TagData.java +++ b/shongo-controller/src/main/java/cz/cesnet/shongo/controller/booking/request/auxdata/tagdata/TagData.java @@ -4,33 +4,21 @@ import cz.cesnet.shongo.controller.booking.request.auxdata.AuxData; import cz.cesnet.shongo.controller.booking.request.auxdata.AuxDataFilter; import cz.cesnet.shongo.controller.booking.resource.Tag; -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; - +import lombok.Getter; +import lombok.RequiredArgsConstructor; +import lombok.ToString; +import lombok.extern.slf4j.Slf4j; + +@Slf4j +@Getter +@ToString +@RequiredArgsConstructor public abstract class TagData { - protected static Logger logger = LoggerFactory.getLogger(TagData.class); - protected final Tag tag; protected final AuxData aux; - public TagData(Tag tag, AuxData aux) - { - this.tag = tag; - this.aux = aux; - } - - public Tag getTag() - { - return tag; - } - - public AuxData getAuxData() - { - return aux; - } - public abstract T getData(); public static TagData create(Tag tag, AuxData auxData) @@ -64,12 +52,4 @@ public boolean filter(AuxDataFilter filter) } return true; } - - @Override - public String toString() { - return "TagData{" + - "tag=" + tag + - ", aux=" + aux + - '}'; - } } From 474de5e554b17dcdec75412b279052fc23dfaace Mon Sep 17 00:00:00 2001 From: Filip Karnis Date: Tue, 25 Jul 2023 20:06:56 +0200 Subject: [PATCH 10/20] use lombok 2 --- .../booking/request/auxdata/AuxDataFilter.java | 17 ++--------------- .../booking/request/auxdata/AuxDataService.java | 4 ---- .../request/auxdata/tagdata/TagData.java | 4 ++-- 3 files changed, 4 insertions(+), 21 deletions(-) diff --git a/shongo-controller/src/main/java/cz/cesnet/shongo/controller/booking/request/auxdata/AuxDataFilter.java b/shongo-controller/src/main/java/cz/cesnet/shongo/controller/booking/request/auxdata/AuxDataFilter.java index 57977b045..9c03fea12 100644 --- a/shongo-controller/src/main/java/cz/cesnet/shongo/controller/booking/request/auxdata/AuxDataFilter.java +++ b/shongo-controller/src/main/java/cz/cesnet/shongo/controller/booking/request/auxdata/AuxDataFilter.java @@ -2,7 +2,9 @@ import cz.cesnet.shongo.controller.api.TagType; import lombok.Builder; +import lombok.Getter; +@Getter @Builder public class AuxDataFilter { @@ -10,19 +12,4 @@ public class AuxDataFilter private final String tagName; private final TagType tagType; private final Boolean enabled; - - public String getTagName() - { - return tagName; - } - - public TagType getTagType() - { - return tagType; - } - - public Boolean isEnabled() - { - return enabled; - } } diff --git a/shongo-controller/src/main/java/cz/cesnet/shongo/controller/booking/request/auxdata/AuxDataService.java b/shongo-controller/src/main/java/cz/cesnet/shongo/controller/booking/request/auxdata/AuxDataService.java index daf88484d..6b27c9f30 100644 --- a/shongo-controller/src/main/java/cz/cesnet/shongo/controller/booking/request/auxdata/AuxDataService.java +++ b/shongo-controller/src/main/java/cz/cesnet/shongo/controller/booking/request/auxdata/AuxDataService.java @@ -9,8 +9,6 @@ import cz.cesnet.shongo.controller.booking.resource.Tag; import cz.cesnet.shongo.controller.booking.room.RoomSpecification; import cz.cesnet.shongo.controller.booking.specification.Specification; -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; import javax.persistence.EntityManager; import java.util.ArrayList; @@ -20,8 +18,6 @@ public class AuxDataService { - private static final Logger logger = LoggerFactory.getLogger(AuxDataService.class); - public static > List getTagData( AbstractReservationRequest reservationRequest, AuxDataFilter filter, EntityManager entityManager diff --git a/shongo-controller/src/main/java/cz/cesnet/shongo/controller/booking/request/auxdata/tagdata/TagData.java b/shongo-controller/src/main/java/cz/cesnet/shongo/controller/booking/request/auxdata/tagdata/TagData.java index 30a3af142..df8221982 100644 --- a/shongo-controller/src/main/java/cz/cesnet/shongo/controller/booking/request/auxdata/tagdata/TagData.java +++ b/shongo-controller/src/main/java/cz/cesnet/shongo/controller/booking/request/auxdata/tagdata/TagData.java @@ -45,8 +45,8 @@ public boolean filter(AuxDataFilter filter) return false; } } - if (filter.isEnabled() != null) { - if (!filter.isEnabled().equals(aux.isEnabled())) { + if (filter.getEnabled() != null) { + if (!filter.getEnabled().equals(aux.isEnabled())) { return false; } } From 455186baaf9d5e057b09a0ad0223034229a01a31 Mon Sep 17 00:00:00 2001 From: Filip Karnis Date: Fri, 28 Jul 2023 21:41:55 +0200 Subject: [PATCH 11/20] add default value to auxData --- shongo-deployment/migrations/2023-02-24/migration.sql | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/shongo-deployment/migrations/2023-02-24/migration.sql b/shongo-deployment/migrations/2023-02-24/migration.sql index 4eca33f3e..5444f336e 100644 --- a/shongo-deployment/migrations/2023-02-24/migration.sql +++ b/shongo-deployment/migrations/2023-02-24/migration.sql @@ -3,6 +3,6 @@ */ BEGIN TRANSACTION; -ALTER TABLE abstract_reservation_request ADD COLUMN aux_data jsonb; +ALTER TABLE abstract_reservation_request ADD COLUMN aux_data jsonb DEFAULT '[]'::jsonb NOT NULL; COMMIT TRANSACTION; From 6b60d23f1a7ea23931fad5197683b367f415f471 Mon Sep 17 00:00:00 2001 From: Filip Karnis Date: Fri, 28 Jul 2023 22:01:19 +0200 Subject: [PATCH 12/20] merge aux data with tag data in sql query --- .../AbstractReservationRequestAuxData.java | 30 +++++++++ .../request/ReservationRequestManager.java | 28 +++++++++ .../request/auxdata/AuxDataException.java | 15 ----- .../request/auxdata/AuxDataService.java | 62 ++++++------------- .../auxdata/tagdata/AuxDataMerged.java | 20 ++++++ .../notification/ReservationNotification.java | 13 +--- .../main/resources/sql/postgresql/init.sql | 9 +++ 7 files changed, 107 insertions(+), 70 deletions(-) create mode 100644 shongo-controller/src/main/java/cz/cesnet/shongo/controller/booking/request/AbstractReservationRequestAuxData.java delete mode 100644 shongo-controller/src/main/java/cz/cesnet/shongo/controller/booking/request/auxdata/AuxDataException.java create mode 100644 shongo-controller/src/main/java/cz/cesnet/shongo/controller/booking/request/auxdata/tagdata/AuxDataMerged.java diff --git a/shongo-controller/src/main/java/cz/cesnet/shongo/controller/booking/request/AbstractReservationRequestAuxData.java b/shongo-controller/src/main/java/cz/cesnet/shongo/controller/booking/request/AbstractReservationRequestAuxData.java new file mode 100644 index 000000000..92ebe267b --- /dev/null +++ b/shongo-controller/src/main/java/cz/cesnet/shongo/controller/booking/request/AbstractReservationRequestAuxData.java @@ -0,0 +1,30 @@ +package cz.cesnet.shongo.controller.booking.request; + +import com.fasterxml.jackson.databind.JsonNode; +import cz.cesnet.shongo.controller.booking.specification.Specification; +import lombok.Getter; +import lombok.Setter; +import org.hibernate.annotations.Immutable; +import org.hibernate.annotations.Type; + +import javax.persistence.*; + +@Getter +@Setter +@Entity +@Immutable +@Table(name = "arr_aux_data") +public class AbstractReservationRequestAuxData +{ + + @Id + private Long id; + + private String tagName; + private Boolean enabled; + @Type(type = "jsonb") + @Column(columnDefinition = "text") + private JsonNode data; + @ManyToOne(cascade = CascadeType.ALL, optional = false, fetch = FetchType.LAZY) + private Specification specification; +} diff --git a/shongo-controller/src/main/java/cz/cesnet/shongo/controller/booking/request/ReservationRequestManager.java b/shongo-controller/src/main/java/cz/cesnet/shongo/controller/booking/request/ReservationRequestManager.java index 1b657cbac..31b28ad2c 100644 --- a/shongo-controller/src/main/java/cz/cesnet/shongo/controller/booking/request/ReservationRequestManager.java +++ b/shongo-controller/src/main/java/cz/cesnet/shongo/controller/booking/request/ReservationRequestManager.java @@ -1,8 +1,10 @@ package cz.cesnet.shongo.controller.booking.request; +import com.fasterxml.jackson.databind.JsonNode; import cz.cesnet.shongo.AbstractManager; import cz.cesnet.shongo.CommonReportSet; import cz.cesnet.shongo.controller.ControllerReportSetHelper; +import cz.cesnet.shongo.controller.api.TagType; import cz.cesnet.shongo.controller.authorization.AuthorizationManager; import cz.cesnet.shongo.controller.booking.Allocation; import cz.cesnet.shongo.controller.booking.compartment.CompartmentSpecification; @@ -10,6 +12,7 @@ import cz.cesnet.shongo.controller.booking.participant.InvitedPersonParticipant; import cz.cesnet.shongo.controller.booking.participant.AbstractParticipant; import cz.cesnet.shongo.controller.booking.participant.PersonParticipant; +import cz.cesnet.shongo.controller.booking.request.auxdata.tagdata.AuxDataMerged; import cz.cesnet.shongo.controller.booking.specification.Specification; import cz.cesnet.shongo.controller.booking.reservation.Reservation; import cz.cesnet.shongo.controller.booking.reservation.ReservationManager; @@ -20,6 +23,7 @@ import javax.persistence.EntityManager; import javax.persistence.NoResultException; import java.util.*; +import java.util.stream.Collectors; /** * Manager for {@link AbstractReservationRequest}. @@ -635,4 +639,28 @@ public List detachReports(ReservationRequest reservationRequest reservationRequest.clearReports(); return reports; } + + public List getAllAuxData(AbstractReservationRequest reservationRequest) + { + return entityManager.createQuery( + "SELECT arr.tagName, rt.tag.type, arr.enabled, arr.data, rt.tag.data" + + " FROM AbstractReservationRequestAuxData arr" + + " JOIN ResourceSpecification res_spec ON res_spec.id = arr.specification.id" + + " JOIN ResourceTag rt ON rt.resource.id = res_spec.resource.id" + + " WHERE rt.tag.name = arr.tagName AND arr.id = :id", + Object[].class) + .setParameter("id", reservationRequest.getId()) + .getResultList() + .stream() + .map(record -> { + AuxDataMerged auxDataMerged = new AuxDataMerged(); + auxDataMerged.setTagName((String) record[0]); + auxDataMerged.setType((TagType) record[1]); + auxDataMerged.setEnabled((Boolean) record[2]); + auxDataMerged.setAuxData((JsonNode) record[3]); + auxDataMerged.setData((JsonNode) record[4]); + return auxDataMerged; + }) + .collect(Collectors.toList()); + } } diff --git a/shongo-controller/src/main/java/cz/cesnet/shongo/controller/booking/request/auxdata/AuxDataException.java b/shongo-controller/src/main/java/cz/cesnet/shongo/controller/booking/request/auxdata/AuxDataException.java deleted file mode 100644 index feb1363f1..000000000 --- a/shongo-controller/src/main/java/cz/cesnet/shongo/controller/booking/request/auxdata/AuxDataException.java +++ /dev/null @@ -1,15 +0,0 @@ -package cz.cesnet.shongo.controller.booking.request.auxdata; - -public class AuxDataException extends Exception -{ - - public AuxDataException(String message) - { - super(message); - } - - public AuxDataException(String message, Throwable cause) - { - super(message, cause); - } -} diff --git a/shongo-controller/src/main/java/cz/cesnet/shongo/controller/booking/request/auxdata/AuxDataService.java b/shongo-controller/src/main/java/cz/cesnet/shongo/controller/booking/request/auxdata/AuxDataService.java index 6b27c9f30..8851d0890 100644 --- a/shongo-controller/src/main/java/cz/cesnet/shongo/controller/booking/request/auxdata/AuxDataService.java +++ b/shongo-controller/src/main/java/cz/cesnet/shongo/controller/booking/request/auxdata/AuxDataService.java @@ -1,17 +1,11 @@ package cz.cesnet.shongo.controller.booking.request.auxdata; -import com.fasterxml.jackson.core.JsonProcessingException; import cz.cesnet.shongo.controller.booking.request.AbstractReservationRequest; +import cz.cesnet.shongo.controller.booking.request.ReservationRequestManager; import cz.cesnet.shongo.controller.booking.request.auxdata.tagdata.TagData; -import cz.cesnet.shongo.controller.booking.resource.Resource; -import cz.cesnet.shongo.controller.booking.resource.ResourceManager; -import cz.cesnet.shongo.controller.booking.resource.ResourceSpecification; import cz.cesnet.shongo.controller.booking.resource.Tag; -import cz.cesnet.shongo.controller.booking.room.RoomSpecification; -import cz.cesnet.shongo.controller.booking.specification.Specification; import javax.persistence.EntityManager; -import java.util.ArrayList; import java.util.List; import java.util.stream.Collectors; @@ -21,7 +15,7 @@ public class AuxDataService public static > List getTagData( AbstractReservationRequest reservationRequest, AuxDataFilter filter, EntityManager entityManager - ) throws AuxDataException, JsonProcessingException + ) { List> tagData = getAllTagData(reservationRequest, entityManager); @@ -35,41 +29,23 @@ public static > List getTagData( private static List> getAllTagData( AbstractReservationRequest reservationRequest, EntityManager entityManager - ) throws AuxDataException, JsonProcessingException + ) { - if (reservationRequest.getAuxData() == null) { - throw new AuxDataException("AuxData is null"); - } - - List auxData = reservationRequest.getAuxDataList(); - - Resource resource = getResource(reservationRequest); - if (resource == null) { - throw new AuxDataException("Resource is null"); - } - List resourceTags = new ResourceManager(entityManager).getResourceTags(resource); - - List> tagData = new ArrayList<>(); - for (Tag tag : resourceTags) { - for (AuxData auxData1 : auxData) { - if (auxData1.getTagName().equals(tag.getName())) { - tagData.add(TagData.create(tag, auxData1)); - } - } - } - return tagData; - } - - private static Resource getResource(AbstractReservationRequest reservationRequest) throws AuxDataException - { - Specification specification = reservationRequest.getSpecification(); - if (specification instanceof ResourceSpecification) { - return ((ResourceSpecification) specification).getResource(); - } - else if (specification instanceof RoomSpecification) { - return ((RoomSpecification) specification).getDeviceResource(); - } - throw new AuxDataException(String.format("Specification: %s does not have a resource (so neither tags)", - specification.getClass())); + ReservationRequestManager reservationRequestManager = new ReservationRequestManager(entityManager); + return reservationRequestManager.getAllAuxData(reservationRequest) + .stream() + .map(auxDataMerged -> { + Tag tag = new Tag(); + tag.setName(auxDataMerged.getTagName()); + tag.setType(auxDataMerged.getType()); + tag.setData(auxDataMerged.getData()); + + AuxData auxData = new AuxData(); + auxData.setTagName(auxDataMerged.getTagName()); + auxData.setEnabled(auxDataMerged.getEnabled()); + auxData.setData(auxDataMerged.getAuxData()); + + return TagData.create(tag, auxData); + }).collect(Collectors.toList()); } } diff --git a/shongo-controller/src/main/java/cz/cesnet/shongo/controller/booking/request/auxdata/tagdata/AuxDataMerged.java b/shongo-controller/src/main/java/cz/cesnet/shongo/controller/booking/request/auxdata/tagdata/AuxDataMerged.java new file mode 100644 index 000000000..23dfac9fc --- /dev/null +++ b/shongo-controller/src/main/java/cz/cesnet/shongo/controller/booking/request/auxdata/tagdata/AuxDataMerged.java @@ -0,0 +1,20 @@ +package cz.cesnet.shongo.controller.booking.request.auxdata.tagdata; + +import com.fasterxml.jackson.databind.JsonNode; +import cz.cesnet.shongo.controller.api.TagType; +import lombok.AllArgsConstructor; +import lombok.Data; +import lombok.NoArgsConstructor; + +@Data +@NoArgsConstructor +@AllArgsConstructor +public class AuxDataMerged +{ + + private String tagName; + private TagType type; + private Boolean enabled; + private JsonNode data; + private JsonNode auxData; +} diff --git a/shongo-controller/src/main/java/cz/cesnet/shongo/controller/notification/ReservationNotification.java b/shongo-controller/src/main/java/cz/cesnet/shongo/controller/notification/ReservationNotification.java index 92e9083ae..365bf9f24 100644 --- a/shongo-controller/src/main/java/cz/cesnet/shongo/controller/notification/ReservationNotification.java +++ b/shongo-controller/src/main/java/cz/cesnet/shongo/controller/notification/ReservationNotification.java @@ -1,7 +1,6 @@ package cz.cesnet.shongo.controller.notification; -import com.fasterxml.jackson.core.JsonProcessingException; import cz.cesnet.shongo.AliasType; import cz.cesnet.shongo.PersonInformation; import cz.cesnet.shongo.TodoImplementException; @@ -14,7 +13,6 @@ import cz.cesnet.shongo.controller.booking.ObjectIdentifier; import cz.cesnet.shongo.controller.booking.alias.Alias; import cz.cesnet.shongo.controller.booking.request.AbstractReservationRequest; -import cz.cesnet.shongo.controller.booking.request.auxdata.AuxDataException; import cz.cesnet.shongo.controller.booking.request.auxdata.AuxDataFilter; import cz.cesnet.shongo.controller.booking.request.auxdata.AuxDataService; import cz.cesnet.shongo.controller.booking.request.auxdata.tagdata.NotifyEmailAuxData; @@ -86,16 +84,7 @@ private void addRecipientsFromNotificationTags(AbstractReservationRequest reserv .enabled(true) .build(); - List notifyEmailAuxData; - try { - notifyEmailAuxData = AuxDataService.getTagData(reservationRequest, filter, entityManager); - } catch (JsonProcessingException e) { - logger.error("Error while parsing auxData", e); - return; - } catch (AuxDataException e) { - logger.warn("Error while getting notify email aux data for reservation request {}.", reservationRequest.getId(), e); - return; - } + List notifyEmailAuxData = AuxDataService.getTagData(reservationRequest, filter, entityManager); List tagPersonInformationList = notifyEmailAuxData .stream() diff --git a/shongo-controller/src/main/resources/sql/postgresql/init.sql b/shongo-controller/src/main/resources/sql/postgresql/init.sql index 760fb4fca..4b120d52c 100644 --- a/shongo-controller/src/main/resources/sql/postgresql/init.sql +++ b/shongo-controller/src/main/resources/sql/postgresql/init.sql @@ -13,6 +13,7 @@ DROP VIEW IF EXISTS reservation_request_earliest_usage; DROP VIEW IF EXISTS reservation_summary; DROP VIEW IF EXISTS executable_summary_view; DROP VIEW IF EXISTS room_endpoint_earliest_usage; +DROP VIEW IF EXISTS arr_aux_data; /** * Create missing foreign keys' indexes. @@ -541,3 +542,11 @@ ORDER BY executable.id, alias.id; CREATE TABLE executable_summary AS SELECT * FROM executable_summary_view; CREATE TABLE specification_summary AS SELECT * FROM specification_summary_view; + +CREATE VIEW arr_aux_data AS +SELECT + arr.*, + jsonb_array_elements(aux_data)->>'tagName' AS tag_name, + (jsonb_array_elements(aux_data)->>'enabled')::boolean AS enabled, + jsonb_array_elements(aux_data)->'data' AS data +FROM abstract_reservation_request arr; From b16f0ad49e2c321de957a7105a8479e37559eae2 Mon Sep 17 00:00:00 2001 From: Filip Karnis Date: Fri, 28 Jul 2023 22:08:53 +0200 Subject: [PATCH 13/20] use auxdatamerged directly --- .../request/ReservationRequestManager.java | 2 +- .../auxdata/{tagdata => }/AuxDataMerged.java | 2 +- .../request/auxdata/AuxDataService.java | 16 ++------------ .../auxdata/tagdata/NotifyEmailAuxData.java | 11 +++++----- .../auxdata/tagdata/ReservationAuxData.java | 7 +++--- .../request/auxdata/tagdata/TagData.java | 22 +++++++++---------- .../notification/ReservationNotification.java | 2 +- 7 files changed, 23 insertions(+), 39 deletions(-) rename shongo-controller/src/main/java/cz/cesnet/shongo/controller/booking/request/auxdata/{tagdata => }/AuxDataMerged.java (85%) diff --git a/shongo-controller/src/main/java/cz/cesnet/shongo/controller/booking/request/ReservationRequestManager.java b/shongo-controller/src/main/java/cz/cesnet/shongo/controller/booking/request/ReservationRequestManager.java index 31b28ad2c..a32796aa2 100644 --- a/shongo-controller/src/main/java/cz/cesnet/shongo/controller/booking/request/ReservationRequestManager.java +++ b/shongo-controller/src/main/java/cz/cesnet/shongo/controller/booking/request/ReservationRequestManager.java @@ -12,7 +12,7 @@ import cz.cesnet.shongo.controller.booking.participant.InvitedPersonParticipant; import cz.cesnet.shongo.controller.booking.participant.AbstractParticipant; import cz.cesnet.shongo.controller.booking.participant.PersonParticipant; -import cz.cesnet.shongo.controller.booking.request.auxdata.tagdata.AuxDataMerged; +import cz.cesnet.shongo.controller.booking.request.auxdata.AuxDataMerged; import cz.cesnet.shongo.controller.booking.specification.Specification; import cz.cesnet.shongo.controller.booking.reservation.Reservation; import cz.cesnet.shongo.controller.booking.reservation.ReservationManager; diff --git a/shongo-controller/src/main/java/cz/cesnet/shongo/controller/booking/request/auxdata/tagdata/AuxDataMerged.java b/shongo-controller/src/main/java/cz/cesnet/shongo/controller/booking/request/auxdata/AuxDataMerged.java similarity index 85% rename from shongo-controller/src/main/java/cz/cesnet/shongo/controller/booking/request/auxdata/tagdata/AuxDataMerged.java rename to shongo-controller/src/main/java/cz/cesnet/shongo/controller/booking/request/auxdata/AuxDataMerged.java index 23dfac9fc..799ffe5a3 100644 --- a/shongo-controller/src/main/java/cz/cesnet/shongo/controller/booking/request/auxdata/tagdata/AuxDataMerged.java +++ b/shongo-controller/src/main/java/cz/cesnet/shongo/controller/booking/request/auxdata/AuxDataMerged.java @@ -1,4 +1,4 @@ -package cz.cesnet.shongo.controller.booking.request.auxdata.tagdata; +package cz.cesnet.shongo.controller.booking.request.auxdata; import com.fasterxml.jackson.databind.JsonNode; import cz.cesnet.shongo.controller.api.TagType; diff --git a/shongo-controller/src/main/java/cz/cesnet/shongo/controller/booking/request/auxdata/AuxDataService.java b/shongo-controller/src/main/java/cz/cesnet/shongo/controller/booking/request/auxdata/AuxDataService.java index 8851d0890..b01bcefa7 100644 --- a/shongo-controller/src/main/java/cz/cesnet/shongo/controller/booking/request/auxdata/AuxDataService.java +++ b/shongo-controller/src/main/java/cz/cesnet/shongo/controller/booking/request/auxdata/AuxDataService.java @@ -3,7 +3,6 @@ import cz.cesnet.shongo.controller.booking.request.AbstractReservationRequest; import cz.cesnet.shongo.controller.booking.request.ReservationRequestManager; import cz.cesnet.shongo.controller.booking.request.auxdata.tagdata.TagData; -import cz.cesnet.shongo.controller.booking.resource.Tag; import javax.persistence.EntityManager; import java.util.List; @@ -34,18 +33,7 @@ private static List> getAllTagData( ReservationRequestManager reservationRequestManager = new ReservationRequestManager(entityManager); return reservationRequestManager.getAllAuxData(reservationRequest) .stream() - .map(auxDataMerged -> { - Tag tag = new Tag(); - tag.setName(auxDataMerged.getTagName()); - tag.setType(auxDataMerged.getType()); - tag.setData(auxDataMerged.getData()); - - AuxData auxData = new AuxData(); - auxData.setTagName(auxDataMerged.getTagName()); - auxData.setEnabled(auxDataMerged.getEnabled()); - auxData.setData(auxDataMerged.getAuxData()); - - return TagData.create(tag, auxData); - }).collect(Collectors.toList()); + .map(TagData::create) + .collect(Collectors.toList()); } } diff --git a/shongo-controller/src/main/java/cz/cesnet/shongo/controller/booking/request/auxdata/tagdata/NotifyEmailAuxData.java b/shongo-controller/src/main/java/cz/cesnet/shongo/controller/booking/request/auxdata/tagdata/NotifyEmailAuxData.java index d6a0bdeed..5f012f7f2 100644 --- a/shongo-controller/src/main/java/cz/cesnet/shongo/controller/booking/request/auxdata/tagdata/NotifyEmailAuxData.java +++ b/shongo-controller/src/main/java/cz/cesnet/shongo/controller/booking/request/auxdata/tagdata/NotifyEmailAuxData.java @@ -1,8 +1,7 @@ package cz.cesnet.shongo.controller.booking.request.auxdata.tagdata; import com.fasterxml.jackson.databind.JsonNode; -import cz.cesnet.shongo.controller.booking.request.auxdata.AuxData; -import cz.cesnet.shongo.controller.booking.resource.Tag; +import cz.cesnet.shongo.controller.booking.request.auxdata.AuxDataMerged; import java.util.ArrayList; import java.util.List; @@ -10,9 +9,9 @@ public class NotifyEmailAuxData extends TagData> { - public NotifyEmailAuxData(Tag tag, AuxData auxData) + public NotifyEmailAuxData(AuxDataMerged auxData) { - super(tag, auxData); + super(auxData); } @Override @@ -20,10 +19,10 @@ public List getData() { List emails = new ArrayList<>(); - for (JsonNode child : tag.getData()) { + for (JsonNode child : auxData.getAuxData()) { emails.add(child.asText()); } - for (JsonNode child : aux.getData()) { + for (JsonNode child : auxData.getData()) { emails.add(child.asText()); } return emails; diff --git a/shongo-controller/src/main/java/cz/cesnet/shongo/controller/booking/request/auxdata/tagdata/ReservationAuxData.java b/shongo-controller/src/main/java/cz/cesnet/shongo/controller/booking/request/auxdata/tagdata/ReservationAuxData.java index a19d5487b..b7d616fa7 100644 --- a/shongo-controller/src/main/java/cz/cesnet/shongo/controller/booking/request/auxdata/tagdata/ReservationAuxData.java +++ b/shongo-controller/src/main/java/cz/cesnet/shongo/controller/booking/request/auxdata/tagdata/ReservationAuxData.java @@ -1,15 +1,14 @@ package cz.cesnet.shongo.controller.booking.request.auxdata.tagdata; import cz.cesnet.shongo.TodoImplementException; -import cz.cesnet.shongo.controller.booking.request.auxdata.AuxData; -import cz.cesnet.shongo.controller.booking.resource.Tag; +import cz.cesnet.shongo.controller.booking.request.auxdata.AuxDataMerged; public class ReservationAuxData extends TagData { - public ReservationAuxData(Tag tag, AuxData auxData) + public ReservationAuxData(AuxDataMerged auxData) { - super(tag, auxData); + super(auxData); } @Override diff --git a/shongo-controller/src/main/java/cz/cesnet/shongo/controller/booking/request/auxdata/tagdata/TagData.java b/shongo-controller/src/main/java/cz/cesnet/shongo/controller/booking/request/auxdata/tagdata/TagData.java index df8221982..76e890a6b 100644 --- a/shongo-controller/src/main/java/cz/cesnet/shongo/controller/booking/request/auxdata/tagdata/TagData.java +++ b/shongo-controller/src/main/java/cz/cesnet/shongo/controller/booking/request/auxdata/tagdata/TagData.java @@ -1,9 +1,8 @@ package cz.cesnet.shongo.controller.booking.request.auxdata.tagdata; import cz.cesnet.shongo.TodoImplementException; -import cz.cesnet.shongo.controller.booking.request.auxdata.AuxData; import cz.cesnet.shongo.controller.booking.request.auxdata.AuxDataFilter; -import cz.cesnet.shongo.controller.booking.resource.Tag; +import cz.cesnet.shongo.controller.booking.request.auxdata.AuxDataMerged; import lombok.Getter; import lombok.RequiredArgsConstructor; import lombok.ToString; @@ -16,37 +15,36 @@ public abstract class TagData { - protected final Tag tag; - protected final AuxData aux; + protected final AuxDataMerged auxData; public abstract T getData(); - public static TagData create(Tag tag, AuxData auxData) + public static TagData create(AuxDataMerged auxData) { - switch (tag.getType()) { + switch (auxData.getType()) { case NOTIFY_EMAIL: - return new NotifyEmailAuxData(tag, auxData); + return new NotifyEmailAuxData(auxData); case RESERVATION_DATA: - return new ReservationAuxData(tag, auxData); + return new ReservationAuxData(auxData); default: - throw new TodoImplementException("Not implemented for tag type: " + tag.getType()); + throw new TodoImplementException("Not implemented for tag type: " + auxData.getType()); } } public boolean filter(AuxDataFilter filter) { if (filter.getTagName() != null) { - if (!filter.getTagName().equals(tag.getName())) { + if (!filter.getTagName().equals(auxData.getTagName())) { return false; } } if (filter.getTagType() != null) { - if (!filter.getTagType().equals(tag.getType())) { + if (!filter.getTagType().equals(auxData.getType())) { return false; } } if (filter.getEnabled() != null) { - if (!filter.getEnabled().equals(aux.isEnabled())) { + if (!filter.getEnabled().equals(auxData.getEnabled())) { return false; } } diff --git a/shongo-controller/src/main/java/cz/cesnet/shongo/controller/notification/ReservationNotification.java b/shongo-controller/src/main/java/cz/cesnet/shongo/controller/notification/ReservationNotification.java index 365bf9f24..2dde150e7 100644 --- a/shongo-controller/src/main/java/cz/cesnet/shongo/controller/notification/ReservationNotification.java +++ b/shongo-controller/src/main/java/cz/cesnet/shongo/controller/notification/ReservationNotification.java @@ -100,7 +100,7 @@ private Collection notifyEmailDataToPersonInformation(Noti return notifyEmailAuxData .getData() .stream() - .map(email -> new TagPersonInformation(notifyEmailAuxData.getTag().getName(), email)) + .map(email -> new TagPersonInformation(notifyEmailAuxData.getAuxData().getTagName(), email)) .collect(Collectors.toList()); } From 1f2dde4ed60f4e98302e5651740993cb630878d2 Mon Sep 17 00:00:00 2001 From: Filip Karnis Date: Fri, 28 Jul 2023 22:42:39 +0200 Subject: [PATCH 14/20] remove auxdata service --- .../request/ReservationRequestManager.java | 68 ++++++++++++++++--- .../request/auxdata/AuxDataService.java | 39 ----------- .../notification/ReservationNotification.java | 9 +-- 3 files changed, 64 insertions(+), 52 deletions(-) delete mode 100644 shongo-controller/src/main/java/cz/cesnet/shongo/controller/booking/request/auxdata/AuxDataService.java diff --git a/shongo-controller/src/main/java/cz/cesnet/shongo/controller/booking/request/ReservationRequestManager.java b/shongo-controller/src/main/java/cz/cesnet/shongo/controller/booking/request/ReservationRequestManager.java index a32796aa2..272f2a0b1 100644 --- a/shongo-controller/src/main/java/cz/cesnet/shongo/controller/booking/request/ReservationRequestManager.java +++ b/shongo-controller/src/main/java/cz/cesnet/shongo/controller/booking/request/ReservationRequestManager.java @@ -12,7 +12,9 @@ import cz.cesnet.shongo.controller.booking.participant.InvitedPersonParticipant; import cz.cesnet.shongo.controller.booking.participant.AbstractParticipant; import cz.cesnet.shongo.controller.booking.participant.PersonParticipant; +import cz.cesnet.shongo.controller.booking.request.auxdata.AuxDataFilter; import cz.cesnet.shongo.controller.booking.request.auxdata.AuxDataMerged; +import cz.cesnet.shongo.controller.booking.request.auxdata.tagdata.TagData; import cz.cesnet.shongo.controller.booking.specification.Specification; import cz.cesnet.shongo.controller.booking.reservation.Reservation; import cz.cesnet.shongo.controller.booking.reservation.ReservationManager; @@ -22,6 +24,7 @@ import javax.persistence.EntityManager; import javax.persistence.NoResultException; +import javax.persistence.TypedQuery; import java.util.*; import java.util.stream.Collectors; @@ -640,16 +643,63 @@ public List detachReports(ReservationRequest reservationRequest return reports; } - public List getAllAuxData(AbstractReservationRequest reservationRequest) + /** + * Creates {@link TagData} for given {@link AbstractReservationRequest} and its corresponding + * {@link cz.cesnet.shongo.controller.booking.resource.Tag}s. + * + * @param reservationRequest reservation request for which the {@link TagData} shall be created + * @param filter filter for data desired + * @return specific implementation of {@link TagData} based on {@link TagType} + * @param TagData implementation for corresponding {@link TagType} + */ + public > List getTagData(AbstractReservationRequest reservationRequest, AuxDataFilter filter) { - return entityManager.createQuery( - "SELECT arr.tagName, rt.tag.type, arr.enabled, arr.data, rt.tag.data" + - " FROM AbstractReservationRequestAuxData arr" + - " JOIN ResourceSpecification res_spec ON res_spec.id = arr.specification.id" + - " JOIN ResourceTag rt ON rt.resource.id = res_spec.resource.id" + - " WHERE rt.tag.name = arr.tagName AND arr.id = :id", - Object[].class) - .setParameter("id", reservationRequest.getId()) + return getAuxData(reservationRequest, filter) + .stream() + .map(TagData::create) + .map(data -> (T) data) + .collect(Collectors.toList()); + } + + /** + * Merge {@link cz.cesnet.shongo.controller.booking.request.auxdata.AuxData} from {@link AbstractReservationRequest} + * and data from its corresponding {@link cz.cesnet.shongo.controller.booking.resource.Tag}s. + * + * @param reservationRequest reservation request for which the data shall be merged + * @param filter filter for data desired + * @return merged data + */ + private List getAuxData(AbstractReservationRequest reservationRequest, AuxDataFilter filter) + { + String queryString = "SELECT arr.tagName, rt.tag.type, arr.enabled, arr.data, rt.tag.data" + + " FROM AbstractReservationRequestAuxData arr" + + " JOIN ResourceSpecification res_spec ON res_spec.id = arr.specification.id" + + " JOIN ResourceTag rt ON rt.resource.id = res_spec.resource.id" + + " WHERE rt.tag.name = arr.tagName" + + " AND arr.id = :id"; + if (filter.getTagName() != null) { + queryString += " AND rt.tag.name = :tagName"; + } + if (filter.getTagType() != null) { + queryString += " AND rt.tag.type = :type"; + } + if (filter.getEnabled() != null) { + queryString += " AND arr.enabled = :enabled"; + } + + TypedQuery query = entityManager.createQuery(queryString, Object[].class) + .setParameter("id", reservationRequest.getId()); + if (filter.getTagName() != null) { + query.setParameter("tagName", filter.getTagName()); + } + if (filter.getTagType() != null) { + query.setParameter("type", filter.getTagType()); + } + if (filter.getEnabled() != null) { + query.setParameter("enabled", filter.getEnabled()); + } + + return query .getResultList() .stream() .map(record -> { diff --git a/shongo-controller/src/main/java/cz/cesnet/shongo/controller/booking/request/auxdata/AuxDataService.java b/shongo-controller/src/main/java/cz/cesnet/shongo/controller/booking/request/auxdata/AuxDataService.java deleted file mode 100644 index b01bcefa7..000000000 --- a/shongo-controller/src/main/java/cz/cesnet/shongo/controller/booking/request/auxdata/AuxDataService.java +++ /dev/null @@ -1,39 +0,0 @@ -package cz.cesnet.shongo.controller.booking.request.auxdata; - -import cz.cesnet.shongo.controller.booking.request.AbstractReservationRequest; -import cz.cesnet.shongo.controller.booking.request.ReservationRequestManager; -import cz.cesnet.shongo.controller.booking.request.auxdata.tagdata.TagData; - -import javax.persistence.EntityManager; -import java.util.List; -import java.util.stream.Collectors; - -public class AuxDataService -{ - - public static > List getTagData( - AbstractReservationRequest reservationRequest, - AuxDataFilter filter, EntityManager entityManager - ) - { - List> tagData = getAllTagData(reservationRequest, entityManager); - - return tagData - .stream() - .filter(data -> data.filter(filter)) - .map(data -> (T) data) - .collect(Collectors.toList()); - } - - private static List> getAllTagData( - AbstractReservationRequest reservationRequest, - EntityManager entityManager - ) - { - ReservationRequestManager reservationRequestManager = new ReservationRequestManager(entityManager); - return reservationRequestManager.getAllAuxData(reservationRequest) - .stream() - .map(TagData::create) - .collect(Collectors.toList()); - } -} diff --git a/shongo-controller/src/main/java/cz/cesnet/shongo/controller/notification/ReservationNotification.java b/shongo-controller/src/main/java/cz/cesnet/shongo/controller/notification/ReservationNotification.java index 2dde150e7..f2b57dd5f 100644 --- a/shongo-controller/src/main/java/cz/cesnet/shongo/controller/notification/ReservationNotification.java +++ b/shongo-controller/src/main/java/cz/cesnet/shongo/controller/notification/ReservationNotification.java @@ -13,8 +13,8 @@ import cz.cesnet.shongo.controller.booking.ObjectIdentifier; import cz.cesnet.shongo.controller.booking.alias.Alias; import cz.cesnet.shongo.controller.booking.request.AbstractReservationRequest; +import cz.cesnet.shongo.controller.booking.request.ReservationRequestManager; import cz.cesnet.shongo.controller.booking.request.auxdata.AuxDataFilter; -import cz.cesnet.shongo.controller.booking.request.auxdata.AuxDataService; import cz.cesnet.shongo.controller.booking.request.auxdata.tagdata.NotifyEmailAuxData; import cz.cesnet.shongo.controller.booking.reservation.Reservation; import cz.cesnet.shongo.controller.booking.resource.Resource; @@ -55,6 +55,7 @@ private ReservationNotification(Reservation reservation, super(reservationRequest); EntityManager entityManager = authorizationManager.getEntityManager(); + ReservationRequestManager reservationRequestManager = new ReservationRequestManager(entityManager); String updatedBy = getReservationRequestUpdatedBy(); if (updatedBy != null && UserInformation.isLocal(updatedBy)) { @@ -68,7 +69,7 @@ private ReservationNotification(Reservation reservation, // Add administrators as recipients addAdministratorRecipientsForReservation(reservation.getTargetReservation(), authorizationManager); - addRecipientsFromNotificationTags(reservationRequest, entityManager); + addRecipientsFromNotificationTags(reservationRequest, reservationRequestManager); // Add child targets for (Reservation childReservation : reservation.getChildReservations()) { @@ -77,14 +78,14 @@ private ReservationNotification(Reservation reservation, } private void addRecipientsFromNotificationTags(AbstractReservationRequest reservationRequest, - EntityManager entityManager) + ReservationRequestManager reservationRequestManager) { AuxDataFilter filter = AuxDataFilter.builder() .tagType(TagType.NOTIFY_EMAIL) .enabled(true) .build(); - List notifyEmailAuxData = AuxDataService.getTagData(reservationRequest, filter, entityManager); + List notifyEmailAuxData = reservationRequestManager.getTagData(reservationRequest, filter); List tagPersonInformationList = notifyEmailAuxData .stream() From b6c6091ec22861d7c2ae20e91d3309303eebce05 Mon Sep 17 00:00:00 2001 From: Filip Karnis Date: Fri, 28 Jul 2023 23:03:41 +0200 Subject: [PATCH 15/20] move ReservationRequestManager in ReservationNotification to parameter --- .../notification/ReservationNotification.java | 19 +++++++++++-------- .../controller/scheduler/Scheduler.java | 2 +- 2 files changed, 12 insertions(+), 9 deletions(-) diff --git a/shongo-controller/src/main/java/cz/cesnet/shongo/controller/notification/ReservationNotification.java b/shongo-controller/src/main/java/cz/cesnet/shongo/controller/notification/ReservationNotification.java index f2b57dd5f..44096943a 100644 --- a/shongo-controller/src/main/java/cz/cesnet/shongo/controller/notification/ReservationNotification.java +++ b/shongo-controller/src/main/java/cz/cesnet/shongo/controller/notification/ReservationNotification.java @@ -50,12 +50,13 @@ public abstract class ReservationNotification extends AbstractReservationRequest private Map childTargetByReservation = new LinkedHashMap(); private ReservationNotification(Reservation reservation, - AbstractReservationRequest reservationRequest, AuthorizationManager authorizationManager) + AbstractReservationRequest reservationRequest, + AuthorizationManager authorizationManager, + ReservationRequestManager reservationRequestManager) { super(reservationRequest); EntityManager entityManager = authorizationManager.getEntityManager(); - ReservationRequestManager reservationRequestManager = new ReservationRequestManager(entityManager); String updatedBy = getReservationRequestUpdatedBy(); if (updatedBy != null && UserInformation.isLocal(updatedBy)) { @@ -374,9 +375,10 @@ public static class New extends ReservationNotification { private Long previousReservationId; - public New(Reservation reservation, Reservation previousReservation, AuthorizationManager authorizationManager) + public New(Reservation reservation, Reservation previousReservation, AuthorizationManager authorizationManager, + ReservationRequestManager reservationRequestManager) { - super(reservation, getReservationRequest(reservation), authorizationManager); + super(reservation, getReservationRequest(reservation), authorizationManager, reservationRequestManager); this.previousReservationId = (previousReservation != null ? previousReservation.getId() : null); } @@ -408,14 +410,15 @@ protected String getTitleReservationId(RenderContext renderContext) public static class Deleted extends ReservationNotification { public Deleted(Reservation reservation, AbstractReservationRequest reservationRequest, - AuthorizationManager authorizationManager) + AuthorizationManager authorizationManager, ReservationRequestManager reservationRequestManager) { - super(reservation, reservationRequest, authorizationManager); + super(reservation, reservationRequest, authorizationManager, reservationRequestManager); } - public Deleted(Reservation reservation, AuthorizationManager authorizationManager) + public Deleted(Reservation reservation, AuthorizationManager authorizationManager, + ReservationRequestManager reservationRequestManager) { - super(reservation, getReservationRequest(reservation), authorizationManager); + super(reservation, getReservationRequest(reservation), authorizationManager, reservationRequestManager); } @Override diff --git a/shongo-controller/src/main/java/cz/cesnet/shongo/controller/scheduler/Scheduler.java b/shongo-controller/src/main/java/cz/cesnet/shongo/controller/scheduler/Scheduler.java index 54b95b6d9..e5995e98d 100644 --- a/shongo-controller/src/main/java/cz/cesnet/shongo/controller/scheduler/Scheduler.java +++ b/shongo-controller/src/main/java/cz/cesnet/shongo/controller/scheduler/Scheduler.java @@ -590,7 +590,7 @@ private void allocateReservationRequest(ReservationRequest reservationRequest, S // Create notification contextState.addNotification(new ReservationNotification.New( - allocatedReservation, previousReservation, authorizationManager)); + allocatedReservation, previousReservation, authorizationManager, reservationRequestManager)); // Update reservation request if (context.getRequestWantedState() != null) { From e76f4f57f31a47c3dd136e0b72681f8454cc1800 Mon Sep 17 00:00:00 2001 From: Filip Karnis Date: Fri, 28 Jul 2023 23:16:21 +0200 Subject: [PATCH 16/20] add DefaultAuxData --- .../auxdata/tagdata/DefaultAuxData.java | 18 ++++++++++++++++++ .../request/auxdata/tagdata/TagData.java | 2 ++ 2 files changed, 20 insertions(+) create mode 100644 shongo-controller/src/main/java/cz/cesnet/shongo/controller/booking/request/auxdata/tagdata/DefaultAuxData.java diff --git a/shongo-controller/src/main/java/cz/cesnet/shongo/controller/booking/request/auxdata/tagdata/DefaultAuxData.java b/shongo-controller/src/main/java/cz/cesnet/shongo/controller/booking/request/auxdata/tagdata/DefaultAuxData.java new file mode 100644 index 000000000..4b0fc4d8b --- /dev/null +++ b/shongo-controller/src/main/java/cz/cesnet/shongo/controller/booking/request/auxdata/tagdata/DefaultAuxData.java @@ -0,0 +1,18 @@ +package cz.cesnet.shongo.controller.booking.request.auxdata.tagdata; + +import cz.cesnet.shongo.controller.booking.request.auxdata.AuxDataMerged; + +public class DefaultAuxData extends TagData +{ + + public DefaultAuxData(AuxDataMerged auxData) + { + super(auxData); + } + + @Override + public Void getData() + { + return null; + } +} diff --git a/shongo-controller/src/main/java/cz/cesnet/shongo/controller/booking/request/auxdata/tagdata/TagData.java b/shongo-controller/src/main/java/cz/cesnet/shongo/controller/booking/request/auxdata/tagdata/TagData.java index 76e890a6b..5a21debb9 100644 --- a/shongo-controller/src/main/java/cz/cesnet/shongo/controller/booking/request/auxdata/tagdata/TagData.java +++ b/shongo-controller/src/main/java/cz/cesnet/shongo/controller/booking/request/auxdata/tagdata/TagData.java @@ -22,6 +22,8 @@ public abstract class TagData public static TagData create(AuxDataMerged auxData) { switch (auxData.getType()) { + case DEFAULT: + return new DefaultAuxData(auxData); case NOTIFY_EMAIL: return new NotifyEmailAuxData(auxData); case RESERVATION_DATA: From 55571ec13b51f25eb7b94857a47355743bab0498 Mon Sep 17 00:00:00 2001 From: Filip Karnis Date: Fri, 25 Aug 2023 15:37:00 +0200 Subject: [PATCH 17/20] validate emails --- .../request/ReservationRequestManager.java | 13 ++++--- .../request/auxdata/AuxDataMerged.java | 16 ++++----- .../auxdata/tagdata/DefaultAuxData.java | 2 +- .../auxdata/tagdata/NotifyEmailAuxData.java | 34 ++++++++++++++++++- .../auxdata/tagdata/ReservationAuxData.java | 2 +- .../request/auxdata/tagdata/TagData.java | 13 ++++--- 6 files changed, 56 insertions(+), 24 deletions(-) diff --git a/shongo-controller/src/main/java/cz/cesnet/shongo/controller/booking/request/ReservationRequestManager.java b/shongo-controller/src/main/java/cz/cesnet/shongo/controller/booking/request/ReservationRequestManager.java index 272f2a0b1..3516db3b0 100644 --- a/shongo-controller/src/main/java/cz/cesnet/shongo/controller/booking/request/ReservationRequestManager.java +++ b/shongo-controller/src/main/java/cz/cesnet/shongo/controller/booking/request/ReservationRequestManager.java @@ -703,13 +703,12 @@ private List getAuxData(AbstractReservationRequest reservationReq .getResultList() .stream() .map(record -> { - AuxDataMerged auxDataMerged = new AuxDataMerged(); - auxDataMerged.setTagName((String) record[0]); - auxDataMerged.setType((TagType) record[1]); - auxDataMerged.setEnabled((Boolean) record[2]); - auxDataMerged.setAuxData((JsonNode) record[3]); - auxDataMerged.setData((JsonNode) record[4]); - return auxDataMerged; + final String tagName = (String) record[0]; + final TagType type = (TagType) record[1]; + final Boolean enabled = (Boolean) record[2]; + final JsonNode auxData = (JsonNode) record[3]; + final JsonNode data = (JsonNode) record[4]; + return new AuxDataMerged(tagName, type, enabled, data, auxData); }) .collect(Collectors.toList()); } diff --git a/shongo-controller/src/main/java/cz/cesnet/shongo/controller/booking/request/auxdata/AuxDataMerged.java b/shongo-controller/src/main/java/cz/cesnet/shongo/controller/booking/request/auxdata/AuxDataMerged.java index 799ffe5a3..d501d2bf5 100644 --- a/shongo-controller/src/main/java/cz/cesnet/shongo/controller/booking/request/auxdata/AuxDataMerged.java +++ b/shongo-controller/src/main/java/cz/cesnet/shongo/controller/booking/request/auxdata/AuxDataMerged.java @@ -3,18 +3,16 @@ import com.fasterxml.jackson.databind.JsonNode; import cz.cesnet.shongo.controller.api.TagType; import lombok.AllArgsConstructor; -import lombok.Data; -import lombok.NoArgsConstructor; +import lombok.Value; -@Data -@NoArgsConstructor +@Value @AllArgsConstructor public class AuxDataMerged { - private String tagName; - private TagType type; - private Boolean enabled; - private JsonNode data; - private JsonNode auxData; + String tagName; + TagType type; + Boolean enabled; + JsonNode data; + JsonNode auxData; } diff --git a/shongo-controller/src/main/java/cz/cesnet/shongo/controller/booking/request/auxdata/tagdata/DefaultAuxData.java b/shongo-controller/src/main/java/cz/cesnet/shongo/controller/booking/request/auxdata/tagdata/DefaultAuxData.java index 4b0fc4d8b..59504529d 100644 --- a/shongo-controller/src/main/java/cz/cesnet/shongo/controller/booking/request/auxdata/tagdata/DefaultAuxData.java +++ b/shongo-controller/src/main/java/cz/cesnet/shongo/controller/booking/request/auxdata/tagdata/DefaultAuxData.java @@ -11,7 +11,7 @@ public DefaultAuxData(AuxDataMerged auxData) } @Override - public Void getData() + protected Void constructData() { return null; } diff --git a/shongo-controller/src/main/java/cz/cesnet/shongo/controller/booking/request/auxdata/tagdata/NotifyEmailAuxData.java b/shongo-controller/src/main/java/cz/cesnet/shongo/controller/booking/request/auxdata/tagdata/NotifyEmailAuxData.java index 5f012f7f2..d59d7623f 100644 --- a/shongo-controller/src/main/java/cz/cesnet/shongo/controller/booking/request/auxdata/tagdata/NotifyEmailAuxData.java +++ b/shongo-controller/src/main/java/cz/cesnet/shongo/controller/booking/request/auxdata/tagdata/NotifyEmailAuxData.java @@ -1,22 +1,37 @@ package cz.cesnet.shongo.controller.booking.request.auxdata.tagdata; import com.fasterxml.jackson.databind.JsonNode; +import cz.cesnet.shongo.controller.api.TagType; import cz.cesnet.shongo.controller.booking.request.auxdata.AuxDataMerged; +import lombok.extern.slf4j.Slf4j; +import javax.mail.internet.AddressException; +import javax.mail.internet.InternetAddress; import java.util.ArrayList; import java.util.List; +@Slf4j public class NotifyEmailAuxData extends TagData> { public NotifyEmailAuxData(AuxDataMerged auxData) { super(auxData); + if (!TagType.NOTIFY_EMAIL.equals(auxData.getType())) { + throw new IllegalArgumentException("AuxData is not of type NOTIFY_EMAIL"); + } } @Override - public List getData() + protected List constructData() { + if (!auxData.getData().isArray()) { + throw new IllegalArgumentException("Tag data is not an array"); + } + if (!auxData.getAuxData().isArray()) { + throw new IllegalArgumentException("AuxData data is not an array"); + } + List emails = new ArrayList<>(); for (JsonNode child : auxData.getAuxData()) { @@ -25,6 +40,23 @@ public List getData() for (JsonNode child : auxData.getData()) { emails.add(child.asText()); } + emails.forEach(email -> { + if (!isValidEmailAddress(email)) { + throw new IllegalArgumentException("Invalid email address: " + email); + } + }); + return emails; } + + public static boolean isValidEmailAddress(String email) { + try { + InternetAddress emailAddr = new InternetAddress(email); + emailAddr.validate(); + } catch (AddressException ex) { + log.info("Invalid email address: " + email, ex); + return false; + } + return true; + } } diff --git a/shongo-controller/src/main/java/cz/cesnet/shongo/controller/booking/request/auxdata/tagdata/ReservationAuxData.java b/shongo-controller/src/main/java/cz/cesnet/shongo/controller/booking/request/auxdata/tagdata/ReservationAuxData.java index b7d616fa7..77cc3e505 100644 --- a/shongo-controller/src/main/java/cz/cesnet/shongo/controller/booking/request/auxdata/tagdata/ReservationAuxData.java +++ b/shongo-controller/src/main/java/cz/cesnet/shongo/controller/booking/request/auxdata/tagdata/ReservationAuxData.java @@ -12,7 +12,7 @@ public ReservationAuxData(AuxDataMerged auxData) } @Override - public String getData() + protected String constructData() { throw new TodoImplementException("Not implemented"); } diff --git a/shongo-controller/src/main/java/cz/cesnet/shongo/controller/booking/request/auxdata/tagdata/TagData.java b/shongo-controller/src/main/java/cz/cesnet/shongo/controller/booking/request/auxdata/tagdata/TagData.java index 5a21debb9..01744c8f0 100644 --- a/shongo-controller/src/main/java/cz/cesnet/shongo/controller/booking/request/auxdata/tagdata/TagData.java +++ b/shongo-controller/src/main/java/cz/cesnet/shongo/controller/booking/request/auxdata/tagdata/TagData.java @@ -4,20 +4,23 @@ import cz.cesnet.shongo.controller.booking.request.auxdata.AuxDataFilter; import cz.cesnet.shongo.controller.booking.request.auxdata.AuxDataMerged; import lombok.Getter; -import lombok.RequiredArgsConstructor; import lombok.ToString; -import lombok.extern.slf4j.Slf4j; -@Slf4j @Getter @ToString -@RequiredArgsConstructor public abstract class TagData { protected final AuxDataMerged auxData; + protected final T data; - public abstract T getData(); + protected TagData(AuxDataMerged auxData) + { + this.auxData = auxData; + this.data = constructData(); + } + + protected abstract T constructData(); public static TagData create(AuxDataMerged auxData) { From 80597f464c52b7c6006e001e4a27929da5b73040 Mon Sep 17 00:00:00 2001 From: Filip Karnis Date: Thu, 31 Aug 2023 15:01:38 +0200 Subject: [PATCH 18/20] impl ReservationAuxData --- .../auxdata/tagdata/ReservationAuxData.java | 18 ++++++++++++++---- 1 file changed, 14 insertions(+), 4 deletions(-) diff --git a/shongo-controller/src/main/java/cz/cesnet/shongo/controller/booking/request/auxdata/tagdata/ReservationAuxData.java b/shongo-controller/src/main/java/cz/cesnet/shongo/controller/booking/request/auxdata/tagdata/ReservationAuxData.java index 77cc3e505..f5483db41 100644 --- a/shongo-controller/src/main/java/cz/cesnet/shongo/controller/booking/request/auxdata/tagdata/ReservationAuxData.java +++ b/shongo-controller/src/main/java/cz/cesnet/shongo/controller/booking/request/auxdata/tagdata/ReservationAuxData.java @@ -1,19 +1,29 @@ package cz.cesnet.shongo.controller.booking.request.auxdata.tagdata; -import cz.cesnet.shongo.TodoImplementException; +import com.fasterxml.jackson.core.type.TypeReference; +import com.fasterxml.jackson.databind.ObjectMapper; +import cz.cesnet.shongo.controller.api.TagType; import cz.cesnet.shongo.controller.booking.request.auxdata.AuxDataMerged; -public class ReservationAuxData extends TagData +import java.util.Map; + +public class ReservationAuxData extends TagData> { public ReservationAuxData(AuxDataMerged auxData) { super(auxData); + if (!TagType.RESERVATION_DATA.equals(auxData.getType())) { + throw new IllegalArgumentException("AuxData is not of type RESERVATION_DATA"); + } } @Override - protected String constructData() + protected Map constructData() { - throw new TodoImplementException("Not implemented"); + Map tagMap = new ObjectMapper().convertValue(auxData.getData(), new TypeReference<>() {}); + Map auxMap = new ObjectMapper().convertValue(auxData.getAuxData(), new TypeReference<>() {}); + tagMap.putAll(auxMap); + return tagMap; } } From 6246c3c68cf3cc4059996ddc84c7298451aad831 Mon Sep 17 00:00:00 2001 From: Filip Karnis Date: Sun, 10 Sep 2023 01:16:10 +0200 Subject: [PATCH 19/20] test fix --- .../cz/cesnet/shongo/controller/booking/resource/TagTest.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/shongo-controller/src/test/java/cz/cesnet/shongo/controller/booking/resource/TagTest.java b/shongo-controller/src/test/java/cz/cesnet/shongo/controller/booking/resource/TagTest.java index 6bf148999..55dd073a2 100644 --- a/shongo-controller/src/test/java/cz/cesnet/shongo/controller/booking/resource/TagTest.java +++ b/shongo-controller/src/test/java/cz/cesnet/shongo/controller/booking/resource/TagTest.java @@ -27,7 +27,7 @@ public void testCreateTag() { final String tagName1 = "testTag1"; final String tagName2 = "testTag2"; - final TagType tagType2 = TagType.RESERVATION_DATA; + final TagType tagType2 = TagType.NOTIFY_EMAIL; final String tagData2 = "[\"karnis@cesnet.cz\",\"filip.karnis@cesnet.cz\"]"; ResourceService resourceService = getResourceService(); From d656db7d0319f98656d4a2a9595fd4352fe5f434 Mon Sep 17 00:00:00 2001 From: Filip Karnis Date: Fri, 22 Sep 2023 14:48:40 +0200 Subject: [PATCH 20/20] add view creation to DB migration --- shongo-deployment/migrations/2023-02-24/migration.sql | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/shongo-deployment/migrations/2023-02-24/migration.sql b/shongo-deployment/migrations/2023-02-24/migration.sql index 5444f336e..8f97bec87 100644 --- a/shongo-deployment/migrations/2023-02-24/migration.sql +++ b/shongo-deployment/migrations/2023-02-24/migration.sql @@ -5,4 +5,13 @@ BEGIN TRANSACTION; ALTER TABLE abstract_reservation_request ADD COLUMN aux_data jsonb DEFAULT '[]'::jsonb NOT NULL; +-- Has to be here, otherwise JPA creates TABLE instead of VIEW +CREATE VIEW arr_aux_data AS +SELECT + arr.*, + jsonb_array_elements(aux_data)->>'tagName' AS tag_name, + (jsonb_array_elements(aux_data)->>'enabled')::boolean AS enabled, + jsonb_array_elements(aux_data)->'data' AS data +FROM abstract_reservation_request arr; + COMMIT TRANSACTION;