Skip to content

Commit

Permalink
server: support json object in query parameters for configurations
Browse files Browse the repository at this point in the history
This commit also includes the corresponding swagger updates.

Signed-off-by: Bernd Hufmann <[email protected]>
  • Loading branch information
bhufmann committed Sep 9, 2024
1 parent 3ddd71f commit b629159
Show file tree
Hide file tree
Showing 8 changed files with 290 additions and 25 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -34,6 +34,9 @@ Import-Package: com.fasterxml.jackson.annotation,
com.fasterxml.jackson.jaxrs.json,
com.google.common.base,
com.google.common.collect,
com.google.gson;version="2.8.2",
com.google.gson.annotations;version="2.8.2",
com.google.gson.reflect;version="2.8.2",
javax.ws.rs,
javax.ws.rs.client,
javax.ws.rs.core,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -16,4 +16,5 @@ bin.includes = META-INF/,\
about.html,\
plugin.properties,\
plugin.xml,\
schema/
schema/,\
config/
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
{
"cpus": ["0", "1", "2"],
"thread": "my-thread",
"phone": "(123)345-567"
}
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,9 @@
import static org.junit.Assert.fail;

import java.io.File;
import java.io.FileInputStream;
import java.io.IOException;
import java.io.InputStream;
import java.net.URISyntaxException;
import java.net.URL;
import java.util.Collections;
Expand All @@ -33,24 +35,31 @@
import javax.ws.rs.core.Response;

import org.eclipse.core.runtime.FileLocator;
import org.eclipse.core.runtime.IPath;
import org.eclipse.core.runtime.Path;
import org.eclipse.core.runtime.Platform;
import org.eclipse.jdt.annotation.NonNull;
import org.eclipse.jdt.annotation.Nullable;
import org.eclipse.tracecompass.incubator.internal.trace.server.jersey.rest.core.model.views.ConfigurationQueryParameters;
import org.eclipse.tracecompass.incubator.internal.trace.server.jersey.rest.core.model.views.QueryParameters;
import org.eclipse.tracecompass.incubator.internal.trace.server.jersey.rest.core.services.ConfigurationManagerService;
import org.eclipse.tracecompass.incubator.trace.server.jersey.rest.core.tests.stubs.ExperimentModelStub;
import org.eclipse.tracecompass.incubator.trace.server.jersey.rest.core.tests.stubs.TmfConfigurationSourceTypeStub;
import org.eclipse.tracecompass.incubator.trace.server.jersey.rest.core.tests.stubs.TmfConfigurationStub;
import org.eclipse.tracecompass.incubator.trace.server.jersey.rest.core.tests.stubs.config.TestSchemaConfigurationSource.Parameters;
import org.eclipse.tracecompass.incubator.trace.server.jersey.rest.core.tests.utils.RestServerTest;
import org.eclipse.tracecompass.internal.tmf.analysis.xml.core.module.XmlUtils;
import org.eclipse.tracecompass.tmf.core.config.ITmfConfigParamDescriptor;
import org.eclipse.tracecompass.tmf.core.config.ITmfConfiguration;
import org.eclipse.tracecompass.tmf.core.config.ITmfConfigurationSourceType;
import org.eclipse.tracecompass.tmf.core.config.TmfConfiguration;
import org.junit.After;
import org.junit.Test;
import org.osgi.framework.Bundle;

import com.fasterxml.jackson.databind.JsonNode;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.google.gson.Gson;

