8000 Support for SRV records for service discovery · aashish13/rabbitmq-java-client@6863353 · GitHub
[go: up one dir, main page]

Skip to content

Commit 6863353

Browse files
committed
Support for SRV records for service discovery
Fixes rabbitmq#104
1 parent 92b6c0f commit 6863353

File tree

6 files changed

+271
-1
lines changed

6 files changed

+271
-1
lines changed

src/main/java/com/rabbitmq/client/AddressResolver.java

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,18 @@
1+
// Copyright (c) 2007-Present Pivotal Software, Inc. All rights reserved.
2+
//
3+
// This software, the RabbitMQ Java client library, is triple-licensed under the
4+
// Mozilla Public License 1.1 ("MPL"), the GNU General Public License version 2
5+
// ("GPL") and the Apache License version 2 ("ASL"). For the MPL, please see
6+
// LICENSE-MPL-RabbitMQ. For the GPL, please see LICENSE-GPL2. For the ASL,
7+
// please see LICENSE-APACHE2.
8+
//
9+
// This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY KIND,
10+
// either express or implied. See the LICENSE file for specific language governing
11+
// rights and limitations of this software.
12+
//
13+
// If you have any questions regarding licensing, please contact us at
14+
// info@rabbitmq.com.
15+
116
package com.rabbitmq.client;
217

318
import java.io.IOException;

src/main/java/com/rabbitmq/client/DnsRecordIpAddressResolver.java

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,18 @@
1+
// Copyright (c) 2007-Present Pivotal Software, Inc. All rights reserved.
2+
//
3+
// This software, the RabbitMQ Java client library, is triple-licensed under the
4+
// Mozilla Public License 1.1 ("MPL"), the GNU General Public License version 2
5+
// ("GPL") and the Apache License version 2 ("ASL"). For the MPL, please see
6+
// LICENSE-MPL-RabbitMQ. For the GPL, please see LICENSE-GPL2. For the ASL,
7+
// please see LICENSE-APACHE2.
8+
//
9+
// This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY KIND,
10+
// either express or implied. See the LICENSE file for specific language governing
11+
// rights and limitations of this software.
12+
//
13+
// If you have any questions regarding licensing, please contact us at
14+
// info@rabbitmq.com.
15+
116
package com.rabbitmq.client;
217

