/*
 * Copyright DataStax, Inc.
 *
 * 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 com.datastax.dse.driver.internal.core.graph;

import com.datastax.dse.driver.api.core.graph.GraphNode;
import com.datastax.oss.driver.api.core.type.reflect.GenericType;
import com.datastax.oss.driver.shaded.guava.common.base.Objects;
import com.datastax.oss.driver.shaded.guava.common.base.Preconditions;
import java.io.ByteArrayInputStream;
import java.io.IOException;
import java.io.UncheckedIOException;
import java.nio.charset.StandardCharsets;
import java.util.List;
import java.util.Map;
import java.util.Set;
import net.jcip.annotations.Immutable;
import org.apache.tinkerpop.gremlin.process.traversal.Path;
import org.apache.tinkerpop.gremlin.structure.Edge;
import org.apache.tinkerpop.gremlin.structure.Property;
import org.apache.tinkerpop.gremlin.structure.Vertex;
import org.apache.tinkerpop.gremlin.structure.VertexProperty;
import org.apache.tinkerpop.gremlin.structure.io.graphson.GraphSONTokens;
import org.apache.tinkerpop.gremlin.structure.util.Attachable;
import org.apache.tinkerpop.shaded.jackson.core.JsonParser;
import org.apache.tinkerpop.shaded.jackson.databind.JavaType;
import org.apache.tinkerpop.shaded.jackson.databind.JsonNode;
import org.apache.tinkerpop.shaded.jackson.databind.ObjectMapper;

Legacy implementation for GraphSON 1 results.

The server returns plain JSON with no type information. The driver works with the JSON representation directly.

/** * Legacy implementation for GraphSON 1 results. * * <p>The server returns plain JSON with no type information. The driver works with the JSON * representation directly. */
@Immutable public class LegacyGraphNode implements GraphNode { private static final String TYPE = "type"; private static final String VERTEX_TYPE = "vertex"; private static final String EDGE_TYPE = "edge"; private static final GenericType<List<Object>> LIST_TYPE = GenericType.listOf(Object.class); private static final GenericType<Map<String, Object>> MAP_TYPE = GenericType.mapOf(String.class, Object.class); private final JsonNode delegate; private final ObjectMapper objectMapper; public LegacyGraphNode(JsonNode delegate, ObjectMapper objectMapper) { Preconditions.checkNotNull(delegate); Preconditions.checkNotNull(objectMapper); this.delegate = delegate; this.objectMapper = objectMapper; }
The underlying JSON representation.

This is an implementation detail, it's only exposed through the internal API.

/** * The underlying JSON representation. * * <p>This is an implementation detail, it's only exposed through the internal API. */
public JsonNode getDelegate() { return delegate; }
The object mapper used to deserialize results in as(Class<Object>) and as(GenericType<Object>).

This is an implementation detail, it's only exposed through the internal API.

/** * The object mapper used to deserialize results in {@link #as(Class)} and {@link * #as(GenericType)}. * * <p>This is an implementation detail, it's only exposed through the internal API. */
public ObjectMapper getObjectMapper() { return objectMapper; } @Override public boolean isNull() { return delegate.isNull(); } @Override public boolean isMap() { return delegate.isObject(); } @Override public Iterable<?> keys() { return (Iterable<String>) delegate::fieldNames; } @Override public LegacyGraphNode getByKey(Object key) { if (!(key instanceof String)) { return null; } JsonNode node = delegate.get(((String) key)); if (node == null) { return null; } return new LegacyGraphNode(node, objectMapper); } @Override @SuppressWarnings("unchecked") public <K, V> Map<K, V> asMap() { return (Map<K, V>) as(MAP_TYPE); } @Override public boolean isList() { return delegate.isArray(); } @Override public int size() { return delegate.size(); } @Override public LegacyGraphNode getByIndex(int index) { JsonNode node = delegate.get(index); if (node == null) { return null; } return new LegacyGraphNode(node, objectMapper); } @Override @SuppressWarnings("unchecked") public <T> List<T> asList() { return (List<T>) as(LIST_TYPE); } @Override public boolean isValue() { return delegate.isValueNode(); } @Override public int asInt() { return delegate.asInt(); } @Override public boolean asBoolean() { return delegate.asBoolean(); } @Override public long asLong() { return delegate.asLong(); } @Override public double asDouble() { return delegate.asDouble(); } @Override public String asString() { return delegate.asText(); } @Override public boolean isVertex() { return isType(VERTEX_TYPE); } @Override public Vertex asVertex() { try { return GraphSONUtils.GRAPHSON1_READER .get() .readVertex( new ByteArrayInputStream(delegate.toString().getBytes(StandardCharsets.UTF_8)), null, null, null); } catch (IOException e) { throw new UncheckedIOException("Could not deserialize node as Vertex.", e); } } @Override public boolean isEdge() { return isType(EDGE_TYPE); } @Override public Edge asEdge() { try { return GraphSONUtils.GRAPHSON1_READER .get() .readEdge( new ByteArrayInputStream(delegate.toString().getBytes(StandardCharsets.UTF_8)), Attachable::get); } catch (IOException e) { throw new UncheckedIOException("Could not deserialize node as Edge.", e); } } @Override public boolean isPath() { return false; } @Override public Path asPath() { throw new UnsupportedOperationException( "GraphSON1 does not support Path, use another Graph sub-protocol such as GraphSON2."); } @Override public boolean isProperty() { return delegate.has(GraphSONTokens.KEY) && delegate.has(GraphSONTokens.VALUE); } @Override @SuppressWarnings("unchecked") public <T> Property<T> asProperty() { try { return GraphSONUtils.GRAPHSON1_READER .get() .readProperty( new ByteArrayInputStream(delegate.toString().getBytes(StandardCharsets.UTF_8)), Attachable::get); } catch (IOException e) { throw new UncheckedIOException("Could not deserialize node as Property.", e); } } @Override public boolean isVertexProperty() { return delegate.has(GraphSONTokens.ID) && delegate.has(GraphSONTokens.VALUE) && delegate.has(GraphSONTokens.LABEL); } @Override @SuppressWarnings("unchecked") public <T> VertexProperty<T> asVertexProperty() { try { return GraphSONUtils.GRAPHSON1_READER .get() .readVertexProperty( new ByteArrayInputStream(delegate.toString().getBytes(StandardCharsets.UTF_8)), Attachable::get); } catch (IOException e) { throw new UncheckedIOException("Could not deserialize node as VertexProperty.", e); } } @Override public boolean isSet() { return false; } @Override public <T> Set<T> asSet() { throw new UnsupportedOperationException( "GraphSON1 does not support Set, use another Graph sub-protocol such as GraphSON2."); } @Override public <ResultT> ResultT as(Class<ResultT> clazz) { try { return objectMapper.treeToValue(delegate, clazz); } catch (IOException e) { throw new UncheckedIOException("Could not deserialize node as: " + clazz, e); } } @Override public <ResultT> ResultT as(GenericType<ResultT> type) { try { JsonParser parser = objectMapper.treeAsTokens(delegate); JavaType javaType = objectMapper.constructType(type.__getToken().getType()); return objectMapper.readValue(parser, javaType); } catch (IOException e) { throw new UncheckedIOException("Could not deserialize node as: " + type, e); } } @Override public boolean equals(Object o) { if (this == o) { return true; } if (!(o instanceof LegacyGraphNode)) { return false; } LegacyGraphNode that = (LegacyGraphNode) o; return Objects.equal(delegate, that.delegate); } @Override public int hashCode() { return Objects.hashCode(delegate); } @Override public String toString() { return delegate.toString(); } private boolean isType(String expectedTypeName) { JsonNode type = delegate.get(TYPE); return type != null && expectedTypeName.equals(type.asText()); } }