/**
* Basic test for the {@link ConfigurationManagerService}.
Expand All @@ -67,6 +76,7 @@ public class ConfigurationManagerServiceTest extends RestServerTest {
private static final String PATH_VALID = "test_xml_files/test_valid/";
private static final String PATH = "path";
private static final String XML_ANALYSIS_TYPE_ID = "org.eclipse.tracecompass.tmf.core.config.xmlsourcetype";
private static final String CONFIG_WITH_SCHEMA_ANALYSIS_TYPE_ID = "org.eclipse.tracecompass.tmf.core.config.testschemasourcetype";
private static final String EXPECTED_TYPE_NAME = "XML Data-driven analyses"; //$NON-NLS-1$
private static final String EXPECTED_TYPE_DESCRIPTION = "Data-driven analyses described in XML"; //$NON-NLS-1$
private static final String EXPECTED_KEY_NAME = "path";
Expand All @@ -80,6 +90,11 @@ public class ConfigurationManagerServiceTest extends RestServerTest {
private static final String EXPECTED_CONFIG_DESCRIPTION = "XML Data-driven analysis: " + VALID_NAME;
private static final String PATH_TO_INVALID_PATH = getPath(PATH_INVALID + INVALID_XML_FILE);
private static final String PATH_TO_VALID_PATH = getPath(PATH_VALID + VALID_XML_FILE);
private static final String VALID_JSON_FILENAME = "custome-execution-analysis.json";

private static final String EXPECTED_JSON_CONFIG_NAME = "My Config Name";
private static final String EXPECTED_JSON_CONFIG_DESCRIPTION = "My Config Description";
private static final String EXPECTED_JSON_CONFIG_ID = "My Config Id";

private static final GenericType<TmfConfigurationStub> CONFIGURATION = new GenericType<>() { };
private static final GenericType<List<TmfConfigurationStub>> LIST_CONFIGURATION_TYPE = new GenericType<>() { };
Expand Down Expand Up @@ -204,6 +219,37 @@ public void testCreateGetAndDelete() {
}
}

/**
* Test POST to create configurations using a schema.
*
* @throws IOException
* if exception occurs
* @throws URISyntaxException
* if exception occurs
*/
@Test
public void testCreateGetAndDeleteSchema() throws URISyntaxException, IOException {
try (Response response = createJsonConfig(VALID_JSON_FILENAME)) {
assertEquals(200, response.getStatus());
TmfConfigurationStub config = response.readEntity(CONFIGURATION);
assertNotNull(config);
validateJsonConfig(config);
}

List<TmfConfigurationStub> configurations = getConfigurations(CONFIG_WITH_SCHEMA_ANALYSIS_TYPE_ID);
assertEquals("Valid JSON configuration should be added", 1, configurations.size());
assertTrue("Valid configuration instance should exist", configurations.stream().anyMatch(conf -> conf.getName().equals(EXPECTED_JSON_CONFIG_NAME)));

TmfConfigurationStub config = getConfiguration(CONFIG_WITH_SCHEMA_ANALYSIS_TYPE_ID, configurations.get(0).getId());
assertNotNull(config);
assertTrue("JSON configuration instance should exist", config.getId().equals(EXPECTED_JSON_CONFIG_ID));

try (Response response = deleteConfig(CONFIG_WITH_SCHEMA_ANALYSIS_TYPE_ID, config.getId())) {
assertEquals(200, response.getStatus());
assertEquals("JSON configuration should have been deleted", 0, getConfigurations(CONFIG_WITH_SCHEMA_ANALYSIS_TYPE_ID).size());
}
}

/**
* Test PUT to update configurations using XML configuration source type.
*/
Expand Down Expand Up @@ -316,8 +362,29 @@ private static Response createConfig(String path, boolean isCorrectType) {
if (path != null) {
parameters.put(PATH, path);
}
ObjectMapper mapper = new ObjectMapper();
return endpoint.request(MediaType.APPLICATION_JSON)
.post(Entity.json(new QueryParameters(parameters, Collections.emptyList())));
.post(Entity.json(new ConfigurationQueryParameters(mapper.valueToTree(parameters))));
}

private static Response createJsonConfig(String jsonFileName) throws URISyntaxException, IOException {
String typeId = CONFIG_WITH_SCHEMA_ANALYSIS_TYPE_ID;
WebTarget endpoint = getApplicationEndpoint()
.path(CONFIG_PATH)
.path(TYPES_PATH)
.path(typeId)
.path(CONFIG_INSTANCES_PATH);

Bundle bundle = Platform.getBundle("org.eclipse.tracecompass.incubator.trace.server.jersey.rest.core.tests");
IPath defaultPath = new org.eclipse.core.runtime.Path("config/custom-execution-analysis.json"); //$NON-NLS-1$
URL url = FileLocator.find(bundle, defaultPath, null);
File jsonFile = new File(FileLocator.toFileURL(url).toURI());
try (InputStream inputStream = new FileInputStream(jsonFile)) {
ObjectMapper mapper = new ObjectMapper();
JsonNode json = mapper.readTree(inputStream);
return endpoint.request(MediaType.APPLICATION_JSON)
.post(Entity.json(new ConfigurationQueryParameters(json)));
}
}