318
import java.io.IOException;
Lines changed: 167 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,167 @@
1+
// Copyright (c) 2007-Present Pivotal Software, Inc. All rights reserved.
2+
//
3+
// This software, the RabbitMQ Java client library, is triple-licensed under the
4+
// Mozilla Public License 1.1 ("MPL"), the GNU General Public License version 2
5+
// ("GPL") and the Apache License version 2 ("ASL"). For the MPL, please see
6+
// LICENSE-MPL-RabbitMQ. For the GPL, please see LICENSE-GPL2. For the ASL,
7+
// please see LICENSE-APACHE2.
8+
//
9+
// This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY KIND,
10+
// either express or implied. See the LICENSE file for specific language governing
11+
// rights and limitations of this software.
12+
//
13+
// If you have any questions regarding licensing, please contact us at
14+
// info@rabbitmq.com.
15+
16+
package com.rabbitmq.client;
17+
18+
import javax.naming.NamingEnumeration;
19+
import javax.naming.NamingException;
6D40 20+
import javax.naming.directory.Attributes;
21+
import javax.naming.directory.DirContext;
22+
import javax.naming.directory.InitialDirContext;
23+
import java.io.IOException;
24+
import java.util.ArrayList;
25+
import java.util.Collections;
26+
import java.util.Hashtable;
27+
import java.util.List;
28+
29+
/**
30+
* {@link AddressResolver} that resolves addresses against a DNS SRV request.
31+
* SRV records contain the hostname and the port for a given service.
32+
* They also support priorities, to give precedence to a given host
33+
* over other hosts.
34+
* Note the hosts returned by the SRV query must be resolvable by
35+
* the DNS servers of the underlying platform (or the default ones
36+
* specified for this Java process). This class does not issue a
37+
* query for A records after the SRV query.
38+
* This implementation returns the highest-priority records first.
39+
* This behavior can be changed by overriding the {@code sort} method.
40+
*
41+
* This implementation uses internally the {@code com.sun.jndi.dns.DnsContextFactory}
42+
* class for the DNS query.
43+
*
44+
* The first returned address is used when automatic recovery is NOT enabled
45+
* at the {@link ConnectionFactory} level.
46+
* When automatic recovery is enabled, a random address will be picked up
47+
* from the returned list of {@link Address}es.
48+
*
49+
*/
50+
public class DnsSrvRecordAddressResolver implements AddressResolver {
51+
52+
/**
53+
* the SRV service information.
54+
* e.g. _sip._tcp.example.com or rabbitmq.service.consul
55+
*/
56+
private final String service;
57+
58+
/**
59+
* URLs of the DNS servers.
60+
* e.g. dns://server1.example.com/example.com
61+
* Default to {@code dns:}, that is the DNS server of the
62+
* underlying platform.
63+
*/
64+
private final String dnsUrls;
65+
66+
public DnsSrvRecordAddressResol F438 ver(String service) {
67+
this(service, "dns:");
68+
}
69+
70+
public DnsSrvRecordAddressResolver(String service, String dnsUrls) {
71+
this.service = service;
72+
this.dnsUrls = dnsUrls;
73+
}
74+
75+
@Override
76+
public List<Address> getAddresses() throws IOException {
77+
List<SrvRecord> records = lookupSrvRecords(service, dnsUrls);
78+
records = sort(records);
79+
80+
List<Address> addresses = new ArrayList<Address>();
81+
for (SrvRecord record : records) {
82+
addresses.add(new Address(record.getHost(), record.getPort()));
83+
}
84+
85+
return addresses;
86+
}
87+
88+
protected List<SrvRecord> lookupSrvRecords(String service, String dnsUrls) throws IOException {
89+
Hashtable<String, String> env = new Hashtable<String, String>();
90+
env.put("java.naming.factory.initial", "com.sun.jndi.dns.DnsContextFactory");
91+
env.put("java.naming.provider.url", dnsUrls);
92+
93+
List<SrvRecord> records = new ArrayList<SrvRecord>();
94+
try {
95+
DirContext ctx = new InitialDirContext(env);
96+
Attributes attributes = ctx.getAttributes(service, new String[] { "SRV" });
97+
NamingEnumeration<?> servers = attributes.get("srv").getAll();
98+
while (servers.hasMore()) {
99+
records.add(mapSrvRecord((String) servers.next()));
100+
}
101+
} catch(NamingException e) {
102+
throw new IOException("Error during DNS SRV query", e);
103+
}
104+
105+
return records;
106+
}
107+
108+
protected SrvRecord mapSrvRecord(String srvResult) {
109+
return SrvRecord.fromSrvQueryResult(srvResult);
110+
}
111+
112+
protected List<SrvRecord> sort(List<SrvRecord> records) {
113+
Collections.sort(records);
114+
return records;
115+
}
116+
117+
public static class SrvRecord implements Comparable<SrvRecord> {
118+
119+
private final int priority;
120+
private final int weight;
121+
private final int port;
122+
private final String host;
123+
124+
public SrvRecord(int priority, int weight, int port, String host) {
125+
this.priority = priority;
126+
this.weight = weight;
127+
this.port = port;
128+
int lastDotIndex = host.lastIndexOf(".");
129+
if(lastDotIndex > 0) {
130+
this.host = host.substring(0, lastDotIndex);
131+
} else {
132+
this.host = host;
133+
}
134+
}
135+
136+
public int getPriority() {
137+
return priority;
138+
}
139+
140+
public int getWeight() {
141+
return weight;
142+
}
143+
144+
public int getPort() {
145+
return port;
146+
}
147+
148+
public String getHost() {
149+
return host;
150+
}
151+
152+
public static SrvRecord fromSrvQueryResult(String srvResult) {
153+
String[] fields = srvResult.split(" ");
154+
return new SrvRecord(
155+
Integer.parseInt(fields[0]),
156+
Integer.parseInt(fields[1]),
157+
Integer.parseInt(fields[2]),
158+
fields[3]
159+
);
160+
}
161+
162+
@Override
163+
public int compareTo(SrvRecord o) {
164+
return (this.priority < o.getPriority()) ? -1 : ((this.priority == o.getPriority()) ? 0 : 1);
165+
}
166+
}
167+
}

