All Downloads are FREE. Search and download functionalities are using the official Maven repository.

org.neo4j.dbms.systemgraph.CommunityTopologyGraphDbmsModelUtil Maven / Gradle / Ivy

Go to download

Neo4j kernel is a lightweight, embedded Java database designed to store data structured as graphs rather than tables. For more information, see http://neo4j.org.

There is a newer version: 5.25.1
Show newest version
/*
 * Copyright (c) "Neo4j"
 * Neo4j Sweden AB [https://neo4j.com]
 *
 * This file is part of Neo4j.
 *
 * Neo4j is free software: you can redistribute it and/or modify
 * it under the terms of the GNU General Public License as published by
 * the Free Software Foundation, either version 3 of the License, or
 * (at your option) any later version.
 *
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU General Public License for more details.
 *
 * You should have received a copy of the GNU General Public License
 * along with this program.  If not, see .
 */
package org.neo4j.dbms.systemgraph;

import static org.neo4j.dbms.systemgraph.DriverSettings.Keys.CONNECTION_POOL_ACQUISITION_TIMEOUT;

import java.net.URI;
import java.util.List;
import java.util.Map;
import java.util.Optional;
import java.util.UUID;
import java.util.function.Supplier;
import java.util.stream.Stream;
import java.util.stream.StreamSupport;
import org.neo4j.configuration.connectors.BoltConnector;
import org.neo4j.configuration.helpers.RemoteUri;
import org.neo4j.configuration.helpers.SocketAddress;
import org.neo4j.configuration.helpers.SocketAddressParser;
import org.neo4j.graphdb.Direction;
import org.neo4j.graphdb.Entity;
import org.neo4j.graphdb.Node;
import org.neo4j.graphdb.NotFoundException;
import org.neo4j.graphdb.Relationship;
import org.neo4j.graphdb.Transaction;
import org.neo4j.kernel.database.DatabaseIdFactory;
import org.neo4j.kernel.database.DatabaseReference;
import org.neo4j.kernel.database.DatabaseReferenceImpl;
import org.neo4j.kernel.database.DatabaseReferenceImpl.Internal;
import org.neo4j.kernel.database.NamedDatabaseId;
import org.neo4j.kernel.database.NormalizedDatabaseName;
import org.neo4j.logging.Level;
import org.neo4j.values.storable.DurationValue;

public final class CommunityTopologyGraphDbmsModelUtil {
    private CommunityTopologyGraphDbmsModelUtil() {}

    static Stream getAllPrimaryStandardDatabaseReferencesInRoot(Transaction tx) {
        return tx.findNodes(TopologyGraphDbmsModel.DATABASE_LABEL).stream()
                .filter(node -> !node.hasProperty(TopologyGraphDbmsModel.DATABASE_VIRTUAL_PROPERTY))
                .map(CommunityTopologyGraphDbmsModelUtil::getDatabaseId)
                .map(CommunityTopologyGraphDbmsModelUtil::primaryRefFromDatabaseId);
    }

    private static Internal primaryRefFromDatabaseId(NamedDatabaseId databaseId) {
        var alias = new NormalizedDatabaseName(databaseId.name());
        return new Internal(alias, databaseId, true);
    }

    static NormalizedDatabaseName getNameProperty(String labelName, Node node) {
        return new NormalizedDatabaseName(
                getPropertyOnNode(labelName, node, TopologyGraphDbmsModel.NAME_PROPERTY, String.class));
    }

    static TopologyGraphDbmsModel.DatabaseAccess getDatabaseAccess(Node databaseNode) {
        var accessString = (String) databaseNode.getProperty(
                TopologyGraphDbmsModel.DATABASE_ACCESS_PROPERTY,
                TopologyGraphDbmsModel.DatabaseAccess.READ_WRITE.toString());
        return Enum.valueOf(TopologyGraphDbmsModel.DatabaseAccess.class, accessString);
    }

