![JAR search and dependency download from the Maven repository](/logo.png)
org.neo4j.server.rest.discovery.DiscoverableURIs Maven / Gradle / Ivy
/*
* 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.server.rest.discovery;
import static org.neo4j.server.rest.repr.Serializer.joinBaseWithRelativePath;
import java.net.URI;
import java.util.HashMap;
import java.util.Map;
import java.util.function.BiConsumer;
import java.util.function.Predicate;
import org.neo4j.configuration.Config;
import org.neo4j.configuration.GraphDatabaseSettings;
import org.neo4j.configuration.connectors.BoltConnector;
import org.neo4j.configuration.connectors.ConnectorPortRegister;
import org.neo4j.configuration.connectors.ConnectorType;
import org.neo4j.configuration.helpers.SocketAddress;
import org.neo4j.configuration.helpers.SocketAddressParser;
import org.neo4j.dbms.routing.ClientRoutingDomainChecker;
import org.neo4j.graphdb.config.Setting;
import org.neo4j.server.configuration.ServerSettings;
/**
* Repository of URIs that the REST API publicly advertises at the root endpoint.
*/
public class DiscoverableURIs {
private final Map entries;
private DiscoverableURIs(Map entries) {
this.entries = entries;
}
public void forEach(BiConsumer consumer) {
entries.forEach((key, value) -> consumer.accept(key, value.uriString()));
}
/**
* Update http/https by adding the scheme, host, port Update bolt if host is not explicitly set.
*/
public DiscoverableURIs update(URI baseUri) {
entries.forEach((key, value) -> value.update(baseUri));
return this;
}
private interface URITemplate {
String uriString();
void update(URI baseUri);
}
private static class RelativePathBasedURITemplate implements URITemplate {
private final String relativePath;
private String fullPath;
private RelativePathBasedURITemplate(String relativePath) {
this.relativePath = relativePath;
}
@Override
public String uriString() {
return fullPath == null ? relativePath : fullPath;
}
@Override
public void update(URI baseUri) {
fullPath = joinBaseWithRelativePath(baseUri, relativePath);
}
}
private static class ConditionalURIBasedURITemplate implements URITemplate {
private URI uri;
private final Predicate isHostOverridable;
private ConditionalURIBasedURITemplate(URI uri, Predicate isHostOverridable) {
this.uri = uri;
this.isHostOverridable = isHostOverridable;
}
@Override
public String uriString() {
return uri.toASCIIString();
}
@Override
public void update(URI baseUri) {
if (isHostOverridable.test(baseUri)) {
uri = URI.create(String.format("%s://%s:%s", uri.getScheme(), baseUri.getHost(), uri.getPort()));
}
}
}
private static class URIBasedURITemplate implements URITemplate {
private URI uri;
private final boolean isHostOverridable;
private URIBasedURITemplate(URI uri, boolean isHostOverridable) {
this.uri = uri;
this.isHostOverridable = isHostOverridable;
}
@Override
public String uriString() {
return uri.toASCIIString();
}
@Override
public void update(URI baseUri) {
if (isHostOverridable) {
uri = URI.create(String.format("%s://%s:%s", uri.getScheme(), baseUri.getHost(), uri.getPort()));
}
}
}
public static class Builder {
private final Map entries;
private final ClientRoutingDomainChecker clientRoutingDomainChecker;
public Builder(ClientRoutingDomainChecker clientRoutingDomainChecker) {
this.clientRoutingDomainChecker = clientRoutingDomainChecker;
entries = new HashMap<>();
}
/**
* http and/or https endpoints are always relative. The full path will be completed with users' request base uri with {@link DiscoverableURIs#update}
* method.
*/
public Builder addEndpoint(String key, String endpoint) {
var path = new RelativePathBasedURITemplate(endpoint);
entries.put(key, path);
return this;
}
public Builder addBoltEndpoint(Config config, ConnectorPortRegister portRegister) {
if (!config.get(BoltConnector.enabled)) {
// if bolt is not enabled, then no bolt connector entry is discoverable
return this;
}
addBoltEndpoint("bolt_direct", "bolt", ServerSettings.bolt_discoverable_address, config, portRegister);
addBoltEndpoint(
"bolt_routing", "neo4j", ServerSettings.bolt_routing_discoverable_address, config, portRegister);
return this;
}
public DiscoverableURIs build() {
return new DiscoverableURIs(entries);
}
private void addBoltEndpoint(
String key, String scheme, Setting override, Config config, ConnectorPortRegister portRegister) {
URITemplate path;
if (config.isExplicitlySet(override)) {
var uri = config.get(override);
path = new URIBasedURITemplate(uri, false);
} else {
var address = config.get(BoltConnector.advertised_address);
var port = address.getPort() == 0
? portRegister.getLocalAddress(ConnectorType.BOLT).getPort()
: address.getPort();
var host = address.getHostname();
URI uri = URI.create(String.format("%s://%s:%s", scheme, host, port));
if (config.get(GraphDatabaseSettings.routing_default_router)
== GraphDatabaseSettings.RoutingMode.SERVER) {
path = new ConditionalURIBasedURITemplate(
uri,
baseUri -> !(isBoltHostNameExplicitlySet(config)
&& shouldHostGetClientSideRouting(port, baseUri)));
} else {
path = new URIBasedURITemplate(uri, !isBoltHostNameExplicitlySet(config));
}
}
entries.put(key, path);
}
private boolean shouldHostGetClientSideRouting(int port, URI uri) {
return clientRoutingDomainChecker.shouldGetClientRouting(
SocketAddressParser.socketAddress(uri, port, SocketAddress::new));
}
private static boolean isBoltHostNameExplicitlySet(Config config) {
if (config.isExplicitlySet(GraphDatabaseSettings.default_advertised_address)) {
return true;
} else if (config.isExplicitlySet(BoltConnector.advertised_address)) {
var defaultAddress = config.get(GraphDatabaseSettings.default_advertised_address);
var boltAddress = config.get(BoltConnector.advertised_address);
// It is possible that we only set the bolt port without setting the host name
return !boltAddress.getHostname().equals(defaultAddress.getHostname());
}
return false;
}
}
}
© 2015 - 2025 Weber Informatics LLC | Privacy Policy