/* * Copyright 2013 Jive Software, 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.jivesoftware.os.amza.api.ring; import com.fasterxml.jackson.annotation.JsonCreator; import com.fasterxml.jackson.annotation.JsonProperty; import com.jivesoftware.os.amza.api.filer.UIO; import com.jivesoftware.os.mlogger.core.MetricLogger; import com.jivesoftware.os.mlogger.core.MetricLoggerFactory; import java.nio.charset.StandardCharsets; import java.util.Arrays; import java.util.Objects; public class RingHost { private static final MetricLogger LOG = MetricLoggerFactory.getLogger(); public static final RingHost UNKNOWN_RING_HOST = new RingHost("", "", "unknownRingHost", 0); private final String datacenter; private final String rack; private final String host; private final int port; public byte[] toBytes() { // TODO convert to lex byte ordering? byte[] hostBytes = host.getBytes(StandardCharsets.UTF_8); byte[] rackBytes = rack.getBytes(StandardCharsets.UTF_8); byte[] datacenterBytes = datacenter.getBytes(StandardCharsets.UTF_8); byte[] bytes = new byte[1 + 4 + 4 + hostBytes.length + 4 + rackBytes.length + 4 + datacenterBytes.length]; int i = 0; bytes[i] = 1; // version; i++; UIO.intBytes(port, bytes, i); i += 4; UIO.intBytes(hostBytes.length, bytes, i); i += 4; UIO.writeBytes(hostBytes, bytes, i); i += hostBytes.length; UIO.intBytes(rackBytes.length, bytes, i); i += 4; UIO.writeBytes(rackBytes, bytes, i); i += rackBytes.length; UIO.intBytes(datacenterBytes.length, bytes, i); i += 4; UIO.writeBytes(datacenterBytes, bytes, i); return bytes; } public static RingHost fromBytes(byte[] bytes) throws Exception { if (bytes[0] == 0) { int port = UIO.bytesInt(bytes, 1); String host = new String(bytes, 1 + 4, bytes.length - (1 + 4), StandardCharsets.UTF_8); return new RingHost("", "", host, port); } else if (bytes[0] == 1) { int i = 1; int port = UIO.bytesInt(bytes, i); i += 4; int hostLength = UIO.bytesInt(bytes, i); i += 4; String host = new String(bytes, i, hostLength, StandardCharsets.UTF_8); i += hostLength; int rackLength = UIO.bytesInt(bytes, i); i += 4; String rack = new String(bytes, i, rackLength, StandardCharsets.UTF_8); i += rackLength; int datacenterLength = UIO.bytesInt(bytes, i); i += 4; String datacenter = new String(bytes, i, datacenterLength, StandardCharsets.UTF_8); return new RingHost(datacenter, rack, host, port); } LOG.error("Bad RingHost bytes, bytes={}", new Object[] { Arrays.toString(bytes) }, new Throwable()); return null; // Sorry caller } @JsonCreator public RingHost(@JsonProperty("datacenter") String datacenter, @JsonProperty("rack") String rack, @JsonProperty("host") String host, @JsonProperty("port") int port) { this.datacenter = datacenter == null ? "" : datacenter; this.rack = rack == null ? "" : rack; this.host = host; this.port = port; } public String getDatacenter() { return datacenter; } public String getRack() { return rack; } public String getHost() { return host; } public int getPort() { return port; } public String toCanonicalString() { return datacenter + ":" + rack + ":" + host + ":" + port; } public static RingHost fromCanonicalString(String canonical) { String[] split = new String[4]; int i = 0; int fromIndex = 0; for (int toIndex = canonical.indexOf(':'); toIndex >= 0; toIndex = canonical.indexOf(':', toIndex + 1)) { split[i] = canonical.substring(fromIndex, toIndex); fromIndex = toIndex + 1; i++; } split[i] = canonical.substring(fromIndex); i++; if (i == 2) { return new RingHost("", "", split[0], Integer.parseInt(split[1])); } else if (i == 4) { return new RingHost(split[0], split[1], split[2], Integer.parseInt(split[3])); } else { throw new IllegalArgumentException("Malformed canonical:" + canonical + " expect: host:port or datacenter:rack:host:port"); } } @Override public String toString() { return "RingHost{" + "datacenter=" + datacenter + ", rack=" + rack + ", host=" + host + ", port=" + port + '}'; } @Override public boolean equals(Object o) { if (this == o) { return true; } if (o == null || getClass() != o.getClass()) { return false; } RingHost ringHost = (RingHost) o; if (port != ringHost.port) { return false; } if (datacenter != null ? !datacenter.equals(ringHost.datacenter) : ringHost.datacenter != null) { return false; } if (rack != null ? !rack.equals(ringHost.rack) : ringHost.rack != null) { return false; } if (host != null ? !host.equals(ringHost.host) : ringHost.host != null) { return false; } return true; } @Override public int hashCode() { int result = datacenter != null ? datacenter.hashCode() : 0; result = 31 * result + (rack != null ? rack.hashCode() : 0); result = 31 * result + (host != null ? host.hashCode() : 0); result = 31 * result + port; return result; } }