    public static Optional createInternalReference(Node alias, NamedDatabaseId targetedDatabase) {
        return ignoreConcurrentDeletes(() -> {
            var aliasName = new NormalizedDatabaseName(getPropertyOnNode(
                    TopologyGraphDbmsModel.DATABASE_NAME, alias, TopologyGraphDbmsModel.NAME_PROPERTY, String.class));
            var namespace = new NormalizedDatabaseName(getPropertyOnNode(
                    TopologyGraphDbmsModel.DATABASE_NAME,
                    alias,
                    TopologyGraphDbmsModel.NAMESPACE_PROPERTY,
                    String.class));
            var primary = getPropertyOnNode(
                    TopologyGraphDbmsModel.DATABASE_NAME,
                    alias,
                    TopologyGraphDbmsModel.PRIMARY_PROPERTY,
                    Boolean.class);
            return Optional.of(new Internal(aliasName, namespace, targetedDatabase, primary));
        });
    }

    public static Optional createExternalReference(Node ref) {
        return ignoreConcurrentDeletes(() -> {
            var uriString = getPropertyOnNode(
                    TopologyGraphDbmsModel.REMOTE_DATABASE_LABEL_DESCRIPTION,
                    ref,
                    TopologyGraphDbmsModel.URL_PROPERTY,
                    String.class);
            var targetName = new NormalizedDatabaseName(getPropertyOnNode(
                    TopologyGraphDbmsModel.REMOTE_DATABASE_LABEL_DESCRIPTION,
                    ref,
                    TopologyGraphDbmsModel.TARGET_NAME_PROPERTY,
                    String.class));
            var aliasName = new NormalizedDatabaseName(getPropertyOnNode(
                    TopologyGraphDbmsModel.REMOTE_DATABASE_LABEL_DESCRIPTION,
                    ref,
                    TopologyGraphDbmsModel.NAME_PROPERTY,
                    String.class));
            var namespace = new NormalizedDatabaseName(getPropertyOnNode(
                    TopologyGraphDbmsModel.REMOTE_DATABASE_LABEL_DESCRIPTION,
                    ref,
                    TopologyGraphDbmsModel.NAMESPACE_PROPERTY,
                    String.class));

            var uri = URI.create(uriString);
            var host = SocketAddressParser.socketAddress(uri, BoltConnector.DEFAULT_PORT, SocketAddress::new);
            var remoteUri = new RemoteUri(uri.getScheme(), List.of(host), uri.getQuery());
            var uuid = getPropertyOnNode(
                    TopologyGraphDbmsModel.REMOTE_DATABASE_LABEL_DESCRIPTION,
                    ref,
                    TopologyGraphDbmsModel.VERSION_PROPERTY,
                    String.class);
            return Optional.of(new DatabaseReferenceImpl.External(
                    targetName, aliasName, namespace, remoteUri, UUID.fromString(uuid)));
        });
    }

    public static Optional getDriverSettings(Node aliasNode) {
        return ignoreConcurrentDeletes(() -> {
            var connectsWith = StreamSupport.stream(
                            aliasNode
                                    .getRelationships(
                                            Direction.OUTGOING, TopologyGraphDbmsModel.CONNECTS_WITH_RELATIONSHIP)
                                    .spliterator(),
                            false)
                    .toList(); // Must be collected to exhaust the underlying iterator

            return connectsWith.stream()
                    .findFirst()
                    .map(Relationship::getEndNode)
                    .map(CommunityTopologyGraphDbmsModelUtil::createDriverSettings);
        });
    }

    public static Optional> getAliasProperties(Node aliasNode) {
        return ignoreConcurrentDeletes(() -> {
            var propertiesRels = StreamSupport.stream(
                            aliasNode
                                    .getRelationships(
                                            Direction.OUTGOING, TopologyGraphDbmsModel.PROPERTIES_RELATIONSHIP)
                                    .spliterator(),
                            false)
                    .toList(); // Must be collected to exhaust the underlying iterator

            return propertiesRels.stream()
                    .findFirst()
                    .map(Relationship::getEndNode)
                    .map(Entity::getAllProperties);
        });
    }