src/main/java/com/rabbitmq/client/ListAddressResolver.java

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,18 @@
1+
// Copyright (c) 2007-Present Pivotal Software, Inc. All rights reserved.
2+
//
3+
// This software, the RabbitMQ Java client library, is triple-licensed under the
4+
// Mozilla Public License 1.1 ("MPL"), the GNU General Public License version 2
5+
// ("GPL") and the Apache License version 2 ("ASL"). For the MPL, please see
6+
// LICENSE-MPL-RabbitMQ. For the GPL, please see LICENSE-GPL2. For the ASL,
7+
// please see LICENSE-APACHE2.
8+
//
9+
// This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY KIND,
10+
// either express or implied. See the LICENSE file for specific language governing
11+
// rights and limitations of this software.
12+
//
13+
// If you have any questions regarding licensing, please contact us at
14+
// info@rabbitmq.com.
15+
116
package com.rabbitmq.client;
217

318
import java.util.List;

src/test/java/com/rabbitmq/client/test/ClientTests.java

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -39,7 +39,8 @@
3939
AMQBuilderApiTest.class,
4040
AmqpUriTest.class,
4141
JSONReadWriteTest.class,
42-
SharedThreadPoolTest.class
42+
SharedThreadPoolTest.class,
43+
DnsSrvRecordAddressResolverTest.class
4344
})
4445
public class ClientTests {
4546

Lines changed: 57 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,57 @@
1+
// Copyright (c) 2007-Present Pivotal Software, Inc. All rights reserved.
2+
//
3+
// This software, the RabbitMQ Java client library, is triple-licensed under the
4+
// Mozilla Public License 1.1 ("MPL"), the GNU General Public License version 2
5+
// ("GPL") and the Apache License version 2 ("ASL"). For the MPL, please see
6+
// LICENSE-MPL-RabbitMQ. For the GPL, please see LICENSE-GPL2. For the ASL,
7+
// please see LICENSE-APACHE2.
8+
//
9+
// This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY KIND,
10+
// either express or implied. See the LICENSE file for specific language governing
11+
// rights and limitations of this software.
12+
//
13+
// If you have any questions regarding licensing, please contact us at
14+
// info@rabbitmq.com.
15+
16+
package com.rabbitmq.client.test;
17+
18+
import com.rabbitmq.client.Address;
19+
import com.rabbitmq.client.DnsSrvRecordAddressResolver;
20+
import org.junit.Test;
21+
22+
import java.io.IOException;
23+
import java.util.Arrays;
24+
import java.util.List;
25+
26+
import static org.hamcrest.CoreMatchers.is;
27+
import static org.junit.Assert.assertThat;
28+
29+
/**
30+
*
31+
*/
32+
public class DnsSrvRecordAddressResolverTest {
33+
34+
@Test public void recordsParsedAndSorted() throws IOException {
35+
DnsSrvRecordAddressResolver resolver = new DnsSrvRecordAddressResolver("rabbitmq") {
36+
@Override
37+
protected List<SrvRecord> lookupSrvRecords(String service, String dnsUrls) throws IOException {
38+
return Arrays.asList(
39+
DnsSrvRecordAddressResolver.SrvRecord.fromSrvQueryResult("20 0 5269 alt2.xmpp-server.l.google.com."),
40+
DnsSrvRecordAddressResolver.SrvRecord.fromSrvQueryResult("30 0 5269 alt3.xmpp-server.l.google.com."),
41+
DnsSrvRecordAddressResolver.SrvRecord.fromSrvQueryResult("10 0 5269 alt1.xmpp-server.l.google.com."),
42+
DnsSrvRecordAddressResolver.SrvRecord.fromSrvQueryResult("50 0 5269 alt5.xmpp-server.l.google.com."),
43+
DnsSrvRecordAddressResolver.SrvRecord.fromSrvQueryResult("40 0 5269 alt4.xmpp-server.l.google.com.")
44+
);
45+
}
46+
};
47+
48+
List<Address> addresses = resolver.getAddresses();
49+
assertThat(addresses.size(), is(5));
50+
assertThat(addresses.get(0).getHost(), is("alt1.xmpp-server.l.google.com"));
51+
assertThat(addresses.get(1).getHost(), is("alt2.xmpp-server.l.google.com"));
52+
assertThat(addresses.get(2).getHost(), is("alt3.xmpp-server.l.google.com"));
53+
assertThat(addresses.get(3).getHost(), is("alt4.xmpp-server.l.google.com"));
54+
assertThat(addresses.get(4).getHost(), is("alt5.xmpp-server.l.google.com"));
55+
}
56+
57+
}

0 commit comments

Comments
 (0)
0