001: /*
002: * Copyright 2000-2004 Sun Microsystems, Inc. All Rights Reserved.
003: * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
004: *
005: * This code is free software; you can redistribute it and/or modify it
006: * under the terms of the GNU General Public License version 2 only, as
007: * published by the Free Software Foundation. Sun designates this
008: * particular file as subject to the "Classpath" exception as provided
009: * by Sun in the LICENSE file that accompanied this code.
010: *
011: * This code is distributed in the hope that it will be useful, but WITHOUT
012: * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
013: * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
014: * version 2 for more details (a copy is included in the LICENSE file that
015: * accompanied this code).
016: *
017: * You should have received a copy of the GNU General Public License version
018: * 2 along with this work; if not, write to the Free Software Foundation,
019: * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
020: *
021: * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa Clara,
022: * CA 95054 USA or visit www.sun.com if you need additional information or
023: * have any questions.
024: */
025:
026: package com.sun.jndi.dns;
027:
028: import java.net.MalformedURLException;
029: import java.util.ArrayList;
030: import java.util.Hashtable;
031: import java.util.List;
032:
033: import javax.naming.*;
034: import javax.naming.spi.*;
035:
036: import com.sun.jndi.toolkit.url.UrlUtil;
037: import sun.net.dns.ResolverConfiguration; // available since 1.4.1
038:
039: /**
040: * A DnsContextFactory serves as the initial context factory for DNS.
041: *
042: * <p> When an initial context is being created, the environment
043: * property "java.naming.provider.url" should contain a DNS pseudo-URL
044: * (see DnsUrl) or a space-separated list of them. Multiple URLs must
045: * all have the same domain value.
046: * If the property is not set, the default "dns:" is used.
047: *
048: * @author Scott Seligman
049: * @version 1.18 07/05/05
050: */
051:
052: public class DnsContextFactory implements InitialContextFactory {
053:
054: private static final String DEFAULT_URL = "dns:";
055:
056: public Context getInitialContext(Hashtable<?, ?> env)
057: throws NamingException {
058: if (env == null) {
059: env = new Hashtable(5);
060: }
061: return urlToContext(getInitCtxUrl(env), env);
062: }
063:
064: public static DnsContext getContext(String domain,
065: String[] servers, Hashtable<?, ?> env)
066: throws NamingException {
067: return new DnsContext(domain, servers, env);
068: }
069:
070: /*
071: * "urls" are used to determine the servers, but any domain
072: * components are overridden by "domain".
073: */
074: public static DnsContext getContext(String domain, DnsUrl[] urls,
075: Hashtable env) throws NamingException {
076:
077: String[] servers = serversForUrls(urls);
078: DnsContext ctx = getContext(domain, servers, env);
079: if (platformServersUsed(urls)) {
080: ctx.setProviderUrl(constructProviderUrl(domain, servers));
081: }
082: return ctx;
083: }
084:
085: /*
086: * Public for use by product test suite.
087: */
088: public static boolean platformServersAvailable() {
089: return !ResolverConfiguration.open().nameservers().isEmpty();
090: }
091:
092: private static Context urlToContext(String url, Hashtable env)
093: throws NamingException {
094:
095: DnsUrl[] urls;
096: try {
097: urls = DnsUrl.fromList(url);
098: } catch (MalformedURLException e) {
099: throw new ConfigurationException(e.getMessage());
100: }
101: if (urls.length == 0) {
102: throw new ConfigurationException(
103: "Invalid DNS pseudo-URL(s): " + url);
104: }
105: String domain = urls[0].getDomain();
106:
107: // If multiple urls, all must have the same domain.
108: for (int i = 1; i < urls.length; i++) {
109: if (!domain.equalsIgnoreCase(urls[i].getDomain())) {
110: throw new ConfigurationException(
111: "Conflicting domains: " + url);
112: }
113: }
114: return getContext(domain, urls, env);
115: }
116:
117: /*
118: * Returns all the servers specified in a set of URLs.
119: * If a URL has no host (or port), the servers configured on the
120: * underlying platform are used if possible. If no configured
121: * servers can be found, then fall back to the old behavior of
122: * using "localhost".
123: * There must be at least one URL.
124: */
125: private static String[] serversForUrls(DnsUrl[] urls)
126: throws NamingException {
127:
128: if (urls.length == 0) {
129: throw new ConfigurationException("DNS pseudo-URL required");
130: }
131:
132: List servers = new ArrayList();
133:
134: for (int i = 0; i < urls.length; i++) {
135: String server = urls[i].getHost();
136: int port = urls[i].getPort();
137:
138: if (server == null && port < 0) {
139: // No server or port given, so look to underlying platform.
140: // ResolverConfiguration does some limited caching, so the
141: // following is reasonably efficient even if called rapid-fire.
142: List platformServers = ResolverConfiguration.open()
143: .nameservers();
144: if (!platformServers.isEmpty()) {
145: servers.addAll(platformServers);
146: continue; // on to next URL (if any, which is unlikely)
147: }
148: }
149:
150: if (server == null) {
151: server = "localhost";
152: }
153: servers.add((port < 0) ? server : server + ":" + port);
154: }
155: return (String[]) servers.toArray(new String[servers.size()]);
156: }
157:
158: /*
159: * Returns true if serversForUrls(urls) would make use of servers
160: * from the underlying platform.
161: */
162: private static boolean platformServersUsed(DnsUrl[] urls) {
163: if (!platformServersAvailable()) {
164: return false;
165: }
166: for (int i = 0; i < urls.length; i++) {
167: if (urls[i].getHost() == null && urls[i].getPort() < 0) {
168: return true;
169: }
170: }
171: return false;
172: }
173:
174: /*
175: * Returns a value for the PROVIDER_URL property (space-separated URL
176: * Strings) that reflects the given domain and servers.
177: * Each server is of the form "server[:port]".
178: * There must be at least one server.
179: * IPv6 literal host names include delimiting brackets.
180: */
181: private static String constructProviderUrl(String domain,
182: String[] servers) {
183: String path = "";
184: if (!domain.equals(".")) {
185: try {
186: path = "/" + UrlUtil.encode(domain, "ISO-8859-1");
187: } catch (java.io.UnsupportedEncodingException e) {
188: // assert false : "ISO-Latin-1 charset unavailable";
189: }
190: }
191:
192: StringBuffer buf = new StringBuffer();
193: for (int i = 0; i < servers.length; i++) {
194: if (i > 0) {
195: buf.append(' ');
196: }
197: buf.append("dns://").append(servers[i]).append(path);
198: }
199: return buf.toString();
200: }
201:
202: /*
203: * Reads environment to find URL(s) of initial context.
204: * Default URL is "dns:".
205: */
206: private static String getInitCtxUrl(Hashtable env) {
207: String url = (String) env.get(Context.PROVIDER_URL);
208: return ((url != null) ? url : DEFAULT_URL);
209: }
210: }
|