blob: d0b60d144dc34ac7b6be79309d7f9493b1d9c219 [file] [log] [blame]
// Copyright 2015 The Vanadium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
package io.v.v23.naming;
import java.io.ByteArrayOutputStream;
import java.io.DataOutputStream;
import java.io.IOException;
import java.util.Arrays;
/**
* A globally unique ID for routing packets to a given {@link Endpoint}.
* <p>
* Global uniqueness is required in order to support comparing {@link Endpoint endpoints} for
* equality; this is required for sharing connections, for proxying (though global uniqueness is
* not strictly required) and determining if different names resolve to the same endpoint.
*/
public class RoutingId {
private static final int ROUTING_ID_LENGTH = 16;
private static final int FIRST_UNRESERVED_ROUTING_ID = 1024;
/**
* The null route.
*/
public static final RoutingId NULL_ROUTING_ID = new RoutingId(new byte[ROUTING_ID_LENGTH]);
private final byte[] value;
/**
* Creates a new routing id given its serialized string (obtained using {@link #toString}).
* If {@code id} is empty, returns {@link #NULL_ROUTING_ID}.
*/
public static RoutingId fromString(String id) {
if (id.isEmpty()) {
return NULL_ROUTING_ID;
}
return new RoutingId(hexStringToByteArray(id));
}
/**
* Returns a fixed routing ID for the given @{code long} constant.
*/
public static RoutingId fixedRoutingId(long id) {
try (ByteArrayOutputStream stream = new ByteArrayOutputStream(ROUTING_ID_LENGTH);
DataOutputStream output = new DataOutputStream(stream)) {
output.writeLong(0);
output.writeLong(id);
return new RoutingId(stream.toByteArray());
} catch (IOException e) {
// We never expect to see this.
throw new RuntimeException(e);
}
}
private RoutingId(byte[] value) {
if (value.length != ROUTING_ID_LENGTH) {
throw new IllegalArgumentException(
"input has unexpected length (was " + value.length + ", want " +
ROUTING_ID_LENGTH + ")");
}
this.value = new byte[ROUTING_ID_LENGTH];
System.arraycopy(value, 0, this.value, 0, ROUTING_ID_LENGTH);
}
private static byte[] hexStringToByteArray(String s) {
int len = s.length();
byte[] data = new byte[len / 2];
for (int i = 0; i < len; i += 2) {
data[i / 2] = (byte) ((Character.digit(s.charAt(i), 16) << 4)
+ Character.digit(s.charAt(i + 1), 16));
}
return data;
}
/**
* Returns a string representation of this {@code RoutingId} that may be used as a parameter to
* {@link #fromString}.
*/
@Override
public String toString() {
StringBuilder builder = new StringBuilder(2 * value.length);
for (int i = 0; i < value.length; i++) {
int low = value[i] & 0xF;
int high = (value[i] >> 8) & 0xF;
builder.append(Character.forDigit(low, 16));
builder.append(Character.forDigit(high, 16));
}
return builder.toString();
}
@Override
public boolean equals(Object o) {
if (this == o) {
return true;
}
if (o == null || getClass() != o.getClass()) {
return false;
}
RoutingId routingId = (RoutingId) o;
return Arrays.equals(value, routingId.value);
}
@Override
public int hashCode() {
return Arrays.hashCode(value);
}
}