blob: daa95eff05bd0d84fed544ca71cee70d0f1b65dd [file] [log] [blame]
J. Duke319a3b92007-12-01 00:00:00 +00001/*
2 * Copyright 2000-2004 Sun Microsystems, Inc. All Rights Reserved.
3 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
4 *
5 * This code is free software; you can redistribute it and/or modify it
6 * under the terms of the GNU General Public License version 2 only, as
7 * published by the Free Software Foundation. Sun designates this
8 * particular file as subject to the "Classpath" exception as provided
9 * by Sun in the LICENSE file that accompanied this code.
10 *
11 * This code is distributed in the hope that it will be useful, but WITHOUT
12 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
13 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
14 * version 2 for more details (a copy is included in the LICENSE file that
15 * accompanied this code).
16 *
17 * You should have received a copy of the GNU General Public License version
18 * 2 along with this work; if not, write to the Free Software Foundation,
19 * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
20 *
21 * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa Clara,
22 * CA 95054 USA or visit www.sun.com if you need additional information or
23 * have any questions.
24 */
25
26package com.sun.jndi.dns;
27
28
29import java.net.MalformedURLException;
30import java.util.ArrayList;
31import java.util.Hashtable;
32import java.util.List;
33
34import javax.naming.*;
35import javax.naming.spi.*;
36
37import com.sun.jndi.toolkit.url.UrlUtil;
38import sun.net.dns.ResolverConfiguration; // available since 1.4.1
39
40
41/**
42 * A DnsContextFactory serves as the initial context factory for DNS.
43 *
44 * <p> When an initial context is being created, the environment
45 * property "java.naming.provider.url" should contain a DNS pseudo-URL
46 * (see DnsUrl) or a space-separated list of them. Multiple URLs must
47 * all have the same domain value.
48 * If the property is not set, the default "dns:" is used.
49 *
50 * @author Scott Seligman
51 */
52
53
54public class DnsContextFactory implements InitialContextFactory {
55
56 private static final String DEFAULT_URL = "dns:";
57
58
59 public Context getInitialContext(Hashtable<?,?> env) throws NamingException {
60 if (env == null) {
61 env = new Hashtable(5);
62 }
63 return urlToContext(getInitCtxUrl(env), env);
64 }
65
66 public static DnsContext getContext(String domain,
67 String[] servers, Hashtable<?,?> env)
68 throws NamingException {
69 return new DnsContext(domain, servers, env);
70 }
71
72 /*
73 * "urls" are used to determine the servers, but any domain
74 * components are overridden by "domain".
75 */
76 public static DnsContext getContext(String domain,
77 DnsUrl[] urls, Hashtable env)
78 throws NamingException {
79
80 String[] servers = serversForUrls(urls);
81 DnsContext ctx = getContext(domain, servers, env);
82 if (platformServersUsed(urls)) {
83 ctx.setProviderUrl(constructProviderUrl(domain, servers));
84 }
85 return ctx;
86 }
87
88 /*
89 * Public for use by product test suite.
90 */
91 public static boolean platformServersAvailable() {
92 return !ResolverConfiguration.open().nameservers().isEmpty();
93 }
94
95 private static Context urlToContext(String url, Hashtable env)
96 throws NamingException {
97
98 DnsUrl[] urls;
99 try {
100 urls = DnsUrl.fromList(url);
101 } catch (MalformedURLException e) {
102 throw new ConfigurationException(e.getMessage());
103 }
104 if (urls.length == 0) {
105 throw new ConfigurationException(
106 "Invalid DNS pseudo-URL(s): " + url);
107 }
108 String domain = urls[0].getDomain();
109
110 // If multiple urls, all must have the same domain.
111 for (int i = 1; i < urls.length; i++) {
112 if (!domain.equalsIgnoreCase(urls[i].getDomain())) {
113 throw new ConfigurationException(
114 "Conflicting domains: " + url);
115 }
116 }
117 return getContext(domain, urls, env);
118 }
119
120 /*
121 * Returns all the servers specified in a set of URLs.
122 * If a URL has no host (or port), the servers configured on the
123 * underlying platform are used if possible. If no configured
124 * servers can be found, then fall back to the old behavior of
125 * using "localhost".
126 * There must be at least one URL.
127 */
128 private static String[] serversForUrls(DnsUrl[] urls)
129 throws NamingException {
130
131 if (urls.length == 0) {
132 throw new ConfigurationException("DNS pseudo-URL required");
133 }
134
135 List servers = new ArrayList();
136
137 for (int i = 0; i < urls.length; i++) {
138 String server = urls[i].getHost();
139 int port = urls[i].getPort();
140
141 if (server == null && port < 0) {
142 // No server or port given, so look to underlying platform.
143 // ResolverConfiguration does some limited caching, so the
144 // following is reasonably efficient even if called rapid-fire.
145 List platformServers =
146 ResolverConfiguration.open().nameservers();
147 if (!platformServers.isEmpty()) {
148 servers.addAll(platformServers);
149 continue; // on to next URL (if any, which is unlikely)
150 }
151 }
152
153 if (server == null) {
154 server = "localhost";
155 }
156 servers.add((port < 0)
157 ? server
158 : server + ":" + port);
159 }
160 return (String[]) servers.toArray(
161 new String[servers.size()]);
162 }
163
164 /*
165 * Returns true if serversForUrls(urls) would make use of servers
166 * from the underlying platform.
167 */
168 private static boolean platformServersUsed(DnsUrl[] urls) {
169 if (!platformServersAvailable()) {
170 return false;
171 }
172 for (int i = 0; i < urls.length; i++) {
173 if (urls[i].getHost() == null &&
174 urls[i].getPort() < 0) {
175 return true;
176 }
177 }
178 return false;
179 }
180
181 /*
182 * Returns a value for the PROVIDER_URL property (space-separated URL
183 * Strings) that reflects the given domain and servers.
184 * Each server is of the form "server[:port]".
185 * There must be at least one server.
186 * IPv6 literal host names include delimiting brackets.
187 */
188 private static String constructProviderUrl(String domain,
189 String[] servers) {
190 String path = "";
191 if (!domain.equals(".")) {
192 try {
193 path = "/" + UrlUtil.encode(domain, "ISO-8859-1");
194 } catch (java.io.UnsupportedEncodingException e) {
195 // assert false : "ISO-Latin-1 charset unavailable";
196 }
197 }
198
199 StringBuffer buf = new StringBuffer();
200 for (int i = 0; i < servers.length; i++) {
201 if (i > 0) {
202 buf.append(' ');
203 }
204 buf.append("dns://").append(servers[i]).append(path);
205 }
206 return buf.toString();
207 }
208
209 /*
210 * Reads environment to find URL(s) of initial context.
211 * Default URL is "dns:".
212 */
213 private static String getInitCtxUrl(Hashtable env) {
214 String url = (String) env.get(Context.PROVIDER_URL);
215 return ((url != null) ? url : DEFAULT_URL);
216 }
217}