/* * Copyright (c) 2002-2017 "Neo Technology," * Network Engine for Objects in Lund AB [http://neotechnology.com] * * This file is part of Neo4j. * * 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 org.neo4j.driver.internal.cluster; import java.util.LinkedHashSet; import java.util.Set; import org.neo4j.driver.internal.net.BoltServerAddress; import org.neo4j.driver.v1.Record; import org.neo4j.driver.v1.Value; import org.neo4j.driver.v1.util.Function; final class ClusterComposition { private static final long MAX_TTL = Long.MAX_VALUE / 1000L; private static final Function<Value,BoltServerAddress> OF_BoltServerAddress = new Function<Value,BoltServerAddress>() { @Override public BoltServerAddress apply( Value value ) { return new BoltServerAddress( value.asString() ); } }; private final Set<BoltServerAddress> readers; private final Set<BoltServerAddress> writers; private final Set<BoltServerAddress> routers; private final long expirationTimestamp; private ClusterComposition( long expirationTimestamp ) { this.readers = new LinkedHashSet<>(); this.writers = new LinkedHashSet<>(); this.routers = new LinkedHashSet<>(); this.expirationTimestamp = expirationTimestamp; } /** For testing */ ClusterComposition( long expirationTimestamp, Set<BoltServerAddress> readers, Set<BoltServerAddress> writers, Set<BoltServerAddress> routers ) { this( expirationTimestamp ); this.readers.addAll( readers ); this.writers.addAll( writers ); this.routers.addAll( routers ); } public boolean hasWriters() { return !writers.isEmpty(); } public boolean hasRoutersAndReaders() { return !routers.isEmpty() && !readers.isEmpty(); } public Set<BoltServerAddress> readers() { return new LinkedHashSet<>( readers ); } public Set<BoltServerAddress> writers() { return new LinkedHashSet<>( writers ); } public Set<BoltServerAddress> routers() { return new LinkedHashSet<>( routers ); } public long expirationTimestamp() { return this.expirationTimestamp; } @Override public String toString() { return "ClusterComposition{" + "expirationTimestamp=" + expirationTimestamp + ", readers=" + readers + ", writers=" + writers + ", routers=" + routers + '}'; } public static ClusterComposition parse( Record record, long now ) { if ( record == null ) { return null; } final ClusterComposition result = new ClusterComposition( expirationTimestamp( now, record ) ); record.get( "servers" ).asList( new Function<Value,Void>() { @Override public Void apply( Value value ) { result.servers( value.get( "role" ).asString() ) .addAll( value.get( "addresses" ).asList( OF_BoltServerAddress ) ); return null; } } ); return result; } private static long expirationTimestamp( long now, Record record ) { long ttl = record.get( "ttl" ).asLong(); long expirationTimestamp = now + ttl * 1000; if ( ttl < 0 || ttl >= MAX_TTL || expirationTimestamp < 0 ) { expirationTimestamp = Long.MAX_VALUE; } return expirationTimestamp; } private Set<BoltServerAddress> servers( String role ) { switch ( role ) { case "READ": return readers; case "WRITE": return writers; case "ROUTE": return routers; default: throw new IllegalArgumentException( "invalid server role: " + role ); } } }