diff --git a/trace-server/org.eclipse.tracecompass.incubator.trace.server.jersey.rest.core.tests/src/org/eclipse/tracecompass/incubator/trace/server/jersey/rest/core/tests/services/BookmarkManagerServiceTest.java b/trace-server/org.eclipse.tracecompass.incubator.trace.server.jersey.rest.core.tests/src/org/eclipse/tracecompass/incubator/trace/server/jersey/rest/core/tests/services/BookmarkManagerServiceTest.java new file mode 100644 index 000000000..2b5c5a2f3 --- /dev/null +++ b/trace-server/org.eclipse.tracecompass.incubator.trace.server.jersey.rest.core.tests/src/org/eclipse/tracecompass/incubator/trace/server/jersey/rest/core/tests/services/BookmarkManagerServiceTest.java @@ -0,0 +1,352 @@ +/******************************************************************************* + * Copyright (c) 2024 Ericsson + * + * All rights reserved. This program and the accompanying materials are + * made available under the terms of the Eclipse Public License 2.0 which + * accompanies this distribution, and is available at + * https://www.eclipse.org/legal/epl-2.0/ + * + * SPDX-License-Identifier: EPL-2.0 + *******************************************************************************/ + +package org.eclipse.tracecompass.incubator.trace.server.jersey.rest.core.tests.services; + +import static org.junit.Assert.*; + +import java.util.Collections; +import java.util.HashMap; +import java.util.Map; + +import javax.ws.rs.client.Entity; +import javax.ws.rs.client.WebTarget; +import javax.ws.rs.core.Response; + +import org.eclipse.jdt.annotation.NonNull; +import org.eclipse.tracecompass.incubator.internal.trace.server.jersey.rest.core.model.views.QueryParameters; +import org.eclipse.tracecompass.incubator.trace.server.jersey.rest.core.tests.stubs.BookmarkModelStub; +import org.eclipse.tracecompass.incubator.trace.server.jersey.rest.core.tests.stubs.ExperimentModelStub; +import org.eclipse.tracecompass.incubator.trace.server.jersey.rest.core.tests.utils.RestServerTest; +import org.junit.Before; +import org.junit.Test; + +/** + * Test class for BookmarkManagerService + * + * @author Kaveh Shahedi + * @since 10.1 + */ +public class BookmarkManagerServiceTest extends RestServerTest { + + private static final String BOOKMARK_NAME = "TEST"; + private static final long START_TIME = 0L; + private static final long END_TIME = 10L; + private static final @NonNull BookmarkModelStub BOOKMARK = new BookmarkModelStub(BOOKMARK_NAME, START_TIME, END_TIME); + private ExperimentModelStub experiment; + + /** + * Setup method to run before each test. Creates a clean experiment and removes all + * existing bookmarks. + */ + @Before + public void setUp() { + // Create the experiment first + experiment = assertPostExperiment(CONTEXT_SWITCHES_UST_NOT_INITIALIZED_STUB.getName(), + CONTEXT_SWITCHES_UST_NOT_INITIALIZED_STUB); + assertNotNull("Experiment should not be null", experiment); + assertNotNull("Experiment UUID should not be null", experiment.getUUID()); + + // Get all existing bookmarks and delete them + WebTarget application = getApplicationEndpoint(); + WebTarget bookmarkTarget = application.path(EXPERIMENTS) + .path(experiment.getUUID().toString()) + .path(BOOKMARKS); + + Response response = bookmarkTarget.request().get(); + assertEquals("GET request for bookmarks should return 200", 200, response.getStatus()); + + if (response.getStatus() == 200) { + BookmarkModelStub[] existingBookmarks = response.readEntity(BookmarkModelStub[].class); + assertNotNull("Bookmark array should not be null", existingBookmarks); + + for (BookmarkModelStub bookmark : existingBookmarks) { + Response deleteResponse = bookmarkTarget.path(bookmark.getUUID().toString()) + .request() + .delete(); + assertEquals("DELETE request should return 200", 200, deleteResponse.getStatus()); + } + } + } + + /** + * Test the creation of a bookmark with invalid parameters. + */ + @Test + public void testCreateBookmarkInvalidParams() { + WebTarget application = getApplicationEndpoint(); + WebTarget bookmarkTarget = application.path(EXPERIMENTS) + .path(experiment.getUUID().toString()) + .path(BOOKMARKS); + + // Test with null name + Map parameters = new HashMap<>(); + parameters.put(NAME, null); + parameters.put("start", START_TIME); + parameters.put("end", END_TIME); + + Response response = bookmarkTarget.request().post(Entity.json(new QueryParameters(parameters, Collections.emptyList()))); + assertEquals("Should return 400 for null name", 400, response.getStatus()); + + // Test with non-numeric start and end times + parameters.put(NAME, BOOKMARK_NAME); + parameters.put("start", "not a number"); + parameters.put("end", "not a number"); + + response = bookmarkTarget.request().post(Entity.json(new QueryParameters(parameters, Collections.emptyList()))); + assertEquals("Should return 400 for non-numeric times", 400, response.getStatus()); + + // Test with end time before start time + parameters.put(NAME, BOOKMARK_NAME); + parameters.put("start", END_TIME); + parameters.put("end", START_TIME); + + response = bookmarkTarget.request().post(Entity.json(new QueryParameters(parameters, Collections.emptyList()))); + assertEquals("Should return 400 for invalid time range", 400, response.getStatus()); + } + + /** + * Test the creation of a bookmark. + */ + @Test + public void testCreateBookmark() { + WebTarget application = getApplicationEndpoint(); + WebTarget bookmarkTarget = application.path(EXPERIMENTS) + .path(experiment.getUUID().toString()) + .path(BOOKMARKS); + + Map parameters = new HashMap<>(); + parameters.put(NAME, BOOKMARK.getName()); + parameters.put("start", START_TIME); + parameters.put("end", END_TIME); + + Response response = bookmarkTarget.request().post(Entity.json(new QueryParameters(parameters, Collections.emptyList()))); + assertEquals("Response status should be 200", 200, response.getStatus()); + + BookmarkModelStub expStub = response.readEntity(BookmarkModelStub.class); + assertNotNull("Response body should not be null", expStub); + assertEquals("Bookmark name should match", BOOKMARK.getName(), expStub.getName()); + assertEquals("Start time should match", BOOKMARK.getStart(), expStub.getStart()); + assertEquals("End time should match", BOOKMARK.getEnd(), expStub.getEnd()); + assertNotNull("UUID should not be null", expStub.getUUID()); + } + + /** + * Test the creation of a bookmark with a repetitive name. + */ + @Test + public void testCreateBookmarkRepetitiveName() { + WebTarget application = getApplicationEndpoint(); + WebTarget bookmarkTarget = application.path(EXPERIMENTS) + .path(experiment.getUUID().toString()) + .path(BOOKMARKS); + + // Create first bookmark + Map parameters = new HashMap<>(); + parameters.put(NAME, BOOKMARK.getName()); + parameters.put("start", START_TIME); + parameters.put("end", END_TIME); + + Response response = bookmarkTarget.request().post(Entity.json(new QueryParameters(parameters, Collections.emptyList()))); + BookmarkModelStub firstBookmark = response.readEntity(BookmarkModelStub.class); + assertEquals("First bookmark creation should succeed", 200, response.getStatus()); + assertNotNull("First bookmark should not be null", firstBookmark); + + // Try to create second bookmark with same name but different times + parameters.replace("start", START_TIME + 1); + parameters.replace("end", END_TIME + 1); + + response = bookmarkTarget.request().post(Entity.json(new QueryParameters(parameters, Collections.emptyList()))); + assertEquals("Should return conflict for duplicate name", 409, response.getStatus()); + + // Verify the original bookmark wasn't modified + Response getResponse = bookmarkTarget.path(firstBookmark.getUUID().toString()).request().get(); + BookmarkModelStub retrievedBookmark = getResponse.readEntity(BookmarkModelStub.class); + assertEquals("Original bookmark should remain unchanged", firstBookmark, retrievedBookmark); + } + + /** + * Test the fetching of all bookmarks. + */ + @Test + public void testGetAllBookmarks() { + WebTarget application = getApplicationEndpoint(); + WebTarget bookmarkTarget = application.path(EXPERIMENTS) + .path(experiment.getUUID().toString()) + .path(BOOKMARKS); + + // Initially there should be no bookmarks + Response response = bookmarkTarget.request().get(); + BookmarkModelStub[] initialBookmarks = response.readEntity(BookmarkModelStub[].class); + assertEquals("Should start with no bookmarks", 0, initialBookmarks.length); + + // Create multiple bookmarks + Map parameters = new HashMap<>(); + parameters.put("start", START_TIME); + parameters.put("end", END_TIME); + + // Create first bookmark + parameters.put(NAME, "Bookmark1"); + response = bookmarkTarget.request().post(Entity.json(new QueryParameters(parameters, Collections.emptyList()))); + assertEquals("First bookmark creation should succeed", 200, response.getStatus()); + + // Create second bookmark + parameters.put(NAME, "Bookmark2"); + response = bookmarkTarget.request().post(Entity.json(new QueryParameters(parameters, Collections.emptyList()))); + assertEquals("Second bookmark creation should succeed", 200, response.getStatus()); + + // Get all bookmarks + response = bookmarkTarget.request().get(); + BookmarkModelStub[] allBookmarks = response.readEntity(BookmarkModelStub[].class); + assertEquals("Should have 2 bookmarks", 2, allBookmarks.length); + + // Verify bookmark properties + for (BookmarkModelStub bookmark : allBookmarks) { + assertNotNull("Bookmark should not be null", bookmark); + assertNotNull("Bookmark UUID should not be null", bookmark.getUUID()); + assertEquals("Start time should match", START_TIME, bookmark.getStart()); + assertEquals("End time should match", END_TIME, bookmark.getEnd()); + assertTrue("Name should be either Bookmark1 or Bookmark2", + bookmark.getName().equals("Bookmark1") || bookmark.getName().equals("Bookmark2")); + } + } + + /** + * Test the fetching of a specific bookmark. + */ + @Test + public void testGetSpecificBookmark() { + WebTarget application = getApplicationEndpoint(); + WebTarget bookmarkTarget = application.path(EXPERIMENTS) + .path(experiment.getUUID().toString()) + .path(BOOKMARKS); + + // Create a bookmark + Map parameters = new HashMap<>(); + parameters.put(NAME, BOOKMARK.getName()); + parameters.put("start", START_TIME); + parameters.put("end", END_TIME); + + Response response = bookmarkTarget.request().post(Entity.json(new QueryParameters(parameters, Collections.emptyList()))); + assertEquals("Bookmark creation should succeed", 200, response.getStatus()); + BookmarkModelStub createdBookmark = response.readEntity(BookmarkModelStub.class); + + // Test getting non-existent bookmark + Response nonExistentResponse = bookmarkTarget.path("non-existent-uuid").request().get(); + assertEquals("Should return 404 for non-existent bookmark", 404, nonExistentResponse.getStatus()); + + // Test getting existing bookmark + response = bookmarkTarget.path(createdBookmark.getUUID().toString()).request().get(); + assertEquals("Should successfully get existing bookmark", 200, response.getStatus()); + + BookmarkModelStub retrievedBookmark = response.readEntity(BookmarkModelStub.class); + assertEquals("Retrieved bookmark should match created bookmark", createdBookmark, retrievedBookmark); + } + + /** + * Test updating a bookmark. + */ + @Test + public void testUpdateBookmark() { + WebTarget application = getApplicationEndpoint(); + WebTarget bookmarkTarget = application.path(EXPERIMENTS) + .path(experiment.getUUID().toString()) + .path(BOOKMARKS); + + // Create initial bookmark + Map parameters = new HashMap<>(); + parameters.put(NAME, BOOKMARK.getName()); + parameters.put("start", START_TIME); + parameters.put("end", END_TIME); + + Response response = bookmarkTarget.request().post(Entity.json(new QueryParameters(parameters, Collections.emptyList()))); + BookmarkModelStub originalBookmark = response.readEntity(BookmarkModelStub.class); + assertEquals("Initial bookmark creation should succeed", 200, response.getStatus()); + + // Test updating non-existent bookmark + WebTarget nonExistentTarget = bookmarkTarget.path("non-existent-uuid"); + Response nonExistentResponse = nonExistentTarget.request() + .put(Entity.json(new QueryParameters(parameters, Collections.emptyList()))); + assertEquals("Should return 404 for non-existent bookmark", 404, nonExistentResponse.getStatus()); + + // Test updating with invalid parameters + parameters.put("start", END_TIME); + parameters.put("end", START_TIME); + Response invalidResponse = bookmarkTarget.path(originalBookmark.getUUID().toString()) + .request() + .put(Entity.json(new QueryParameters(parameters, Collections.emptyList()))); + assertEquals("Should return 400 for invalid parameters", 400, invalidResponse.getStatus()); + + // Test successful update + parameters.put("name", "Updated Name"); + parameters.put("start", START_TIME + 5); + parameters.put("end", END_TIME + 5); + + response = bookmarkTarget.path(originalBookmark.getUUID().toString()) + .request() + .put(Entity.json(new QueryParameters(parameters, Collections.emptyList()))); + + assertEquals("Update should succeed", 200, response.getStatus()); + BookmarkModelStub updatedBookmark = response.readEntity(BookmarkModelStub.class); + + assertNotNull("Updated bookmark should not be null", updatedBookmark); + assertEquals("UUID should remain the same", originalBookmark.getUUID(), updatedBookmark.getUUID()); + assertEquals("Name should be updated", "Updated Name", updatedBookmark.getName()); + assertEquals("Start time should be updated", START_TIME + 5, updatedBookmark.getStart()); + assertEquals("End time should be updated", END_TIME + 5, updatedBookmark.getEnd()); + } + + /** + * Test the deletion of a bookmark with various scenarios. + */ + @Test + public void testDeleteBookmark() { + WebTarget application = getApplicationEndpoint(); + WebTarget bookmarkTarget = application.path(EXPERIMENTS) + .path(experiment.getUUID().toString()) + .path(BOOKMARKS); + + // Try deleting non-existent bookmark + Response nonExistentResponse = bookmarkTarget.path("non-existent-uuid") + .request() + .delete(); + assertEquals("Should return 404 for non-existent bookmark", 404, nonExistentResponse.getStatus()); + + // Create a bookmark to delete + Map parameters = new HashMap<>(); + parameters.put(NAME, BOOKMARK.getName()); + parameters.put("start", START_TIME); + parameters.put("end", END_TIME); + + Response response = bookmarkTarget.request().post(Entity.json(new QueryParameters(parameters, Collections.emptyList()))); + BookmarkModelStub createdBookmark = response.readEntity(BookmarkModelStub.class); + assertEquals("Bookmark creation should succeed", 200, response.getStatus()); + + // Delete the bookmark + response = bookmarkTarget.path(createdBookmark.getUUID().toString()) + .request() + .delete(); + assertEquals("Delete should succeed", 200, response.getStatus()); + BookmarkModelStub deletedBookmark = response.readEntity(BookmarkModelStub.class); + assertEquals("Deleted bookmark should match created bookmark", createdBookmark, deletedBookmark); + + // Verify the bookmark is actually deleted + Response getResponse = bookmarkTarget.path(createdBookmark.getUUID().toString()) + .request() + .get(); + assertEquals("Should return 404 for deleted bookmark", 404, getResponse.getStatus()); + + // Verify it's not in the list of all bookmarks + Response getAllResponse = bookmarkTarget.request().get(); + BookmarkModelStub[] allBookmarks = getAllResponse.readEntity(BookmarkModelStub[].class); + assertEquals("Should have no bookmarks after deletion", 0, allBookmarks.length); + } +} \ No newline at end of file diff --git a/trace-server/org.eclipse.tracecompass.incubator.trace.server.jersey.rest.core.tests/src/org/eclipse/tracecompass/incubator/trace/server/jersey/rest/core/tests/stubs/BookmarkModelStub.java b/trace-server/org.eclipse.tracecompass.incubator.trace.server.jersey.rest.core.tests/src/org/eclipse/tracecompass/incubator/trace/server/jersey/rest/core/tests/stubs/BookmarkModelStub.java new file mode 100644 index 000000000..e3f8e3c5c --- /dev/null +++ b/trace-server/org.eclipse.tracecompass.incubator.trace.server.jersey.rest.core.tests/src/org/eclipse/tracecompass/incubator/trace/server/jersey/rest/core/tests/stubs/BookmarkModelStub.java @@ -0,0 +1,162 @@ +/******************************************************************************* + * Copyright (c) 2024 Ericsson + * + * All rights reserved. This program and the accompanying materials are + * made available under the terms of the Eclipse Public License 2.0 which + * accompanies this distribution, and is available at + * https://www.eclipse.org/legal/epl-2.0/ + * + * SPDX-License-Identifier: EPL-2.0 + *******************************************************************************/ + +package org.eclipse.tracecompass.incubator.trace.server.jersey.rest.core.tests.stubs; + +import java.io.Serializable; +import java.nio.charset.Charset; +import java.util.Objects; +import java.util.UUID; + +import com.fasterxml.jackson.annotation.JsonCreator; +import com.fasterxml.jackson.annotation.JsonIgnoreProperties; +import com.fasterxml.jackson.annotation.JsonProperty; + +/** + * A Stub class for the bookmark model. It matches the trace server protocol's + * BookmarkModel schema + * + * @author Kaveh Shahedi + * @since 10.1 + */ +@JsonIgnoreProperties(ignoreUnknown = true) +public class BookmarkModelStub implements Serializable { + private static final long serialVersionUID = -1945923534635091200L; + + private final UUID fUUID; + private final String fName; + private final long fStart; + private final long fEnd; + + /** + * {@link JsonCreator} Constructor for final fields + * + * @param uuid + * The bookmark's UUID + * @param name + * The bookmark name + * @param start + * The start time + * @param end + * The end time + */ + @JsonCreator + public BookmarkModelStub( + @JsonProperty("uuid") UUID uuid, + @JsonProperty("name") String name, + @JsonProperty("start") long start, + @JsonProperty("end") long end) { + fUUID = Objects.requireNonNull(uuid, "The 'UUID' json field was not set"); + fName = Objects.requireNonNull(name, "The 'name' json field was not set"); + fStart = start; + fEnd = end; + } + + /** + * Constructor for comparing equality + * + * @param name + * bookmark name + * @param start + * start time + * @param end + * end time + */ + public BookmarkModelStub(String name, long start, long end) { + this(getUUID(name), name, start, end); + } + + private static UUID getUUID(String name) { + return UUID.nameUUIDFromBytes(Objects.requireNonNull(name.getBytes(Charset.defaultCharset()))); + } + + /** + * Get the UUID + * + * @return The UUID + */ + public UUID getUUID() { + return fUUID; + } + + /** + * Get the bookmark name + * + * @return The bookmark name + */ + public String getName() { + return fName; + } + + /** + * Get the start time + * + * @return The start time + */ + public long getStart() { + return fStart; + } + + /** + * Get the end time + * + * @return The end time + */ + public long getEnd() { + return fEnd; + } + + @Override + public boolean equals(Object obj) { + if (this == obj) { + return true; + } + if (obj == null) { + return false; + } + if (getClass() != obj.getClass()) { + return false; + } + BookmarkModelStub other = (BookmarkModelStub) obj; + if (fEnd != other.fEnd) { + return false; + } + if (fName == null) { + if (other.fName != null) { + return false; + } + } else if (!fName.equals(other.fName)) { + return false; + } + if (fStart != other.fStart) { + return false; + } + if (fUUID == null) { + if (other.fUUID != null) { + return false; + } + } else if (!fUUID.equals(other.fUUID)) { + return false; + } + return true; + } + + + @Override + public String toString() { + return "BookmarkModelStub [fUUID=" + fUUID + ", fName=" + fName + ", fStart=" + fStart + ", fEnd=" + fEnd + "]"; + } + + @Override + public int hashCode() { + return super.hashCode(); + } +} diff --git a/trace-server/org.eclipse.tracecompass.incubator.trace.server.jersey.rest.core.tests/src/org/eclipse/tracecompass/incubator/trace/server/jersey/rest/core/tests/stubs/webapp/TestWebApplication.java b/trace-server/org.eclipse.tracecompass.incubator.trace.server.jersey.rest.core.tests/src/org/eclipse/tracecompass/incubator/trace/server/jersey/rest/core/tests/stubs/webapp/TestWebApplication.java index 0a5e92773..54af8e84b 100644 --- a/trace-server/org.eclipse.tracecompass.incubator.trace.server.jersey.rest.core.tests/src/org/eclipse/tracecompass/incubator/trace/server/jersey/rest/core/tests/stubs/webapp/TestWebApplication.java +++ b/trace-server/org.eclipse.tracecompass.incubator.trace.server.jersey.rest.core.tests/src/org/eclipse/tracecompass/incubator/trace/server/jersey/rest/core/tests/stubs/webapp/TestWebApplication.java @@ -11,6 +11,7 @@ package org.eclipse.tracecompass.incubator.trace.server.jersey.rest.core.tests.stubs.webapp; +import org.eclipse.tracecompass.incubator.internal.trace.server.jersey.rest.core.services.BookmarkManagerService; import org.eclipse.tracecompass.incubator.internal.trace.server.jersey.rest.core.services.ConfigurationManagerService; import org.eclipse.tracecompass.incubator.internal.trace.server.jersey.rest.core.services.ExperimentManagerService; import org.eclipse.tracecompass.incubator.internal.trace.server.jersey.rest.core.services.FilterService; @@ -52,5 +53,6 @@ protected void registerResourcesAndMappers(ResourceConfig rc) { rc.register(CORSFilter.class); rc.register(JacksonObjectMapperProvider.class); rc.register(OpenApiResource.class); + rc.register(BookmarkManagerService.class); } } diff --git a/trace-server/org.eclipse.tracecompass.incubator.trace.server.jersey.rest.core.tests/src/org/eclipse/tracecompass/incubator/trace/server/jersey/rest/core/tests/utils/RestServerTest.java b/trace-server/org.eclipse.tracecompass.incubator.trace.server.jersey.rest.core.tests/src/org/eclipse/tracecompass/incubator/trace/server/jersey/rest/core/tests/utils/RestServerTest.java index 0fb4f9d13..e5fd2bf4a 100644 --- a/trace-server/org.eclipse.tracecompass.incubator.trace.server.jersey.rest.core.tests/src/org/eclipse/tracecompass/incubator/trace/server/jersey/rest/core/tests/utils/RestServerTest.java +++ b/trace-server/org.eclipse.tracecompass.incubator.trace.server.jersey.rest.core.tests/src/org/eclipse/tracecompass/incubator/trace/server/jersey/rest/core/tests/utils/RestServerTest.java @@ -79,6 +79,10 @@ public abstract class RestServerTest { * Experiments endpoint path (relative to application). */ public static final String EXPERIMENTS = "experiments"; + /** + * Bookmarks endpoint path (relative to application). + */ + public static final String BOOKMARKS = "bookmarks"; /** * Outputs path segment diff --git a/trace-server/org.eclipse.tracecompass.incubator.trace.server.jersey.rest.core/src/org/eclipse/tracecompass/incubator/internal/trace/server/jersey/rest/core/model/Bookmark.java b/trace-server/org.eclipse.tracecompass.incubator.trace.server.jersey.rest.core/src/org/eclipse/tracecompass/incubator/internal/trace/server/jersey/rest/core/model/Bookmark.java index 5a6da9fea..61e66cbd6 100644 --- a/trace-server/org.eclipse.tracecompass.incubator.trace.server.jersey.rest.core/src/org/eclipse/tracecompass/incubator/internal/trace/server/jersey/rest/core/model/Bookmark.java +++ b/trace-server/org.eclipse.tracecompass.incubator.trace.server.jersey.rest.core/src/org/eclipse/tracecompass/incubator/internal/trace/server/jersey/rest/core/model/Bookmark.java @@ -30,7 +30,7 @@ public interface Bookmark { /** * @return The bookmark UUID. */ - @JsonProperty("UUID") + @JsonProperty("uuid") @Schema(description = "The bookmark's unique identifier") UUID getUUID(); @@ -41,13 +41,6 @@ public interface Bookmark { @Schema(description = "User defined name for the bookmark") String getName(); - /** - * @return The experiment ID. - */ - @NonNull - @Schema(description = "The experiment's unique identifier this bookmark belongs to") - String getExperimentId(); - /** * @return The start time. */ diff --git a/trace-server/org.eclipse.tracecompass.incubator.trace.server.jersey.rest.core/src/org/eclipse/tracecompass/incubator/internal/trace/server/jersey/rest/core/services/Bookmark.java b/trace-server/org.eclipse.tracecompass.incubator.trace.server.jersey.rest.core/src/org/eclipse/tracecompass/incubator/internal/trace/server/jersey/rest/core/services/Bookmark.java index 0bafdb8ce..d787a3acb 100644 --- a/trace-server/org.eclipse.tracecompass.incubator.trace.server.jersey.rest.core/src/org/eclipse/tracecompass/incubator/internal/trace/server/jersey/rest/core/services/Bookmark.java +++ b/trace-server/org.eclipse.tracecompass.incubator.trace.server.jersey.rest.core/src/org/eclipse/tracecompass/incubator/internal/trace/server/jersey/rest/core/services/Bookmark.java @@ -1,11 +1,19 @@ +/******************************************************************************* + * Copyright (c) 2024 Ericsson + * + * All rights reserved. This program and the accompanying materials are + * made available under the terms of the Eclipse Public License 2.0 which + * accompanies this distribution, and is available at + * https://www.eclipse.org/legal/epl-2.0/ + * + * SPDX-License-Identifier: EPL-2.0 + *******************************************************************************/ package org.eclipse.tracecompass.incubator.internal.trace.server.jersey.rest.core.services; import java.io.Serializable; import java.util.UUID; import com.fasterxml.jackson.annotation.JsonCreator; import com.fasterxml.jackson.annotation.JsonProperty; -import com.fasterxml.jackson.databind.JsonNode; -import com.fasterxml.jackson.databind.ObjectMapper; /** * Bookmark model for TSP @@ -14,15 +22,13 @@ * @since 10.1 */ public class Bookmark implements Serializable { - private static final long serialVersionUID = -3626414315455912960L; - private static final ObjectMapper MAPPER = new ObjectMapper(); + + private static final long serialVersionUID = 6126770413230064175L; private final UUID fUUID; private final String fName; - private final String fExperimentId; private final long fStart; private final long fEnd; - private final JsonNode fPayload; /** * {@link JsonCreator} Constructor for final fields @@ -31,47 +37,21 @@ public class Bookmark implements Serializable { * the stub's UUID * @param name * bookmark name - * @param experimentId - * experiment id * @param start * start time * @param end * end time - * @param payload - * additional JSON data associated with the bookmark (optional) */ @JsonCreator public Bookmark( - @JsonProperty("UUID") UUID uuid, + @JsonProperty("uuid") UUID uuid, @JsonProperty("name") String name, - @JsonProperty("experimentId") String experimentId, @JsonProperty("start") long start, - @JsonProperty("end") long end, - @JsonProperty(value = "payload", required = false) JsonNode payload) { + @JsonProperty("end") long end) { fUUID = uuid; fName = name; - fExperimentId = experimentId; fStart = start; fEnd = end; - fPayload = (payload != null) ? payload : MAPPER.createObjectNode(); - } - - /** - * Constructor without payload - * - * @param uuid - * the stub's UUID - * @param name - * bookmark name - * @param experimentId - * experiment id - * @param start - * start time - * @param end - * end time - */ - public Bookmark(UUID uuid, String name, String experimentId, long start, long end) { - this(uuid, name, experimentId, start, end, MAPPER.createObjectNode()); } /** @@ -92,15 +72,6 @@ public String getName() { return fName; } - /** - * Get the experiment id - * - * @return the experiment id - */ - public String getExperimentId() { - return fExperimentId; - } - /** * Get the start time * @@ -119,18 +90,9 @@ public long getEnd() { return fEnd; } - /** - * Get the payload - * - * @return the JSON payload, empty JSON object if no payload was set - */ - public JsonNode getPayload() { - return fPayload; - } - @Override public String toString() { - return "Bookmark [fUUID=" + fUUID + ", fName=" + fName + ", fExperimentId=" + fExperimentId //$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$ - + ", fStart=" + fStart + ", fEnd=" + fEnd + ", fPayload=" + fPayload + "]"; //$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$ //$NON-NLS-4$ + return "Bookmark [fUUID=" + fUUID + ", fName=" + fName //$NON-NLS-1$ //$NON-NLS-2$ + + ", fStart=" + fStart + ", fEnd=" + fEnd + "]"; //$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$ } } \ No newline at end of file diff --git a/trace-server/org.eclipse.tracecompass.incubator.trace.server.jersey.rest.core/src/org/eclipse/tracecompass/incubator/internal/trace/server/jersey/rest/core/services/BookmarkManagerService.java b/trace-server/org.eclipse.tracecompass.incubator.trace.server.jersey.rest.core/src/org/eclipse/tracecompass/incubator/internal/trace/server/jersey/rest/core/services/BookmarkManagerService.java index c307dcdae..8d3dbc721 100644 --- a/trace-server/org.eclipse.tracecompass.incubator.trace.server.jersey.rest.core/src/org/eclipse/tracecompass/incubator/internal/trace/server/jersey/rest/core/services/BookmarkManagerService.java +++ b/trace-server/org.eclipse.tracecompass.incubator.trace.server.jersey.rest.core/src/org/eclipse/tracecompass/incubator/internal/trace/server/jersey/rest/core/services/BookmarkManagerService.java @@ -53,15 +53,13 @@ import org.eclipse.core.runtime.CoreException; import org.eclipse.jdt.annotation.NonNull; import org.eclipse.tracecompass.incubator.internal.trace.server.jersey.rest.core.Activator; +import org.eclipse.tracecompass.incubator.internal.trace.server.jersey.rest.core.model.BookmarkQueryParameters; import org.eclipse.tracecompass.incubator.internal.trace.server.jersey.rest.core.model.views.QueryParameters; import org.eclipse.tracecompass.tmf.core.TmfCommonConstants; import org.eclipse.tracecompass.tmf.core.trace.experiment.TmfExperiment; import com.google.common.collect.Lists; -import com.fasterxml.jackson.databind.JsonNode; -import com.fasterxml.jackson.databind.ObjectMapper; - import io.swagger.v3.oas.annotations.Operation; import io.swagger.v3.oas.annotations.Parameter; import io.swagger.v3.oas.annotations.media.ArraySchema; @@ -84,8 +82,6 @@ public class BookmarkManagerService { private static final Map> EXPERIMENT_BOOKMARKS = Collections.synchronizedMap(initBookmarkResources()); private static final String BOOKMARKS_FOLDER = "Bookmarks"; //$NON-NLS-1$ - private static final ObjectMapper MAPPER = new ObjectMapper(); - private static Map> initBookmarkResources() { IWorkspaceRoot root = ResourcesPlugin.getWorkspace().getRoot(); IProject project = root.getProject(TmfCommonConstants.DEFAULT_TRACE_PROJECT_NAME); @@ -93,6 +89,10 @@ private static Map> initBookmarkResources() { try { project.refreshLocal(IResource.DEPTH_INFINITE, null); IFolder bookmarksFolder = project.getFolder(BOOKMARKS_FOLDER); + // Check if the folder exists. If not, create it + if (!bookmarksFolder.exists()) { + bookmarksFolder.create(true, true, null); + } bookmarksFolder.accept((IResourceVisitor) resource -> { if (resource.equals(bookmarksFolder)) { return true; @@ -205,7 +205,9 @@ public Response getBookmark( }) public Response createBookmark( @Parameter(description = EXP_UUID) @PathParam("expUUID") UUID expUUID, - @RequestBody(required = true) QueryParameters queryParameters) { + @RequestBody(content = { + @Content(schema = @Schema(implementation = BookmarkQueryParameters.class)) + }, required = true) QueryParameters queryParameters) { if (queryParameters == null) { return Response.status(Status.BAD_REQUEST).entity(MISSING_PARAMETERS).build(); @@ -226,21 +228,6 @@ public Response createBookmark( long start = Objects.requireNonNull((Number) parameters.get("start")).longValue(); //$NON-NLS-1$ long end = Objects.requireNonNull((Number) parameters.get("end")).longValue(); //$NON-NLS-1$ - // Handle payload, defaulting to empty JSON object if not provided - JsonNode payload = null; - Object rawPayload = parameters.get("payload"); - if (rawPayload != null) { - try { - if (rawPayload instanceof String) { - payload = MAPPER.readTree((String) rawPayload); - } else { - payload = MAPPER.valueToTree(rawPayload); - } - } catch (IOException e) { - return Response.status(Status.BAD_REQUEST).entity("Invalid payload format").build(); - } - } - try { IFolder bookmarkFolder = getBookmarkFolder(expUUID); UUID bookmarkUUID = UUID.nameUUIDFromBytes(Objects.requireNonNull(name.getBytes(Charset.defaultCharset()))); @@ -260,7 +247,7 @@ public Response createBookmark( createFolder(bookmarkFolder); - Bookmark bookmark = new Bookmark(bookmarkUUID, name, expUUID.toString(), start, end, payload); + Bookmark bookmark = new Bookmark(bookmarkUUID, name, start, end); // Save to file system IFile bookmarkFile = bookmarkFolder.getFile(bookmarkUUID.toString() + ".bookmark"); //$NON-NLS-1$ @@ -314,7 +301,9 @@ public Response createBookmark( public Response updateBookmark( @Parameter(description = EXP_UUID) @PathParam("expUUID") UUID expUUID, @Parameter(description = "Bookmark UUID") @PathParam("bookmarkUUID") UUID bookmarkUUID, - @RequestBody(required = true) QueryParameters queryParameters) { + @RequestBody(content = { + @Content(schema = @Schema(implementation = BookmarkQueryParameters.class)) + }, required = true) QueryParameters queryParameters) { if (queryParameters == null) { return Response.status(Status.BAD_REQUEST).entity(MISSING_PARAMETERS).build(); @@ -340,24 +329,9 @@ public Response updateBookmark( long start = Objects.requireNonNull((Number) parameters.get("start")).longValue(); //$NON-NLS-1$ long end = Objects.requireNonNull((Number) parameters.get("end")).longValue(); //$NON-NLS-1$ - // Handle payload, defaulting to empty JSON object if not provided - JsonNode payload = null; - Object rawPayload = parameters.get("payload"); - if (rawPayload != null) { - try { - if (rawPayload instanceof String) { - payload = MAPPER.readTree((String) rawPayload); - } else { - payload = MAPPER.valueToTree(rawPayload); - } - } catch (IOException e) { - return Response.status(Status.BAD_REQUEST).entity("Invalid payload format").build(); - } - } - try { IFolder bookmarkFolder = getBookmarkFolder(expUUID); - Bookmark updatedBookmark = new Bookmark(bookmarkUUID, name, expUUID.toString(), start, end, payload); + Bookmark updatedBookmark = new Bookmark(bookmarkUUID, name, start, end); // Update file system IFile bookmarkFile = bookmarkFolder.getFile(bookmarkUUID.toString() + ".bookmark"); //$NON-NLS-1$ diff --git a/trace-server/org.eclipse.tracecompass.incubator.trace.server.jersey.rest.core/src/org/eclipse/tracecompass/incubator/internal/trace/server/jersey/rest/core/services/QueryParametersUtil.java b/trace-server/org.eclipse.tracecompass.incubator.trace.server.jersey.rest.core/src/org/eclipse/tracecompass/incubator/internal/trace/server/jersey/rest/core/services/QueryParametersUtil.java index cb3f38e18..e13f7f8fc 100644 --- a/trace-server/org.eclipse.tracecompass.incubator.trace.server.jersey.rest.core/src/org/eclipse/tracecompass/incubator/internal/trace/server/jersey/rest/core/services/QueryParametersUtil.java +++ b/trace-server/org.eclipse.tracecompass.incubator.trace.server.jersey.rest.core/src/org/eclipse/tracecompass/incubator/internal/trace/server/jersey/rest/core/services/QueryParametersUtil.java @@ -33,10 +33,6 @@ import org.eclipse.tracecompass.tmf.core.model.timegraph.TimeGraphArrow; import org.eclipse.tracecompass.tmf.core.model.timegraph.TimeGraphState; -import com.fasterxml.jackson.core.JsonProcessingException; -import com.fasterxml.jackson.databind.JsonNode; -import com.fasterxml.jackson.databind.ObjectMapper; - /** * Utility methods to validate and convert query parameters from the input Trace * Server Protocol to the output data provider interfaces. @@ -65,7 +61,6 @@ private interface ElementType { private static final String TIME = "time"; //$NON-NLS-1$ private static final String TRACES = "traces"; //$NON-NLS-1$ private static final String URI = "uri"; //$NON-NLS-1$ - private static final String PAYLOAD = "payload"; //$NON-NLS-1$ private static final long MAX_NBTIMES = 1 << 16; private static final @NonNull OutputElementStyle EMPTY_STYLE = new OutputElementStyle(null, Collections.emptyMap()); @@ -485,23 +480,6 @@ public static String validateBookmarkQueryParameters(Map params) return INVALID_PARAMETERS + SEP + "Start time cannot be after end time"; //$NON-NLS-1$ } - // Validate payload - Object payload = params.get(PAYLOAD); - if (payload != null) { - // Check if it is a JSON parseable object - try { - if (payload instanceof String) { - // Try parsing string as JSON - new ObjectMapper().readTree((String) payload); - } else if (!(payload instanceof Map) && !(payload instanceof List) && !(payload instanceof JsonNode)) { - // If not a string, should be a Map, List, or already a JsonNode - return INVALID_PARAMETERS + SEP + "Payload must be a valid JSON structure"; //$NON-NLS-1$ - } - } catch (JsonProcessingException e) { - return INVALID_PARAMETERS + SEP + "Invalid JSON payload format"; //$NON-NLS-1$ - } - } - return null; } }