private static Response updateConfig(String path, String id) {
Expand Down Expand Up @@ -349,32 +416,57 @@ private static Response updateConfig(String path, String id, boolean isCorrectTy
parameters.put(PATH, path);
}
return endpoint.request(MediaType.APPLICATION_JSON)
.put(Entity.json(new QueryParameters(parameters, Collections.emptyList())));
.put(Entity.json(new QueryParameters(parameters, null)));
}

private static Response deleteConfig(String id) {
return deleteConfig(null, id);
}

private static Response deleteConfig(String type, String id) {
String requestType = type;
if (requestType == null) {
requestType = XML_ANALYSIS_TYPE_ID;
}
WebTarget endpoint = getApplicationEndpoint()
.path(CONFIG_PATH)
.path(TYPES_PATH)
.path(XML_ANALYSIS_TYPE_ID)
.path(requestType)
.path(CONFIG_INSTANCES_PATH);
return endpoint.path(id).request().delete();
}

private static List<TmfConfigurationStub> getConfigurations() {
return getConfigurations(null);
}

private static List<TmfConfigurationStub> getConfigurations(@Nullable String type) {
String requestType = type;
if (requestType == null) {
requestType = XML_ANALYSIS_TYPE_ID;
}

WebTarget endpoint = getApplicationEndpoint()
.path(CONFIG_PATH)
.path(TYPES_PATH)
.path(XML_ANALYSIS_TYPE_ID)
.path(requestType)
.path(CONFIG_INSTANCES_PATH);
return endpoint.request().get(LIST_CONFIGURATION_TYPE);
}

private static TmfConfigurationStub getConfiguration(String configId) {
return getConfiguration(null, configId);
}