    public static Optional getDatabaseCredentials(Node aliasNode) {
        return ignoreConcurrentDeletes(() -> {
            var username = getPropertyOnNode(
                    TopologyGraphDbmsModel.REMOTE_DATABASE,
                    aliasNode,
                    TopologyGraphDbmsModel.USERNAME_PROPERTY,
                    String.class);
            var password = getPropertyOnNode(
                    TopologyGraphDbmsModel.REMOTE_DATABASE,
                    aliasNode,
                    TopologyGraphDbmsModel.PASSWORD_PROPERTY,
                    byte[].class);
            var iv = getPropertyOnNode(
                    TopologyGraphDbmsModel.REMOTE_DATABASE,
                    aliasNode,
                    TopologyGraphDbmsModel.IV_PROPERTY,
                    byte[].class);
            return Optional.of(new ExternalDatabaseCredentials(username, password, iv));
        });
    }

    private static DriverSettings createDriverSettings(Node driverSettingsNode) {
        var builder = DriverSettings.builder();
        // TODO: Remove sslEnabled and use sslPolicy? Needs Cypher support
        getOptionalPropertyOnNode(
                        TopologyGraphDbmsModel.DRIVER_SETTINGS,
                        driverSettingsNode,
                        TopologyGraphDbmsModel.SSL_ENFORCED,
                        Boolean.class)
                .ifPresent(builder::withSslEnforced);
        getOptionalPropertyOnNode(
                        TopologyGraphDbmsModel.DRIVER_SETTINGS,
                        driverSettingsNode,
                        TopologyGraphDbmsModel.CONNECTION_TIMEOUT,
                        DurationValue.class)
                .ifPresent(builder::withConnectionTimeout);
        getOptionalPropertyOnNode(
                        TopologyGraphDbmsModel.DRIVER_SETTINGS,
                        driverSettingsNode,
                        TopologyGraphDbmsModel.CONNECTION_MAX_LIFETIME,
                        DurationValue.class)
                .ifPresent(builder::withConnectionMaxLifeTime);
        getOptionalPropertyOnNode(
                        TopologyGraphDbmsModel.DRIVER_SETTINGS,
                        driverSettingsNode,
                        CONNECTION_POOL_ACQUISITION_TIMEOUT.toString(),
                        DurationValue.class)
                .ifPresent(builder::withConnectionPoolAcquisitionTimeout);
        getOptionalPropertyOnNode(
                        TopologyGraphDbmsModel.DRIVER_SETTINGS,
                        driverSettingsNode,
                        TopologyGraphDbmsModel.CONNECTION_POOL_IDLE_TEST,
                        DurationValue.class)
                .ifPresent(builder::withConnectionPoolIdleTest);
        getOptionalPropertyOnNode(
                        TopologyGraphDbmsModel.DRIVER_SETTINGS,
                        driverSettingsNode,
                        TopologyGraphDbmsModel.CONNECTION_POOL_MAX_SIZE,
                        Number.class)
                .ifPresent(value -> builder.withConnectionPoolMaxSize(value.intValue()));
        getOptionalPropertyOnNode(
                        TopologyGraphDbmsModel.DRIVER_SETTINGS,
                        driverSettingsNode,
                        TopologyGraphDbmsModel.LOGGING_LEVEL,
                        String.class)
                .ifPresent(level -> builder.withLoggingLevel(Level.valueOf(level)));

        return builder.build();
    }

    static Optional getInternalDatabaseReference(Transaction tx, String databaseName) {
        var aliasNode = findAliasNodeInDefaultNamespace(tx, databaseName);
        return aliasNode.flatMap(alias -> getTargetedDatabase(alias).flatMap(db -> createInternalReference(alias, db)));
    }

    static Optional getExternalDatabaseReference(Transaction tx, String databaseName) {
        var aliasNode = findAliasNodeInDefaultNamespace(tx, databaseName);
        return aliasNode
                .filter(node -> node.hasLabel(TopologyGraphDbmsModel.REMOTE_DATABASE_LABEL))
                .flatMap(CommunityTopologyGraphDbmsModelUtil::createExternalReference);
    }

    static Optional getDatabaseIdByAlias(Transaction tx, String databaseName) {
        return findAliasNodeInDefaultNamespace(tx, databaseName)
                .flatMap(CommunityTopologyGraphDbmsModelUtil::getTargetedDatabase);
    }

