Skip to content

Commit

Permalink
feat(graphql): add top-level query for targetNodes (#307)
Browse files Browse the repository at this point in the history
* feat(graphql): add top-level query for targetNodes

* return targets with distinct JVM IDs, implement archived recordings query

* implement active recordings query

* refactor enum registration

* implement subqueries (actually nested mutations) for doStartRecording and doSnapshot

* add mbeanMetrics query

* messaging server uses shared ObjectMapper

* add Jackson serialization customizer so Map<String, String> is encoded the same way GraphQL extension does
  • Loading branch information
andrewazores committed Mar 20, 2024
1 parent bf86879 commit 0d51f89
Show file tree
Hide file tree
Showing 9 changed files with 697 additions and 221 deletions.
83 changes: 83 additions & 0 deletions src/main/java/io/cryostat/ObjectMapperCustomization.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,83 @@
/*
* Copyright The Cryostat Authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package io.cryostat;

import java.io.IOException;
import java.util.Map;

import com.fasterxml.jackson.core.JsonGenerator;
import com.fasterxml.jackson.core.Version;
import com.fasterxml.jackson.databind.BeanDescription;
import com.fasterxml.jackson.databind.JsonSerializer;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.fasterxml.jackson.databind.SerializationConfig;
import com.fasterxml.jackson.databind.SerializerProvider;
import com.fasterxml.jackson.databind.module.SimpleModule;
import com.fasterxml.jackson.databind.ser.BeanSerializerModifier;
import com.fasterxml.jackson.databind.type.MapType;
import io.quarkus.jackson.ObjectMapperCustomizer;
import jakarta.inject.Singleton;

@Singleton
public class ObjectMapperCustomization implements ObjectMapperCustomizer {

@Override
public void customize(ObjectMapper objectMapper) {
// FIXME get this version information from the maven build somehow
SimpleModule mapModule =
new SimpleModule(
"MapSerialization", new Version(3, 0, 0, null, "io.cryostat", "cryostat"));

mapModule.setSerializerModifier(new MapSerializerModifier());

objectMapper.registerModule(mapModule);
}

static class MapSerializerModifier extends BeanSerializerModifier {
@Override
public JsonSerializer<?> modifyMapSerializer(
SerializationConfig config,
MapType valueType,
BeanDescription beanDesc,
JsonSerializer serializer) {
if (valueType.getKeyType().getRawClass().equals(String.class)
&& valueType.getContentType().getRawClass().equals(String.class)) {
return new MapSerializer();
}
return serializer;
}
}

static class MapSerializer extends JsonSerializer<Map<?, ?>> {

@Override
public void serialize(Map<?, ?> map, JsonGenerator gen, SerializerProvider serializers)
throws IOException {
gen.writeStartArray();

for (var entry : map.entrySet()) {
gen.writeStartObject();

gen.writePOJOField("key", entry.getKey());
gen.writePOJOField("value", entry.getValue());

gen.writeEndObject();
}

gen.writeEndArray();
}
}
}
6 changes: 4 additions & 2 deletions src/main/java/io/cryostat/graphql/RootNode.java
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,7 @@
import io.cryostat.discovery.DiscoveryNode;
import io.cryostat.graphql.matchers.LabelSelectorMatcher;

import edu.umd.cs.findbugs.annotations.SuppressFBWarnings;
import io.smallrye.graphql.api.Nullable;
import org.eclipse.microprofile.graphql.Description;
import org.eclipse.microprofile.graphql.GraphQLApi;
Expand All @@ -43,7 +44,7 @@ public DiscoveryNode getRootNode() {
"Get target nodes that are descendants of this node. That is, get the set of leaf nodes"
+ " from anywhere below this node's subtree.")
public List<DiscoveryNode> descendantTargets(
@Source DiscoveryNode discoveryNode, DescendantTargetsFilterInput filter) {
@Source DiscoveryNode discoveryNode, DiscoveryNodeFilter filter) {
// TODO do this filtering at the database query level as much as possible. As is, this will
// load the entire discovery tree out of the database, then perform the filtering at the
// application level.
Expand All @@ -64,7 +65,8 @@ private Set<DiscoveryNode> recurseChildren(
return result;
}

public static class DescendantTargetsFilterInput implements Predicate<DiscoveryNode> {
@SuppressFBWarnings(value = "URF_UNREAD_PUBLIC_OR_PROTECTED_FIELD")
public static class DiscoveryNodeFilter implements Predicate<DiscoveryNode> {
public @Nullable Long id;
public @Nullable String name;
public @Nullable List<String> names;
Expand Down
Loading

0 comments on commit 0d51f89

Please sign in to comment.