private static TmfConfigurationStub getConfiguration(String type, String configId) {
String requestType = type;
if (requestType == null) {
requestType = XML_ANALYSIS_TYPE_ID;
}
WebTarget endpoint = getApplicationEndpoint()
.path(CONFIG_PATH)
.path(TYPES_PATH)
.path(XML_ANALYSIS_TYPE_ID)
.path(requestType)
.path(CONFIG_INSTANCES_PATH)
.path(configId);
return endpoint.request().get(CONFIGURATION);
Expand All @@ -388,4 +480,20 @@ private static void validateConfig(ITmfConfiguration config) {
assertEquals(EXPECTED_CONFIG_DESCRIPTION, config.getDescription());
assertTrue(config.getParameters().isEmpty());
}

@SuppressWarnings("null")
private static void validateJsonConfig(ITmfConfiguration config) {
assertEquals(EXPECTED_JSON_CONFIG_NAME, config.getName());
assertEquals(EXPECTED_JSON_CONFIG_ID, config.getId());
assertEquals(CONFIG_WITH_SCHEMA_ANALYSIS_TYPE_ID, config.getSourceTypeId());
assertEquals(EXPECTED_JSON_CONFIG_DESCRIPTION, config.getDescription());
Map<String, Object> parameters = config.getParameters();
assertNotNull(parameters);
Object json = parameters.get(TmfConfiguration.JSON_STRING_KEY);
assertNotNull(json);
assertTrue(json instanceof String);
// Use Gson to verify JsonString
Parameters paramObj = new Gson().fromJson((String) json, Parameters.class);
assertNotNull(paramObj);
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -28,10 +28,15 @@
import org.eclipse.tracecompass.tmf.core.config.ITmfConfiguration;
import org.eclipse.tracecompass.tmf.core.config.ITmfConfigurationSource;
import org.eclipse.tracecompass.tmf.core.config.ITmfConfigurationSourceType;
import org.eclipse.tracecompass.tmf.core.config.TmfConfiguration;
import org.eclipse.tracecompass.tmf.core.config.TmfConfigurationSourceType;
import org.eclipse.tracecompass.tmf.core.exceptions.TmfConfigurationException;
import org.osgi.framework.Bundle;

import com.google.common.collect.ImmutableList;
import com.google.gson.annotations.Expose;
import com.google.gson.annotations.SerializedName;

/**
* Test class
*/
Expand All @@ -43,6 +48,12 @@ public class TestSchemaConfigurationSource implements ITmfConfigurationSource {
private static final @NonNull String NAME = nullToEmptyString("Test Schema Type"); //$NON-NLS-1$
private static final @NonNull String DESCRIPTION = nullToEmptyString("Test Type with schema"); //$NON-NLS-1$

private static final @NonNull String TEST_CONFIG_ID = "My Config Id"; //$NON-NLS-1$
private static final @NonNull String TEST_CONFIG_NAME = "My Config Name"; //$NON-NLS-1$
private static final @NonNull String TEST_CONFIG_DESCRIPTION = "My Config Description"; //$NON-NLS-1$

private ITmfConfiguration fConfiguration;

static {
Bundle bundle = Platform.getBundle("org.eclipse.tracecompass.incubator.trace.server.jersey.rest.core.tests");
IPath defaultPath = new org.eclipse.core.runtime.Path("schema/custom-execution-analysis.json"); //$NON-NLS-1$
Expand Down Expand Up @@ -74,7 +85,19 @@ public TestSchemaConfigurationSource() {

@Override
public @NonNull ITmfConfiguration create(@NonNull Map<@NonNull String, @NonNull Object> parameters) throws TmfConfigurationException {
throw new TmfConfigurationException("Not implemented yet"); //$NON-NLS-1$
Object json = parameters.get(TmfConfiguration.JSON_STRING_KEY);
if (json instanceof String) {
TmfConfiguration.Builder builder = new TmfConfiguration.Builder();
ITmfConfiguration configuration = builder.setId(TEST_CONFIG_ID)
.setSourceTypeId(TEST_ANALYSIS_TYPE_ID)
.setDescription(TEST_CONFIG_DESCRIPTION) // should be taken from json string
.setName(TEST_CONFIG_NAME) // should be taken from json string
.setParameters(parameters)
.build();
fConfiguration = configuration;
return configuration;
}
throw new TmfConfigurationException("No or invalid json provided: " + json); //$NON-NLS-1$
}

@Override
Expand All @@ -84,25 +107,72 @@ public TestSchemaConfigurationSource() {

@Override
public @Nullable ITmfConfiguration get(@NonNull String id) {
return null;
return fConfiguration;
}

@Override
public @Nullable ITmfConfiguration remove(@NonNull String id) {
return null;
ITmfConfiguration configuration = fConfiguration;
fConfiguration = null;
return configuration;
}

@Override
public boolean contains(@NonNull String id) {
return false;
ITmfConfiguration configuration = fConfiguration;
return configuration != null;
}

@Override
public @NonNull List<@NonNull ITmfConfiguration> getConfigurations() {
return Collections.emptyList();
ITmfConfiguration configuration = fConfiguration;
if (configuration == null) {
return Collections.emptyList();
}
return ImmutableList.of(configuration);
}

@Override
public void dispose() {
}

/**
* Class to deserialize json string
*/
public class Parameters {
@Expose
@SerializedName(value = "label")
private String fLabel;
@Expose
@SerializedName(value = "thread")
private String fThread;
@Expose
@SerializedName(value = "phone")
private String fPhone;
@Expose
@SerializedName(value = "cpus")
private List<Integer> fCpus;

/**
* Default constructor for GSON
*/
public Parameters() {
fLabel = ""; //$NON-NLS-1$
fThread = ""; //$NON-NLS-1$
fPhone = ""; //$NON-NLS-1$
fCpus = Collections.emptyList(); //$NON-NLS-1$
}

@Override
public String toString() {
StringBuilder builder = new StringBuilder();
return builder.append("[label=").append(fLabel)
.append(", thread=").append(fThread)
.append(", phone=").append("phone")
.append(", fCpus=").append(fCpus)
.append("]")
.toString();
}
}

}
Original file line number Diff line number Diff line change
Expand Up @@ -23,9 +23,9 @@
public interface ConfigurationQueryParameters {

/**
* @return The query parameter map.
* @return The query parameters.
*/
@NonNull
@Schema(required = true, description = "Parameters as specified in corresponding ConfigurationTypeDescriptor. Use key `path` for file URI string values.")
Map<String, Object> getParameters();
@Schema(required = true, oneOf = { Object.class, Map.class }, description = "Parameters as JSON object as specified in schema of the corresponding ConfigurationTypeDescriptor or as Map<String, Object>. Use key `path` for file URI string values.")
Object getParameters();
}
Loading

0 comments on commit b629159

Please sign in to comment.