    static Optional getDatabaseIdBy(Transaction tx, String propertyKey, String propertyValue) {
        try {
            var node = tx.findNode(TopologyGraphDbmsModel.DATABASE_LABEL, propertyKey, propertyValue);

            if (node == null) {
                return Optional.empty();
            }

            var databaseName = getPropertyOnNode(
                    TopologyGraphDbmsModel.DATABASE_LABEL.name(),
                    node,
                    TopologyGraphDbmsModel.DATABASE_NAME_PROPERTY,
                    String.class);
            var databaseUuid = getPropertyOnNode(
                    TopologyGraphDbmsModel.DATABASE_LABEL.name(),
                    node,
                    TopologyGraphDbmsModel.DATABASE_UUID_PROPERTY,
                    String.class);

            return Optional.of(DatabaseIdFactory.from(databaseName, UUID.fromString(databaseUuid)));
        } catch (RuntimeException e) {
            throw e;
        } catch (Exception e) {
            throw new RuntimeException(e);
        }
    }

    /**
     * *Note* may return `Optional.empty`.
     * 

* It s semantically invalid for an alias to *not* have target, but we ignore it because of the possibility of concurrent deletes. */ private static Optional getTargetedDatabase(Node aliasNode) { return ignoreConcurrentDeletes( () -> { try (Stream stream = aliasNode .getRelationships(Direction.OUTGOING, TopologyGraphDbmsModel.TARGETS_RELATIONSHIP) .stream()) { return stream.findFirst() .map(Relationship::getEndNode) .map(CommunityTopologyGraphDbmsModelUtil::getDatabaseId); } }); } public static Optional getTargetedDatabaseNode(Node aliasNode) { return ignoreConcurrentDeletes( () -> { try (Stream stream = aliasNode .getRelationships(Direction.OUTGOING, TopologyGraphDbmsModel.TARGETS_RELATIONSHIP) .stream()) { return stream.findFirst().map(Relationship::getEndNode); } }); } static NamedDatabaseId getDatabaseId(Node databaseNode) { var name = (String) databaseNode.getProperty(TopologyGraphDbmsModel.DATABASE_NAME_PROPERTY); var uuid = UUID.fromString((String) databaseNode.getProperty(TopologyGraphDbmsModel.DATABASE_UUID_PROPERTY)); return DatabaseIdFactory.from(name, uuid); } private static Optional getOptionalPropertyOnNode(String labelName, Node node, String key, Class type) { Object value; try { value = node.getProperty(key); } catch (NotFoundException e) { return Optional.empty(); } if (value == null) { return Optional.empty(); } if (!type.isInstance(value)) { throw new IllegalStateException( String.format("%s has non %s property %s.", labelName, type.getSimpleName(), key)); } return Optional.of(type.cast(value)); } private static T getPropertyOnNode(String labelName, Node node, String key, Class type) { var value = node.getProperty(key); if (value == null) { throw new IllegalStateException(String.format("%s has no property %s.", labelName, key)); } if (!type.isInstance(value)) { throw new IllegalStateException( String.format("%s has non %s property %s.", labelName, type.getSimpleName(), key)); } return type.cast(value); } private static Optional findAliasNodeInDefaultNamespace(Transaction tx, String databaseName) { try (var nodes = tx.findNodes( TopologyGraphDbmsModel.DATABASE_NAME_LABEL, TopologyGraphDbmsModel.NAME_PROPERTY, databaseName)) { return nodes.stream() .filter(n -> getOptionalPropertyOnNode( TopologyGraphDbmsModel.DATABASE_NAME, n, TopologyGraphDbmsModel.NAMESPACE_PROPERTY, String.class) .orElse(TopologyGraphDbmsModel.DEFAULT_NAMESPACE) .equals(TopologyGraphDbmsModel.DEFAULT_NAMESPACE)) .findFirst(); } } static Optional ignoreConcurrentDeletes(Supplier> operation) { try { return operation.get(); } catch (NotFoundException e) { return Optional.empty(); } } }





© 2015 - 2024 Weber Informatics LLC | Privacy Policy